diff options
Diffstat (limited to 'web/index.cgi')
-rwxr-xr-x | web/index.cgi | 235 |
1 files changed, 157 insertions, 78 deletions
diff --git a/web/index.cgi b/web/index.cgi index e503f50ba..62a882e6b 100755 --- a/web/index.cgi +++ b/web/index.cgi @@ -16,6 +16,8 @@ use RABX; use CGI::Carp; use URI::Escape; +# use Carp::Always; + use CrossSell; use FixMyStreet::Geocode; use mySociety::AuthToken; @@ -29,6 +31,13 @@ use mySociety::PostcodeUtil; use mySociety::Random; use mySociety::VotingArea; use mySociety::Web qw(ent NewURL); +use Utils; + +sub debug (@) { + return; + my ( $format, @args ) = @_; + warn sprintf $format, map { defined $_ ? $_ : 'undef' } @args; +} BEGIN { if (!dbh()->selectrow_array('select secret from secret for update of secret')) { @@ -47,13 +56,13 @@ sub main { my $id = mySociety::AuthToken::retrieve('partial', $partial); if ($id) { my @row = dbh()->selectrow_array( - "select easting, northing, name, email, title, (photo is not null) as has_photo, phone, detail + "select latitude, longitude, name, email, title, (photo is not null) as has_photo, phone, detail from problem where id=? and state='partial'", {}, $id); if (@row) { $q->param('anonymous', 1); $q->param('submit_map', 1); - $q->param('easting', $row[0]); - $q->param('northing', $row[1]); + $q->param('latitude', $row[0]); + $q->param('longitude', $row[1]); $q->param('name', $row[2]); $q->param('email', $row[3]); $q->param('title', $row[4]); @@ -82,9 +91,11 @@ sub main { } elsif ($q->param('id')) { ($out, %params) = display_problem($q, [], {}); $params{title} .= ' - ' . _('Viewing a problem'); - } elsif ($q->param('pc') || ($q->param('x') && $q->param('y')) || ($q->param('e') && $q->param('n'))) { + } elsif ($q->param('pc') || ($q->param('x') && $q->param('y')) || ($q->param('lat') || $q->param('lon'))) { ($out, %params) = display_location($q); $params{title} = _('Viewing a location'); + } elsif ($q->param('e') && $q->param('n')) { + ($out, %params) = redirect_from_osgb_to_wgs84($q); } else { ($out, %params) = front_page($q); } @@ -253,7 +264,7 @@ sub submit_update { sub submit_problem { my $q = shift; - my @vars = qw(council title detail name email phone pc easting northing skipped anonymous category partial upload_fileid lat lon); + my @vars = qw(council title detail name email phone pc skipped anonymous category partial upload_fileid latitude longitude); my %input = map { $_ => scalar $q->param($_) } @vars; for (qw(title detail)) { $input{$_} = lc $input{$_} if $input{$_} !~ /[a-z]/; @@ -265,15 +276,17 @@ sub submit_problem { my @errors; my %field_errors; - if ($input{lat}) { + + # If in UK and we have a lat,lon coocdinate check it is in UK + if ( $input{latitude} && mySociety::Config::get('COUNTRY') eq 'GB' ) { try { - ($input{easting}, $input{northing}) = mySociety::GeoUtil::wgs84_to_national_grid($input{lat}, $input{lon}, 'G'); + mySociety::GeoUtil::wgs84_to_national_grid($input{latitude}, $input{longitude}, 'G'); } catch Error::Simple with { my $e = shift; push @errors, "We had a problem with the supplied co-ordinates - outside the UK?"; }; } - + my $fh = $q->upload('photo'); if ($fh) { my $err = Page::check_photo($q, $fh); @@ -305,8 +318,9 @@ sub submit_problem { return display_form($q, \@errors, \%field_errors) if (@errors || scalar keys %field_errors); # Short circuit my $areas; - if ($input{easting} && $input{northing}) { - $areas = mySociety::MaPit::call('point', "27700/$input{easting},$input{northing}"); + if (defined $input{latitude} && defined $input{longitude}) { + my $mapit_query = "4326/$input{longitude},$input{latitude}"; + $areas = mySociety::MaPit::call( 'point', $mapit_query ); if ($input{council} =~ /^[\d,]+(\|[\d,]+)?$/) { my $no_details = $1 || ''; my %va = map { $_ => 1 } @$mySociety::VotingArea::council_parent_types; @@ -345,10 +359,10 @@ sub submit_problem { $input{council} = join(',', @valid_councils) . $no_details; } $areas = ',' . join(',', sort keys %$areas) . ','; - } elsif ($input{easting} || $input{northing}) { + } elsif (defined $input{latitude} || defined $input{longitude}) { push(@errors, _('Somehow, you only have one co-ordinate. Please try again.')); } else { - push(@errors, _('You haven\'t specified any sort of co-ordinates. Please try again.')); + push(@errors, _("You haven't specified any sort of co-ordinates. Please try again.")); } my $image; @@ -378,10 +392,10 @@ sub submit_problem { if (my $token = $input{partial}) { my $id = mySociety::AuthToken::retrieve('partial', $token); if ($id) { - dbh()->do("update problem set postcode=?, easting=?, northing=?, title=?, detail=?, + dbh()->do("update problem set postcode=?, latitude=?, longitude=?, title=?, detail=?, name=?, email=?, phone=?, state='confirmed', council=?, used_map='t', anonymous=?, category=?, areas=?, cobrand=?, cobrand_data=?, confirmed=ms_current_timestamp(), - lastupdate=ms_current_timestamp() where id=?", {}, $input{pc}, $input{easting}, $input{northing}, + lastupdate=ms_current_timestamp() where id=?", {}, $input{pc}, $input{latitude}, $input{longitude}, $input{title}, $input{detail}, $input{name}, $input{email}, $input{phone}, $input{council}, $input{anonymous} ? 'f' : 't', $input{category}, $areas, $cobrand, $cobrand_data, $id); @@ -400,11 +414,11 @@ Please <a href="/contact">let us know what went on</a> and we\'ll look into it.' } else { $id = dbh()->selectrow_array("select nextval('problem_id_seq');"); Utils::workaround_pg_bytea("insert into problem - (id, postcode, easting, northing, title, detail, name, + (id, postcode, latitude, longitude, title, detail, name, email, phone, photo, state, council, used_map, anonymous, category, areas, lang, cobrand, cobrand_data) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'unconfirmed', ?, ?, ?, ?, ?, ?, ?, ?)", 10, - $id, $input{pc}, $input{easting}, $input{northing}, $input{title}, + $id, $input{pc}, $input{latitude}, $input{longitude}, $input{title}, $input{detail}, $input{name}, $input{email}, $input{phone}, $image, $input{council}, $used_map, $input{anonymous} ? 'f': 't', $input{category}, $areas, $mySociety::Locale::lang, $cobrand, $cobrand_data); @@ -430,22 +444,29 @@ sub display_form { push @errors, _('There were problems with your report. Please see below.') if (scalar keys %field_errors); my ($pin_x, $pin_y, $pin_tile_x, $pin_tile_y) = (0,0,0,0); - my @vars = qw(title detail name email phone pc easting northing x y skipped council anonymous partial upload_fileid lat lon); - my %input = map { $_ => $q->param($_) || '' } @vars; - my %input_h = map { $_ => $q->param($_) ? ent($q->param($_)) : '' } @vars; + my @vars = qw(title detail name email phone pc latitude longitude x y skipped council anonymous partial upload_fileid); - # Convert lat/lon to easting/northing if given - if ($input{lat}) { - try { - ($input{easting}, $input{northing}) = mySociety::GeoUtil::wgs84_to_national_grid($input{lat}, $input{lon}, 'G'); - $input_h{easting} = $input{easting}; - $input_h{northing} = $input{northing}; - } catch Error::Simple with { - my $e = shift; - push @errors, "We had a problem with the supplied co-ordinates - outside the UK?"; - }; + my %input = (); + my %input_h = (); + + foreach my $key (@vars) { + my $val = $q->param($key); + $input{$key} = defined($val) ? $val : ''; # '0' is valid for longitude + $input_h{$key} = ent( $input{$key} ); } + # Convert lat/lon to easting/northing if given + # if ($input{lat}) { + # try { + # ($input{easting}, $input{northing}) = mySociety::GeoUtil::wgs84_to_national_grid($input{lat}, $input{lon}, 'G'); + # $input_h{easting} = $input{easting}; + # $input_h{northing} = $input{northing}; + # } catch Error::Simple with { + # my $e = shift; + # push @errors, "We had a problem with the supplied co-ordinates - outside the UK?"; + # }; + # } + # Get tile co-ordinates if map clicked ($input{x}) = $input{x} =~ /^(\d+)/; $input{x} ||= 0; ($input{y}) = $input{y} =~ /^(\d+)/; $input{y} ||= 0; @@ -458,28 +479,30 @@ sub display_form { # We need either a map click, an E/N, to be skipping the map, or be filling in a partial form return display_location($q, @errors) unless ($pin_x && $pin_y) - || ($input{easting} && $input{northing}) + || ($input{latitude} && $input{longitude}) || ($input{skipped} && $input{pc}) || ($input{partial} && $input{pc}); # Work out some co-ordinates from whatever we've got - my ($easting, $northing); + my ($latitude, $longitude); if ($input{skipped}) { # Map is being skipped - if ($input{easting} && $input{northing}) { - $easting = $input{easting}; - $northing = $input{northing}; + if ( length $input{latitude} && length $input{longitude} ) { + $latitude = $input{latitude}; + $longitude = $input{longitude}; } else { - my ($e, $n, $error) = FixMyStreet::Geocode::lookup($input{pc}, $q); - $easting = $e; $northing = $n; + my ( $lat, $lon, $error ) = + FixMyStreet::Geocode::lookup( $input{pc}, $q ); + $latitude = $lat; + $longitude = $lon; } } elsif ($pin_x && $pin_y) { # tilma map was clicked on - ($easting, $northing) = FixMyStreet::Map::click_to_os($pin_tile_x, $pin_x, $pin_tile_y, $pin_y); - } elsif ($input{partial} && $input{pc} && !$input{easting} && !$input{northing}) { + ($latitude, $longitude) = FixMyStreet::Map::click_to_wgs84($pin_tile_x, $pin_x, $pin_tile_y, $pin_y); + } elsif ( $input{partial} && $input{pc} && !length $input{latitude} && !length $input{longitude} ) { my $error; try { - ($easting, $northing, $error) = FixMyStreet::Geocode::lookup($input{pc}, $q); + ($latitude, $longitude, $error) = FixMyStreet::Geocode::lookup($input{pc}, $q); } catch Error::Simple with { $error = shift; }; @@ -487,8 +510,8 @@ sub display_form { return front_page($q, $error) if $error; } else { # Normal form submission - $easting = $input_h{easting}; - $northing = $input_h{northing}; + $latitude = $input_h{latitude}; + $longitude = $input_h{longitude}; } # Look up councils and do checks for the point we've got @@ -496,7 +519,7 @@ sub display_form { $parent_types = [qw(DIS LBO MTD UTA LGD COI)] # No CTY if $q->{site} eq 'emptyhomes'; # XXX: I think we want in_gb_locale around the next line, needs testing - my $all_councils = mySociety::MaPit::call('point', "27700/$easting,$northing", type => $parent_types); + my $all_councils = mySociety::MaPit::call('point', "4326/$longitude,$latitude", type => $parent_types); # Let cobrand do a check my ($success, $error_msg) = Cobrand::council_check($cobrand, { all_councils => $all_councils }, $q, 'submit_problem'); @@ -504,10 +527,10 @@ sub display_form { return front_page($q, $error_msg); } - # Ipswich & St Edmundsbury are responsible for everything in their areas, no Suffolk + # Ipswich & St Edmundsbury are responsible for everything in their areas, not Suffolk delete $all_councils->{2241} if $all_councils->{2446} || $all_councils->{2443}; - # Norwich is responsible for everything in its areas, no Norfolk + # Norwich is responsible for everything in its areas, not Norfolk delete $all_councils->{2233} if $all_councils->{2391}; return display_location($q, _('That spot does not appear to be covered by a council. @@ -587,9 +610,9 @@ EOF $type = 1; } $vars{form_start} = FixMyStreet::Map::display_map($q, - easting => $easting, northing => $northing, + latitude => $latitude, longitude => $longitude, type => $type, - pins => [ [ $easting, $northing, 'purple' ] ], + pins => [ [ $latitude, $longitude, 'purple' ] ], ); my $partial_id; if (my $token = $input{partial}) { @@ -683,8 +706,8 @@ photo of the problem if you have one), etc.')); } $vars{text_help} .= ' -<input type="hidden" name="easting" value="' . $easting . '"> -<input type="hidden" name="northing" value="' . $northing . '">'; +<input type="hidden" name="latitude" value="' . $latitude . '"> +<input type="hidden" name="longitude" value="' . $longitude . '">'; if (@errors) { $vars{errors} = '<ul class="error"><li>' . join('</li><li>', @errors) . '</li></ul>'; @@ -763,40 +786,87 @@ EOF return (Page::template_include('report-form', $q, Page::template_root($q), %vars), robots => 'noindex,nofollow'); } +# redirect from osgb +sub redirect_from_osgb_to_wgs84 { + my ($q) = @_; + + my $e = $q->param('e'); + my $n = $q->param('n'); + + my ( $lat, $lon ) = Utils::convert_en_to_latlon_truncated( $e, $n ); + + my $lat_lon_url = NewURL( + $q, + -retain => 1, + e => undef, + n => undef, + lat => $lat, + lon => $lon + ); + + print $q->redirect( + -location => $lat_lon_url, + -status => 301, # permanent + ); + + return ''; +} + sub display_location { my ($q, @errors) = @_; my $cobrand = Page::get_cobrand($q); - my @vars = qw(pc x y e n all_pins no_pins); - my %input = map { $_ => $q->param($_) || '' } @vars; - my %input_h = map { $_ => $q->param($_) ? ent($q->param($_)) : '' } @vars; + my @vars = qw(pc x y lat lon all_pins no_pins); - (my $easting) = $input{e} =~ /^(\d+)/; $easting ||= 0; - (my $northing) = $input{n} =~ /^(\d+)/; $northing ||= 0; + my %input = (); + my %input_h = (); + + foreach my $key (@vars) { + my $val = $q->param($key); + $input{$key} = defined($val) ? $val : ''; # '0' is valid for longitude + $input_h{$key} = ent( $input{$key} ); + } + + my $latitude = $input{lat}; + my $longitude = $input{lon}; # X/Y referring to tiles old-school (my $x) = $input{x} =~ /^(\d+)/; $x ||= 0; (my $y) = $input{y} =~ /^(\d+)/; $y ||= 0; - return front_page($q, @errors) unless $x || $y || $input{pc} || $easting || $northing; - if ($x && $y) { + return front_page( $q, @errors ) + unless ( $x && $y ) + || $input{pc} + || ( defined $latitude && defined $longitude ); + + if ( $x && $y ) { + # Convert the tile co-ordinates to real ones. - $easting = FixMyStreet::Map::tile_to_os($x); - $northing = FixMyStreet::Map::tile_to_os($y); - } elsif ($easting && $northing) { + ( $latitude, $longitude ) = + FixMyStreet::Map::tile_xy_to_wgs84( $x, $y ); + } + elsif ( $latitude && $longitude ) { + # Don't need to do anything - } else { + } + else { my $error; try { - ($easting, $northing, $error) = FixMyStreet::Geocode::lookup($input{pc}, $q); - } catch Error::Simple with { + ( $latitude, $longitude, $error ) = + FixMyStreet::Geocode::lookup( $input{pc}, $q ); + + debug 'Looked up postcode "%s": lat: "%s", lon: "%s", error: "%s"', + $input{pc}, $latitude, $longitude, $error; + } + catch Error::Simple with { $error = shift; }; - return FixMyStreet::Geocode::list_choices($error, '/', $q) if (ref($error) eq 'ARRAY'); - return front_page($q, $error) if $error; + return FixMyStreet::Geocode::list_choices( $error, '/', $q ) + if ( ref($error) eq 'ARRAY' ); + return front_page( $q, $error ) if $error; } # Check this location is okay to be displayed for the cobrand - my ($success, $error_msg) = Cobrand::council_check($cobrand, { e => $easting, n => $northing }, $q, 'display_location'); + my ($success, $error_msg) = Cobrand::council_check($cobrand, { lat => $latitude, lon => $longitude }, $q, 'display_location'); return front_page($q, $error_msg) unless $success; # Deal with pin hiding/age @@ -810,10 +880,10 @@ sub display_location { $interval = '6 months'; } - my ($on_map_all, $on_map, $around_map, $dist) = FixMyStreet::Map::map_features($q, $easting, $northing, $interval); + my ($on_map_all, $on_map, $around_map, $dist) = FixMyStreet::Map::map_features($q, $latitude, $longitude, $interval); my @pins; foreach (@$on_map_all) { - push @pins, [ $_->{easting}, $_->{northing}, $_->{state} eq 'fixed' ? 'green' : 'red' ]; + push @pins, [ $_->{latitude}, $_->{longitude}, $_->{state} eq 'fixed' ? 'green' : 'red' ]; } my $on_list = ''; foreach (@$on_map) { @@ -839,7 +909,7 @@ sub display_location { $around_list .= $dist . 'km)</small>'; $around_list .= ' <small>' . _('(fixed)') . '</small>' if $_->{state} eq 'fixed'; $around_list .= '</li>'; - push @pins, [ $_->{easting}, $_->{northing}, $_->{state} eq 'fixed' ? 'green' : 'red' ]; + push @pins, [ $_->{latitude}, $_->{longitude}, $_->{state} eq 'fixed' ? 'green' : 'red' ]; } $around_list = $q->li(_('No problems found.')) unless $around_list; @@ -856,21 +926,27 @@ sub display_location { my $url_skip = NewURL($q, -retain=>1, pc => undef, x => undef, 'y' => undef, - easting => $easting, northing => $northing, + latitude => $latitude, longitude => $longitude, 'submit_map'=>1, skipped=>1 ); my $pc_h = ent($q->param('pc') || ''); + + # truncate the lat,lon for nicer rss urls + my ( $short_lat, $short_lon ) = + map { Utils::truncate_coordinate($_) } # + ( $latitude, $longitude ); + my %vars = ( 'map' => FixMyStreet::Map::display_map($q, - easting => $easting, northing => $northing, + latitude => $latitude, longitude => $longitude, type => 1, pins => \@pins, post => $map_links ), map_end => FixMyStreet::Map::display_map_end(1), url_home => Cobrand::url($cobrand, '/', $q), - url_rss => Cobrand::url($cobrand, NewURL($q, -retain => 1, -url=> "/rss/n/$easting,$northing", pc => undef, x => undef, 'y' => undef), $q), - url_email => Cobrand::url($cobrand, NewURL($q, -retain => 1, pc => undef, -url=>'/alert', e=>$easting, 'n'=>$northing, feed=>"local:$easting:$northing"), $q), + url_rss => Cobrand::url($cobrand, NewURL($q, -retain => 1, -url=> "/rss/l/$short_lat,$short_lon", pc => undef, x => undef, y => undef, lat => undef, lon => undef ), $q), + url_email => Cobrand::url($cobrand, NewURL($q, -retain => 1, pc => undef, lat => $short_lat, lon => $short_lon, -url=>'/alert', feed=>"local:$short_lat:$short_lon"), $q), url_skip => $url_skip, email_me => _('Email me new local problems'), rss_alt => _('RSS feed'), @@ -890,7 +966,7 @@ sub display_location { ); my %params = ( - rss => [ _('Recent local problems, FixMyStreet'), "/rss/n/$easting,$northing" ], + rss => [ _('Recent local problems, FixMyStreet'), "/rss/l/$short_lat,$short_lon" ], robots => 'noindex,nofollow', ); @@ -931,9 +1007,12 @@ sub display_problem { my $extra_data = Cobrand::extra_data($cobrand, $q); my $google_link = Cobrand::base_url_for_emails($cobrand, $extra_data) . '/report/' . $problem->{id}; - my ($lat, $lon) = mySociety::GeoUtil::national_grid_to_wgs84($problem->{easting}, $problem->{northing}, 'G'); - my $map_links = "<p id='sub_map_links'><a href=\"http://maps.google.co.uk/maps?output=embed&z=16&q=" - . URI::Escape::uri_escape_utf8($problem->{title} . ' - ' . $google_link) . "\@$lat,$lon\">View on Google Maps</a></p>"; + + my $map_links = + "<p id='sub_map_links'>" + . "<a href=\"http://maps.google.co.uk/maps?output=embed&z=16&q=" + . URI::Escape::uri_escape_utf8( $problem->{title} . ' - ' . $google_link ) + . "\@$problem->{latitude},$problem->{longitude}\">View on Google Maps</a></p>"; my $banner; if ($q->{site} ne 'emptyhomes' && $problem->{state} eq 'confirmed' && $problem->{duration} > 8*7*24*60*60) { @@ -945,7 +1024,7 @@ sub display_problem { my $contact_url = Cobrand::url($cobrand, NewURL($q, -retain => 1, pc => undef, x => undef, 'y' => undef, -url=>'/contact?id=' . $input{id}), $q); my $back = Cobrand::url($cobrand, NewURL($q, -url => '/', - 'e' => int($problem->{easting}), 'n' => int($problem->{northing}), + lat => $problem->{latitude}, lon => $problem->{longitude}, -retain => 1, pc => undef, x => undef, 'y' => undef, id => undef ), $q); my $fixed = ($input{fixed}) ? ' checked' : ''; @@ -953,9 +1032,9 @@ sub display_problem { my %vars = ( banner => $banner, map_start => FixMyStreet::Map::display_map($q, - easting => $problem->{easting}, northing => $problem->{northing}, + latitude => $problem->{latitude}, longitude => $problem->{longitude}, type => 0, - pins => [ [ $problem->{easting}, $problem->{northing}, 'blue' ] ], + pins => [ [ $problem->{latitude}, $problem->{longitude}, 'blue' ] ], post => $map_links ), map_end => FixMyStreet::Map::display_map_end(0), |