aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet')
-rw-r--r--perllib/FixMyStreet/App.pm3
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm77
-rw-r--r--perllib/FixMyStreet/App/Controller/Alert.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Around.pm3
-rw-r--r--perllib/FixMyStreet/App/Controller/Contact.pm7
-rw-r--r--perllib/FixMyStreet/App/Controller/Council.pm1
-rw-r--r--perllib/FixMyStreet/App/Controller/Dashboard.pm2
-rwxr-xr-xperllib/FixMyStreet/App/Controller/JS.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Location.pm44
-rw-r--r--perllib/FixMyStreet/App/Controller/Open311.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Photo.pm3
-rwxr-xr-xperllib/FixMyStreet/App/Controller/Questionnaire.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm24
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm86
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/Update.pm5
-rw-r--r--perllib/FixMyStreet/App/Controller/Reports.pm75
-rw-r--r--perllib/FixMyStreet/App/Controller/Root.pm7
-rwxr-xr-xperllib/FixMyStreet/App/Controller/Rss.pm13
-rw-r--r--perllib/FixMyStreet/App/View/Web.pm1
-rw-r--r--perllib/FixMyStreet/Cobrand/Bromley.pm6
-rw-r--r--perllib/FixMyStreet/Cobrand/Default.pm147
-rw-r--r--perllib/FixMyStreet/Cobrand/FiksGataMi.pm2
-rw-r--r--perllib/FixMyStreet/Cobrand/FixMyBarangay.pm54
-rw-r--r--perllib/FixMyStreet/Cobrand/LichfieldDC.pm12
-rw-r--r--perllib/FixMyStreet/Cobrand/Oxfordshire.pm55
-rw-r--r--perllib/FixMyStreet/Cobrand/SeeSomething.pm148
-rw-r--r--perllib/FixMyStreet/Cobrand/Stevenage.pm41
-rw-r--r--perllib/FixMyStreet/Cobrand/UK.pm23
-rw-r--r--perllib/FixMyStreet/Cobrand/UKCouncils.pm14
-rw-r--r--perllib/FixMyStreet/Cobrand/Zurich.pm16
-rw-r--r--perllib/FixMyStreet/DB/Result/Comment.pm12
-rw-r--r--perllib/FixMyStreet/DB/Result/Contact.pm14
-rw-r--r--perllib/FixMyStreet/DB/Result/Open311conf.pm7
-rw-r--r--perllib/FixMyStreet/DB/Result/Problem.pm26
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/AlertType.pm27
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Nearby.pm1
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Problem.pm97
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm7
-rw-r--r--perllib/FixMyStreet/EmailSend.pm5
-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.pm13
-rw-r--r--perllib/FixMyStreet/Geocode/Zurich.pm107
-rw-r--r--perllib/FixMyStreet/Map.pm25
-rw-r--r--perllib/FixMyStreet/Map/OSM.pm25
-rw-r--r--perllib/FixMyStreet/Map/Zurich.pm177
-rw-r--r--perllib/FixMyStreet/SendReport.pm10
-rw-r--r--perllib/FixMyStreet/SendReport/Email.pm13
-rw-r--r--perllib/FixMyStreet/SendReport/EmptyHomes.pm2
-rw-r--r--perllib/FixMyStreet/SendReport/NI.pm2
-rw-r--r--perllib/FixMyStreet/SendReport/Open311.pm51
-rw-r--r--perllib/FixMyStreet/TestMech.pm107
53 files changed, 1428 insertions, 217 deletions
diff --git a/perllib/FixMyStreet/App.pm b/perllib/FixMyStreet/App.pm
index fda9d665c..9c7aba9e5 100644
--- a/perllib/FixMyStreet/App.pm
+++ b/perllib/FixMyStreet/App.pm
@@ -274,9 +274,8 @@ sub send_email {
my $template = shift;
my $extra_stash_values = shift || {};
- my $sender = $c->cobrand->contact_email;
+ my $sender = $c->config->{DO_NOT_REPLY_EMAIL};
my $sender_name = $c->cobrand->contact_name;
- $sender =~ s/team/fms-DO-NOT-REPLY/;
# create the vars to pass to the email template
my $vars = {
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm
index 54d744ccd..e14c7dc66 100644
--- a/perllib/FixMyStreet/App/Controller/Admin.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin.pm
@@ -7,6 +7,7 @@ BEGIN { extends 'Catalyst::Controller'; }
use POSIX qw(strftime strcoll);
use Digest::MD5 qw(md5_hex);
use mySociety::EmailUtil qw(is_valid_email);
+use if !$ENV{TRAVIS}, 'Image::Magick';
use FixMyStreet::SendReport;
@@ -32,6 +33,11 @@ sub begin : Private {
my ( $self, $c ) = @_;
$c->uri_disposition('relative');
+
+ if ( $c->cobrand->moniker eq 'seesomething' ) {
+ $c->detach( '/auth/redirect' ) unless $c->user_exists;
+ $c->detach( '/auth/redirect' ) unless $c->user->from_council;
+ }
}
sub summary : Path( 'summary' ) : Args(0) {
@@ -299,9 +305,14 @@ sub update_contacts : Private {
$contact->email( $email );
$contact->confirmed( $c->req->param('confirmed') ? 1 : 0 );
$contact->deleted( $c->req->param('deleted') ? 1 : 0 );
+ $contact->non_public( $c->req->param('non_public') ? 1 : 0 );
$contact->note( $c->req->param('note') );
$contact->whenedited( \'ms_current_timestamp()' );
$contact->editor( $editor );
+ $contact->endpoint( $c->req->param('endpoint') );
+ $contact->jurisdiction( $c->req->param('jurisdiction') );
+ $contact->api_key( $c->req->param('api_key') );
+ $contact->send_method( $c->req->param('send_method') );
if ( $contact->in_storage ) {
$c->stash->{updated} = _('Values updated');
@@ -338,7 +349,7 @@ sub update_contacts : Private {
} elsif ( $posted eq 'open311' ) {
$c->forward('check_token');
- my %params = map { $_ => $c->req->param($_) || '' } qw/open311_id endpoint jurisdiction api_key area_id send_method send_comments suppress_alerts extended_statuses comment_user_id/;
+ my %params = map { $_ => $c->req->param($_) || '' } qw/open311_id endpoint jurisdiction api_key area_id send_method send_comments suppress_alerts extended_statuses comment_user_id devolved/;
if ( $params{open311_id} ) {
my $conf = $c->model('DB::Open311Conf')->find( { id => $params{open311_id} } );
@@ -350,6 +361,7 @@ sub update_contacts : Private {
$conf->send_comments( $params{send_comments} || 0);
$conf->suppress_alerts( $params{suppress_alerts} || 0);
$conf->comment_user_id( $params{comment_user_id} || undef );
+ $conf->can_be_devolved( $params{devolved} || 0 );
$conf->send_extended_statuses( $params{extended_statuses} || 0 );
$conf->update();
@@ -365,6 +377,7 @@ sub update_contacts : Private {
$conf->send_comments( $params{send_comments} || 0);
$conf->suppress_alerts( $params{suppress_alerts} || 0);
$conf->comment_user_id( $params{comment_user_id} || undef );
+ $conf->can_be_devolved( $params{devolved} || 0 );
$conf->send_extended_statuses( $params{extended_statuses} || 0 );
$conf->insert();
@@ -461,6 +474,9 @@ sub council_edit : Path('council_edit') : Args(2) {
$c->stash->{history} = $history;
+ my @methods = map { $_ =~ s/FixMyStreet::SendReport:://; $_ } keys %{ FixMyStreet::SendReport->get_senders };
+ $c->stash->{send_methods} = \@methods;
+
return 1;
}
@@ -640,6 +656,7 @@ sub report_edit : Path('report_edit') : Args(1) {
}
my $flagged = $c->req->param('flagged') ? 1 : 0;
+ my $non_public = $c->req->param('non_public') ? 1 : 0;
# do this here so before we update the values in problem
if ( $c->req->param('anonymous') ne $problem->anonymous
@@ -647,7 +664,8 @@ sub report_edit : Path('report_edit') : Args(1) {
|| $c->req->param('email') ne $problem->user->email
|| $c->req->param('title') ne $problem->title
|| $c->req->param('detail') ne $problem->detail
- || $flagged != $problem->flagged )
+ || $flagged != $problem->flagged
+ || $non_public != $problem->non_public )
{
$edited = 1;
}
@@ -658,6 +676,7 @@ sub report_edit : Path('report_edit') : Args(1) {
$problem->state( $c->req->param('state') );
$problem->name( $c->req->param('name') );
$problem->flagged( $flagged );
+ $problem->non_public( $non_public );
if ( $c->req->param('email') ne $problem->user->email ) {
my $user = $c->model('DB::User')->find_or_create(
@@ -725,8 +744,24 @@ sub search_users: Path('search_users') : Args(0) {
]
}
);
+ my @users = $users->all;
+ my %email2user = map { $_->email => $_ } @users;
+ $c->stash->{users} = [ @users ];
+
+ my $emails = $c->model('DB::Abuse')->search(
+ {
+ email => { ilike => $isearch }
+ }
+ );
+ foreach my $email ($emails->all) {
+ # Slight abuse of the boolean flagged value
+ if ($email2user{$email->email}) {
+ $email2user{$email->email}->flagged( 2 );
+ } else {
+ push @{$c->stash->{users}}, { email => $email->email, flagged => 2 };
+ }
+ }
- $c->stash->{users} = [ $users->all ];
}
return 1;
@@ -833,26 +868,6 @@ sub update_edit : Path('update_edit') : Args(1) {
return 1;
}
-sub search_abuse : Path('search_abuse') : Args(0) {
- my ( $self, $c ) = @_;
-
- $c->forward('check_page_allowed');
-
- my $search = $c->req->param('search');
-
- if ($search) {
- my $emails = $c->model('DB::Abuse')->search(
- {
- email => { ilike => "\%$search\%" }
- }
- );
-
- $c->stash->{emails} = [ $emails->all ];
- }
-
- return 1;
-}
-
sub user_edit : Path('user_edit') : Args(1) {
my ( $self, $c, $id ) = @_;
@@ -917,6 +932,10 @@ sub stats : Path('stats') : Args(0) {
$c->forward('set_up_council_details');
+ if ( $c->cobrand->moniker eq 'seesomething' ) {
+ return $c->cobrand->admin_stats();
+ }
+
if ( $c->req->param('getcounts') ) {
my ( $start_date, $end_date, @errors );
@@ -1019,13 +1038,12 @@ sub set_allowed_pages : Private {
if( !$pages ) {
$pages = {
'summary' => [_('Summary'), 0],
- 'council_list' => [_('Council contacts'), 1],
- 'search_reports' => [_('Search Reports'), 2],
+ 'council_list' => [_('Bodies'), 1],
+ 'search_reports' => [_('Reports'), 2],
'timeline' => [_('Timeline'), 3],
- 'questionnaire' => [_('Survey Results'), 4],
- 'search_users' => [_('Search Users'), 5],
- 'search_abuse' => [_('Search Abuse'), 5],
- 'list_flagged' => [_('List Flagged'), 6],
+ 'questionnaire' => [_('Survey'), 4],
+ 'search_users' => [_('Users'), 5],
+ 'list_flagged' => [_('Flagged'), 6],
'stats' => [_('Stats'), 6],
'user_edit' => [undef, undef],
'council_contacts' => [undef, undef],
@@ -1276,7 +1294,6 @@ sub trim {
sub _rotate_image {
my ($photo, $direction) = @_;
- use Image::Magick;
my $image = Image::Magick->new;
$image->BlobToImage($photo);
my $err = $image->Rotate($direction);
diff --git a/perllib/FixMyStreet/App/Controller/Alert.pm b/perllib/FixMyStreet/App/Controller/Alert.pm
index 4e5319a59..91ea61fbc 100644
--- a/perllib/FixMyStreet/App/Controller/Alert.pm
+++ b/perllib/FixMyStreet/App/Controller/Alert.pm
@@ -438,7 +438,7 @@ sub determine_location : Private {
$c->detach('choose');
}
- $c->go('index') if $c->stash->{location_error};
+ $c->go('index');
}
# truncate the lat,lon for nicer urls
diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm
index 3047b195c..f2bb23350 100644
--- a/perllib/FixMyStreet/App/Controller/Around.pm
+++ b/perllib/FixMyStreet/App/Controller/Around.pm
@@ -45,7 +45,7 @@ sub around_index : Path : Args(0) {
|| $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');
+ return unless $c->cobrand->moniker eq 'fixmybarangay' || $c->forward('check_location_is_acceptable');
# If we have a partial - redirect to /report/new so that it can be
# completed.
@@ -204,6 +204,7 @@ sub display_location : Private {
longitude => $short_longitude,
clickable => 1,
pins => \@pins,
+ area => $c->cobrand->areas_on_around,
);
return 1;
diff --git a/perllib/FixMyStreet/App/Controller/Contact.pm b/perllib/FixMyStreet/App/Controller/Contact.pm
index 926a3f2a5..04360301e 100644
--- a/perllib/FixMyStreet/App/Controller/Contact.pm
+++ b/perllib/FixMyStreet/App/Controller/Contact.pm
@@ -113,6 +113,9 @@ sub validate : Private {
or $c->req->param('update_id')
&& $c->req->param('update_id') !~ /^[1-9]\d*$/;
+ push @errors, _('There was a problem showing this page. Please try again later.')
+ if $c->req->params->{message} && $c->req->params->{message} =~ /\[url=/;
+
unshift @errors,
_('There were problems with your report. Please see below.')
if scalar keys %field_errors;
@@ -184,7 +187,7 @@ generally required to stash
sub setup_request : Private {
my ( $self, $c ) = @_;
- $c->stash->{contact_email} = $c->cobrand->contact_email( 'contact' );
+ $c->stash->{contact_email} = $c->cobrand->contact_email;
$c->stash->{contact_email} =~ s/\@/@/;
for my $param (qw/em subject message/) {
@@ -206,7 +209,7 @@ Sends the email
sub send_email : Private {
my ( $self, $c ) = @_;
- my $recipient = $c->cobrand->contact_email( 'contact' );
+ my $recipient = $c->cobrand->contact_email;
my $recipient_name = $c->cobrand->contact_name();
$c->stash->{host} = $c->req->header('HOST');
diff --git a/perllib/FixMyStreet/App/Controller/Council.pm b/perllib/FixMyStreet/App/Controller/Council.pm
index a6ce533e4..cb9e78421 100644
--- a/perllib/FixMyStreet/App/Controller/Council.pm
+++ b/perllib/FixMyStreet/App/Controller/Council.pm
@@ -52,7 +52,6 @@ sub load_and_check_councils : Private {
my $short_latitude = Utils::truncate_coordinate($latitude);
my $short_longitude = Utils::truncate_coordinate($longitude);
- # TODO: I think we want in_gb_locale around the MaPit line, needs testing
my $all_councils;
if ( $c->stash->{fetch_all_areas} ) {
my %area_types = map { $_ => 1 } @$area_types;
diff --git a/perllib/FixMyStreet/App/Controller/Dashboard.pm b/perllib/FixMyStreet/App/Controller/Dashboard.pm
index b52e682a5..17fd8b867 100644
--- a/perllib/FixMyStreet/App/Controller/Dashboard.pm
+++ b/perllib/FixMyStreet/App/Controller/Dashboard.pm
@@ -96,7 +96,7 @@ sub index : Path : Args(0) {
$c->stash->{council} = $council_detail;
my $children = mySociety::MaPit::call('area/children', $council,
- type => $mySociety::VotingArea::council_child_types,
+ type => $c->cobrand->area_types_children,
);
$c->stash->{children} = $children;
diff --git a/perllib/FixMyStreet/App/Controller/JS.pm b/perllib/FixMyStreet/App/Controller/JS.pm
index ae2f06605..d7847af75 100755
--- a/perllib/FixMyStreet/App/Controller/JS.pm
+++ b/perllib/FixMyStreet/App/Controller/JS.pm
@@ -24,6 +24,8 @@ sub validation_strings : LocalRegex('^validation_strings\.(.*?)\.js$') : Args(0)
$c->res->content_type( 'application/javascript' );
}
+sub validation_rules : Path('validation_rules.js') : Args(0) { }
+
__PACKAGE__->meta->make_immutable;
1;
diff --git a/perllib/FixMyStreet/App/Controller/Location.pm b/perllib/FixMyStreet/App/Controller/Location.pm
index c3d754485..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
@@ -64,6 +65,19 @@ sub determine_location_from_pc : Private {
$pc ||= $c->req->param('pc') || return;
$c->stash->{pc} = $pc; # for template
+ if ( $pc =~ /^(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)$/ ) {
+ $c->stash->{latitude} = $1;
+ $c->stash->{longitude} = $2;
+ return $c->forward( 'check_location' );
+ }
+ if ( $c->cobrand->country eq 'GB' && $pc =~ /^([A-Z])([A-Z])([\d\s]{4,})$/i) {
+ if (my $convert = gridref_to_latlon( $1, $2, $3 )) {
+ $c->stash->{latitude} = $convert->{latitude};
+ $c->stash->{longitude} = $convert->{longitude};
+ return $c->forward( 'check_location' );
+ }
+ }
+
my ( $latitude, $longitude, $error ) =
FixMyStreet::Geocode::lookup( $pc, $c );
@@ -114,6 +128,36 @@ sub check_location : Private {
return 1;
}
+# Utility function for if someone (rarely) enters a grid reference
+sub gridref_to_latlon {
+ my ( $a, $b, $num ) = @_;
+ $a = ord(uc $a) - 65; $a-- if $a > 7;
+ $b = ord(uc $b) - 65; $b-- if $b > 7;
+ my $e = (($a-2)%5)*5 + $b%5;
+ my $n = 19 - int($a/5)*5 - int($b/5);
+
+ $num =~ s/\s+//g;
+ my $l = length($num);
+ return if $l % 2 or $l > 10;
+
+ $l /= 2;
+ $e .= substr($num, 0, $l);
+ $n .= substr($num, $l);
+
+ if ( $l < 5 ) {
+ $e .= 5;
+ $n .= 5;
+ $e .= 0 x (4-$l);
+ $n .= 0 x (4-$l);
+ }
+
+ my ( $lat, $lon ) = Utils::convert_en_to_latlon( $e, $n );
+ return {
+ latitude => $lat,
+ longitude => $lon,
+ };
+}
+
=head1 AUTHOR
Struan Donald
diff --git a/perllib/FixMyStreet/App/Controller/Open311.pm b/perllib/FixMyStreet/App/Controller/Open311.pm
index 040b0d3e6..3382c0cea 100644
--- a/perllib/FixMyStreet/App/Controller/Open311.pm
+++ b/perllib/FixMyStreet/App/Controller/Open311.pm
@@ -100,7 +100,7 @@ sub error : Private {
sub get_discovery : Private {
my ( $self, $c ) = @_;
- my $contact_email = $c->config->{CONTACT_EMAIL};
+ my $contact_email = $c->cobrand->contact_email;
my $prod_url = 'http://www.fiksgatami.no/open311';
my $test_url = 'http://fiksgatami-dev.nuug.no/open311';
my $prod_changeset = '2011-04-08T00:00:00Z';
diff --git a/perllib/FixMyStreet/App/Controller/Photo.pm b/perllib/FixMyStreet/App/Controller/Photo.pm
index fc4c3fde7..fa4baf045 100644
--- a/perllib/FixMyStreet/App/Controller/Photo.pm
+++ b/perllib/FixMyStreet/App/Controller/Photo.pm
@@ -9,6 +9,7 @@ use Digest::SHA1 qw(sha1_hex);
use File::Path;
use File::Slurp;
use Path::Class;
+use if !$ENV{TRAVIS}, 'Image::Magick';
=head1 NAME
@@ -116,7 +117,6 @@ sub no_photo : Private {
# Shrinks a picture to the specified size, but keeping in proportion.
sub _shrink {
my ($photo, $size) = @_;
- use Image::Magick;
my $image = Image::Magick->new;
$image->BlobToImage($photo);
my $err = $image->Scale(geometry => "$size>");
@@ -130,7 +130,6 @@ sub _shrink {
# Shrinks a picture to 90x60, cropping so that it is exactly that.
sub _crop {
my ($photo) = @_;
- use Image::Magick;
my $image = Image::Magick->new;
$image->BlobToImage($photo);
my $err = $image->Resize( geometry => "90x60^" );
diff --git a/perllib/FixMyStreet/App/Controller/Questionnaire.pm b/perllib/FixMyStreet/App/Controller/Questionnaire.pm
index f0cc72e07..46d6350d7 100755
--- a/perllib/FixMyStreet/App/Controller/Questionnaire.pm
+++ b/perllib/FixMyStreet/App/Controller/Questionnaire.pm
@@ -157,6 +157,8 @@ sub submit_standard : Private {
my $new_state = '';
$new_state = 'fixed - user' if $c->stash->{been_fixed} eq 'Yes' &&
FixMyStreet::DB::Result::Problem->open_states()->{$old_state};
+ $new_state = 'fixed - user' if $c->stash->{been_fixed} eq 'Yes' &&
+ FixMyStreet::DB::Result::Problem->closed_states()->{$old_state};
$new_state = 'confirmed' if $c->stash->{been_fixed} eq 'No' &&
FixMyStreet::DB::Result::Problem->fixed_states()->{$old_state};
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm
index d36ba32fe..ef966a8a8 100644
--- a/perllib/FixMyStreet/App/Controller/Report.pm
+++ b/perllib/FixMyStreet/App/Controller/Report.pm
@@ -56,6 +56,23 @@ sub display : Path('') : Args(1) {
$c->forward( 'format_problem_for_display' );
}
+sub support : Path('support') : Args(0) {
+ my ( $self, $c ) = @_;
+
+ my $id = $c->req->param('id');
+
+ my $uri =
+ $id
+ ? $c->uri_for( '/report', $id )
+ : $c->uri_for('/');
+
+ if ( $id && $c->cobrand->can_support_problems && $c->user && $c->user->from_council ) {
+ $c->forward( 'load_problem_or_display_error', [ $id ] );
+ $c->stash->{problem}->update( { interest_count => \'interest_count +1' } );
+ }
+ $c->res->redirect( $uri );
+}
+
sub load_problem_or_display_error : Private {
my ( $self, $c, $id ) = @_;
@@ -74,6 +91,13 @@ sub load_problem_or_display_error : Private {
'/page_error_410_gone',
[ _('That report has been removed from FixMyStreet.') ] #
);
+ } elsif ( $problem->non_public ) {
+ if ( !$c->user || $c->user->id != $problem->user->id ) {
+ $c->detach(
+ '/page_error_403_access_denied',
+ [ sprintf(_('That report cannot be viewed on %s.'), $c->cobrand->site_title) ] #
+ );
+ }
}
$c->stash->{problem} = $problem;
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index ede0cd219..9194f5318 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -4,9 +4,7 @@ use Moose;
use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller'; }
-use FixMyStreet::Geocode;
use Encode;
-use Image::Magick;
use List::MoreUtils qw(uniq);
use POSIX 'strcoll';
use HTML::Entities;
@@ -14,7 +12,6 @@ use mySociety::MaPit;
use Path::Class;
use Utils;
use mySociety::EmailUtil;
-use mySociety::TempFiles;
use JSON;
=head1 NAME
@@ -197,6 +194,7 @@ sub report_form_ajax : Path('ajax') : Args(0) {
councils_text => $councils_text,
category => $category,
extra_name_info => $extra_name_info,
+ categories => $c->stash->{category_options},
}
);
@@ -595,6 +593,8 @@ sub setup_categories_and_councils : Private {
my @category_options = (); # categories to show
my $category_label = undef; # what to call them
my %category_extras = (); # extra fields to fill in for open311
+ my %non_public_categories =
+ (); # categories for which the reports are not public
# FIXME - implement in cobrand
if ( $c->cobrand->moniker eq 'emptyhomes' ) {
@@ -646,6 +646,8 @@ sub setup_categories_and_councils : Private {
$category_extras{ $contact->category } = $contact->extra
if $contact->extra;
+
+ $non_public_categories{ $contact->category } = 1 if $contact->non_public;
}
$seen{$contact->category} = 1;
}
@@ -663,6 +665,7 @@ sub setup_categories_and_councils : Private {
$c->stash->{category_label} = $category_label;
$c->stash->{category_options} = \@category_options;
$c->stash->{category_extras} = \%category_extras;
+ $c->stash->{non_public_categories} = \%non_public_categories;
$c->stash->{category_extras_json} = encode_json \%category_extras;
$c->stash->{extra_name_info} = $first_council->{id} == COUNCIL_ID_BROMLEY ? 1 : 0;
@@ -704,22 +707,31 @@ sub process_user : Private {
my $report = $c->stash->{report};
+ # Extract all the params to a hash to make them easier to work with
+ my %params = map { $_ => scalar $c->req->param($_) }
+ ( 'email', 'name', 'phone', 'password_register', 'fms_extra_title' );
+
+ my $user_title = Utils::trim_text( $params{fms_extra_title} );
+
+ if ( $c->cobrand->allow_anonymous_reports ) {
+ my $anon_details = $c->cobrand->anonymous_account;
+
+ for my $key ( qw( email name ) ) {
+ $params{ $key } ||= $anon_details->{ $key };
+ }
+ }
+
# The user is already signed in
if ( $c->user_exists ) {
my $user = $c->user->obj;
- my %params = map { $_ => scalar $c->req->param($_) } ( 'name', 'phone', 'fms_extra_title' );
$user->name( Utils::trim_text( $params{name} ) ) if $params{name};
$user->phone( Utils::trim_text( $params{phone} ) );
- $user->title( Utils::trim_text( $params{fms_extra_title} ) );
+ $user->title( $user_title ) if $user_title;
$report->user( $user );
$report->name( $user->name );
return 1;
}
- # Extract all the params to a hash to make them easier to work with
- my %params = map { $_ => scalar $c->req->param($_) }
- ( 'email', 'name', 'phone', 'password_register', 'fms_extra_title' );
-
# cleanup the email address
my $email = $params{email} ? lc $params{email} : '';
$email =~ s{\s+}{}g;
@@ -747,7 +759,7 @@ sub process_user : Private {
$report->user->phone( Utils::trim_text( $params{phone} ) );
$report->user->password( Utils::trim_text( $params{password_register} ) )
if $params{password_register};
- $report->user->title( Utils::trim_text( $params{fms_extra_title} ) );
+ $report->user->title( $user_title ) if $user_title;
$report->name( Utils::trim_text( $params{name} ) );
return 1;
@@ -773,7 +785,9 @@ sub process_report : Private {
'detail_offensive',
'may_show_name', #
'category', #
+ 'subcategory', #
'partial', #
+ 'service', #
);
# load the report
@@ -798,9 +812,14 @@ sub process_report : Private {
}
$report->detail( $detail );
+ # mobile device type
+ $report->service( $params{service} ) if $params{service};
+
# set these straight from the params
$report->category( _ $params{category} ) if $params{category};
+ $report->subcategory( $params{subcategory} );
+
my $areas = $c->stash->{all_areas};
$report->areas( ',' . join( ',', sort keys %$areas ) . ',' );
@@ -872,10 +891,14 @@ sub process_report : Private {
};
}
+ if ( $c->stash->{non_public_categories}->{ $report->category } ) {
+ $report->non_public( 1 );
+ }
+
$c->cobrand->process_extras( $c, $contacts[0]->area_id, \@extra );
if ( @extra ) {
- $c->stash->{report_meta} = \@extra;
+ $c->stash->{report_meta} = { map { $_->{name} => $_ } @extra };
$report->extra( \@extra );
}
} elsif ( @{ $c->stash->{area_ids_to_list} } ) {
@@ -914,11 +937,14 @@ sub check_for_errors : Private {
# let the model check for errors
$c->stash->{field_errors} ||= {};
- my %field_errors = (
- %{ $c->stash->{field_errors} },
- %{ $c->stash->{report}->user->check_for_errors },
- %{ $c->stash->{report}->check_for_errors },
- );
+ my %field_errors = $c->cobrand->report_check_for_errors( $c );
+
+ # Zurich, we don't care about title or name
+ # There is no title, and name is optional
+ if ( $c->cobrand->moniker eq 'zurich' ) {
+ delete $field_errors{title};
+ delete $field_errors{name};
+ }
# FIXME: need to check for required bromley fields here
@@ -956,7 +982,14 @@ sub save_user_and_report : Private {
my $report = $c->stash->{report};
# Save or update the user if appropriate
- if ( !$report->user->in_storage ) {
+ if ( $c->cobrand->never_confirm_reports ) {
+ if ( $report->user->in_storage() ) {
+ $report->user->update();
+ } else {
+ $report->user->insert();
+ }
+ $report->confirm();
+ } elsif ( !$report->user->in_storage ) {
# User does not exist.
# Store changes in token for when token is validated.
$c->stash->{token_data} = {
@@ -1001,6 +1034,13 @@ sub save_user_and_report : Private {
# Set unknown to DB unknown
$report->council( undef ) if $report->council eq '-1';
+ # if there is a Message Manager message ID, pass it back to the client view
+ if ($c->cobrand->moniker eq 'fixmybarangay' && $c->req->param('external_source_id')=~/^\d+$/) {
+ $c->stash->{external_source_id} = $c->req->param('external_source_id');
+ $report->external_source_id( $c->req->param('external_source_id') );
+ $report->external_source( $c->config->{MESSAGE_MANAGER_URL} ) ;
+ }
+
# save the report;
$report->in_storage ? $report->update : $report->insert();
@@ -1071,7 +1111,17 @@ sub redirect_or_confirm_creation : Private {
if ( $report->confirmed ) {
# Subscribe problem reporter to email updates
$c->forward( 'create_reporter_alert' );
- my $report_uri = $c->cobrand->base_url_for_report( $report ) . $report->url;
+ my $report_uri;
+
+ if ( $c->cobrand->moniker eq 'fixmybarangay' && $c->user->from_council && $c->stash->{external_source_id}) {
+ $report_uri = $c->uri_for( '/report', $report->id, undef, { external_source_id => $c->stash->{external_source_id} } );
+ } elsif ( $c->cobrand->never_confirm_reports && $report->non_public ) {
+ $c->log->info( 'cobrand was set to always confirm reports and report was non public, success page showed');
+ $c->stash->{template} = 'report_created.html';
+ return 1;
+ } else {
+ $report_uri = $c->cobrand->base_url_for_report( $report ) . $report->url;
+ }
$c->log->info($report->user->id . ' was logged in, redirecting to /report/' . $report->id);
$c->res->redirect($report_uri);
$c->detach;
diff --git a/perllib/FixMyStreet/App/Controller/Report/Update.pm b/perllib/FixMyStreet/App/Controller/Report/Update.pm
index 3fc8bfee8..5e0d9f388 100644
--- a/perllib/FixMyStreet/App/Controller/Report/Update.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/Update.pm
@@ -76,6 +76,10 @@ sub update_problem : Private {
$problem->state('confirmed');
}
+ if ( $c->cobrand->can_support_problems && $c->user && $c->user->from_council && $c->req->param('external_source_id') ) {
+ $problem->interest_count( \'interest_count + 1' );
+ }
+
$problem->lastupdate( \'ms_current_timestamp()' );
$problem->update;
@@ -364,6 +368,7 @@ sub redirect_or_confirm_creation : Private {
if ( $update->confirmed ) {
$c->forward( 'update_problem' );
$c->forward( 'signup_for_alerts' );
+
my $report_uri = $c->cobrand->base_url_for_report( $update->problem ) . $update->problem->url;
$c->res->redirect($report_uri);
$c->detach;
diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm
index 37766db44..ec41dc17f 100644
--- a/perllib/FixMyStreet/App/Controller/Reports.pm
+++ b/perllib/FixMyStreet/App/Controller/Reports.pm
@@ -6,7 +6,6 @@ use File::Slurp;
use List::MoreUtils qw(zip);
use POSIX qw(strcoll);
use mySociety::MaPit;
-use mySociety::VotingArea;
BEGIN { extends 'Catalyst::Controller'; }
@@ -71,7 +70,7 @@ sub index : Path : Args(0) {
if ($@) {
$c->stash->{message} = _("There was a problem showing the All Reports page. Please try again later.");
if ($c->config->{STAGING_SITE}) {
- $c->stash->{message} .= '</p><p>Perhaps the bin/update-all-reports script needs running.</p><p>'
+ $c->stash->{message} .= '</p><p>Perhaps the bin/update-all-reports script needs running. Use: bin/cron-wrapper bin/update-all-reports</p><p>'
. sprintf(_('The error was: %s'), $@);
}
$c->stash->{template} = 'errors/generic.html';
@@ -84,13 +83,13 @@ sub index : Path : Args(0) {
=head2 index
-Show the summary page for a particular council.
+Show the summary page for a particular body.
=cut
-sub council : Path : Args(1) {
- my ( $self, $c, $council ) = @_;
- $c->detach( 'ward', [ $council ] );
+sub body : Path : Args(1) {
+ my ( $self, $c, $body ) = @_;
+ $c->detach( 'ward', [ $body ] );
}
=head2 index
@@ -102,7 +101,7 @@ Show the summary page for a particular ward.
sub ward : Path : Args(2) {
my ( $self, $c, $council, $ward ) = @_;
- $c->forward( 'council_check', [ $council ] );
+ $c->forward( 'body_check', [ $council ] );
$c->forward( 'ward_check', [ $ward ] )
if $ward;
$c->forward( 'load_parent' );
@@ -133,9 +132,10 @@ sub ward : Path : Args(2) {
$c->cobrand->tweak_all_reports_map( $c );
# List of wards
- unless ($c->stash->{ward}) {
+ # Ignore external_body special council thing
+ unless ($c->stash->{ward} || !$c->stash->{council}->{id}) {
my $children = mySociety::MaPit::call('area/children', [ $c->stash->{council}->{id} ],
- type => $mySociety::VotingArea::council_child_types,
+ type => $c->cobrand->area_types_children,
);
foreach (values %$children) {
$_->{url} = $c->uri_for( $c->stash->{council_url}
@@ -146,9 +146,9 @@ sub ward : Path : Args(2) {
}
}
-sub rss_council : Regex('^rss/(reports|area)$') : Args(1) {
- my ( $self, $c, $council ) = @_;
- $c->detach( 'rss_ward', [ $council ] );
+sub rss_body : Regex('^rss/(reports|area)$') : Args(1) {
+ my ( $self, $c, $body ) = @_;
+ $c->detach( 'rss_ward', [ $body ] );
}
sub rss_ward : Regex('^rss/(reports|area)$') : Args(2) {
@@ -158,8 +158,8 @@ sub rss_ward : Regex('^rss/(reports|area)$') : Args(2) {
$c->stash->{rss} = 1;
- $c->forward( 'council_check', [ $council ] );
- $c->forward( 'ward_check', [ $ward ] ) if $ward;
+ $c->forward( 'body_check', [ $council ] );
+ $c->forward( 'ward_check', [ $ward ] ) if $ward;
if ($rss eq 'area' && $c->stash->{council}{type} ne 'DIS' && $c->stash->{council}{type} ne 'CTY') {
# Two possibilites are the same for one-tier councils, so redirect one to the other
@@ -170,13 +170,6 @@ sub rss_ward : Regex('^rss/(reports|area)$') : Args(2) {
$url .= '/' . $c->cobrand->short_name( $c->stash->{ward} ) if $c->stash->{ward};
$c->stash->{qs} = "/$url";
- my @params;
- push @params, $c->stash->{council}->{id} if $rss eq 'reports';
- push @params, $c->stash->{ward}
- ? $c->stash->{ward}->{id}
- : $c->stash->{council}->{id};
- $c->stash->{db_params} = [ @params ];
-
if ( $rss eq 'area' && $c->stash->{ward} ) {
# All problems within a particular ward
$c->stash->{type} = 'area_problems';
@@ -203,15 +196,15 @@ sub rss_ward : Regex('^rss/(reports|area)$') : Args(2) {
$c->forward( '/rss/output' );
}
-=head2 council_check
+=head2 body_check
-This action checks the council name (or code) given in a URI exists, is valid
-and so on. If it is, it stores the Area in the stash, otherwise it redirects
-to the all reports page.
+This action checks the council or external_body name (or code) given in a URI
+exists, is valid and so on. If it is, it stores the area or body in the stash,
+otherwise it redirects to the all reports page.
=cut
-sub council_check : Private {
+sub body_check : Private {
my ( $self, $c, $q_council ) = @_;
$q_council =~ s/\+/ /g;
@@ -219,7 +212,7 @@ sub council_check : Private {
# Check cobrand specific incantations - e.g. ONS codes for UK,
# Oslo/ kommunes sharing a name in Norway
- return if $c->cobrand->reports_council_check( $c, $q_council );
+ return if $c->cobrand->reports_body_check( $c, $q_council );
# If we're passed an ID number (don't think this is used anywhere, it
# certainly shouldn't be), just look that up on MaPit and redirect
@@ -230,12 +223,22 @@ sub council_check : Private {
$c->detach( 'redirect_area' );
}
+ if ( $c->cobrand->reports_by_body ) {
+ my $problem = $c->cobrand->problems->search({ 'lower(me.external_body)' => lc $q_council }, { columns => [ 'external_body' ], rows => 1 })->single;
+ if ( $problem ) {
+ # If external_body, put as a council with ID 0 for the moment.
+ $c->stash->{council} = { id => 0, name => $problem->external_body };
+ return;
+ }
+ }
+
# We must now have a string to check
my $area_types = $c->cobrand->area_types;
my $areas = mySociety::MaPit::call( 'areas', $q_council,
type => $area_types,
min_generation => $c->cobrand->area_min_generation
);
+
if (keys %$areas == 1) {
($c->stash->{council}) = values %$areas;
return;
@@ -255,9 +258,8 @@ sub council_check : Private {
=head2 ward_check
This action checks the ward name from a URI exists and is part of the right
-parent, already found with council_check. It either stores the ward Area if
+parent, already found with body_check. It either stores the ward Area if
okay, or redirects to the council page if bad.
-This is currently only used in the UK, hence the use of mySociety::VotingArea.
=cut
@@ -271,7 +273,7 @@ sub ward_check : Private {
my $council = $c->stash->{council};
my $qw = mySociety::MaPit::call('areas', $ward,
- type => $mySociety::VotingArea::council_child_types,
+ type => $c->cobrand->area_types_children,
min_generation => $c->cobrand->area_min_generation
);
foreach my $area (sort { $a->{name} cmp $b->{name} } values %$qw) {
@@ -318,7 +320,8 @@ sub load_and_group_problems : Private {
my $page = $c->req->params->{p} || 1;
my $where = {
- state => [ FixMyStreet::DB::Result::Problem->visible_states() ]
+ non_public => 0,
+ state => [ FixMyStreet::DB::Result::Problem->visible_states() ]
};
if ($c->stash->{ward}) {
$where->{areas} = { 'like', '%,' . $c->stash->{ward}->{id} . ',%' };
@@ -328,6 +331,9 @@ sub load_and_group_problems : Private {
{ 'like', $c->stash->{council}->{id} . ',%' },
{ 'like', '%,' . $c->stash->{council}->{id} },
];
+ } elsif ($c->stash->{council} && $c->stash->{council}->{id} == 0) {
+ # A proxy for an external_body
+ $where->{'lower(external_body)'} = lc $c->stash->{council}->{name};
} elsif ($c->stash->{council}) {
$where->{areas} = { 'like', '%,' . $c->stash->{council}->{id} . ',%' };
$where->{council} = [
@@ -363,6 +369,11 @@ sub load_and_group_problems : Private {
my %problem = zip @cols, @problem;
$problem{is_fixed} = FixMyStreet::DB::Result::Problem->fixed_states()->{$problem{state}};
$c->log->debug( $problem{'cobrand'} . ', cobrand is ' . $c->cobrand->moniker );
+ if ( !$c->stash->{council}->{id} ) {
+ # An external_body entry
+ add_row( \%problem, 0, \%problems, \@pins );
+ next;
+ }
if ( !$problem{council} ) {
# Problem was not sent to any council, add to possible councils
$problem{councils} = 0;
@@ -375,7 +386,7 @@ sub load_and_group_problems : Private {
my @council = split( /,/, $council );
$problem{councils} = scalar @council;
foreach ( @council ) {
- next if $c->stash->{council} && $_ != $c->stash->{council}->{id};
+ next if $_ != $c->stash->{council}->{id};
add_row( \%problem, $_, \%problems, \@pins );
}
}
diff --git a/perllib/FixMyStreet/App/Controller/Root.pm b/perllib/FixMyStreet/App/Controller/Root.pm
index 7f7d7f5fd..769a147bf 100644
--- a/perllib/FixMyStreet/App/Controller/Root.pm
+++ b/perllib/FixMyStreet/App/Controller/Root.pm
@@ -94,6 +94,13 @@ sub page_error_410_gone : Private {
$c->response->status(410);
}
+sub page_error_403_access_denied : Private {
+ my ( $self, $c, $error_msg ) = @_;
+ $c->stash->{template} = 'index.html';
+ $c->stash->{error} = $error_msg;
+ $c->response->status(403);
+}
+
=head2 end
Attempt to render a view, if needed.
diff --git a/perllib/FixMyStreet/App/Controller/Rss.pm b/perllib/FixMyStreet/App/Controller/Rss.pm
index fe4b652ed..baaa3b927 100755
--- a/perllib/FixMyStreet/App/Controller/Rss.pm
+++ b/perllib/FixMyStreet/App/Controller/Rss.pm
@@ -106,10 +106,19 @@ sub local_problems_pc_distance : Path('pc') : Args(2) {
}
-sub local_problems : LocalRegex('^(n|l)/([\d.-]+)[,/]([\d.-]+)(?:/(\d+))?$') {
+sub local_problems_dist : LocalRegex('^(n|l)/([\d.-]+)[,/]([\d.-]+)/(\d+)$') {
my ( $self, $c ) = @_;
+ $c->forward( 'local_problems', $c->req->captures );
+}
+
+sub local_problems_no_dist : LocalRegex('^(n|l)/([\d.-]+)[,/]([\d.-]+)$') {
+ my ( $self, $c ) = @_;
+ $c->forward( 'local_problems', $c->req->captures );
+}
+
+sub local_problems : Private {
+ my ( $self, $c, $type, $a, $b, $d ) = @_;
- my ( $type, $a, $b, $d) = @{ $c->req->captures };
$c->forward( 'get_query_parameters', [ $d ] );
$c->detach( 'redirect_lat_lon', [ $a, $b ] )
diff --git a/perllib/FixMyStreet/App/View/Web.pm b/perllib/FixMyStreet/App/View/Web.pm
index eac194dff..42878be37 100644
--- a/perllib/FixMyStreet/App/View/Web.pm
+++ b/perllib/FixMyStreet/App/View/Web.pm
@@ -171,6 +171,7 @@ sub version {
my $path = FixMyStreet->path_to('web', $file);
$version_hash{$file} = ( stat( $path ) )[9];
}
+ $version_hash{$file} ||= '';
return "$file?$version_hash{$file}";
}
diff --git a/perllib/FixMyStreet/Cobrand/Bromley.pm b/perllib/FixMyStreet/Cobrand/Bromley.pm
index c33135673..0d4894aa8 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 {
@@ -80,9 +80,7 @@ sub process_extras {
sub contact_email {
my $self = shift;
- my $type = shift || '';
- return join( '@', 'info', 'bromley.gov.uk' ) if $type eq 'contact';
- return $self->next::method();
+ return join( '@', 'info', 'bromley.gov.uk' );
}
sub contact_name { 'Bromley Council (do not reply)'; }
diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm
index 04265963a..11851c5a1 100644
--- a/perllib/FixMyStreet/Cobrand/Default.pm
+++ b/perllib/FixMyStreet/Cobrand/Default.pm
@@ -4,6 +4,8 @@ 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);
@@ -143,6 +145,14 @@ Can be specified in template.
sub enter_postcode_text { }
+=head2 site_title
+
+The name of the site
+
+=cut
+
+sub site_title { return 'FixMyStreet'; }
+
=head2 set_lang_and_domain
my $set_lang = $cobrand->set_lang_and_domain( $lang, $unicode, $dir )
@@ -158,7 +168,8 @@ sub set_lang_and_domain {
my $lang_override = $self->language_override || $lang;
my $lang_domain = $self->language_domain || 'FixMyStreet';
- my $set_lang = mySociety::Locale::negotiate_language( $languages, $lang_override );
+ my $headers = $self->{c} ? $self->{c}->req->headers : undef;
+ my $set_lang = mySociety::Locale::negotiate_language( $languages, $lang_override, $headers );
mySociety::Locale::gettext_domain( $lang_domain, $unicode, $dir );
mySociety::Locale::change();
return $set_lang;
@@ -590,6 +601,13 @@ For UK sub-cobrands, to specify various alternations needed for them.
=cut
sub is_council { 0; }
+=item is_two_tier
+
+For UK sub-cobrands, to specify various alternations needed for them.
+
+=cut
+sub is_two_tier { 0; }
+
=item council_rss_alert_options
Generate a set of options for council rss alerts.
@@ -615,14 +633,14 @@ sub council_rss_alert_options {
return ( \@options, @reported_to_options ? \@reported_to_options : undef );
}
-=head2 reports_council_check
+=head2 reports_body_check
This function is called by the All Reports page, and lets you do some cobrand
-specific checking on the URL passed to try and match to a relevant area.
+specific checking on the URL passed to try and match to a relevant body.
=cut
-sub reports_council_check {
+sub reports_body_check {
my ( $self, $c, $code ) = @_;
return 0;
}
@@ -644,12 +662,59 @@ Get stats to display on the council reports page
sub get_report_stats { return 0; }
-sub get_council_sender { return 'Email' };
+sub get_council_sender {
+ my ( $self, $area_id, $area_info, $category ) = @_;
+
+ my $send_method;
+
+ my $council_config = FixMyStreet::App->model("DB::Open311conf")->search( { area_id => $area_id } )->first;
+ $send_method = $council_config->send_method if $council_config;
+
+ if ( $council_config && $council_config->can_be_devolved ) {
+ # look up via category
+ my $config = FixMyStreet::App->model("DB::Contact")->search( { area_id => $area_id, category => $category } )->first;
+ if ( $config->send_method ) {
+ return { method => $config->send_method, config => $config };
+ } else {
+ return { method => $send_method, config => $council_config };
+ }
+ } elsif ( $send_method ) {
+ return { method => $send_method, config => $council_config };
+ }
+
+ return $self->_fallback_council_sender( $area_id, $area_info, $category );
+}
+
+sub _fallback_council_sender {
+ my ( $self, $area_id, $area_info, $category ) = @_;
+
+ return { method => 'Email' };
+};
sub example_places {
- return FixMyStreet->config('EXAMPLE_PLACES') || [ 'High Street', 'Main Street' ];
+ my $e = FixMyStreet->config('EXAMPLE_PLACES') || [ 'High Street', 'Main Street' ];
+ $e = [ map { Encode::decode('UTF-8', $_) } @$e ];
+ return $e;
}
+=head2 only_authed_can_create
+
+If true, only users with the from_council flag set are able to create reports.
+
+=cut
+
+sub only_authed_can_create {
+ return 0;
+}
+
+=head2 areas_on_around
+
+If set to an arrayref, will plot those area ID(s) from mapit on all the /around pages.
+
+=cut
+
+sub areas_on_around { []; }
+
sub process_extras {}
=head 2 pin_colour
@@ -675,5 +740,75 @@ Used in some cobrands to improve the intial display for Internet Explorer.
sub tweak_all_reports_map {}
+sub can_support_problems { return 0; }
+
+sub default_map_zoom { undef };
+
+sub users_can_hide { return 0; }
+
+=head2 reports_by_body
+
+Can /reports show reports indexed by external_body? This is a temporary measure
+until the contacts/area/body handling is rewritten to be better.
+
+=cut
+
+sub reports_by_body { 0; }
+
+=head2 default_show_name
+
+Returns true if the show name checkbox should be ticked by default.
+
+=cut
+
+sub default_show_name {
+ 1;
+}
+
+=head2 report_check_for_errors
+
+Perform validation for new reports. Takes Catalyst context object as an argument
+
+=cut
+
+sub report_check_for_errors {
+ my $self = shift;
+ my $c = shift;
+
+ return (
+ %{ $c->stash->{field_errors} },
+ %{ $c->stash->{report}->user->check_for_errors },
+ %{ $c->stash->{report}->check_for_errors },
+ );
+}
+
+sub report_sent_confirmation_email { 0; }
+
+=head2 never_confirm_reports
+
+If true then we never send an email to confirm a report
+
+=cut
+
+sub never_confirm_reports { 0; }
+
+=head2 allow_anonymous_reports
+
+If true then can have reports that are truely anonymous - i.e with no email or name. You
+need to also put details in the anonymous_account function too.
+
+=cut
+
+sub allow_anonymous_reports { 0; }
+
+=head2 anonymous_account
+
+Details to use for anonymous reports. This should return a hashref with an email and
+a name key
+
+=cut
+
+sub anonymous_account { undef; }
+
1;
diff --git a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
index 85ebf035e..6bec115dd 100644
--- a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
+++ b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
@@ -215,7 +215,7 @@ sub council_rss_alert_options {
}
-sub reports_council_check {
+sub reports_body_check {
my ( $self, $c, $council ) = @_;
if ($council eq 'Oslo') {
diff --git a/perllib/FixMyStreet/Cobrand/FixMyBarangay.pm b/perllib/FixMyStreet/Cobrand/FixMyBarangay.pm
new file mode 100644
index 000000000..8ccbb57f5
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand/FixMyBarangay.pm
@@ -0,0 +1,54 @@
+package FixMyStreet::Cobrand::FixMyBarangay;
+use base 'FixMyStreet::Cobrand::Default';
+
+use strict;
+use warnings;
+
+sub path_to_web_templates {
+ my $self = shift;
+ return [
+ FixMyStreet->path_to( 'templates/web', $self->moniker )->stringify,
+ FixMyStreet->path_to( 'templates/web/fixmystreet' )->stringify
+ ];
+}
+
+sub country {
+ return 'PH';
+}
+
+sub language_domain { 'FixMyBarangay' }
+
+sub area_types {
+ return [ 'BGY' ];
+}
+
+sub disambiguate_location {
+ return {
+ country => 'ph',
+ bing_country => 'Philippines',
+ };
+}
+
+sub only_authed_can_create {
+ return 1;
+}
+
+sub areas_on_around {
+ return [ 1, 2 ];
+}
+
+sub can_support_problems {
+ return 1;
+}
+
+sub reports_by_body { 1 }
+
+sub default_show_name {
+ my $self = shift;
+
+ return 0 if $self->{c}->user->from_council;
+ return 1;
+}
+
+1;
+
diff --git a/perllib/FixMyStreet/Cobrand/LichfieldDC.pm b/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
index 5c8a04681..31d5bf987 100644
--- a/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
+++ b/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
@@ -8,6 +8,7 @@ sub council_id { return 2434; }
sub council_area { return 'Lichfield district'; }
sub council_name { return 'Lichfield District Council'; }
sub council_url { return 'lichfielddc'; }
+sub is_two_tier { return 1; }
# Different to councils parent due to this being a two-tier council. If we get
# more, this can be genericised in the parent.
@@ -26,15 +27,8 @@ sub disambiguate_location {
};
}
-# If we ever link to a county problem report, needs to be to main FixMyStreet
-sub base_url_for_report {
- my ( $self, $report ) = @_;
- my %councils = map { $_ => 1 } @{$report->councils};
- if ( $councils{2434} ) {
- return $self->base_url;
- } else {
- return FixMyStreet->config('BASE_URL');
- }
+sub map_type {
+ return 'OSM';
}
1;
diff --git a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
new file mode 100644
index 000000000..9aa054020
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
@@ -0,0 +1,55 @@
+package FixMyStreet::Cobrand::Oxfordshire;
+use base 'FixMyStreet::Cobrand::UKCouncils';
+
+use strict;
+use warnings;
+
+sub council_id { return 2237; }
+sub council_area { return 'Oxfordshire'; }
+sub council_name { return 'Oxfordshire County Council'; }
+sub council_url { return 'oxfordshire'; }
+sub is_two_tier { return 1; }
+
+sub base_url {
+ return FixMyStreet->config('BASE_URL') if FixMyStreet->config('STAGING_SITE');
+ return 'http://fixmystreet.oxfordshire.gov.uk';
+}
+
+# Different to councils parent due to this being a two-tier council. If we get
+# more, this can be genericised in the parent.
+sub problems_clause {
+ return { council => { like => '%2237%' } };
+}
+
+sub path_to_web_templates {
+ my $self = shift;
+ return [
+ FixMyStreet->path_to( 'templates/web', $self->moniker )->stringify,
+ FixMyStreet->path_to( 'templates/web/fixmystreet' )->stringify
+ ];
+}
+
+sub enter_postcode_text {
+ my ($self) = @_;
+ return 'Enter an Oxfordshire postcode, or street name and area';
+}
+
+sub disambiguate_location {
+ my $self = shift;
+ my $string = shift;
+ return {
+ %{ $self->SUPER::disambiguate_location() },
+ centre => '51.765765,-1.322324',
+ span => '0.154963,0.24347', # NB span is not correct
+ bounds => [ 51.459413, -1.719500, 52.168471, -0.870066 ],
+ };
+}
+
+sub example_places {
+ return ( 'OX20 1SZ', 'Park St, Woodstock' );
+}
+
+sub default_show_name { 0 }
+
+1;
+
diff --git a/perllib/FixMyStreet/Cobrand/SeeSomething.pm b/perllib/FixMyStreet/Cobrand/SeeSomething.pm
new file mode 100644
index 000000000..dc28156dc
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand/SeeSomething.pm
@@ -0,0 +1,148 @@
+package FixMyStreet::Cobrand::SeeSomething;
+use parent 'FixMyStreet::Cobrand::UKCouncils';
+
+use strict;
+use warnings;
+
+sub council_id { return [ 2520, 2522, 2514, 2546, 2519, 2538, 2535 ]; }
+sub council_area { return 'West Midlands'; }
+sub council_name { return 'See Something Say Something'; }
+sub council_url { return 'seesomething'; }
+sub area_types { [ 'MTD' ] }
+sub site_title { return 'See Something, Say Something'; }
+
+
+sub site_restriction {
+ my $self = shift;
+ return { council => { IN => $self->council_id } };
+}
+
+sub problems_clause {
+ my $self = shift;
+ return { council => { IN => $self->council_id } };
+}
+
+sub path_to_web_templates {
+ my $self = shift;
+ return [
+ FixMyStreet->path_to( 'templates/web', $self->moniker )->stringify,
+ FixMyStreet->path_to( 'templates/web/fixmystreet' )->stringify
+ ];
+}
+
+sub council_check {
+ my ( $self, $params, $context ) = @_;
+
+ my $councils = $params->{all_councils};
+ my $council_match = grep { $councils->{$_} } @{ $self->council_id };
+
+ if ($council_match) {
+ return 1;
+ }
+
+ return ( 0, "That location is not covered by See Something, Say Something" );
+}
+
+sub disambiguate_location {
+ my $self = shift;
+ my $string = shift;
+
+ my $town = 'West Midlands';
+
+ return {
+ %{ $self->SUPER::disambiguate_location() },
+ town => $town,
+ centre => '52.4803101685267,-2.2708272758854',
+ span => '1.4002794815887,2.06340043925997',
+ bounds => [ 51.8259444771676, -3.23554082684068, 53.2262239587563, -1.17214038758071 ],
+ };
+}
+
+sub example_places {
+ return ( 'WS1 4NH', 'Austin Drive, Coventry' );
+}
+
+sub send_questionnaires {
+ return 0;
+}
+
+sub ask_ever_reported {
+ return 0;
+}
+
+sub report_sent_confirmation_email { 1; }
+
+sub report_check_for_errors { return (); }
+
+sub never_confirm_reports { 1; }
+
+sub allow_anonymous_reports { 1; }
+
+sub anonymous_account { return { name => 'Anonymous Submission', email => FixMyStreet->config('DO_NOT_REPLY_EMAIL') }; }
+
+sub admin_pages {
+ my $self = shift;
+
+ return {
+ 'stats' => ['Reports', 0],
+ };
+};
+
+sub admin_stats {
+ my $self = shift;
+ my $c = $self->{c};
+
+ my %filters = ();
+
+ my %councils =
+ map {
+ $c->stash->{council_details}->{$_}->{name} =~ s/(?:Borough|City) Council//;
+ $_ => $c->stash->{council_details}->{$_}
+ }
+ @{ $self->council_id };
+
+ $c->stash->{council_details} = \%councils;
+
+ if ( !$c->user_exists || !grep { $_ == $c->user->from_council } @{ $self->council_id } ) {
+ $c->detach( '/page_error_404_not_found' );
+ }
+
+ if ( $c->req->param('category') ) {
+ $filters{category} = $c->req->param('category');
+ $c->stash->{category} = $c->req->param('category');
+ }
+
+ if ( $c->req->param('subcategory') ) {
+ $filters{subcategory} = $c->req->param('subcategory');
+ $c->stash->{subcategory} = $c->req->param('subcategory');
+ }
+
+ if ( $c->req->param('service') ) {
+ $filters{service} = { -ilike => $c->req->param('service') };
+ $c->stash->{service} = $c->req->param('service');
+ }
+
+ my $page = $c->req->params->{p} || 1;
+
+ my $p = $c->model('DB::Problem')->search(
+ {
+ confirmed => { not => undef },
+ %filters
+ },
+ {
+ columns => [ qw(
+ service category subcategory council confirmed
+ ) ],
+ order_by => { -desc=> [ 'confirmed' ] },
+ rows => 20,
+ }
+ )->page( $page );
+
+ $c->stash->{reports} = $p;
+ $c->stash->{pager} = $p->pager;
+
+ return 1;
+}
+
+1;
+
diff --git a/perllib/FixMyStreet/Cobrand/Stevenage.pm b/perllib/FixMyStreet/Cobrand/Stevenage.pm
new file mode 100644
index 000000000..560baba37
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand/Stevenage.pm
@@ -0,0 +1,41 @@
+package FixMyStreet::Cobrand::Stevenage;
+use parent 'FixMyStreet::Cobrand::UKCouncils';
+
+use strict;
+use warnings;
+
+sub council_id { return 2347; }
+sub council_area { return 'Stevenage'; }
+sub council_name { return 'Stevenage Council'; }
+sub council_url { return 'stevenage'; }
+sub is_two_tier { return 1; }
+
+sub path_to_web_templates {
+ my $self = shift;
+ return [
+ FixMyStreet->path_to( 'templates/web', $self->moniker )->stringify,
+ FixMyStreet->path_to( 'templates/web/fixmystreet' )->stringify
+ ];
+}
+
+sub disambiguate_location {
+ my $self = shift;
+ return {
+ %{ $self->SUPER::disambiguate_location() },
+ town => 'Stevenage',
+ centre => '51.904330,-0.189364',
+ span => '0.063112,0.087585',
+ bounds => [ 51.869319, -0.234382, 51.932431, -0.146796 ],
+ };
+}
+
+sub example_places {
+ return [ 'SG1 1HN', 'Lyton Way' ];
+}
+
+sub default_map_zoom { return 3; }
+
+sub users_can_hide { return 1; }
+
+1;
+
diff --git a/perllib/FixMyStreet/Cobrand/UK.pm b/perllib/FixMyStreet/Cobrand/UK.pm
index 0d6f98590..4eee1869e 100644
--- a/perllib/FixMyStreet/Cobrand/UK.pm
+++ b/perllib/FixMyStreet/Cobrand/UK.pm
@@ -31,19 +31,11 @@ sub disambiguate_location {
};
}
-sub get_council_sender {
- my ( $self, $area_id, $area_info ) = @_;
-
- my $send_method;
-
- my $council_config = FixMyStreet::App->model("DB::Open311conf")->search( { area_id => $area_id } )->first;
- $send_method = $council_config->send_method if $council_config;
-
- return $send_method if $send_method;
-
- return 'London' if $area_info->{type} eq 'LBO';
- return 'NI' if $area_info->{type} eq 'LGD';
- return 'Email';
+sub _fallback_council_sender {
+ my ( $self, $area_id, $area_info, $category ) = @_;
+ return { method => 'London' } if $area_info->{type} eq 'LBO';
+ return { method => 'NI' } if $area_info->{type} eq 'LGD';
+ return { method => 'Email' };
}
sub process_extras {
@@ -53,7 +45,7 @@ sub process_extras {
my $extra = shift;
my $fields = shift || [];
- if ( $area_id == 2482 ) {
+ if ( $area_id eq '2482' ) {
my @fields = ( 'fms_extra_title', @$fields );
for my $field ( @fields ) {
my $value = $ctx->request->param( $field );
@@ -152,7 +144,6 @@ sub find_closest {
my $str = $self->SUPER::find_closest( $latitude, $longitude, $problem );
- # Get nearest postcode from Matthew's random gazetteer (put in MaPit? Or elsewhere?)
my $url = "http://mapit.mysociety.org/nearest/4326/$longitude,$latitude";
my $j = LWP::Simple::get($url);
if ($j) {
@@ -166,7 +157,7 @@ sub find_closest {
return $str;
}
-sub reports_council_check {
+sub reports_body_check {
my ( $self, $c, $code ) = @_;
# Manual misspelling redirect
diff --git a/perllib/FixMyStreet/Cobrand/UKCouncils.pm b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
index a9ebb1b3f..4c80da4f3 100644
--- a/perllib/FixMyStreet/Cobrand/UKCouncils.pm
+++ b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
@@ -86,4 +86,18 @@ sub recent_photos {
return $self->problems->recent_photos( $num, $lat, $lon, $dist );
}
+sub base_url_for_report {
+ my ( $self, $report ) = @_;
+ if ( $self->is_two_tier ) {
+ my %councils = map { $_ => 1 } @{$report->councils};
+ if ( $councils{$self->council_id} ) {
+ return $self->base_url;
+ } else {
+ return FixMyStreet->config('BASE_URL');
+ }
+ } else {
+ return $self->base_url;
+ }
+}
+
1;
diff --git a/perllib/FixMyStreet/Cobrand/Zurich.pm b/perllib/FixMyStreet/Cobrand/Zurich.pm
new file mode 100644
index 000000000..e5d646c8b
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand/Zurich.pm
@@ -0,0 +1,16 @@
+package FixMyStreet::Cobrand::Zurich;
+use base 'FixMyStreet::Cobrand::Default';
+
+use strict;
+use warnings;
+
+sub enter_postcode_text {
+ my ( $self ) = @_;
+ return _('Enter a Z&uuml;rich street name');
+}
+
+sub example_places {
+ return [ 'Langstrasse', 'Basteiplatz' ];
+}
+
+1;
diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm
index 4f155ace3..b551be9ef 100644
--- a/perllib/FixMyStreet/DB/Result/Comment.pm
+++ b/perllib/FixMyStreet/DB/Result/Comment.pm
@@ -54,10 +54,6 @@ __PACKAGE__->add_columns(
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
"problem_state",
{ data_type => "text", is_nullable => 1 },
- "external_id",
- { data_type => "text", is_nullable => 1 },
- "extra",
- { data_type => "text", is_nullable => 1 },
"send_fail_count",
{ data_type => "integer", default_value => 0, is_nullable => 0 },
"send_fail_reason",
@@ -66,6 +62,10 @@ __PACKAGE__->add_columns(
{ data_type => "timestamp", is_nullable => 1 },
"whensent",
{ data_type => "timestamp", is_nullable => 1 },
+ "external_id",
+ { data_type => "text", is_nullable => 1 },
+ "extra",
+ { data_type => "text", is_nullable => 1 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->belongs_to(
@@ -82,8 +82,8 @@ __PACKAGE__->belongs_to(
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-03-26 15:44:18
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:nvkElEgSU6XcLd9znSqhmQ
+# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-07-11 18:53:26
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:tSejJzLxHD/fMWjpa10lfA
__PACKAGE__->filter_column(
extra => {
diff --git a/perllib/FixMyStreet/DB/Result/Contact.pm b/perllib/FixMyStreet/DB/Result/Contact.pm
index c32b75d0c..993e3524b 100644
--- a/perllib/FixMyStreet/DB/Result/Contact.pm
+++ b/perllib/FixMyStreet/DB/Result/Contact.pm
@@ -36,13 +36,23 @@ __PACKAGE__->add_columns(
{ data_type => "text", is_nullable => 0 },
"extra",
{ data_type => "text", is_nullable => 1 },
+ "non_public",
+ { data_type => "boolean", default_value => \"false", is_nullable => 1 },
+ "endpoint",
+ { data_type => "text", is_nullable => 1 },
+ "jurisdiction",
+ { data_type => "text", default_value => "", is_nullable => 1 },
+ "api_key",
+ { data_type => "text", default_value => "", is_nullable => 1 },
+ "send_method",
+ { data_type => "text", is_nullable => 1 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->add_unique_constraint("contacts_area_id_category_idx", ["area_id", "category"]);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-03-08 17:19:55
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:hyvU0bMWSFxEPAJT7wqM/Q
+# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-08-31 10:29:17
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:t6yOPhZmedV/eH6AUvHI6w
__PACKAGE__->filter_column(
extra => {
diff --git a/perllib/FixMyStreet/DB/Result/Open311conf.pm b/perllib/FixMyStreet/DB/Result/Open311conf.pm
index 6748db825..f01a20dec 100644
--- a/perllib/FixMyStreet/DB/Result/Open311conf.pm
+++ b/perllib/FixMyStreet/DB/Result/Open311conf.pm
@@ -34,6 +34,8 @@ __PACKAGE__->add_columns(
{ data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
"suppress_alerts",
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
+ "can_be_devolved",
+ { data_type => "boolean", default_value => \"false", is_nullable => 0 },
"send_extended_statuses",
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
);
@@ -52,9 +54,8 @@ __PACKAGE__->belongs_to(
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-10-03 14:49:22
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:OO3kNIohRp+84PGI2154fg
-
+# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-08-29 14:04:20
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Yoult8K/ldH6DMAKURtr3Q
# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;
diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm
index 83939bfab..b1f59e78a 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -85,13 +85,23 @@ __PACKAGE__->add_columns(
"geocode",
{ data_type => "bytea", is_nullable => 1 },
"send_fail_count",
- { data_type => "integer", is_nullable => 1 },
+ { data_type => "integer", default_value => 0, is_nullable => 0 },
"send_fail_reason",
{ data_type => "text", is_nullable => 1 },
"send_fail_timestamp",
{ data_type => "timestamp", is_nullable => 1 },
"send_method_used",
{ data_type => "text", is_nullable => 1 },
+ "non_public",
+ { data_type => "boolean", default_value => \"false", is_nullable => 1 },
+ "external_source",
+ { data_type => "text", is_nullable => 1 },
+ "external_source_id",
+ { data_type => "text", is_nullable => 1 },
+ "interest_count",
+ { data_type => "integer", is_nullable => 1 },
+ "subcategory",
+ { data_type => "text", is_nullable => 1 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->has_many(
@@ -114,8 +124,8 @@ __PACKAGE__->belongs_to(
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-05-03 16:05:20
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:EvwI91Ot7SioQWqwnXRTBQ
+# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-12-03 17:48:10
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:xN/RB8Vx50CwyOeBjvJezQ
# Add fake relationship to stored procedure table
__PACKAGE__->has_one(
@@ -606,9 +616,6 @@ sub meta_line {
}
- $meta .= '; ' . _('the map was not used so pin location may be inaccurate')
- unless $problem->used_map;
-
return $meta;
}
@@ -644,7 +651,8 @@ sub body {
# Note: this only makes sense when called on a problem that has been sent!
sub can_display_external_id {
my $self = shift;
- if ($self->external_id && $self->send_method_used && $self->send_method_used eq 'barnet') {
+ if ($self->external_id && $self->send_method_used &&
+ ($self->send_method_used eq 'barnet' || $self->council =~ /2237/)) {
return 1;
}
return 0;
@@ -664,11 +672,11 @@ sub processed_summary_string {
my ( $problem, $c ) = @_;
my ($duration_clause, $external_ref_clause);
if ($problem->whensent) {
- $duration_clause = $problem->duration_string($c)
+ $duration_clause = $problem->duration_string($c);
}
if ($problem->can_display_external_id) {
if ($duration_clause) {
- $external_ref_clause = sprintf(_('their ref:&nbsp;%s'), $problem->external_id);
+ $external_ref_clause = sprintf(_('council ref:&nbsp;%s'), $problem->external_id);
} else {
$external_ref_clause = sprintf(_('%s ref:&nbsp;%s'), $problem->external_body, $problem->external_id);
}
diff --git a/perllib/FixMyStreet/DB/ResultSet/AlertType.pm b/perllib/FixMyStreet/DB/ResultSet/AlertType.pm
index a0320ccc3..d903f8eb2 100644
--- a/perllib/FixMyStreet/DB/ResultSet/AlertType.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/AlertType.pm
@@ -65,6 +65,9 @@ sub email_alerts ($) {
# call checks if this is the host that sends mail for this cobrand.
next unless $cobrand->email_host;
+ # this is for the new_updates alerts
+ next if $row->{non_public} and $row->{user_id} != $row->{alert_user_id};
+
my $hashref_restriction = $cobrand->site_restriction( $row->{cobrand_data} );
FixMyStreet::App->model('DB::AlertSent')->create( {
@@ -91,7 +94,23 @@ sub email_alerts ($) {
}
# this is currently only for new_updates
if ($row->{item_text}) {
- $data{problem_url} = $url . "/report/" . $row->{id};
+ if ( $row->{alert_user_id} == $row->{user_id} ) {
+ # This is an alert to the same user who made the report - make this a login link
+ my $user = FixMyStreet::App->model('DB::User')->find( {
+ id => $row->{alert_user_id}
+ } );
+ $data{alert_email} = $user->email;
+ my $token_obj = FixMyStreet::App->model('DB::Token')->create( {
+ scope => 'email_sign_in',
+ data => {
+ email => $user->email,
+ r => 'report/' . $row->{id},
+ }
+ } );
+ $data{problem_url} = $url . "/M/" . $token_obj->token;
+ } else {
+ $data{problem_url} = $url . "/report/" . $row->{id};
+ }
$data{data} .= $row->{item_name} . ' : ' if $row->{item_name} && !$row->{item_anonymous};
$data{data} .= $row->{item_text} . "\n\n------\n\n";
# this is ward and council problems
@@ -151,6 +170,7 @@ sub email_alerts ($) {
where nearby.problem_id = problem.id
and problem.user_id = users.id
and problem.state in ($states)
+ and problem.non_public = 'f'
and problem.confirmed >= ? and problem.confirmed >= ms_current_timestamp() - '7 days'::interval
and (select whenqueued from alert_sent where alert_sent.alert_id = ? and alert_sent.parameter::integer = problem.id) is null
and users.email <> ?
@@ -210,13 +230,12 @@ sub _send_aggregated_alert_email(%) {
unless -e $template;
$template = Utils::read_file($template);
- my $sender = $cobrand->contact_email;
- (my $from = $sender) =~ s/team/fms-DO-NOT-REPLY/; # XXX
+ my $sender = FixMyStreet->config('DO_NOT_REPLY_EMAIL');
my $result = FixMyStreet::App->send_email_cron(
{
_template_ => $template,
_parameters_ => \%data,
- From => [ $from, _($cobrand->contact_name) ],
+ From => [ $sender, _($cobrand->contact_name) ],
To => $data{alert_email},
},
$sender,
diff --git a/perllib/FixMyStreet/DB/ResultSet/Nearby.pm b/perllib/FixMyStreet/DB/ResultSet/Nearby.pm
index 83fc85a88..191223572 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Nearby.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Nearby.pm
@@ -8,6 +8,7 @@ sub nearby {
my ( $rs, $c, $dist, $ids, $limit, $mid_lat, $mid_lon, $interval ) = @_;
my $params = {
+ non_public => 0,
state => [ FixMyStreet::DB::Result::Problem::visible_states() ],
};
$params->{'current_timestamp-lastupdate'} = { '<', \"'$interval'::interval" }
diff --git a/perllib/FixMyStreet/DB/ResultSet/Problem.pm b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
index 4036c4b05..faed3b8ac 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Problem.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
@@ -85,7 +85,8 @@ sub _recent {
$key .= ":$site_key:$num";
my $query = {
- state => [ FixMyStreet::DB::Result::Problem->visible_states() ],
+ non_public => 0,
+ state => [ FixMyStreet::DB::Result::Problem->visible_states() ],
};
$query->{photo} = { '!=', undef } if $photos;
@@ -141,6 +142,7 @@ sub around_map {
$attr->{rows} = $limit if $limit;
my $q = {
+ non_public => 0,
state => [ FixMyStreet::DB::Result::Problem->visible_states() ],
latitude => { '>=', $min_lat, '<', $max_lat },
longitude => { '>=', $min_lon, '<', $max_lon },
@@ -286,6 +288,16 @@ sub send_reports {
$h{closest_address} = $cobrand->find_closest( $h{latitude}, $h{longitude}, $row );
}
+ if ( $cobrand->allow_anonymous_reports &&
+ $row->user->email eq $cobrand->anonymous_account->{'email'}
+ ) {
+ $h{anonymous_report} = 1;
+ $h{user_details} = _('This report was submitted anonymously');
+ } else {
+ $h{user_details} = sprintf(_('Name: %s'), $row->name) . "\n\n";
+ $h{user_details} .= sprintf(_('Email: %s'), $row->user->email) . "\n\n";
+ }
+
my %reporters = ();
my ( $sender_count );
if ($site eq 'emptyhomes') {
@@ -308,8 +320,8 @@ sub send_reports {
foreach my $council (@councils) {
my $name = $areas_info->{$council}->{name};
- my $sender = $cobrand->get_council_sender( $council, $areas_info->{$council} );
- $sender = "FixMyStreet::SendReport::$sender";
+ my $sender_info = $cobrand->get_council_sender( $council, $areas_info->{$council}, $row->category );
+ my $sender = "FixMyStreet::SendReport::" . $sender_info->{method};
if ( ! exists $senders->{ $sender } ) {
warn "No such sender [ $sender ] for council $name ( $council )";
@@ -322,7 +334,7 @@ sub send_reports {
$reporters{ $sender }->skipped;
} else {
push @dear, $name;
- $reporters{ $sender }->add_council( $council, $areas_info->{$council} );
+ $reporters{ $sender }->add_council( $council, $areas_info->{$council}, $sender_info->{config} );
}
}
@@ -334,6 +346,10 @@ sub send_reports {
$h{category_line} = sprintf(_("Category: %s"), $h{category}) . "\n\n";
}
+ if ( $row->subcategory ) {
+ $h{subcategory_line} = sprintf(_("Subcategory: %s"), $row->subcategory) . "\n\n";
+ }
+
$h{councils_name} = join(_(' and '), @dear);
if ($h{category} eq _('Other')) {
$h{multiple} = @dear>1 ? "[ " . _("This email has been sent to both councils covering the location of the problem, as the user did not categorise it; please ignore it if you're not the correct council to deal with the issue, or let us know what category of problem this is so we can add it to our system.") . " ]\n\n"
@@ -361,8 +377,33 @@ sub send_reports {
if (mySociety::Config::get('STAGING_SITE')) {
# on a staging server send emails to ourselves rather than the councils
- my @testing_councils = split( '\|', mySociety::Config::get('TESTING_COUNCILS') || '' );
- unless ( grep { $row->council eq $_ } @testing_councils ) {
+ # however, we can configure a list of councils that we use non email
+ # delivery, e.g. Open311, for testing purposes. For those we want to
+ # send using the non email method and for everyone else we want to use
+ # email
+ my @testing_councils = split( '\|', mySociety::Config::get('TESTING_COUNCILS') );
+
+ # we only care about non missing councils so we get the missing ones
+ # and then essentially throw them away as we're not going to have
+ # configured them to do anything.
+ my %councils = map { $_ => 1 } @{ $row->councils };
+
+ # We now take the councils that we have contact details for and if any of them
+ # are in the list of testing councils we look a bit harder otherwise we throw
+ # away all the non email delivery methods
+ if ( grep { $councils{ $_ } } @testing_councils ) {
+ my %tc = map { $_ => 1 } @testing_councils;
+ my @non_matching = grep { !$tc{$_} } keys %councils;
+ for my $sender ( keys %reporters ) {
+ next if $sender =~ /FixMyStreet::SendReport::(Email|NI)/;
+ for my $council ( @non_matching ) {
+ $reporters{$sender}->delete_council( $council );
+ }
+ }
+ if ( @non_matching ) {
+ $reporters{'FixMyStreet::SendReport::Email'} = FixMyStreet::SendReport::Email->new();
+ }
+ } else {
%reporters = map { $_ => $reporters{$_} } grep { /FixMyStreet::SendReport::(Email|NI)/ } keys %reporters;
unless (%reporters) {
%reporters = ( 'FixMyStreet::SendReport::Email' => FixMyStreet::SendReport::Email->new() );
@@ -393,6 +434,9 @@ sub send_reports {
whensent => \'ms_current_timestamp()',
lastupdate => \'ms_current_timestamp()',
} );
+ if ( $cobrand->report_sent_confirmation_email && !$h{anonymous_report}) {
+ _send_report_sent_email( $row, \%h, $nomail );
+ }
} else {
my @errors;
for my $sender ( keys %reporters ) {
@@ -420,7 +464,48 @@ sub send_reports {
}
printf " %-24s %4d\n", "Total:", $c;
}
+ my $sending_errors = '';
+ my $unsent = FixMyStreet::App->model("DB::Problem")->search( {
+ state => [ 'confirmed', 'fixed' ],
+ whensent => undef,
+ council => { '!=', undef },
+ send_fail_count => { '>', 0 }
+ } );
+ while (my $row = $unsent->next) {
+ $sending_errors .= "* http://www.fixmystreet.com/report/" . $row->id . ", failed "
+ . $row->send_fail_count . " times, last at " . $row->send_fail_timestamp
+ . ", reason " . $row->send_fail_reason . "\n";
+ }
+ if ($sending_errors) {
+ print "The following reports had problems sending:\n$sending_errors";
+ }
}
}
+sub _send_report_sent_email {
+ my $row = shift;
+ my $h = shift;
+ my $nomail = shift;
+
+ my $template = 'confirm_report_sent.txt';
+ my $template_path = FixMyStreet->path_to( "templates", "email", $row->cobrand, $row->lang, $template )->stringify;
+ $template_path = FixMyStreet->path_to( "templates", "email", $row->cobrand, $template )->stringify
+ unless -e $template_path;
+ $template_path = FixMyStreet->path_to( "templates", "email", "default", $template )->stringify
+ unless -e $template_path;
+ $template = Utils::read_file( $template_path );
+
+ my $result = FixMyStreet::App->send_email_cron(
+ {
+ _template_ => $template,
+ _parameters_ => $h,
+ To => $row->user->email,
+ From => mySociety::Config::get('CONTACT_EMAIL'),
+ },
+ mySociety::Config::get('CONTACT_EMAIL'),
+ [ $row->user->email ],
+ $nomail
+ );
+}
+
1;
diff --git a/perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm b/perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm
index bbf0c9a9e..1b9521a9f 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm
@@ -62,7 +62,9 @@ sub send_questionnaires_period {
($template = $period) =~ s/ //;
$template = Utils::read_file( FixMyStreet->path_to( "templates/email/emptyhomes/" . $row->lang . "/questionnaire-$template.txt" )->stringify );
} else {
- $template = FixMyStreet->path_to( "templates", "email", $cobrand->moniker, "questionnaire.txt" )->stringify;
+ $template = FixMyStreet->path_to( "templates", "email", $cobrand->moniker, $row->lang, "questionnaire.txt" )->stringify;
+ $template = FixMyStreet->path_to( "templates", "email", $cobrand->moniker, "questionnaire.txt" )->stringify
+ unless -e $template;
$template = FixMyStreet->path_to( "templates", "email", "default", "questionnaire.txt" )->stringify
unless -e $template;
$template = Utils::read_file( $template );
@@ -87,9 +89,8 @@ sub send_questionnaires_period {
} );
$h{url} = $cobrand->base_url($row->cobrand_data) . '/Q/' . $token->token;
- my $sender = $cobrand->contact_email;
+ my $sender = FixMyStreet->config('DO_NOT_REPLY_EMAIL');
my $sender_name = _($cobrand->contact_name);
- $sender =~ s/team/fms-DO-NOT-REPLY/;
print "Sending questionnaire " . $questionnaire->id . ", problem "
. $row->id . ", token " . $token->token . " to "
diff --git a/perllib/FixMyStreet/EmailSend.pm b/perllib/FixMyStreet/EmailSend.pm
index 61d8a70c2..8b6eed462 100644
--- a/perllib/FixMyStreet/EmailSend.pm
+++ b/perllib/FixMyStreet/EmailSend.pm
@@ -2,10 +2,7 @@ package FixMyStreet::EmailSend;
use base Email::Send::SMTP;
sub get_env_sender {
- # Should really use cobrand's contact_email function, but not sure how
- # best to access that from in here.
- my $sender = FixMyStreet->config('CONTACT_EMAIL');
- $sender =~ s/team/fms-DO-NOT-REPLY/;
+ my $sender = FixMyStreet->config('DO_NOT_REPLY_EMAIL');
return $sender;
}
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 ba939b443..fd14b0acc 100644
--- a/perllib/FixMyStreet/Geocode/OSM.pm
+++ b/perllib/FixMyStreet/Geocode/OSM.pm
@@ -15,9 +15,10 @@ use Digest::MD5 qw(md5_hex);
use Encode;
use File::Slurp;
use File::Path ();
-use LWP::Simple;
+use LWP::Simple qw($ua);
use Memcached;
use XML::Simple;
+use mySociety::Locale;
my $osmapibase = "http://www.openstreetmap.org/api/";
my $nominatimbase = "http://nominatim.openstreetmap.org/";
@@ -28,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,
@@ -49,6 +55,7 @@ sub string {
if (-s $cache_file) {
$js = File::Slurp::read_file($cache_file);
} else {
+ $ua->timeout(15);
$js = LWP::Simple::get($url);
$js = encode_utf8($js) if utf8::is_utf8($js);
File::Path::mkpath($cache_dir);
@@ -56,7 +63,7 @@ sub string {
}
if (!$js) {
- return { error => _('Sorry, we could not parse that location. Please try again.') };
+ return { error => _('Sorry, we could not find that location.') };
}
$js = JSON->new->utf8->allow_nonref->decode($js);
diff --git a/perllib/FixMyStreet/Geocode/Zurich.pm b/perllib/FixMyStreet/Geocode/Zurich.pm
new file mode 100644
index 000000000..5aaca2c8e
--- /dev/null
+++ b/perllib/FixMyStreet/Geocode/Zurich.pm
@@ -0,0 +1,107 @@
+#!/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 Digest::MD5 qw(md5_hex);
+use File::Path ();
+use Geo::Coordinates::CH1903;
+use SOAP::Lite;
+use Storable;
+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 $cache_dir = FixMyStreet->config('GEO_CACHE') . 'zurich/';
+ my $cache_file = $cache_dir . md5_hex($s);
+ my $result;
+ if (-s $cache_file) {
+ $result = retrieve($cache_file);
+ } else {
+ my $search = SOAP::Data->name('search' => $s)->type('');
+ my $count = SOAP::Data->name('count' => 10)->type('');
+ eval {
+ $result = $soap->call($method, $security, $search, $count);
+ };
+ if ($@) {
+ return { error => 'The geocoder appears to be down.' };
+ }
+ $result = $result->result;
+ File::Path::mkpath($cache_dir);
+ store $result, $cache_file if $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;
+
diff --git a/perllib/FixMyStreet/Map.pm b/perllib/FixMyStreet/Map.pm
index d36b91ffe..a1876e150 100644
--- a/perllib/FixMyStreet/Map.pm
+++ b/perllib/FixMyStreet/Map.pm
@@ -52,10 +52,6 @@ sub set_map_class {
$map_class = $str;
}
-sub header_js {
- return $map_class->header_js(@_);
-}
-
sub display_map {
return $map_class->display_map(@_);
}
@@ -118,7 +114,26 @@ sub _map_features {
}
sub map_pins {
- return $map_class->map_pins(@_);
+ my ($c, $interval) = @_;
+
+ my $bbox = $c->req->param('bbox');
+ my ( $min_lon, $min_lat, $max_lon, $max_lat ) = split /,/, $bbox;
+
+ my ( $around_map, $around_map_list, $nearby, $dist ) =
+ FixMyStreet::Map::map_features_bounds( $c, $min_lon, $min_lat, $max_lon, $max_lat, $interval );
+
+ # create a list of all the pins
+ my @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 : $_;
+ my $colour = $c->cobrand->pin_colour( $p, 'around' );
+ [ $p->latitude, $p->longitude,
+ $colour,
+ $p->id, $p->title
+ ]
+ } @$around_map, @$nearby;
+
+ return (\@pins, $around_map_list, $nearby, $dist);
}
sub click_to_wgs84 {
diff --git a/perllib/FixMyStreet/Map/OSM.pm b/perllib/FixMyStreet/Map/OSM.pm
index 693f42e4f..d8abc9dd6 100644
--- a/perllib/FixMyStreet/Map/OSM.pm
+++ b/perllib/FixMyStreet/Map/OSM.pm
@@ -62,7 +62,7 @@ sub display_map {
# Adjust zoom level dependent upon population density
my $dist = $c->stash->{distance}
|| mySociety::Gaze::get_radius_containing_population( $params{latitude}, $params{longitude}, 200_000 );
- my $default_zoom = $numZoomLevels - 3;
+ my $default_zoom = $c->cobrand->default_map_zoom() ? $c->cobrand->default_map_zoom() : $numZoomLevels - 3;
$default_zoom = $numZoomLevels - 2 if $dist < 10;
# Map centre may be overridden in the query string
@@ -94,29 +94,6 @@ sub display_map {
};
}
-sub map_pins {
- my ($self, $c, $interval) = @_;
-
- my $bbox = $c->req->param('bbox');
- my ( $min_lon, $min_lat, $max_lon, $max_lat ) = split /,/, $bbox;
-
- my ( $around_map, $around_map_list, $nearby, $dist ) =
- FixMyStreet::Map::map_features_bounds( $c, $min_lon, $min_lat, $max_lon, $max_lat, $interval );
-
- # create a list of all the pins
- my @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 : $_;
- my $colour = $c->cobrand->pin_colour( $p, 'around' );
- [ $p->latitude, $p->longitude,
- $colour,
- $p->id, $p->title
- ]
- } @$around_map, @$nearby;
-
- return (\@pins, $around_map_list, $nearby, $dist);
-}
-
sub compass {
my ( $x, $y, $z ) = @_;
return {
diff --git a/perllib/FixMyStreet/Map/Zurich.pm b/perllib/FixMyStreet/Map/Zurich.pm
new file mode 100644
index 000000000..d2f7a35af
--- /dev/null
+++ b/perllib/FixMyStreet/Map/Zurich.pm
@@ -0,0 +1,177 @@
+#!/usr/bin/perl
+#
+# FixMyStreet:Map::Zurich
+# Zurich have their own tileserver.
+#
+# Copyright (c) 2012 UK Citizens Online Democracy. All rights reserved.
+# Email: steve@mysociety.org; WWW: http://www.mysociety.org/
+
+package FixMyStreet::Map::Zurich;
+
+use strict;
+use Geo::Coordinates::CH1903;
+use Math::Trig;
+use Utils;
+
+use constant ZOOM_LEVELS => 10;
+use constant DEFAULT_ZOOM => 7;
+use constant MIN_ZOOM_LEVEL => 0;
+
+sub map_tiles {
+ my ( $self, %params ) = @_;
+ my ( $col, $row, $z ) = ( $params{x_tile}, $params{y_tile}, $params{matrix_id} );
+ my $tile_url = $self->base_tile_url();
+ return [
+ "$tile_url/$z/" . ($row - 1) . "/" . ($col - 1) . ".jpg",
+ "$tile_url/$z/" . ($row - 1) . "/$col.jpg",
+ "$tile_url/$z/$row/" . ($col - 1) . ".jpg",
+ "$tile_url/$z/$row/$col.jpg",
+ ];
+}
+
+sub base_tile_url {
+ return 'http://www.wmts.stadt-zuerich.ch/Luftbild/MapServer/WMTS/tile/1.0.0/Luftbild/default/nativeTileMatrixSet';
+}
+
+sub copyright {
+ return '&copy; Stadt Z&uuml;rich';
+}
+
+# display_map C PARAMS
+# PARAMS include:
+# latitude, longitude for the centre point of the map
+# CLICKABLE is set if the map is clickable
+# PINS is array of pins to show, location and colour
+sub display_map {
+ my ($self, $c, %params) = @_;
+
+ my $numZoomLevels = ZOOM_LEVELS;
+ my $zoomOffset = MIN_ZOOM_LEVEL;
+# if ($params{any_zoom}) {
+# $numZoomLevels = 10;
+# $zoomOffset = 0;
+# }
+
+ # TODO Adjust zoom level dependent upon population density
+ my $default_zoom = DEFAULT_ZOOM;
+
+ # Map centre may be overridden in the query string
+ $params{latitude} = Utils::truncate_coordinate($c->req->params->{lat} + 0)
+ if defined $c->req->params->{lat};
+ $params{longitude} = Utils::truncate_coordinate($c->req->params->{lon} + 0)
+ if defined $c->req->params->{lon};
+
+ my $zoom = defined $c->req->params->{zoom} ? $c->req->params->{zoom} + 0 : $default_zoom;
+ $zoom = $numZoomLevels - 1 if $zoom >= $numZoomLevels;
+ $zoom = 0 if $zoom < 0;
+ $params{zoom_act} = $zoomOffset + $zoom;
+
+ ($params{x_tile}, $params{y_tile}, $params{matrix_id}) = latlon_to_tile_with_adjust($params{latitude}, $params{longitude}, $params{zoom_act});
+
+ foreach my $pin (@{$params{pins}}) {
+ ($pin->{px}, $pin->{py}) = latlon_to_px($pin->{latitude}, $pin->{longitude}, $params{x_tile}, $params{y_tile}, $params{zoom_act});
+ }
+
+ $c->stash->{map} = {
+ %params,
+ type => 'zurich',
+ map_type => 'OpenLayers.Layer.WMTS',
+ tiles => $self->map_tiles( %params ),
+ copyright => $self->copyright(),
+ zoom => $zoom,
+ zoomOffset => $zoomOffset,
+ numZoomLevels => $numZoomLevels,
+ };
+}
+
+# Given a lat/lon, convert it to Zurch tile co-ordinates (precise).
+sub latlon_to_tile($$$) {
+ my ($lat, $lon, $zoom) = @_;
+
+ my ($x, $y) = Geo::Coordinates::CH1903::from_latlon($lat, $lon);
+
+ my $matrix_id = $zoom - 1;
+ $matrix_id = 0 if $matrix_id < 0;
+
+ my @scales = ( '250000', '125000', '64000', '32000', '16000', '8000', '4000', '2000', '1000', '500' );
+ my $tileOrigin = { lat => 30814423, lon => -29386322 };
+ my $tileSize = 256;
+ my $res = $scales[$zoom] / (39.3701 * 96); # OpenLayers.INCHES_PER_UNIT[units] * OpenLayers.DOTS_PER_INCH
+
+ my $fx = ( $x - $tileOrigin->{lon} ) / ($res * $tileSize);
+ my $fy = ( $tileOrigin->{lat} - $y ) / ($res * $tileSize);
+
+ return ( $fx, $fy, $matrix_id );
+}
+
+# Given a lat/lon, convert it to OSM tile co-ordinates (nearest actual tile,
+# adjusted so the point will be near the centre of a 2x2 tiled map).
+sub latlon_to_tile_with_adjust($$$) {
+ my ($lat, $lon, $zoom) = @_;
+ my ($x_tile, $y_tile, $matrix_id) = latlon_to_tile($lat, $lon, $zoom);
+
+ # Try and have point near centre of map
+ if ($x_tile - int($x_tile) > 0.5) {
+ $x_tile += 1;
+ }
+ if ($y_tile - int($y_tile) > 0.5) {
+ $y_tile += 1;
+ }
+
+ return ( int($x_tile), int($y_tile), $matrix_id );
+}
+
+sub tile_to_latlon {
+ my ($fx, $fy, $zoom) = @_;
+
+ my @scales = ( '250000', '125000', '64000', '32000', '16000', '8000', '4000', '2000', '1000', '500' );
+ my $tileOrigin = { lat => 30814423, lon => -29386322 };
+ my $tileSize = 256;
+ my $res = $scales[$zoom] / (39.3701 * 96); # OpenLayers.INCHES_PER_UNIT[units] * OpenLayers.DOTS_PER_INCH
+
+ my $x = $fx * $res * $tileSize + $tileOrigin->{lon};
+ my $y = $tileOrigin->{lat} - $fy * $res * $tileSize;
+
+ my ($lat, $lon) = Geo::Coordinates::CH1903::to_latlon($x, $y);
+
+ return ( $lat, $lon );
+}
+
+# Given a lat/lon, convert it to pixel co-ordinates from the top left of the map
+sub latlon_to_px($$$$$) {
+ my ($lat, $lon, $x_tile, $y_tile, $zoom) = @_;
+ my ($pin_x_tile, $pin_y_tile) = latlon_to_tile($lat, $lon, $zoom);
+ my $pin_x = tile_to_px($pin_x_tile, $x_tile);
+ my $pin_y = tile_to_px($pin_y_tile, $y_tile);
+ return ($pin_x, $pin_y);
+}
+
+# Convert tile co-ordinates to pixel co-ordinates from top left of map
+# C is centre tile reference of displayed map
+sub tile_to_px {
+ my ($p, $c) = @_;
+ $p = 256 * ($p - $c + 1);
+ $p = int($p + .5 * ($p <=> 0));
+ return $p;
+}
+
+sub click_to_tile {
+ my ($pin_tile, $pin) = @_;
+ $pin -= 256 while $pin > 256;
+ $pin += 256 while $pin < 0;
+ return $pin_tile + $pin / 256;
+}
+
+# Given some click co-ords (the tile they were on, and where in the
+# tile they were), convert to WGS84 and return.
+# XXX Note use of MIN_ZOOM_LEVEL here. (Copied from OSM, needed here?)
+sub click_to_wgs84 {
+ my ($self, $c, $pin_tile_x, $pin_x, $pin_tile_y, $pin_y) = @_;
+ my $tile_x = click_to_tile($pin_tile_x, $pin_x);
+ my $tile_y = click_to_tile($pin_tile_y, $pin_y);
+ my $zoom = MIN_ZOOM_LEVEL + (defined $c->req->params->{zoom} ? $c->req->params->{zoom} : DEFAULT_ZOOM);
+ my ($lat, $lon) = tile_to_latlon($tile_x, $tile_y, $zoom);
+ return ( $lat, $lon );
+}
+
+1;
diff --git a/perllib/FixMyStreet/SendReport.pm b/perllib/FixMyStreet/SendReport.pm
index f750ef479..f679d826e 100644
--- a/perllib/FixMyStreet/SendReport.pm
+++ b/perllib/FixMyStreet/SendReport.pm
@@ -39,8 +39,16 @@ sub add_council {
my $self = shift;
my $council = shift;
my $info = shift;
+ my $config = shift;
- $self->councils->{ $council } = $info;
+ $self->councils->{ $council } = { info => $info, config => $config };
+}
+
+sub delete_council {
+ my $self = shift;
+ my $council = shift;
+
+ delete $self->councils->{$council};
}
diff --git a/perllib/FixMyStreet/SendReport/Email.pm b/perllib/FixMyStreet/SendReport/Email.pm
index 654ed6b3a..f26116bc4 100644
--- a/perllib/FixMyStreet/SendReport/Email.pm
+++ b/perllib/FixMyStreet/SendReport/Email.pm
@@ -12,6 +12,7 @@ sub build_recipient_list {
my $all_confirmed = 1;
foreach my $council ( keys %{ $self->councils } ) {
+
my $contact = FixMyStreet::App->model("DB::Contact")->find( {
deleted => 0,
area_id => $council,
@@ -32,7 +33,13 @@ sub build_recipient_list {
$self->unconfirmed_notes->{$council_email}{$row->category} = $note;
}
- push @{ $self->to }, [ $council_email, $self->councils->{ $council }->{name} ];
+ # see something uses council areas but doesn't send to councils so just use a
+ # generic name here to minimise confusion
+ if ( $row->cobrand eq 'seesomething' ) {
+ push @{ $self->to }, [ $council_email, 'See Something, Say Something' ];
+ } else {
+ push @{ $self->to }, [ $council_email, $self->councils->{ $council }->{info}->{name} ];
+ }
$recips{$council_email} = 1;
}
@@ -45,7 +52,9 @@ sub get_template {
my $template = 'submit.txt';
$template = 'submit-brent.txt' if $row->council eq 2488 || $row->council eq 2237;
- my $template_path = FixMyStreet->path_to( "templates", "email", $row->cobrand, $template )->stringify;
+ my $template_path = FixMyStreet->path_to( "templates", "email", $row->cobrand, $row->lang, $template )->stringify;
+ $template_path = FixMyStreet->path_to( "templates", "email", $row->cobrand, $template )->stringify
+ unless -e $template_path;
$template_path = FixMyStreet->path_to( "templates", "email", "default", $template )->stringify
unless -e $template_path;
$template = Utils::read_file( $template_path );
diff --git a/perllib/FixMyStreet/SendReport/EmptyHomes.pm b/perllib/FixMyStreet/SendReport/EmptyHomes.pm
index e1b914523..4a6f058fe 100644
--- a/perllib/FixMyStreet/SendReport/EmptyHomes.pm
+++ b/perllib/FixMyStreet/SendReport/EmptyHomes.pm
@@ -28,7 +28,7 @@ sub build_recipient_list {
#$note{$council_email}{$row->category} = $note;
}
- push @{ $self->to }, [ $council_email, $self->councils->{ $council }->{name} ];
+ push @{ $self->to }, [ $council_email, $self->councils->{ $council }->{ info }->{name} ];
$recips{$council_email} = 1;
my $country = $self->councils->{$council}->{country};
diff --git a/perllib/FixMyStreet/SendReport/NI.pm b/perllib/FixMyStreet/SendReport/NI.pm
index 0783a385b..810ee60e2 100644
--- a/perllib/FixMyStreet/SendReport/NI.pm
+++ b/perllib/FixMyStreet/SendReport/NI.pm
@@ -23,7 +23,7 @@ sub build_recipient_list {
$email = 'N/A' unless $email;
}
- my $name = $self->councils->{$council}->{name};
+ my $name = $self->councils->{$council}->{info}->{name};
if ( $email =~ /^roads.([^@]*)\@drdni/ ) {
$name = "Roads Service (\u$1)";
$h->{councils_name} = $name;
diff --git a/perllib/FixMyStreet/SendReport/Open311.pm b/perllib/FixMyStreet/SendReport/Open311.pm
index 42c103b82..93b96ce00 100644
--- a/perllib/FixMyStreet/SendReport/Open311.pm
+++ b/perllib/FixMyStreet/SendReport/Open311.pm
@@ -9,6 +9,9 @@ use FixMyStreet::App;
use mySociety::Config;
use DateTime::Format::W3CDTF;
use Open311;
+use Readonly;
+
+Readonly::Scalar my $COUNCIL_ID_OXFORDSHIRE => 2237;
sub should_skip {
my $self = shift;
@@ -28,13 +31,13 @@ sub send {
my $result = -1;
foreach my $council ( keys %{ $self->councils } ) {
- my $conf = FixMyStreet::App->model("DB::Open311conf")->search( { area_id => $council, endpoint => { '!=', '' } } )->first;
+ my $conf = $self->councils->{$council}->{config};
my $always_send_latlong = 1;
my $send_notpinpointed = 0;
my $use_service_as_deviceid = 0;
- my $basic_desc = 0;
+ my $extended_desc = 1;
# Extra bromley fields
if ( $row->council =~ /2482/ ) {
@@ -64,7 +67,22 @@ sub send {
push @$extra, { name => 'last_name', value => $lastname };
}
- $basic_desc = 1;
+ $extended_desc = 0;
+ }
+
+ # extra Oxfordshire fields: send nearest street, postcode, northing and easting, and the FMS id
+ if ( $row->council =~ /$COUNCIL_ID_OXFORDSHIRE/ ) {
+
+ my $extra = $row->extra;
+ push @$extra, { name => 'external_id', value => $row->id };
+ push @$extra, { name => 'closest_address', value => $h->{closest_address} } if $h->{closest_address};
+ if ( $row->used_map || ( !$row->used_map && !$row->postcode ) ) {
+ push @$extra, { name => 'northing', value => $h->{northing} };
+ push @$extra, { name => 'easting', value => $h->{easting} };
+ }
+ $row->extra( $extra );
+
+ $extended_desc = 'oxfordshire';
}
# FIXME: we've already looked this up before
@@ -81,7 +99,7 @@ sub send {
always_send_latlong => $always_send_latlong,
send_notpinpointed => $send_notpinpointed,
use_service_as_deviceid => $use_service_as_deviceid,
- basic_description => $basic_desc,
+ extended_description => $extended_desc,
);
# non standard west berks end points
@@ -89,21 +107,44 @@ sub send {
$open311->endpoints( { services => 'Services', requests => 'Requests' } );
}
+ # non-standard Oxfordshire endpoint (because it's just a script, not a full Open311 service)
+ if ( $row->council =~ /$COUNCIL_ID_OXFORDSHIRE/ ) {
+ $open311->endpoints( { requests => 'open311_service_request.cgi' } );
+ }
+
# required to get round issues with CRM constraints
if ( $row->council =~ /2218/ ) {
$row->user->name( $row->user->id . ' ' . $row->user->name );
}
+ if ($row->cobrand eq 'fixmybarangay') {
+ # FixMyBarangay endpoints expect external_id as an attribute, as do Oxfordshire
+ $row->extra( [ { 'name' => 'external_id', 'value' => $row->id } ] );
+ }
+
my $resp = $open311->send_service_request( $row, $h, $contact->email );
# make sure we don't save user changes from above
- if ( $row->council =~ /2218/ || $row->council =~ /2482/ ) {
+ if ( $row->council =~ /(2218|2482|$COUNCIL_ID_OXFORDSHIRE)/ || $row->cobrand eq 'fixmybarangay') {
$row->discard_changes();
}
if ( $resp ) {
$row->external_id( $resp );
$row->send_method_used('Open311');
+ if ($row->cobrand eq 'fixmybarangay') {
+ # FixMyBarangay: currently the external bodies using Open311 are DPS, DEPW, DPWH
+ # for now identify the latter two by their name in the service_code ($contact->email)
+ # So: this works because we are anticipating the service codes for (e.g., potholes) look
+ # like this:
+ # POTDEPW or POTDPWH
+ # (TODO: this will change when we have 'body' logic in place, meanwhile: hardcoded)
+ if ($contact->email =~ /(DEPW|DPWH)$/i) {
+ $row->external_body(uc $1); # body is DEPW (city roads) or DPWH (national roads)
+ } else {
+ $row->external_body("DPS"); # only other open311 dept is DPS
+ }
+ }
$result *= 0;
$self->success( 1 );
} else {
diff --git a/perllib/FixMyStreet/TestMech.pm b/perllib/FixMyStreet/TestMech.pm
index 2a49cc2f8..7f81c0fc2 100644
--- a/perllib/FixMyStreet/TestMech.pm
+++ b/perllib/FixMyStreet/TestMech.pm
@@ -378,6 +378,49 @@ sub extract_update_metas {
return \@metas;
}
+=head2 extract_problem_list
+
+ $problems = $mech->extract_problem_list
+
+Returns an array ref of all problem titles on a page featuring standard issue lists
+
+=cut
+
+sub extract_problem_list {
+ my $mech = shift;
+
+ my $result = scraper {
+ process 'ul.issue-list-a li a h4', 'problems[]', 'TEXT';
+ }->scrape( $mech->response );
+
+ return $result->{ problems } || [];
+}
+
+=head2 extract_report_stats
+
+ $stats = $mech->extract_report_stats
+
+Returns a hash ref keyed by council name of all the council stats from the all reports
+page. Each value is an array ref with the first element being the council name and the
+rest being the stats in the order the appear in each row.
+
+=cut
+
+sub extract_report_stats {
+ my $mech = shift;
+
+ my $result = scraper {
+ process 'tr[align=center]', 'councils[]' => scraper {
+ process 'td.title a', 'council', 'TEXT',
+ process 'td', 'stats[]', 'TEXT'
+ }
+ }->scrape( $mech->response );
+
+ my %councils = map { $_->{council} => $_->{stats} } @{ $result->{councils} };
+
+ return \%councils;
+}
+
=head2 visible_form_values
$hashref = $mech->visible_form_values( );
@@ -417,6 +460,7 @@ sub visible_form_values {
grep { ref($_) ne 'HTML::Form::SubmitInput' }
grep { ref($_) ne 'HTML::Form::ImageInput' }
grep { ref($_) ne 'HTML::Form::TextInput' || $_->type ne 'hidden' }
+ grep { !$_->disabled }
$form->inputs;
my @visible_field_names = map { $_->name } @visible_fields;
@@ -475,4 +519,67 @@ sub get_ok_json {
return decode_json( $res->content );
}
+sub delete_problems_for_council {
+ my $mech = shift;
+ my $council = shift;
+
+ my $reports = FixMyStreet::App->model('DB::Problem')->search( { council => $council } );
+ if ( $reports ) {
+ for my $r ( $reports->all ) {
+ $r->comments->delete;
+ }
+ $reports->delete;
+ }
+}
+
+sub create_problems_for_council {
+ my ( $mech, $count, $council, $title, $params ) = @_;
+
+ my $dt = $params->{dt} || DateTime->now();
+
+ my $user = $params->{user} ||
+ FixMyStreet::App->model('DB::User')
+ ->find_or_create( { email => 'test@example.com', name => 'Test User' } );
+
+ delete $params->{user};
+ delete $params->{dt};
+
+ my @problems;
+
+ while ($count) {
+ my $default_params = {
+ postcode => 'SW1A 1AA',
+ council => $council,
+ areas => ',105255,11806,11828,2247,2504,',
+ category => 'Other',
+ title => "$title Test $count for $council",
+ detail => "$title Test $count for $council Detail",
+ used_map => 't',
+ name => 'Test User',
+ anonymous => 'f',
+ state => 'confirmed',
+ confirmed => $dt->ymd . ' ' . $dt->hms,
+ lang => 'en-gb',
+ service => '',
+ cobrand => 'default',
+ cobrand_data => '',
+ send_questionnaire => 't',
+ latitude => '51.5016605453401',
+ longitude => '-0.142497580865087',
+ user_id => $user->id,
+ photo => 1,
+ };
+
+ my %report_params = ( %$default_params, %$params );
+
+ my $problem =
+ FixMyStreet::App->model('DB::Problem')->create( \%report_params );
+
+ push @problems, $problem;
+ $count--;
+ }
+
+ return @problems;
+}
+
1;