aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/App/Controller/Around.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet/App/Controller/Around.pm')
-rw-r--r--perllib/FixMyStreet/App/Controller/Around.pm300
1 files changed, 300 insertions, 0 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm
new file mode 100644
index 000000000..82d920b3e
--- /dev/null
+++ b/perllib/FixMyStreet/App/Controller/Around.pm
@@ -0,0 +1,300 @@
+package FixMyStreet::App::Controller::Around;
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'Catalyst::Controller'; }
+
+use FixMyStreet::Map;
+use List::MoreUtils qw(any);
+use Encode;
+use FixMyStreet::Map;
+use Utils;
+
+=head1 NAME
+
+FixMyStreet::App::Controller::Around - Catalyst Controller
+
+=head1 DESCRIPTION
+
+Allow the user to search for reports around a particular location.
+
+=head1 METHODS
+
+=head2 around
+
+Find the location search and display nearby reports (for pc or lat,lon).
+
+For x,y searches convert to lat,lon and 301 redirect to them.
+
+If no search redirect back to the homepage.
+
+=cut
+
+sub around_index : Path : Args(0) {
+ my ( $self, $c ) = @_;
+
+ # handle old coord systems
+ $c->forward('redirect_en_or_xy_to_latlon');
+
+ # Check if we have a partial report
+ my $partial_report = $c->forward('load_partial');
+
+ # Try to create a location for whatever we have
+ return
+ unless $c->forward('/location/determine_location_from_coords')
+ || $c->forward('/location/determine_location_from_pc');
+
+ # Check to see if the spot is covered by a council - if not show an error.
+ return unless $c->forward('check_location_is_acceptable');
+
+ # If we have a partial - redirect to /report/new so that it can be
+ # completed.
+ if ($partial_report) {
+ my $new_uri = $c->uri_for(
+ '/report/new',
+ {
+ partial => $c->stash->{partial_token}->token,
+ latitude => $c->stash->{latitude},
+ longitude => $c->stash->{longitude},
+ pc => $c->stash->{pc},
+ }
+ );
+ return $c->res->redirect($new_uri);
+ }
+
+ # Show the nearby reports
+ $c->detach('display_location');
+}
+
+=head2 redirect_en_or_xy_to_latlon
+
+ # detaches if there was a redirect
+ $c->forward('redirect_en_or_xy_to_latlon');
+
+Handle coord systems that are no longer in use.
+
+=cut
+
+sub redirect_en_or_xy_to_latlon : Private {
+ my ( $self, $c ) = @_;
+ my $req = $c->req;
+
+ # check for x,y or e,n requests
+ my $x = $req->param('x');
+ my $y = $req->param('y');
+ my $e = $req->param('e');
+ my $n = $req->param('n');
+
+ # lat and lon - fill in below if we need to
+ my ( $lat, $lon );
+
+ if ( $x || $y ) {
+ ( $lat, $lon ) = FixMyStreet::Map::tile_xy_to_wgs84( $x, $y );
+ }
+ elsif ( $e || $n ) {
+ ( $lat, $lon ) = Utils::convert_en_to_latlon_truncated( $e, $n );
+ }
+ else {
+ return;
+ }
+
+ # create a uri and redirect to it
+ my $ll_uri = $c->uri_for( '/around', { lat => $lat, lon => $lon } );
+ $c->res->redirect( $ll_uri, 301 );
+ $c->detach;
+}
+
+=head2 load_partial
+
+ my $partial_report = $c->forward('load_partial');
+
+Check for the partial token and load the partial report. If found save it and
+token to stash and return report. Otherwise return false.
+
+=cut
+
+sub load_partial : Private {
+ my ( $self, $c ) = @_;
+
+ my $partial = scalar $c->req->param('partial')
+ || return;
+
+ # is it in the database
+ my $token =
+ $c->model("DB::Token")
+ ->find( { scope => 'partial', token => $partial } ) #
+ || last;
+
+ # can we get an id from it?
+ my $report_id = $token->data #
+ || last;
+
+ # load the related problem
+ my $report = $c->cobrand->problems #
+ ->search( { id => $report_id, state => 'partial' } ) #
+ ->first
+ || last;
+
+ # save what we found on the stash.
+ $c->stash->{partial_token} = $token;
+ $c->stash->{partial_report} = $report;
+
+ return $report;
+}
+
+=head2 display_location
+
+Display a specific lat/lng location (which may have come from a pc search).
+
+=cut
+
+sub display_location : Private {
+ my ( $self, $c ) = @_;
+
+ # set the template to use
+ $c->stash->{template} = 'around/display_location.html';
+
+ # get the lat,lng
+ my $latitude = $c->stash->{latitude};
+ my $longitude = $c->stash->{longitude};
+
+ # truncate the lat,lon for nicer rss urls, and strings for outputting
+ my $short_latitude = Utils::truncate_coordinate($latitude);
+ my $short_longitude = Utils::truncate_coordinate($longitude);
+ $c->stash->{short_latitude} = $short_latitude;
+ $c->stash->{short_longitude} = $short_longitude;
+
+ # Deal with pin hiding/age
+ my $all_pins = $c->req->param('all_pins') ? 1 : undef;
+ $c->stash->{all_pins} = $all_pins;
+ my $interval = $all_pins ? undef : $c->cobrand->on_map_default_max_pin_age;
+
+ # get the map features
+ my ( $on_map_all, $on_map, $around_map, $distance ) =
+ FixMyStreet::Map::map_features( $c, $latitude, $longitude,
+ $interval );
+
+ # copy the found reports to the stash
+ $c->stash->{on_map} = $on_map;
+ $c->stash->{around_map} = $around_map;
+ $c->stash->{distance} = $distance;
+
+ # create a list of all the pins
+ my @pins;
+ unless ($c->req->param('no_pins')) {
+ @pins = map {
+ # Here we might have a DB::Problem or a DB::Nearby, we always want the problem.
+ my $p = (ref $_ eq 'FixMyStreet::App::Model::DB::Nearby') ? $_->problem : $_;
+ {
+ latitude => $p->latitude,
+ longitude => $p->longitude,
+ colour => $p->state eq 'fixed' ? 'green' : 'red',
+ id => $p->id,
+ title => $p->title,
+ }
+ } @$on_map_all, @$around_map;
+ }
+
+ FixMyStreet::Map::display_map(
+ $c,
+ latitude => $latitude,
+ longitude => $longitude,
+ clickable => 1,
+ pins => \@pins,
+ );
+
+ return 1;
+}
+
+=head2 check_location_is_acceptable
+
+Find the lat and lon in stash and check that they are acceptable to the council,
+and that they are in UK (if we are in UK).
+
+=cut
+
+sub check_location_is_acceptable : Private {
+ my ( $self, $c ) = @_;
+
+ # These should be set now
+ my $lat = $c->stash->{latitude};
+ my $lon = $c->stash->{longitude};
+
+ # If in UK and we have a lat,lon coocdinate check it is in UK
+ if ( $lat && $c->config->{COUNTRY} eq 'GB' ) {
+ eval { Utils::convert_latlon_to_en( $lat, $lon ); };
+ if ($@) {
+ $c->stash->{location_error} =
+ _( "We had a problem with the supplied co-ordinates - outside the UK?" );
+ return;
+ }
+ }
+
+ # check that there are councils that can accept this location
+ $c->stash->{council_check_action} = 'submit_problem';
+ $c->stash->{remove_redundant_councils} = 1;
+ return $c->forward('/council/load_and_check_councils');
+}
+
+=head2 /ajax
+
+Handle the ajax calls that the map makes when it is dragged. The info returned
+is used to update the pins on the map and the text descriptions on the side of
+the map.
+
+=cut
+
+sub ajax : Path('/ajax') {
+ my ( $self, $c ) = @_;
+
+ # Our current X/Y middle of visible map
+ my $x = ( $c->req->param('x') || 0 ) + 0;
+ my $y = ( $c->req->param('y') || 0 ) + 0;
+
+ # Where we started as that's the (0,0) we have to work to
+ my $sx = ( $c->req->param('sx') || 0 ) + 0;
+ my $sy = ( $c->req->param('sy') || 0 ) + 0;
+
+ # how far back should we go?
+ my $all_pins = $c->req->param('all_pins') ? 1 : undef;
+ my $interval = $all_pins ? undef : $c->cobrand->on_map_default_max_pin_age;
+
+ # extract the data from the map
+ my ( $pins, $on_map, $around_map, $dist ) =
+ FixMyStreet::Map::map_pins( $c, $x, $y, $sx, $sy, $interval );
+
+ # render templates to get the html
+ # my $on_map_list_html = $c->forward(
+ # "View::Web", "render",
+ my $on_map_list_html =
+ $c->view('Web')
+ ->render( $c, 'around/on_map_list_items.html', { on_map => $on_map } );
+
+ # my $around_map_list_html = $c->forward(
+ # "View::Web", "render",
+ my $around_map_list_html = $c->view('Web')->render(
+ $c,
+ 'around/around_map_list_items.html',
+ { around_map => $around_map, dist => $dist }
+ );
+
+ # JSON encode the response
+ my $body = JSON->new->utf8(1)->pretty(1)->encode(
+ {
+ pins => $pins,
+ current => $on_map_list_html,
+ current_near => $around_map_list_html,
+ }
+ );
+
+ # assume this is not cacheable - may need to be more fine-grained later
+ $c->res->content_type('text/javascript; charset=utf-8');
+ $c->res->header( 'Cache_Control' => 'max-age=0' );
+
+ # Set the body - note that the js needs the surrounding brackets.
+ $c->res->body("($body)");
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;