aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet
diff options
context:
space:
mode:
authorMatthew Somerville <matthew@mysociety.org>2012-12-04 16:10:44 +0000
committerMatthew Somerville <matthew@mysociety.org>2012-12-04 16:10:44 +0000
commit93e01b6bf2017f308b85301016f16d7e3619b314 (patch)
tree931c9168347b4fe5e33374cf3de31604b40061a5 /perllib/FixMyStreet
parent429f5b61f56519914dd38c0e62d0709d4d380dee (diff)
Add Zurich geocoder (and allow geocoder choice to be picked in config).
Diffstat (limited to 'perllib/FixMyStreet')
-rw-r--r--perllib/FixMyStreet/App/Controller/Location.pm1
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm1
-rw-r--r--perllib/FixMyStreet/Cobrand/Bromley.pm2
-rw-r--r--perllib/FixMyStreet/Cobrand/Default.pm1
-rw-r--r--perllib/FixMyStreet/Geocode.pm24
-rw-r--r--perllib/FixMyStreet/Geocode/Bing.pm9
-rw-r--r--perllib/FixMyStreet/Geocode/Google.pm7
-rw-r--r--perllib/FixMyStreet/Geocode/OSM.pm7
-rw-r--r--perllib/FixMyStreet/Geocode/Zurich.pm90
9 files changed, 130 insertions, 12 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Location.pm b/perllib/FixMyStreet/App/Controller/Location.pm
index e8bf2cd1c..fd3fadd9f 100644
--- a/perllib/FixMyStreet/App/Controller/Location.pm
+++ b/perllib/FixMyStreet/App/Controller/Location.pm
@@ -5,6 +5,7 @@ use namespace::autoclean;
BEGIN {extends 'Catalyst::Controller'; }
use Encode;
+use FixMyStreet::Geocode;
=head1 NAME
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index dedd447ee..ba45a90ab 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -4,7 +4,6 @@ use Moose;
use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller'; }
-use FixMyStreet::Geocode;
use Encode;
use List::MoreUtils qw(uniq);
use POSIX 'strcoll';
diff --git a/perllib/FixMyStreet/Cobrand/Bromley.pm b/perllib/FixMyStreet/Cobrand/Bromley.pm
index c33135673..a4c4f4ffc 100644
--- a/perllib/FixMyStreet/Cobrand/Bromley.pm
+++ b/perllib/FixMyStreet/Cobrand/Bromley.pm
@@ -29,7 +29,7 @@ sub disambiguate_location {
my $town = 'Bromley';
# Bing turns High St Bromley into Bromley High St which is in
# Bromley by Bow.
- if ( $string =~ /high\+st/i ) {
+ if ( $string =~ /high\s+st/i ) {
$town .= ', BR1';
}
return {
diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm
index cc8f6c526..86ea693b7 100644
--- a/perllib/FixMyStreet/Cobrand/Default.pm
+++ b/perllib/FixMyStreet/Cobrand/Default.pm
@@ -4,6 +4,7 @@ use base 'FixMyStreet::Cobrand::Base';
use strict;
use warnings;
use FixMyStreet;
+use FixMyStreet::Geocode::Bing;
use Encode;
use URI;
use Digest::MD5 qw(md5_hex);
diff --git a/perllib/FixMyStreet/Geocode.pm b/perllib/FixMyStreet/Geocode.pm
index f92e9cc9a..6cfd960ed 100644
--- a/perllib/FixMyStreet/Geocode.pm
+++ b/perllib/FixMyStreet/Geocode.pm
@@ -13,6 +13,7 @@ use URI::Escape;
use FixMyStreet::Geocode::Bing;
use FixMyStreet::Geocode::Google;
use FixMyStreet::Geocode::OSM;
+use FixMyStreet::Geocode::Zurich;
# lookup STRING CONTEXT
# Given a user-inputted string, try and convert it into co-ordinates using either
@@ -33,18 +34,27 @@ sub lookup {
# Canonicalises, and then passes to some external API to look stuff up.
sub string {
my ($s, $c) = @_;
+
+ my $service = $c->config->{GEOCODER};
+ $service = $service->{type} if ref $service;
+ $service = 'OSM' unless $service =~ /^(Bing|Google|OSM|Zurich)$/;
+ $service = 'OSM' if $service eq 'Bing' && !FixMyStreet->config('BING_MAPS_API_KEY');
+ $service = "FixMyStreet::Geocode::${service}::string";
+
+ no strict 'refs';
+ return &$service($s, $c);
+}
+
+# escape STRING CONTEXT
+# Escapes string for putting in URL geocoding call
+sub escape {
+ my ($s, $c) = @_;
$s = lc($s);
$s =~ s/[^-&\w ']/ /g;
$s =~ s/\s+/ /g;
$s = URI::Escape::uri_escape_utf8($s);
$s =~ s/%20/+/g;
- my $params = $c->cobrand->disambiguate_location($s);
- return FixMyStreet::Geocode::Bing::string($s, $c, $params)
- if FixMyStreet->config('BING_MAPS_API_KEY');
- # Fall back to Google API, which allow access with and without a key
- return FixMyStreet::Geocode::Google::string($s, $c, $params)
- if FixMyStreet->config('GOOGLE_MAPS_API_KEY');
- return FixMyStreet::Geocode::OSM::string($s, $c, $params);
+ return $s;
}
1;
diff --git a/perllib/FixMyStreet/Geocode/Bing.pm b/perllib/FixMyStreet/Geocode/Bing.pm
index 18e6b56ce..85eef3d0f 100644
--- a/perllib/FixMyStreet/Geocode/Bing.pm
+++ b/perllib/FixMyStreet/Geocode/Bing.pm
@@ -15,14 +15,21 @@ use File::Path ();
use LWP::Simple;
use Digest::MD5 qw(md5_hex);
+use mySociety::Locale;
+
# string STRING CONTEXT
# Looks up on Bing Maps API, and caches, a user-inputted location.
# Returns array of (LAT, LON, ERROR), where ERROR is either undef, a string, or
# an array of matches if there are more than one. The information in the query
# may be used to disambiguate the location in cobranded versions of the site.
sub string {
- my ( $s, $c, $params ) = @_;
+ my ( $s, $c ) = @_;
+
+ my $params = $c->cobrand->disambiguate_location($s);
+
+ $s = FixMyStreet::Geocode::escape($s);
$s .= '+' . $params->{town} if $params->{town} and $s !~ /$params->{town}/i;
+
my $url = "http://dev.virtualearth.net/REST/v1/Locations?q=$s";
$url .= '&userMapView=' . join(',', @{$params->{bounds}})
if $params->{bounds};
diff --git a/perllib/FixMyStreet/Geocode/Google.pm b/perllib/FixMyStreet/Geocode/Google.pm
index db3a8ae91..fd65b89b1 100644
--- a/perllib/FixMyStreet/Geocode/Google.pm
+++ b/perllib/FixMyStreet/Geocode/Google.pm
@@ -14,6 +14,7 @@ use File::Slurp;
use File::Path ();
use LWP::Simple;
use Digest::MD5 qw(md5_hex);
+use mySociety::Locale;
# string STRING CONTEXT
# Looks up on Google Maps API, and caches, a user-inputted location.
@@ -21,7 +22,11 @@ use Digest::MD5 qw(md5_hex);
# an array of matches if there are more than one. The information in the query
# may be used to disambiguate the location in cobranded versions of the site.
sub string {
- my ( $s, $c, $params ) = @_;
+ my ( $s, $c ) = @_;
+
+ my $params = $c->cobrand->disambiguate_location($s);
+
+ $s = FixMyStreet::Geocode::escape($s);
my $url = 'http://maps.google.com/maps/geo?q=' . $s;
$url .= '&ll=' . $params->{centre} if $params->{centre};
diff --git a/perllib/FixMyStreet/Geocode/OSM.pm b/perllib/FixMyStreet/Geocode/OSM.pm
index d96338c16..fd14b0acc 100644
--- a/perllib/FixMyStreet/Geocode/OSM.pm
+++ b/perllib/FixMyStreet/Geocode/OSM.pm
@@ -29,8 +29,13 @@ my $nominatimbase = "http://nominatim.openstreetmap.org/";
# an array of matches if there are more than one. The information in the query
# may be used to disambiguate the location in cobranded versions of the site.
sub string {
- my ( $s, $c, $params ) = @_;
+ my ( $s, $c ) = @_;
+
+ my $params = $c->cobrand->disambiguate_location($s);
+
+ $s = FixMyStreet::Geocode::escape($s);
$s .= '+' . $params->{town} if $params->{town} and $s !~ /$params->{town}/i;
+
my $url = "${nominatimbase}search?";
my %query_params = (
q => $s,
diff --git a/perllib/FixMyStreet/Geocode/Zurich.pm b/perllib/FixMyStreet/Geocode/Zurich.pm
new file mode 100644
index 000000000..9cffc7a32
--- /dev/null
+++ b/perllib/FixMyStreet/Geocode/Zurich.pm
@@ -0,0 +1,90 @@
+#!/usr/bin/perl
+#
+# FixMyStreet::Geocode::Zurich
+# Geocoding with Zurich web service.
+#
+# Thanks to http://msdn.microsoft.com/en-us/library/ms995764.aspx
+# and http://noisemore.wordpress.com/2009/03/19/perl-soaplite-wsse-web-services-security-soapheader/
+# for SOAP::Lite pointers
+#
+# Copyright (c) 2012 UK Citizens Online Democracy. All rights reserved.
+# Email: matthew@mysociety.org; WWW: http://www.mysociety.org/
+
+package FixMyStreet::Geocode::Zurich;
+
+use strict;
+use Geo::Coordinates::CH1903;
+use SOAP::Lite;
+use mySociety::Locale;
+
+my ($soap, $method, $security);
+
+sub setup_soap {
+ return if $soap;
+
+ # Variables for the SOAP web service
+ my $geocoder = FixMyStreet->config('GEOCODER');
+ my $url = $geocoder->{url};
+ my $username = $geocoder->{username};
+ my $password = $geocoder->{password};
+ my $attr = 'http://ch/geoz/fixmyzuerich/service';
+ my $action = "$attr/IFixMyZuerich/";
+
+ # Set up the SOAP handler
+ $security = SOAP::Header->name("Security")->attr({
+ 'mustUnderstand' => 'true',
+ 'xmlns' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
+ })->value(
+ \SOAP::Header->name(
+ "UsernameToken" => \SOAP::Header->value(
+ SOAP::Header->name('Username', $username),
+ SOAP::Header->name('Password', $password)
+ )
+ )
+ );
+ $soap = SOAP::Lite->on_action( sub { $action . $_[1]; } )->proxy($url);
+ $method = SOAP::Data->name('getLocation')->attr({ xmlns => $attr });
+}
+
+# string STRING CONTEXT
+# Looks up on Zurich web service a user-inputted location.
+# Returns array of (LAT, LON, ERROR), where ERROR is either undef, a string, or
+# an array of matches if there are more than one. The information in the query
+# may be used to disambiguate the location in cobranded versions of the site.
+sub string {
+ my ( $s, $c ) = @_;
+
+ setup_soap();
+
+ my $search = SOAP::Data->name('search' => $s)->type('');
+ my $count = SOAP::Data->name('count' => 10)->type('');
+ my $result = $soap->call($method, $security, $search, $count);
+ $result = $result->result;
+
+ if (!$result || !$result->{Location}) {
+ return { error => _('Sorry, we could not parse that location. Please try again.') };
+ }
+
+ my $results = $result->{Location};
+ $results = [ $results ] unless ref $results eq 'ARRAY';
+
+ my ( $error, @valid_locations, $latitude, $longitude );
+ foreach (@$results) {
+ ($latitude, $longitude) = Geo::Coordinates::CH1903::to_latlon($_->{easting}, $_->{northing});
+ mySociety::Locale::in_gb_locale {
+ push (@$error, {
+ address => $_->{text},
+ latitude => sprintf('%0.6f', $latitude),
+ longitude => sprintf('%0.6f', $longitude)
+ });
+ };
+ push (@valid_locations, $_);
+ last if lc($_->{text}) eq lc($s);
+ }
+
+ return { latitude => $latitude, longitude => $longitude } if scalar @valid_locations == 1;
+ return { error => $error };
+}
+
+1;
+