aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/Page.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/Page.pm')
-rw-r--r--perllib/Page.pm120
1 files changed, 118 insertions, 2 deletions
diff --git a/perllib/Page.pm b/perllib/Page.pm
index 5fd8a665d..ad6e25cb9 100644
--- a/perllib/Page.pm
+++ b/perllib/Page.pm
@@ -6,7 +6,7 @@
# Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
# Email: matthew@mysociety.org; WWW: http://www.mysociety.org/
#
-# $Id: Page.pm,v 1.62 2007-08-27 11:47:55 matthew Exp $
+# $Id: Page.pm,v 1.63 2007-08-29 23:03:16 matthew Exp $
#
package Page;
@@ -17,10 +17,14 @@ use CGI::Fast qw(-no_xhtml);
use Error qw(:try);
use File::Slurp;
use LWP::Simple;
+use Digest::MD5 qw(md5_hex);
use POSIX qw(strftime);
+use URI::Escape;
use mySociety::Config;
-use mySociety::DBHandle qw/select_all/;
+use mySociety::DBHandle qw/dbh select_all/;
use mySociety::EvEl;
+use mySociety::MaPit;
+use mySociety::PostcodeUtil;
use mySociety::WatchUpdate;
use mySociety::Web qw(ent NewURL);
BEGIN {
@@ -52,6 +56,7 @@ sub do_fastcgi {
qq(<blockquote class="errortext">$msg</blockquote>),
q(</body></html);
};
+ dbh()->rollback() if $mySociety::DBHandle::conf_ok;
}
=item header Q [PARAM VALUE ...]
@@ -110,12 +115,19 @@ EOF
=cut
sub footer {
+ my $q = shift;
+ my $pc = '';
+ if ($q) {
+ $pc = $q->param('pc') || '';
+ $pc = "?pc=" . ent($pc) if $pc;
+ }
return <<EOF;
</div></div>
<h2 class="v">Navigation</h2>
<ul id="navigation">
<li><a href="/">Report a problem</a></li>
<li><a href="/reports">All reports</a></li>
+<li id="nav_new"><a href="/alert$pc">Local alerts</a></li>
<li><a href="/faq">Help</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
@@ -438,4 +450,108 @@ sub display_problem_updates {
return $out;
}
+# geocode STRING
+# Given a user-inputted string, try and convert it into co-ordinates using either
+# MaPit if it's a postcode, or Google Maps API otherwise. Returns an array of
+# data, including an error if there is one (which includes a location being in
+# Northern Ireland).
+sub geocode {
+ my ($s) = @_;
+ my ($x, $y, $easting, $northing, $error);
+ if (mySociety::PostcodeUtil::is_valid_postcode($s)) {
+ try {
+ my $location = mySociety::MaPit::get_location($s);
+ my $island = $location->{coordsyst};
+ throw RABX::Error("We do not cover Northern Ireland, I'm afraid, as our licence doesn't include any maps for the region.") if $island eq 'I';
+ $easting = $location->{easting};
+ $northing = $location->{northing};
+ my $xx = Page::os_to_tile($easting);
+ my $yy = Page::os_to_tile($northing);
+ $x = int($xx);
+ $y = int($yy);
+ $x -= 1 if ($xx - $x < 0.5);
+ $y -= 1 if ($yy - $y < 0.5);
+ } catch RABX::Error with {
+ my $e = shift;
+ if ($e->value() && ($e->value() == mySociety::MaPit::BAD_POSTCODE
+ || $e->value() == mySociety::MaPit::POSTCODE_NOT_FOUND)) {
+ $error = 'That postcode was not recognised, sorry.';
+ } else {
+ $error = $e;
+ }
+ }
+ } else {
+ ($x, $y, $easting, $northing, $error) = geocode_string($s);
+ }
+ return ($x, $y, $easting, $northing, $error);
+}
+
+# geocode_string STRING
+# Canonicalises, looks up on Google Maps API, and caches, a user-inputted location.
+# Returns array of (TILE_X, TILE_Y, EASTING, NORTHING, ERROR), where ERROR is
+# either undef, a string, or an array of matches if there are more than one.
+sub geocode_string {
+ my $s = shift;
+ $s = lc($s);
+ $s =~ s/[^-&0-9a-z ']/ /g;
+ $s =~ s/\s+/ /g;
+ $s = uri_escape($s);
+ $s =~ s/%20/+/g;
+ my $url = 'http://maps.google.com/maps/geo?q=' . $s;
+ my $cache_dir = mySociety::Config::get('GEO_CACHE');
+ my $cache_file = $cache_dir . md5_hex($url);
+ my ($js, $error, $x, $y, $easting, $northing);
+ if (-s $cache_file) {
+ $js = File::Slurp::read_file($cache_file);
+ } else {
+ $url .= ',+United+Kingdom' unless $url =~ /united\++kingdom$/ || $url =~ /uk$/i;
+ $url .= '&key=' . mySociety::Config::get('GOOGLE_MAPS_API_KEY');
+ $js = LWP::Simple::get($url);
+ File::Slurp::write_file($cache_file, $js) if $js;
+ }
+
+ if (!$js) {
+ $error = 'Sorry, we had a problem parsing that location. Please try again.';
+ } elsif ($js =~ /BT\d/) {
+ # Northern Ireland, hopefully
+ $error = "We do not cover Northern Ireland, I'm afraid, as our licence doesn't include any maps for the region.";
+ } elsif ($js !~ /"code":200/) {
+ $error = 'Sorry, we could not understand that location.';
+ } elsif ($js =~ /},{/) { # Multiple
+ while ($js =~ /"address":"(.*?)"/g) {
+ push (@$error, $1);
+ }
+ $error = 'Sorry, we could not understand that location.' unless $error;
+ } else {
+ my ($accuracy) = $js =~ /"Accuracy": (\d)/;
+ if ($accuracy < 5) {
+ $error = 'Sorry, that location appears to be too general; please be more specific.';
+ } else {
+ $js =~ /"coordinates":\[(.*?),(.*?),/;
+ my $lon = $1; my $lat = $2;
+ ($easting, $northing) = mySociety::GeoUtil::wgs84_to_national_grid($lat, $lon, 'G');
+ my $xx = Page::os_to_tile($easting);
+ my $yy = Page::os_to_tile($northing);
+ $x = int($xx);
+ $y = int($yy);
+ $x -= 1 if ($xx - $x < 0.5);
+ $y -= 1 if ($yy - $y < 0.5);
+ }
+ }
+ return ($x, $y, $easting, $northing, $error);
+}
+
+sub short_name {
+ my $name = shift;
+ # Special case Durham as it's the only place with two councils of the same name
+ return 'Durham+County' if ($name eq 'Durham County Council');
+ return 'Durham+City' if ($name eq 'Durham City Council');
+ $name =~ s/ (Borough|City|District|County) Council$//;
+ $name =~ s/ Council$//;
+ $name =~ s/ & / and /;
+ $name = uri_escape($name);
+ $name =~ s/%20/+/g;
+ return $name;
+}
+
1;