aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet')
-rw-r--r--perllib/FixMyStreet/App.pm9
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm473
-rw-r--r--perllib/FixMyStreet/App/Controller/Alert.pm6
-rw-r--r--perllib/FixMyStreet/App/Controller/Around.pm73
-rw-r--r--perllib/FixMyStreet/App/Controller/Auth.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Council.pm52
-rw-r--r--perllib/FixMyStreet/App/Controller/Dashboard.pm21
-rwxr-xr-xperllib/FixMyStreet/App/Controller/JS.pm4
-rw-r--r--perllib/FixMyStreet/App/Controller/JSON.pm20
-rw-r--r--perllib/FixMyStreet/App/Controller/Open311.pm24
-rw-r--r--perllib/FixMyStreet/App/Controller/Photo.pm3
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm41
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm122
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/Update.pm8
-rw-r--r--perllib/FixMyStreet/App/Controller/Reports.pm360
-rwxr-xr-xperllib/FixMyStreet/App/Controller/Rss.pm11
-rw-r--r--perllib/FixMyStreet/App/Controller/Tokens.pm22
-rw-r--r--perllib/FixMyStreet/App/View/Web.pm12
-rw-r--r--perllib/FixMyStreet/Cobrand/Default.pm80
-rw-r--r--perllib/FixMyStreet/Cobrand/FiksGataMi.pm23
-rw-r--r--perllib/FixMyStreet/Cobrand/LichfieldDC.pm2
-rw-r--r--perllib/FixMyStreet/Cobrand/Oxfordshire.pm2
-rw-r--r--perllib/FixMyStreet/Cobrand/SeeSomething.pm8
-rw-r--r--perllib/FixMyStreet/Cobrand/UK.pm88
-rw-r--r--perllib/FixMyStreet/Cobrand/UKCouncils.pm14
-rw-r--r--perllib/FixMyStreet/Cobrand/Zurich.pm444
-rw-r--r--perllib/FixMyStreet/DB/Result/Body.pm108
-rw-r--r--perllib/FixMyStreet/DB/Result/BodyArea.pm33
-rw-r--r--perllib/FixMyStreet/DB/Result/Comment.pm5
-rw-r--r--perllib/FixMyStreet/DB/Result/Contact.pm17
-rw-r--r--perllib/FixMyStreet/DB/Result/ContactsHistory.pm6
-rw-r--r--perllib/FixMyStreet/DB/Result/Open311conf.pm61
-rw-r--r--perllib/FixMyStreet/DB/Result/Problem.pm136
-rw-r--r--perllib/FixMyStreet/DB/Result/Token.pm1
-rw-r--r--perllib/FixMyStreet/DB/Result/User.pm60
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/AlertType.pm10
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Body.pm17
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Nearby.pm7
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Problem.pm97
-rw-r--r--perllib/FixMyStreet/Geocode.pm2
-rw-r--r--perllib/FixMyStreet/Geocode/Zurich.pm14
-rw-r--r--perllib/FixMyStreet/Map.pm2
-rw-r--r--perllib/FixMyStreet/Map/Zurich.pm10
-rw-r--r--perllib/FixMyStreet/SendReport.pm22
-rw-r--r--perllib/FixMyStreet/SendReport/Barnet.pm8
-rw-r--r--perllib/FixMyStreet/SendReport/Email.pm37
-rw-r--r--perllib/FixMyStreet/SendReport/EmptyHomes.pm23
-rw-r--r--perllib/FixMyStreet/SendReport/NI.pm8
-rw-r--r--perllib/FixMyStreet/SendReport/Open311.pm26
-rw-r--r--perllib/FixMyStreet/SendReport/Zurich.pm58
-rw-r--r--perllib/FixMyStreet/TestMech.pm34
51 files changed, 1795 insertions, 931 deletions
diff --git a/perllib/FixMyStreet/App.pm b/perllib/FixMyStreet/App.pm
index 9c7aba9e5..b76f4d3ba 100644
--- a/perllib/FixMyStreet/App.pm
+++ b/perllib/FixMyStreet/App.pm
@@ -3,6 +3,7 @@ use Moose;
use namespace::autoclean;
use Catalyst::Runtime 5.80;
+use DateTime;
use FixMyStreet;
use FixMyStreet::Cobrand;
use Memcached;
@@ -188,6 +189,14 @@ sub setup_request {
mySociety::MaPit::configure( "http://$host/fakemapit/" );
}
+ # XXX Put in cobrand / do properly
+ if ($c->cobrand->moniker eq 'zurich') {
+ FixMyStreet::DB::Result::Problem->visible_states_add_unconfirmed();
+ DateTime->DefaultLocale( 'de_CH' );
+ } else {
+ DateTime->DefaultLocale( 'en_US' );
+ }
+
return $c;
}
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm
index e14c7dc66..a3a241590 100644
--- a/perllib/FixMyStreet/App/Controller/Admin.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin.pm
@@ -4,8 +4,9 @@ use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller'; }
+use Path::Class;
use POSIX qw(strftime strcoll);
-use Digest::MD5 qw(md5_hex);
+use Digest::SHA1 qw(sha1_hex);
use mySociety::EmailUtil qw(is_valid_email);
use if !$ENV{TRAVIS}, 'Image::Magick';
@@ -23,23 +24,32 @@ Admin pages
=cut
-=head2 summary
-
-Redirect to index page. There to make the allowed pages stuff neater
-
-=cut
-
sub begin : Private {
my ( $self, $c ) = @_;
$c->uri_disposition('relative');
- if ( $c->cobrand->moniker eq 'seesomething' ) {
+ if ( $c->cobrand->moniker eq 'zurich' || $c->cobrand->moniker eq 'seesomething' ) {
$c->detach( '/auth/redirect' ) unless $c->user_exists;
- $c->detach( '/auth/redirect' ) unless $c->user->from_council;
+ $c->detach( '/auth/redirect' ) unless $c->user->from_body;
+ }
+ if ( $c->cobrand->moniker eq 'zurich' ) {
+ $c->cobrand->admin_type();
}
}
+sub auto : Private {
+ my ( $self, $c ) = @_;
+
+ $c->forward('check_page_allowed');
+}
+
+=head2 summary
+
+Redirect to index page. There to make the allowed pages stuff neater
+
+=cut
+
sub summary : Path( 'summary' ) : Args(0) {
my ( $self, $c ) = @_;
$c->go( 'index' );
@@ -54,7 +64,9 @@ Displays some summary information for the requests.
sub index : Path : Args(0) {
my ( $self, $c ) = @_;
- $c->forward('check_page_allowed');
+ if ($c->cobrand->moniker eq 'zurich' && $c->stash->{admin_type} ne 'super') {
+ return $c->cobrand->admin();
+ }
my $site_restriction = $c->cobrand->site_restriction();
@@ -124,8 +136,6 @@ sub index : Path : Args(0) {
sub timeline : Path( 'timeline' ) : Args(0) {
my ($self, $c) = @_;
- $c->forward('check_page_allowed');
-
my $site_restriction = $c->cobrand->site_restriction();
my %time;
@@ -175,8 +185,6 @@ sub timeline : Path( 'timeline' ) : Args(0) {
sub questionnaire : Path('questionnaire') : Args(0) {
my ( $self, $c ) = @_;
- $c->forward('check_page_allowed');
-
my $questionnaires = $c->model('DB::Questionnaire')->search(
{ whenanswered => { '!=', undef } },
{ group_by => [ 'ever_reported' ],
@@ -207,10 +215,10 @@ sub questionnaire : Path('questionnaire') : Args(0) {
return 1;
}
-sub council_list : Path('council_list') : Args(0) {
+sub bodies : Path('bodies') : Args(0) {
my ( $self, $c ) = @_;
- $c->forward('check_page_allowed');
+ $c->forward( 'get_token' );
my $edit_activity = $c->model('DB::ContactsHistory')->search(
undef,
@@ -224,54 +232,74 @@ sub council_list : Path('council_list') : Args(0) {
$c->stash->{edit_activity} = $edit_activity;
- # Not London, as treated separately
- my $area_types = $c->cobrand->moniker eq 'emptyhomes'
- ? $c->cobrand->area_types
- : [ grep { $_ ne 'LBO' } @{ $c->cobrand->area_types } ];
- my $areas = mySociety::MaPit::call('areas', $area_types);
+ my $posted = $c->req->param('posted') || '';
+ if ( $posted eq 'body' ) {
+ $c->forward('check_token');
- my @councils_ids = sort { strcoll($areas->{$a}->{name}, $areas->{$b}->{name}) } keys %$areas;
- @councils_ids = $c->cobrand->filter_all_council_ids_list( @councils_ids );
+ my $params = $c->forward('body_params');
+ my $body = $c->model('DB::Body')->create( $params );
+ my $area_ids = $c->req->params->{area_ids};
+ if ($area_ids) {
+ $area_ids = [ $area_ids ] unless ref $area_ids;
+ foreach (@$area_ids) {
+ $c->model('DB::BodyArea')->create( { body => $body, area_id => $_ } );
+ }
+ }
+
+ $c->stash->{updated} = _('New body added');
+ }
+
+ $c->forward( 'fetch_all_bodies' );
+
+ # XXX For fixmystreet.com, need to exclude bodies that are covering London.
+ # But soon, this means just don't have bodies covering London.
my $contacts = $c->model('DB::Contact')->search(
undef,
{
- select => [ 'area_id', { count => 'id' }, { count => \'case when deleted then 1 else null end' },
+ select => [ 'body_id', { count => 'id' }, { count => \'case when deleted then 1 else null end' },
{ count => \'case when confirmed then 1 else null end' } ],
- as => [qw/area_id c deleted confirmed/],
- group_by => [ 'area_id' ],
+ as => [qw/body_id c deleted confirmed/],
+ group_by => [ 'body_id' ],
result_class => 'DBIx::Class::ResultClass::HashRefInflator'
}
);
- my %council_info = map { $_->{area_id} => $_ } $contacts->all;
+ my %council_info = map { $_->{body_id} => $_ } $contacts->all;
- my @no_info = grep { !$council_info{$_} } @councils_ids;
- my @one_plus_deleted = grep { $council_info{$_} && $council_info{$_}->{deleted} } @councils_ids;
- my @unconfirmeds = grep { $council_info{$_} && !$council_info{$_}->{deleted} && $council_info{$_}->{confirmed} != $council_info{$_}->{c} } @councils_ids;
- my @all_confirmed = grep { $council_info{$_} && !$council_info{$_}->{deleted} && $council_info{$_}->{confirmed} == $council_info{$_}->{c} } @councils_ids;
-
- $c->stash->{areas} = $areas;
$c->stash->{counts} = \%council_info;
- $c->stash->{no_info} = \@no_info;
- $c->stash->{one_plus_deleted} = \@one_plus_deleted;
- $c->stash->{unconfirmeds} = \@unconfirmeds;
- $c->stash->{all_confirmed} = \@all_confirmed;
+
+ $c->forward( 'body_form_dropdowns' );
return 1;
}
-sub council_contacts : Path('council_contacts') : Args(1) {
- my ( $self, $c, $area_id ) = @_;
+sub body_form_dropdowns : Private {
+ my ( $self, $c ) = @_;
- $c->forward('check_page_allowed');
+ my $areas;
+ if ($c->cobrand->moniker eq 'zurich') {
+ $areas = mySociety::MaPit::call('areas', 274456);
+ } else {
+ $areas = mySociety::MaPit::call('areas', $c->cobrand->area_types);
+ }
+ $c->stash->{areas} = [ sort { strcoll($a->{name}, $b->{name}) } values %$areas ];
- my $posted = $c->req->param('posted') || '';
- $c->stash->{area_id} = $area_id;
+ my @methods = map { $_ =~ s/FixMyStreet::SendReport:://; $_ } keys %{ FixMyStreet::SendReport->get_senders };
+ $c->stash->{send_methods} = \@methods;
+}
+
+sub body : Path('body') : Args(1) {
+ my ( $self, $c, $body_id ) = @_;
+
+ $c->stash->{body_id} = $body_id;
$c->forward( 'get_token' );
+ $c->forward( 'lookup_body' );
+ $c->forward( 'fetch_all_bodies' );
+ $c->forward( 'body_form_dropdowns' );
- if ( $posted ) {
+ if ( $c->req->param('posted') ) {
$c->log->debug( 'posted' );
$c->forward('update_contacts');
}
@@ -285,7 +313,7 @@ sub update_contacts : Private {
my ( $self, $c ) = @_;
my $posted = $c->req->param('posted');
- my $editor = $c->req->remote_user || _('*unknown*');
+ my $editor = $c->forward('get_user');
if ( $posted eq 'new' ) {
$c->forward('check_token');
@@ -297,7 +325,7 @@ sub update_contacts : Private {
my $contact = $c->model('DB::Contact')->find_or_new(
{
- area_id => $c->stash->{area_id},
+ body_id => $c->stash->{body_id},
category => $category,
}
);
@@ -331,7 +359,7 @@ sub update_contacts : Private {
my $contacts = $c->model('DB::Contact')->search(
{
- area_id => $c->stash->{area_id},
+ body_id => $c->stash->{body_id},
category => { -in => \@categories },
}
);
@@ -346,69 +374,50 @@ sub update_contacts : Private {
);
$c->stash->{updated} = _('Values updated');
- } elsif ( $posted eq 'open311' ) {
+ } elsif ( $posted eq 'body' ) {
$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 devolved/;
-
- if ( $params{open311_id} ) {
- my $conf = $c->model('DB::Open311Conf')->find( { id => $params{open311_id} } );
-
- $conf->endpoint( $params{endpoint} );
- $conf->jurisdiction( $params{jurisdiction} );
- $conf->api_key( $params{api_key} );
- $conf->send_method( $params{send_method} );
- $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();
-
- $c->stash->{updated} = _('Configuration updated');
- } else {
- my $conf = $c->model('DB::Open311Conf')->find_or_new( { area_id => $params{area_id} } );
-
- $conf->endpoint( $params{endpoint} );
- $conf->jurisdiction( $params{jurisdiction} );
- $conf->api_key( $params{api_key} );
- $conf->send_method( $params{send_method} );
- $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();
-
- $c->stash->{updated} = _('Configuration updated - contacts will be generated automatically later');
+ my $params = $c->forward( 'body_params' );
+ $c->stash->{body}->update( $params );
+ my @current = $c->stash->{body}->body_areas->all;
+ my %current = map { $_->area_id => 1 } @current;
+ my $area_ids = $c->req->params->{area_ids};
+ if ($area_ids) {
+ $area_ids = [ $area_ids ] unless ref $area_ids;
+ foreach (@$area_ids) {
+ $c->model('DB::BodyArea')->find_or_create( { body => $c->stash->{body}, area_id => $_ } );
+ delete $current{$_};
+ }
}
+ # Remove any others
+ $c->stash->{body}->body_areas->search( { area_id => [ keys %current ] } )->delete;
+
+ $c->stash->{updated} = _('Configuration updated - contacts will be generated automatically later');
}
}
-sub display_contacts : Private {
+sub body_params : Private {
my ( $self, $c ) = @_;
- $c->forward('setup_council_details');
-
- my $area_id = $c->stash->{area_id};
-
- my $contacts = $c->model('DB::Contact')->search(
- { area_id => $area_id },
- { order_by => ['category'] }
+ my @fields = qw/name endpoint jurisdiction api_key send_method send_comments suppress_alerts send_extended_statuses comment_user_id can_be_devolved parent/;
+ my %defaults = map { $_ => '' } @fields;
+ %defaults = ( %defaults,
+ send_comments => 0,
+ suppress_alerts => 0,
+ comment_user_id => undef,
+ send_extended_statuses => 0,
+ can_be_devolved => 0,
+ parent => undef,
);
+ my %params = map { $_ => $c->req->param($_) || $defaults{$_} } @fields;
+ return \%params;
+}
- $c->stash->{contacts} = $contacts;
-
- my @methods = map { $_ =~ s/FixMyStreet::SendReport:://; $_ } keys %{ FixMyStreet::SendReport->get_senders };
- $c->stash->{send_methods} = \@methods;
-
- my $open311 = $c->model('DB::Open311Conf')->search(
- { area_id => $area_id }
- );
+sub display_contacts : Private {
+ my ( $self, $c ) = @_;
- $c->stash->{open311} = $open311;
+ my $contacts = $c->stash->{body}->contacts->search(undef, { order_by => [ 'category' ] } );
+ $c->stash->{contacts} = $contacts;
if ( $c->req->param('text') && $c->req->param('text') == 1 ) {
$c->stash->{template} = 'admin/council_contacts.txt';
@@ -419,59 +428,52 @@ sub display_contacts : Private {
return 1;
}
-sub setup_council_details : Private {
+sub lookup_body : Private {
my ( $self, $c ) = @_;
- my $area_id = $c->stash->{area_id};
-
- my $mapit_data = mySociety::MaPit::call('area', $area_id);
-
- $c->stash->{council_name} = $mapit_data->{name};
-
- my $example_postcode = mySociety::MaPit::call('area/example_postcode', $area_id);
-
- if ($example_postcode && ! ref $example_postcode) {
- $c->stash->{example_pc} = $example_postcode;
+ my $body_id = $c->stash->{body_id};
+ my $body = $c->model('DB::Body')->find($body_id);
+ $c->detach( '/page_error_404_not_found' )
+ unless $body;
+ $c->stash->{body} = $body;
+
+ if ($body->body_areas->first) {
+ my $example_postcode = mySociety::MaPit::call('area/example_postcode', $body->body_areas->first->area_id);
+ if ($example_postcode && ! ref $example_postcode) {
+ $c->stash->{example_pc} = $example_postcode;
+ }
}
return 1;
}
-sub council_edit_all : Path('council_edit') {
- my ( $self, $c, $area_id, @category ) = @_;
+# This is for if the category name contains a '/'
+sub body_edit_all : Path('body_edit') {
+ my ( $self, $c, $body_id, @category ) = @_;
my $category = join( '/', @category );
- $c->go( 'council_edit', [ $area_id, $category ] );
+ $c->go( 'body_edit', [ $body_id, $category ] );
}
-sub council_edit : Path('council_edit') : Args(2) {
- my ( $self, $c, $area_id, $category ) = @_;
+sub body_edit : Path('body_edit') : Args(2) {
+ my ( $self, $c, $body_id, $category ) = @_;
- $c->forward('check_page_allowed');
-
- $c->stash->{area_id} = $area_id;
+ $c->stash->{body_id} = $body_id;
$c->forward( 'get_token' );
- $c->forward('setup_council_details');
-
- my $contact = $c->model('DB::Contact')->search(
- {
- area_id => $area_id,
- category => $category
- }
- )->first;
+ $c->forward( 'lookup_body' );
+ my $contact = $c->stash->{body}->contacts->search( { category => $category } )->first;
$c->stash->{contact} = $contact;
my $history = $c->model('DB::ContactsHistory')->search(
{
- area_id => $area_id,
+ body_id => $body_id,
category => $category
},
{
order_by => ['contacts_history_id']
},
);
-
$c->stash->{history} = $history;
my @methods = map { $_ =~ s/FixMyStreet::SendReport:://; $_ } keys %{ FixMyStreet::SendReport->get_senders };
@@ -480,13 +482,11 @@ sub council_edit : Path('council_edit') : Args(2) {
return 1;
}
-sub search_reports : Path('search_reports') {
+sub reports : Path('reports') {
my ( $self, $c ) = @_;
- $c->forward('check_page_allowed');
-
if (my $search = $c->req->param('search')) {
- $c->stash->{searched} = 1;
+ $c->stash->{searched} = $search;
my $site_restriction = $c->cobrand->site_restriction;
@@ -523,7 +523,7 @@ sub search_reports : Path('search_reports') {
'me.name' => { ilike => $like_search },
'me.title' => { ilike => $like_search },
detail => { ilike => $like_search },
- council => { like => $like_search },
+ bodies_str => { like => $like_search },
cobrand_data => { like => $like_search },
];
}
@@ -542,8 +542,8 @@ sub search_reports : Path('search_reports') {
# will have been turned off
$c->stash->{problems} = [ $problems->all ];
- $c->stash->{edit_council_contacts} = 1
- if ( grep {$_ eq 'councilcontacts'} keys %{$c->stash->{allowed_pages}});
+ $c->stash->{edit_body_contacts} = 1
+ if ( grep {$_ eq 'body'} keys %{$c->stash->{allowed_pages}});
if (is_valid_email($search)) {
$query = [
@@ -574,7 +574,7 @@ sub search_reports : Path('search_reports') {
-or => $query,
},
{
- -select => [ 'me.*', qw/problem.council problem.state/ ],
+ -select => [ 'me.*', qw/problem.bodies_str problem.state/ ],
prefetch => [qw/user problem/],
order_by => [\"(me.state='hidden')",\"(problem.state='hidden')",'me.created']
}
@@ -592,11 +592,7 @@ sub report_edit : Path('report_edit') : Args(1) {
my $site_restriction = $c->cobrand->site_restriction;
- my $problem = $c->cobrand->problems->search(
- {
- id => $id,
- }
- )->first;
+ my $problem = $c->cobrand->problems->search( { id => $id } )->first;
$c->detach( '/page_error_404_not_found' )
unless $problem;
@@ -604,7 +600,32 @@ sub report_edit : Path('report_edit') : Args(1) {
$c->stash->{problem} = $problem;
$c->forward('get_token');
- $c->forward('check_page_allowed');
+
+ if ( $c->req->param('rotate_photo') ) {
+ $c->forward('rotate_photo');
+ return 1;
+ }
+
+ if ( $c->cobrand->moniker eq 'zurich' ) {
+
+ FixMyStreet::Map::display_map(
+ $c,
+ latitude => $problem->latitude,
+ longitude => $problem->longitude,
+ pins => $problem->used_map
+ ? [ {
+ latitude => $problem->latitude,
+ longitude => $problem->longitude,
+ colour => 'yellow',
+ type => 'big',
+ } ]
+ : [],
+ );
+
+ my $done = $c->cobrand->admin_report_edit();
+ return if $done;
+ }
+
$c->forward('check_email_for_abuse', [ $problem->user->email ] );
$c->stash->{updates} =
@@ -633,9 +654,6 @@ sub report_edit : Path('report_edit') : Args(1) {
elsif ( $c->req->param('banuser') ) {
$c->forward('ban_user');
}
- elsif ( $c->req->param('rotate_photo') ) {
- $c->forward('rotate_photo');
- }
elsif ( $c->req->param('submit') ) {
$c->forward('check_token');
@@ -664,6 +682,7 @@ 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
+ || ($c->req->param('body') && $c->req->param('body') ne $problem->bodies_str)
|| $flagged != $problem->flagged
|| $non_public != $problem->non_public )
{
@@ -673,8 +692,10 @@ sub report_edit : Path('report_edit') : Args(1) {
$problem->anonymous( $c->req->param('anonymous') );
$problem->title( $c->req->param('title') );
$problem->detail( $c->req->param('detail') );
- $problem->state( $c->req->param('state') );
+ $problem->state( $new_state );
$problem->name( $c->req->param('name') );
+ $problem->bodies_str( $c->req->param('body') ) if $c->req->param('body');
+
$problem->flagged( $flagged );
$problem->non_public( $non_public );
@@ -721,26 +742,22 @@ sub report_edit : Path('report_edit') : Args(1) {
return 1;
}
-sub search_users: Path('search_users') : Args(0) {
+sub users: Path('users') : Args(0) {
my ( $self, $c ) = @_;
- $c->forward('check_page_allowed');
-
if (my $search = $c->req->param('search')) {
- $c->stash->{searched} = 1;
+ $c->stash->{searched} = $search;
- my $search = $c->req->param('search');
my $isearch = '%' . $search . '%';
-
my $search_n = 0;
$search_n = int($search) if $search =~ /^\d+$/;
my $users = $c->model('DB::User')->search(
{
-or => [
- email => { ilike => $isearch },
- name => { ilike => $isearch },
- from_council => $search_n,
+ email => { ilike => $isearch },
+ name => { ilike => $isearch },
+ from_body => $search_n,
]
}
);
@@ -762,6 +779,9 @@ sub search_users: Path('search_users') : Args(0) {
}
}
+ } else {
+ $c->forward('get_token');
+ $c->forward('fetch_all_bodies');
}
return 1;
@@ -782,7 +802,6 @@ sub update_edit : Path('update_edit') : Args(1) {
unless $update;
$c->forward('get_token');
- $c->forward('check_page_allowed');
$c->stash->{update} = $update;
@@ -837,6 +856,11 @@ sub update_edit : Path('update_edit') : Args(1) {
if ( $new_state eq 'confirmed' and $old_state eq 'unconfirmed' ) {
$update->confirmed( \'ms_current_timestamp()' );
+ if ( $update->problem_state && $update->created > $update->problem->lastupdate ) {
+ $update->problem->state( $update->problem_state );
+ $update->problem->lastupdate( \'ms_current_timestamp()' );
+ $update->problem->update;
+ }
}
$update->update;
@@ -868,16 +892,44 @@ sub update_edit : Path('update_edit') : Args(1) {
return 1;
}
+sub user_add : Path('user_edit') : Args(0) {
+ my ( $self, $c ) = @_;
+
+ $c->stash->{template} = 'admin/user_edit.html';
+ $c->forward('get_token');
+ $c->forward('fetch_all_bodies');
+
+ return 1 unless $c->req->param('submit');
+
+ $c->forward('check_token');
+
+ my $user = $c->model('DB::User')->find_or_create( {
+ name => $c->req->param('name'),
+ email => $c->req->param('email'),
+ from_body => $c->req->param('body') || undef,
+ flagged => $c->req->param('flagged') || 0,
+ }, {
+ key => 'users_email_key'
+ } );
+ $c->stash->{user} = $user;
+
+ $c->forward( 'log_edit', [ $user->id, 'user', 'edit' ] );
+
+ $c->stash->{status_message} =
+ '<p><em>' . _('Updated!') . '</em></p>';
+
+ return 1;
+}
+
sub user_edit : Path('user_edit') : Args(1) {
my ( $self, $c, $id ) = @_;
- $c->forward('check_page_allowed');
$c->forward('get_token');
my $user = $c->model('DB::User')->find( { id => $id } );
$c->stash->{user} = $user;
- $c->forward('set_up_council_details');
+ $c->forward('fetch_all_bodies');
if ( $c->req->param('submit') ) {
$c->forward('check_token');
@@ -886,13 +938,15 @@ sub user_edit : Path('user_edit') : Args(1) {
if ( $user->email ne $c->req->param('email') ||
$user->name ne $c->req->param('name' ) ||
- $user->from_council != $c->req->param('council') ) {
+ ($user->from_body && $user->from_body->id ne $c->req->param('body')) ||
+ (!$user->from_body && $c->req->param('body'))
+ ) {
$edited = 1;
}
$user->name( $c->req->param('name') );
$user->email( $c->req->param('email') );
- $user->from_council( $c->req->param('council') || undef );
+ $user->from_body( $c->req->param('body') || undef );
$user->flagged( $c->req->param('flagged') || 0 );
$user->update;
@@ -907,11 +961,9 @@ sub user_edit : Path('user_edit') : Args(1) {
return 1;
}
-sub list_flagged : Path('list_flagged') : Args(0) {
+sub flagged : Path('flagged') : Args(0) {
my ( $self, $c ) = @_;
- $c->forward('check_page_allowed');
-
my $problems = $c->model('DB::Problem')->search( { flagged => 1 } );
# pass in as array ref as using same template as search_reports
@@ -928,9 +980,7 @@ sub list_flagged : Path('list_flagged') : Args(0) {
sub stats : Path('stats') : Args(0) {
my ( $self, $c ) = @_;
- $c->forward('check_page_allowed');
-
- $c->forward('set_up_council_details');
+ $c->forward('fetch_all_bodies');
if ( $c->cobrand->moniker eq 'seesomething' ) {
return $c->cobrand->admin_stats();
@@ -970,11 +1020,11 @@ sub stats : Path('stats') : Args(0) {
my $bymonth = $c->req->param('bymonth');
$c->stash->{bymonth} = $bymonth;
- my ( %council, %dates );
- $council{council} = { like => $c->req->param('council') }
- if $c->req->param('council');
+ my ( %body, %dates );
+ $body{bodies_str} = { like => $c->req->param('body') }
+ if $c->req->param('body');
- $c->stash->{selected_council} = $c->req->param('council');
+ $c->stash->{selected_body} = $c->req->param('body');
my $field = 'confirmed';
@@ -1009,7 +1059,7 @@ sub stats : Path('stats') : Args(0) {
$field => { '>=', $start_date},
$field => { '<=', $end_date + $one_day },
],
- %council,
+ %body,
%dates,
},
\%select,
@@ -1038,16 +1088,16 @@ sub set_allowed_pages : Private {
if( !$pages ) {
$pages = {
'summary' => [_('Summary'), 0],
- 'council_list' => [_('Bodies'), 1],
- 'search_reports' => [_('Reports'), 2],
+ 'bodies' => [_('Bodies'), 1],
+ 'reports' => [_('Reports'), 2],
'timeline' => [_('Timeline'), 3],
'questionnaire' => [_('Survey'), 4],
- 'search_users' => [_('Users'), 5],
- 'list_flagged' => [_('Flagged'), 6],
+ 'users' => [_('Users'), 5],
+ 'flagged' => [_('Flagged'), 6],
'stats' => [_('Stats'), 6],
'user_edit' => [undef, undef],
- 'council_contacts' => [undef, undef],
- 'council_edit' => [undef, undef],
+ 'body' => [undef, undef],
+ 'body_edit' => [undef, undef],
'report_edit' => [undef, undef],
'update_edit' => [undef, undef],
'abuse_edit' => [undef, undef],
@@ -1062,6 +1112,16 @@ sub set_allowed_pages : Private {
return 1;
}
+sub get_user : Private {
+ my ( $self, $c ) = @_;
+
+ my $user = $c->req->remote_user();
+ $user ||= ($c->user && $c->user->name);
+ $user ||= '';
+
+ return $user;
+}
+
=item get_token
Generate a token based on user and secret
@@ -1072,12 +1132,8 @@ sub get_token : Private {
my ( $self, $c ) = @_;
my $secret = $c->model('DB::Secret')->search()->first;
-
- my $user = $c->req->remote_user();
- $user ||= '';
-
- my $token = md5_hex(($user . $secret->secret));
-
+ my $user = $c->forward('get_user');
+ my $token = sha1_hex($user . $secret->secret);
$c->stash->{token} = $token;
return 1;
@@ -1104,7 +1160,7 @@ sub check_token : Private {
$c->forward( 'log_edit', [ $object_id, $object_type, $action_performed ] );
-Adds an entry into the admin_log table using the current remote_user.
+Adds an entry into the admin_log table using the current user.
=cut
@@ -1112,7 +1168,7 @@ sub log_edit : Private {
my ( $self, $c, $id, $object_type, $action ) = @_;
$c->model('DB::AdminLog')->create(
{
- admin_user => ( $c->req->remote_user() || '' ),
+ admin_user => $c->forward('get_user'),
object_type => $object_type,
action => $action,
object_id => $id,
@@ -1232,21 +1288,42 @@ sub rotate_photo : Private {
my ( $self, $c ) =@_;
my $direction = $c->req->param('rotate_photo');
-
return unless $direction =~ /Left/ or $direction =~ /Right/;
- my $photo = _rotate_image( $c->stash->{problem}->photo, $direction =~ /Left/ ? -90 : 90 );
+ my $photo = $c->stash->{problem}->photo;
+ my $file;
+
+ # If photo field contains a hash
+ if ( length($photo) == 40 ) {
+ $file = file( $c->config->{UPLOAD_DIR}, "$photo.jpeg" );
+ $photo = $file->slurp;
+ }
- if ( $photo ) {
- $c->stash->{rotated} = 1;
- $c->stash->{problem}->photo( $photo );
+ $photo = _rotate_image( $photo, $direction =~ /Left/ ? -90 : 90 );
+ return unless $photo;
+
+ my $fileid;
+ if ( !$file ) {
+ $fileid = sha1_hex($photo);
+ $file = file( $c->config->{UPLOAD_DIR}, "$fileid.jpeg" );
+ }
+
+ $c->stash->{rotated} = 1;
+
+ my $fh = $file->open('w');
+ print $fh $photo;
+ close $fh;
+
+ unlink glob FixMyStreet->path_to( 'web', 'photo', $c->stash->{problem}->id . '.*' );
+
+ if ( $fileid ) {
+ $c->stash->{problem}->photo( $fileid );
$c->stash->{problem}->update();
}
return 1;
}
-
=head2 check_page_allowed
Checks if the current catalyst action is in the list of allowed pages and
@@ -1270,16 +1347,16 @@ sub check_page_allowed : Private {
return 1;
}
-sub set_up_council_details : Private {
+sub fetch_all_bodies : Private {
my ($self, $c ) = @_;
- my $areas = mySociety::MaPit::call('areas', $c->cobrand->area_types);
-
- my @councils_ids = sort { strcoll($areas->{$a}->{name}, $areas->{$b}->{name}) } keys %$areas;
- @councils_ids = $c->cobrand->filter_all_council_ids_list( @councils_ids );
-
- $c->stash->{council_ids} = \@councils_ids;
- $c->stash->{council_details} = $areas;
+ my @bodies = $c->model('DB::Body')->all;
+ if ( $c->cobrand->moniker eq 'zurich' ) {
+ @bodies = $c->cobrand->admin_fetch_all_bodies( @bodies );
+ } else {
+ @bodies = sort { strcoll($a->name, $b->name) } @bodies;
+ }
+ $c->stash->{bodies} = \@bodies;
return 1;
}
diff --git a/perllib/FixMyStreet/App/Controller/Alert.pm b/perllib/FixMyStreet/App/Controller/Alert.pm
index 91ea61fbc..e821b7467 100644
--- a/perllib/FixMyStreet/App/Controller/Alert.pm
+++ b/perllib/FixMyStreet/App/Controller/Alert.pm
@@ -407,13 +407,13 @@ Generate the details required to display the council/ward/area RSS feeds
sub setup_council_rss_feeds : Private {
my ( $self, $c ) = @_;
- $c->stash->{council_check_action} = 'alert';
- unless ( $c->forward('/council/load_and_check_councils_and_wards') ) {
+ $c->stash->{area_check_action} = 'alert';
+ unless ( $c->forward('/council/load_and_check_areas_and_wards') ) {
$c->go('index');
}
( $c->stash->{options}, $c->stash->{reported_to_options} ) =
- $c->cobrand->council_rss_alert_options( $c->stash->{all_councils}, $c );
+ $c->cobrand->council_rss_alert_options( $c->stash->{all_areas}, $c );
return 1;
}
diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm
index f2bb23350..9a754f063 100644
--- a/perllib/FixMyStreet/App/Controller/Around.pm
+++ b/perllib/FixMyStreet/App/Controller/Around.pm
@@ -44,7 +44,7 @@ sub around_index : Path : Args(0) {
unless $c->forward('/location/determine_location_from_coords')
|| $c->forward('/location/determine_location_from_pc');
- # Check to see if the spot is covered by a council - if not show an error.
+ # Check to see if the spot is covered by a area - if not show an error.
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
@@ -192,7 +192,7 @@ sub display_location : Private {
longitude => $p->longitude,
colour => $colour,
id => $p->id,
- title => $p->title,
+ title => $p->title_safe,
}
} @$on_map_all, @$around_map;
}
@@ -212,7 +212,7 @@ sub display_location : Private {
=head2 check_location_is_acceptable
-Find the lat and lon in stash and check that they are acceptable to the council,
+Find the lat and lon in stash and check that they are acceptable to the area,
and that they are in UK (if we are in UK).
=cut
@@ -220,10 +220,10 @@ and that they are in UK (if we are in UK).
sub check_location_is_acceptable : Private {
my ( $self, $c ) = @_;
- # check that there are councils that can accept this location
- $c->stash->{council_check_action} = 'submit_problem';
- $c->stash->{remove_redundant_councils} = 1;
- return $c->forward('/council/load_and_check_councils');
+ # check that there are areas that can accept this location
+ $c->stash->{area_check_action} = 'submit_problem';
+ $c->stash->{remove_redundant_areas} = 1;
+ return $c->forward('/council/load_and_check_areas');
}
=head2 /ajax
@@ -281,6 +281,65 @@ sub ajax : Path('/ajax') {
$c->res->body($body);
}
+
+sub location_autocomplete : Path('/ajax/geocode') {
+ my ( $self, $c ) = @_;
+ $c->res->content_type('application/json; charset=utf-8');
+ unless ( $c->req->param('term') ) {
+ $c->res->status(404);
+ $c->res->body('');
+ return;
+ }
+ # we want the match even if there's no ambiguity, so recommendation doesn't
+ # disappear when it's the last choice being offered in the autocomplete.
+ $c->stash->{allow_single_geocode_match_strings} = 1;
+ return $self->_geocode( $c, $c->req->param('term') );
+}
+
+sub location_lookup : Path('/ajax/lookup_location') {
+ my ( $self, $c ) = @_;
+ $c->res->content_type('application/json; charset=utf-8');
+ unless ( $c->req->param('term') ) {
+ $c->res->status(404);
+ $c->res->body('');
+ return;
+ }
+
+ return $self->_geocode( $c, $c->req->param('term') );
+}
+
+sub _geocode : Private {
+ my ( $self, $c, $term ) = @_;
+
+ my ( $lat, $long, $suggestions ) =
+ FixMyStreet::Geocode::lookup( $c->req->param('term'), $c );
+
+ my ($response, @addresses);
+
+ if ( $lat && $long ) {
+ $response = { latitude => $lat, longitude => $long };
+ } else {
+ if ( ref($suggestions) eq 'ARRAY' ) {
+ foreach (@$suggestions) {
+ push @addresses, decode_utf8($_->{address});
+ }
+ $response = { suggestions => \@addresses };
+ } else {
+ $response = { error => $suggestions };
+ }
+ }
+
+ if ( $c->stash->{allow_single_geocode_match_strings} ) {
+ $response = \@addresses;
+ }
+
+ my $body = JSON->new->utf8(1)->encode(
+ $response
+ );
+ $c->res->body($body);
+
+}
+
__PACKAGE__->meta->make_immutable;
1;
diff --git a/perllib/FixMyStreet/App/Controller/Auth.pm b/perllib/FixMyStreet/App/Controller/Auth.pm
index 3dc25dedf..f4d6d86e4 100644
--- a/perllib/FixMyStreet/App/Controller/Auth.pm
+++ b/perllib/FixMyStreet/App/Controller/Auth.pm
@@ -31,7 +31,7 @@ sub general : Path : Args(0) {
my $req = $c->req;
$c->detach( 'redirect_on_signin', [ $req->param('r') ] )
- if $c->user && $req->param('r');
+ if $c->user && $req->param('r') && $req->param('r') !~ /admin/;
# all done unless we have a form posted to us
return unless $req->method eq 'POST';
diff --git a/perllib/FixMyStreet/App/Controller/Council.pm b/perllib/FixMyStreet/App/Controller/Council.pm
index cb9e78421..5d95c2538 100644
--- a/perllib/FixMyStreet/App/Controller/Council.pm
+++ b/perllib/FixMyStreet/App/Controller/Council.pm
@@ -14,34 +14,34 @@ Catalyst Controller.
=head1 METHODS
-=head2 load_and_check_councils_and_wards
+=head2 load_and_check_areas_and_wards
-Try to load councils and wards for this location and check that we have at least one. If
-there are no councils then return false.
+Try to load areas and wards for this location and check that we have at least one. If
+there are no areas then return false.
=cut
-sub load_and_check_councils_and_wards : Private {
+sub load_and_check_areas_and_wards : Private {
my ( $self, $c ) = @_;
my $area_types = [ @{$c->cobrand->area_types}, @{$c->cobrand->area_types_children} ];
$c->stash->{area_types} = $area_types;
- $c->forward('load_and_check_councils');
+ $c->forward('load_and_check_areas');
}
-=head2 load_and_check_councils
+=head2 load_and_check_areas
-Try to load councils for this location and check that we have at least one. If
-there are no councils then return false.
+Try to load areas for this location and check that we have at least one. If
+there are no areas then return false.
=cut
-sub load_and_check_councils : Private {
+sub load_and_check_areas : Private {
my ( $self, $c ) = @_;
my $latitude = $c->stash->{latitude};
my $longitude = $c->stash->{longitude};
- # Look up councils and do checks for the point we've got
+ # Look up areas and do checks for the point we've got
my $area_types;
if ( $c->stash->{area_types} and scalar @{ $c->stash->{area_types} } ) {
$area_types = $c->stash->{area_types};
@@ -52,49 +52,49 @@ sub load_and_check_councils : Private {
my $short_latitude = Utils::truncate_coordinate($latitude);
my $short_longitude = Utils::truncate_coordinate($longitude);
- my $all_councils;
+ my $all_areas;
if ( $c->stash->{fetch_all_areas} ) {
my %area_types = map { $_ => 1 } @$area_types;
- my $all_areas =
+ $all_areas =
mySociety::MaPit::call( 'point', "4326/$short_longitude,$short_latitude" );
- $c->stash->{all_areas} = $all_areas;
- $all_councils = {
+ $c->stash->{all_areas_mapit} = $all_areas;
+ $all_areas = {
map { $_ => $all_areas->{$_} }
grep { $area_types{ $all_areas->{$_}->{type} } }
keys %$all_areas
};
} else {
- $all_councils =
+ $all_areas =
mySociety::MaPit::call( 'point', "4326/$short_longitude,$short_latitude",
type => $area_types );
}
- if ($all_councils->{error}) {
- $c->stash->{location_error} = $all_councils->{error};
+ if ($all_areas->{error}) {
+ $c->stash->{location_error} = $all_areas->{error};
return;
}
# Let cobrand do a check
my ( $success, $error_msg ) =
- $c->cobrand->council_check( { all_councils => $all_councils },
- $c->stash->{council_check_action} );
+ $c->cobrand->area_check( { all_areas => $all_areas },
+ $c->stash->{area_check_action} );
if ( !$success ) {
$c->stash->{location_error} = $error_msg;
return;
}
# edit hash in-place
- $c->cobrand->remove_redundant_councils($all_councils) if $c->stash->{remove_redundant_councils};
+ $c->cobrand->remove_redundant_areas($all_areas) if $c->stash->{remove_redundant_areas};
- # If we don't have any councils we can't accept the report
- if ( !scalar keys %$all_councils ) {
+ # If we don't have any areas we can't accept the report
+ if ( !scalar keys %$all_areas ) {
$c->stash->{location_error} = _('That location does not appear to be covered by a council; perhaps it is offshore or outside the country. Please try again.');
return;
}
- # all good if we have some councils left
- $c->stash->{all_councils} = $all_councils;
- $c->stash->{all_council_names} =
- [ map { $_->{name} } values %$all_councils ];
+ # all good if we have some areas left
+ $c->stash->{all_areas} = $all_areas;
+ $c->stash->{all_area_names} =
+ [ map { $_->{name} } values %$all_areas ];
return 1;
}
diff --git a/perllib/FixMyStreet/App/Controller/Dashboard.pm b/perllib/FixMyStreet/App/Controller/Dashboard.pm
index 17fd8b867..028b9aadd 100644
--- a/perllib/FixMyStreet/App/Controller/Dashboard.pm
+++ b/perllib/FixMyStreet/App/Controller/Dashboard.pm
@@ -29,7 +29,7 @@ sub example : Local : Args(0) {
}
# TODO Set up manual version of what the below would do
- #$c->forward( '/report/new/setup_categories_and_councils' );
+ #$c->forward( '/report/new/setup_categories_and_bodies' );
# See if we've had anything from the dropdowns - perhaps vary results if so
$c->stash->{ward} = $c->req->param('ward');
@@ -74,9 +74,9 @@ sub check_page_allowed : Private {
$c->detach( '/auth/redirect' ) unless $c->user_exists;
$c->detach( '/page_error_404_not_found' )
- unless $c->user_exists && $c->user->from_council;
+ unless $c->user_exists && $c->user->from_body;
- return $c->user->from_council;
+ return $c->user->from_body;
}
=head2 index
@@ -88,20 +88,23 @@ Show the dashboard table.
sub index : Path : Args(0) {
my ( $self, $c ) = @_;
- my $council = $c->forward('check_page_allowed');
+ my $body = $c->forward('check_page_allowed');
# Set up the data for the dropdowns
- my $council_detail = mySociety::MaPit::call('area', $council );
+ # Just take the first area ID we find
+ my $area_id = $body->body_areas->first->area_id;
+
+ my $council_detail = mySociety::MaPit::call('area', $area_id );
$c->stash->{council} = $council_detail;
- my $children = mySociety::MaPit::call('area/children', $council,
+ my $children = mySociety::MaPit::call('area/children', $area_id,
type => $c->cobrand->area_types_children,
);
$c->stash->{children} = $children;
- $c->stash->{all_councils} = { $council => $council_detail };
- $c->forward( '/report/new/setup_categories_and_councils' );
+ $c->stash->{all_areas} = { $area_id => $council_detail };
+ $c->forward( '/report/new/setup_categories_and_bodies' );
# See if we've had anything from the dropdowns
@@ -109,7 +112,7 @@ sub index : Path : Args(0) {
$c->stash->{category} = $c->req->param('category');
my %where = (
- council => $council, # XXX This will break in a two tier council. Restriction needs looking at...
+ bodies_str => $body->id, # XXX Does this break in a two tier council? Restriction needs looking at...
'problem.state' => [ FixMyStreet::DB::Result::Problem->visible_states() ],
);
$where{areas} = { 'like', '%,' . $c->stash->{ward} . ',%' }
diff --git a/perllib/FixMyStreet/App/Controller/JS.pm b/perllib/FixMyStreet/App/Controller/JS.pm
index d7847af75..483c3c2cc 100755
--- a/perllib/FixMyStreet/App/Controller/JS.pm
+++ b/perllib/FixMyStreet/App/Controller/JS.pm
@@ -11,13 +11,13 @@ FixMyStreet::App::Controller::JS - Catalyst Controller
=head1 DESCRIPTION
JS Catalyst Controller. To return a language-dependent list
-of validation strings.
+of translation strings.
=head1 METHODS
=cut
-sub validation_strings : LocalRegex('^validation_strings\.(.*?)\.js$') : Args(0) {
+sub translation_strings : LocalRegex('^translation_strings\.(.*?)\.js$') : Args(0) {
my ( $self, $c ) = @_;
my $lang = $c->req->captures->[0];
$c->cobrand->set_lang_and_domain( $lang, 1 );
diff --git a/perllib/FixMyStreet/App/Controller/JSON.pm b/perllib/FixMyStreet/App/Controller/JSON.pm
index f3607341a..1a7c1915b 100644
--- a/perllib/FixMyStreet/App/Controller/JSON.pm
+++ b/perllib/FixMyStreet/App/Controller/JSON.pm
@@ -92,7 +92,7 @@ sub problems : Local {
my @problems = $c->cobrand->problems->search( $query, {
order_by => { -asc => 'confirmed' },
columns => [
- 'id', 'title', 'council', 'category',
+ 'id', 'title', 'bodies_str', 'category',
'detail', 'name', 'anonymous', 'confirmed',
'whensent', 'service',
'latitude', 'longitude', 'used_map',
@@ -100,23 +100,13 @@ sub problems : Local {
]
} );
- my @councils;
foreach my $problem (@problems) {
$problem->name( '' ) if $problem->anonymous == 1;
$problem->service( 'Web interface' ) if $problem->service eq '';
- if ($problem->council) {
- (my $council = $problem->council) =~ s/\|.*//g;
- my @council_ids = split /,/, $council;
- push(@councils, @council_ids);
- $problem->council( \@council_ids );
- }
- }
- @councils = uniq @councils;
- my $areas_info = mySociety::MaPit::call('areas', \@councils);
- foreach my $problem (@problems) {
- if ($problem->council) {
- my @council_names = map { $areas_info->{$_}->{name} } @{$problem->council} ;
- $problem->council( join(' and ', @council_names) );
+ my $bodies = $problem->bodies;
+ if (keys %$bodies) {
+ my @body_names = map { $_->name } values %$bodies;
+ $problem->bodies_str( join(' and ', @body_names) );
}
}
diff --git a/perllib/FixMyStreet/App/Controller/Open311.pm b/perllib/FixMyStreet/App/Controller/Open311.pm
index 3382c0cea..7b8cb649f 100644
--- a/perllib/FixMyStreet/App/Controller/Open311.pm
+++ b/perllib/FixMyStreet/App/Controller/Open311.pm
@@ -164,12 +164,12 @@ sub get_services : Private {
if ($lat || $lon) {
my $area_types = $c->cobrand->area_types;
- my $all_councils = mySociety::MaPit::call('point',
+ my $all_areas = mySociety::MaPit::call('point',
"4326/$lon,$lat",
type => $area_types);
$categories = $categories->search( {
- area_id => [ keys %$all_councils ],
- } );
+ 'body_areas.area_id' => [ keys %$all_areas ],
+ }, { join => { 'body' => 'body_areas' } } );
}
my @categories = $categories->search( undef, {
@@ -223,19 +223,11 @@ sub output_requests : Private {
);
my @problemlist;
- my @councils;
while ( my $problem = $problems->next ) {
my $id = $problem->id;
$problem->service( 'Web interface' ) unless $problem->service;
- if ($problem->council) {
- (my $council = $problem->council) =~ s/\|.*//g;
- my @council_ids = split(/,/, $council);
- push(@councils, @council_ids);
- $problem->council( \@council_ids );
- }
-
$problem->state( $statusmap{$problem->state} );
my $request =
@@ -256,7 +248,7 @@ sub output_requests : Private {
'service_code' => [ $problem->category ],
'service_name' => [ $problem->category ],
# 'service_notice' => [ {} ],
- 'agency_responsible' => $problem->council , # FIXME Not according to Open311 v2
+ 'agency_responsible' => $problem->bodies , # FIXME Not according to Open311 v2
# 'zipcode' => [ {} ],
'interface_used' => [ $problem->service ], # Not in Open311 v2
};
@@ -288,12 +280,12 @@ sub output_requests : Private {
}
push(@problemlist, $request);
}
- my $areas_info = mySociety::MaPit::call('areas', \@councils);
+
foreach my $request (@problemlist) {
if ($request->{agency_responsible}) {
- my @council_names = map { $areas_info->{$_}->{name} } @{$request->{agency_responsible}} ;
+ my @body_names = map { $_->name } values %{$request->{agency_responsible}} ;
$request->{agency_responsible} =
- [ {'recipient' => [ @council_names ] } ];
+ [ {'recipient' => [ @body_names ] } ];
}
}
$c->forward( 'format_output', [ {
@@ -319,7 +311,7 @@ sub get_requests : Private {
service_request_id => [ '=', 'id' ],
service_code => [ '=', 'category' ],
status => [ 'IN', 'state' ],
- agency_responsible => [ '~', 'council' ],
+ agency_responsible => [ '~', 'bodies_str' ],
interface_used => [ '=', 'service' ],
has_photo => [ '=', 'photo' ],
);
diff --git a/perllib/FixMyStreet/App/Controller/Photo.pm b/perllib/FixMyStreet/App/Controller/Photo.pm
index fa4baf045..279623922 100644
--- a/perllib/FixMyStreet/App/Controller/Photo.pm
+++ b/perllib/FixMyStreet/App/Controller/Photo.pm
@@ -102,10 +102,7 @@ sub output : Private {
File::Path::make_path( FixMyStreet->path_to( 'web', 'photo', 'c' )->stringify );
File::Slurp::write_file( FixMyStreet->path_to( 'web', $c->req->path )->stringify, \$photo );
- my $dt = DateTime->now()->add( years => 1 );
-
$c->res->content_type( 'image/jpeg' );
- $c->res->header( 'expires', DateTime::Format::HTTP->format_datetime( $dt ) );
$c->res->body( $photo );
}
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm
index ef966a8a8..460ccaec5 100644
--- a/perllib/FixMyStreet/App/Controller/Report.pm
+++ b/perllib/FixMyStreet/App/Controller/Report.pm
@@ -51,6 +51,25 @@ sub display : Path('') : Args(1) {
return $c->res->redirect( $c->uri_for($1), 301 );
}
+ $c->forward( '_display', [ $id ] );
+}
+
+=head2 ajax
+
+Return JSON formatted details of a report
+
+=cut
+
+sub ajax : Path('ajax') : Args(1) {
+ my ( $self, $c, $id ) = @_;
+
+ $c->stash->{ajax} = 1;
+ $c->forward( '_display', [ $id ] );
+}
+
+sub _display : Private {
+ my ( $self, $c, $id ) = @_;
+
$c->forward( 'load_problem_or_display_error', [ $id ] );
$c->forward( 'load_updates' );
$c->forward( 'format_problem_for_display' );
@@ -66,7 +85,7 @@ sub support : Path('support') : Args(0) {
? $c->uri_for( '/report', $id )
: $c->uri_for('/');
- if ( $id && $c->cobrand->can_support_problems && $c->user && $c->user->from_council ) {
+ if ( $id && $c->cobrand->can_support_problems && $c->user && $c->user->from_body ) {
$c->forward( 'load_problem_or_display_error', [ $id ] );
$c->stash->{problem}->update( { interest_count => \'interest_count +1' } );
}
@@ -83,7 +102,7 @@ sub load_problem_or_display_error : Private {
: $c->cobrand->problems->find( { id => $id } );
# check that the problem is suitable to show.
- if ( !$problem || $problem->state eq 'unconfirmed' || $problem->state eq 'partial' ) {
+ if ( !$problem || ($problem->state eq 'unconfirmed' && !$c->cobrand->show_unconfirmed_reports) || $problem->state eq 'partial' ) {
$c->detach( '/page_error_404_not_found', [ _('Unknown problem ID') ] );
}
elsif ( $problem->state eq 'hidden' ) {
@@ -147,10 +166,19 @@ sub format_problem_for_display : Private {
$c->stash->{add_alert} = 1;
}
- $c->stash->{extra_name_info} = $problem->council && $problem->council eq '2482' ? 1 : 0;
+ $c->stash->{extra_name_info} = $problem->bodies_str && $problem->bodies_str eq '2482' ? 1 : 0;
$c->forward('generate_map_tags');
+ if ( $c->stash->{ajax} ) {
+ $c->res->content_type('application/json; charset=utf-8');
+ my $content = JSON->new->utf8(1)->encode(
+ $problem->as_hashref( $c )
+ );
+ $c->res->body( $content );
+ return 1;
+ }
+
return 1;
}
@@ -187,11 +215,10 @@ sub delete :Local :Args(1) {
return $c->res->redirect($uri) unless $c->user_exists;
- my $council = $c->user->obj->from_council;
- return $c->res->redirect($uri) unless $council;
+ my $body = $c->user->obj->from_body;
+ return $c->res->redirect($uri) unless $body;
- my %councils = map { $_ => 1 } @{$p->councils};
- return $c->res->redirect($uri) unless $councils{$council};
+ return $c->res->redirect($uri) unless $p->bodies->{$body};
$p->state('hidden');
$p->lastupdate( \'ms_current_timestamp()' );
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index 9194f5318..687e54fbe 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -89,7 +89,7 @@ sub report_new : Path : Args(0) {
# create a problem from the submitted details
$c->stash->{template} = "report/new/fill_in_details.html";
- $c->forward('setup_categories_and_councils');
+ $c->forward('setup_categories_and_bodies');
$c->forward('generate_map');
$c->forward('check_for_category');
@@ -119,7 +119,7 @@ sub report_new_ajax : Path('mobile') : Args(0) {
return 1;
}
- $c->forward('setup_categories_and_councils');
+ $c->forward('setup_categories_and_bodies');
$c->forward('process_user');
$c->forward('process_report');
$c->forward('/photo/process_photo');
@@ -147,7 +147,7 @@ sub report_new_ajax : Path('mobile') : Args(0) {
} else {
$c->stash->{token_url} = $c->uri_for_email( '/P', $token->token );
$c->send_email( 'problem-confirm.txt', {
- to => [ [ $report->user->email, $report->name ] ],
+ to => [ $report->name ? [ $report->user->email, $report->name ] : $report->user->email ],
} );
$c->stash->{ json_response } = { success => 1 };
}
@@ -180,7 +180,7 @@ sub report_form_ajax : Path('ajax') : Args(0) {
return;
}
- $c->forward('setup_categories_and_councils');
+ $c->forward('setup_categories_and_bodies');
# render templates to get the html
my $category = $c->render_fragment( 'report/new/category.html');
@@ -216,7 +216,7 @@ sub category_extras_ajax : Path('category_extras') : Args(0) {
$c->res->body($body);
return 1;
}
- $c->forward('setup_categories_and_councils');
+ $c->forward('setup_categories_and_bodies');
my $category_extra = '';
if ( $c->stash->{category_extras}->{ $c->req->param('category') } && @{ $c->stash->{category_extras}->{ $c->req->param('category') } } >= 1 ) {
@@ -569,27 +569,34 @@ sub determine_location_from_report : Private {
return;
}
-=head2 setup_categories_and_councils
+=head2 setup_categories_and_bodies
-Look up categories for this council or councils
+Look up categories for the relevant body or bodies.
=cut
-sub setup_categories_and_councils : Private {
+sub setup_categories_and_bodies : Private {
my ( $self, $c ) = @_;
- my $all_councils = $c->stash->{all_councils};
- my $first_council = ( values %$all_councils )[0];
+ my $all_areas = $c->stash->{all_areas};
+ my $first_area = ( values %$all_areas )[0];
+
+ my @bodies = $c->model('DB::Body')->search(
+ { 'body_areas.area_id' => [ keys %$all_areas ] },
+ { join => 'body_areas' }
+ )->all;
+ my %bodies = map { $_->id => $_ } @bodies;
+ my $first_body = ( values %bodies )[0];
my @contacts #
= $c #
->model('DB::Contact') #
->not_deleted #
- ->search( { area_id => [ keys %$all_councils ] } ) #
+ ->search( { body_id => [ keys %bodies ] } )
->all;
# variables to populate
- my %area_ids_to_list = (); # Areas with categories assigned
+ my %bodies_to_list = (); # Bodies with categories assigned
my @category_options = (); # categories to show
my $category_label = undef; # what to call them
my %category_extras = (); # extra fields to fill in for open311
@@ -599,9 +606,9 @@ sub setup_categories_and_councils : Private {
# FIXME - implement in cobrand
if ( $c->cobrand->moniker eq 'emptyhomes' ) {
- # add all areas found to the list
+ # add all bodies found to the list
foreach (@contacts) {
- $area_ids_to_list{ $_->area_id } = 1;
+ $bodies_to_list{ $_->body_id } = 1;
}
# set our own categories
@@ -616,11 +623,11 @@ sub setup_categories_and_councils : Private {
);
$category_label = _('Property type:');
- } elsif ($first_council->{id} != COUNCIL_ID_BROMLEY && $first_council->{type} eq 'LBO') {
+ } elsif ($first_area->{id} != COUNCIL_ID_BROMLEY && $first_area->{type} eq 'LBO') {
- $area_ids_to_list{ $first_council->{id} } = 1;
+ $bodies_to_list{ $first_body->id } = 1;
my @local_categories;
- if ($first_council->{id} == COUNCIL_ID_BARNET) {
+ if ($first_area->{id} == COUNCIL_ID_BARNET) {
@local_categories = sort keys %{ Utils::barnet_categories() }
} else {
@local_categories = sort keys %{ Utils::london_categories() }
@@ -639,7 +646,7 @@ sub setup_categories_and_councils : Private {
my %seen;
foreach my $contact (@contacts) {
- $area_ids_to_list{ $contact->area_id } = 1;
+ $bodies_to_list{ $contact->body_id } = 1;
unless ( $seen{$contact->category} ) {
push @category_options, $contact->category;
@@ -661,24 +668,21 @@ sub setup_categories_and_councils : Private {
}
# put results onto stash for display
- $c->stash->{area_ids_to_list} = [ keys %area_ids_to_list ];
+ $c->stash->{bodies} = \%bodies;
+ $c->stash->{all_body_names} = [ map { $_->name } values %bodies ];
+ $c->stash->{bodies_to_list} = [ keys %bodies_to_list ];
$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;
-
- my @missing_details_councils =
- grep { !$area_ids_to_list{$_} } #
- keys %$all_councils;
+ $c->stash->{extra_name_info} = $first_area->{id} == COUNCIL_ID_BROMLEY ? 1 : 0;
- my @missing_details_council_names =
- map { $all_councils->{$_}->{name} } #
- @missing_details_councils;
+ my @missing_details_bodies = grep { !$bodies_to_list{$_->id} } values %bodies;
+ my @missing_details_body_names = map { $_->name } @missing_details_bodies;
- $c->stash->{missing_details_councils} = \@missing_details_councils;
- $c->stash->{missing_details_council_names} = \@missing_details_council_names;
+ $c->stash->{missing_details_bodies} = \@missing_details_bodies;
+ $c->stash->{missing_details_body_names} = \@missing_details_body_names;
}
=head2 check_form_submitted
@@ -820,60 +824,62 @@ sub process_report : Private {
$report->subcategory( $params{subcategory} );
- my $areas = $c->stash->{all_areas};
+ my $areas = $c->stash->{all_areas_mapit};
$report->areas( ',' . join( ',', sort keys %$areas ) . ',' );
# From earlier in the process.
- my $councils = $c->stash->{all_councils};
- my $first_council = ( values %$councils )[0];
+ $areas = $c->stash->{all_areas};
+ my $bodies = $c->stash->{bodies};
+ my $first_area = ( values %$areas )[0];
+ my $first_body = ( values %$bodies )[0];
if ( $c->cobrand->moniker eq 'emptyhomes' ) {
- $councils = join( ',', @{ $c->stash->{area_ids_to_list} } ) || -1;
- $report->council( $councils );
+ $bodies = join( ',', @{ $c->stash->{bodies_to_list} } ) || -1;
+ $report->bodies_str( $bodies );
- } elsif ( $first_council->{id} == COUNCIL_ID_BARNET ) {
+ } elsif ( $first_area->{id} == COUNCIL_ID_BARNET ) {
unless ( exists Utils::barnet_categories()->{ $report->category } ) {
$c->stash->{field_errors}->{category} = _('Please choose a category');
}
- $report->council( $first_council->{id} );
+ $report->bodies_str( $first_body->id );
- } elsif ( $first_council->{id} != COUNCIL_ID_BROMLEY && $first_council->{type} eq 'LBO') {
+ } elsif ( $first_area->{id} != COUNCIL_ID_BROMLEY && $first_area->{type} eq 'LBO') {
unless ( Utils::london_categories()->{ $report->category } ) {
$c->stash->{field_errors}->{category} = _('Please choose a category');
}
- $report->council( $first_council->{id} );
+ $report->bodies_str( $first_body->id );
} elsif ( $report->category ) {
- # FIXME All contacts were fetched in setup_categories_and_councils,
+ # FIXME All contacts were fetched in setup_categories_and_bodies,
# so can this DB call also be avoided?
my @contacts = $c-> #
model('DB::Contact') #
->not_deleted #
->search(
{
- area_id => [ keys %$councils ],
+ body_id => [ keys %$bodies ],
category => $report->category
}
)->all;
unless ( @contacts ) {
$c->stash->{field_errors}->{category} = _('Please choose a category');
- $report->council( -1 );
+ $report->bodies_str( -1 );
return 1;
}
- # construct the council string:
- # 'x,x' - x are council IDs that have this category
- # 'x,x|y,y' - x are council IDs that have this category, y council IDs with *no* contact
- my $council_string = join( ',', map { $_->area_id } @contacts );
- $council_string .=
- '|' . join( ',', @{ $c->stash->{missing_details_councils} } )
- if $council_string && @{ $c->stash->{missing_details_councils} };
- $report->council($council_string);
+ # construct the bodies string:
+ # 'x,x' - x are body IDs that have this category
+ # 'x,x|y' - x are body IDs that have this category, y body IDs with *no* contact
+ my $body_string = join( ',', map { $_->body_id } @contacts );
+ $body_string .=
+ '|' . join( ',', map { $_->id } @{ $c->stash->{missing_details_bodies} } )
+ if $body_string && @{ $c->stash->{missing_details_bodies} };
+ $report->bodies_str($body_string);
my @extra = ();
my $metas = $contacts[0]->extra;
@@ -895,13 +901,13 @@ sub process_report : Private {
$report->non_public( 1 );
}
- $c->cobrand->process_extras( $c, $contacts[0]->area_id, \@extra );
+ $c->cobrand->process_extras( $c, $contacts[0]->body_id, \@extra );
if ( @extra ) {
$c->stash->{report_meta} = { map { $_->{name} => $_ } @extra };
$report->extra( \@extra );
}
- } elsif ( @{ $c->stash->{area_ids_to_list} } ) {
+ } elsif ( @{ $c->stash->{bodies_to_list} } ) {
# There was an area with categories, but we've not been given one. Bail.
$c->stash->{field_errors}->{category} = _('Please choose a category');
@@ -910,7 +916,7 @@ sub process_report : Private {
# If we're here, we've been submitted somewhere
# where we have no contact information at all.
- $report->council( -1 );
+ $report->bodies_str( -1 );
}
@@ -944,6 +950,8 @@ sub check_for_errors : Private {
if ( $c->cobrand->moniker eq 'zurich' ) {
delete $field_errors{title};
delete $field_errors{name};
+ my $report = $c->stash->{report};
+ $report->title( Utils::cleanup_text( substr($report->detail, 0, 25) ) );
}
# FIXME: need to check for required bromley fields here
@@ -1006,8 +1014,10 @@ sub save_user_and_report : Private {
$c->log->info($report->user->id . ' created for this report');
}
elsif ( $c->user && $report->user->id == $c->user->id ) {
+ # Logged in and matches, so instantly confirm (except Zurich, with no confirmation)
$report->user->update();
- $report->confirm;
+ $report->confirm
+ unless $c->cobrand->moniker eq 'zurich';
$c->log->info($report->user->id . ' is logged in for this report');
}
else {
@@ -1032,7 +1042,7 @@ sub save_user_and_report : Private {
$report->category( _('Other') ) unless $report->category;
# Set unknown to DB unknown
- $report->council( undef ) if $report->council eq '-1';
+ $report->bodies_str( undef ) if $report->bodies_str 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+$/) {
@@ -1113,7 +1123,7 @@ sub redirect_or_confirm_creation : Private {
$c->forward( 'create_reporter_alert' );
my $report_uri;
- if ( $c->cobrand->moniker eq 'fixmybarangay' && $c->user->from_council && $c->stash->{external_source_id}) {
+ if ( $c->cobrand->moniker eq 'fixmybarangay' && $c->user->from_body && $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');
@@ -1138,7 +1148,7 @@ sub redirect_or_confirm_creation : Private {
} );
$c->stash->{token_url} = $c->uri_for_email( '/P', $token->token );
$c->send_email( 'problem-confirm.txt', {
- to => [ [ $report->user->email, $report->name ] ],
+ to => [ $report->name ? [ $report->user->email, $report->name ] : $report->user->email ],
} );
# tell user that they've been sent an email
diff --git a/perllib/FixMyStreet/App/Controller/Report/Update.pm b/perllib/FixMyStreet/App/Controller/Report/Update.pm
index 5e0d9f388..dbfd57e78 100644
--- a/perllib/FixMyStreet/App/Controller/Report/Update.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/Update.pm
@@ -76,7 +76,7 @@ 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') ) {
+ if ( $c->cobrand->can_support_problems && $c->user && $c->user->from_body && $c->req->param('external_source_id') ) {
$problem->interest_count( \'interest_count + 1' );
}
@@ -201,7 +201,7 @@ sub process_update : Private {
if ( $params{state} ) {
$params{state} = 'fixed - council'
- if $params{state} eq 'fixed' && $c->user && $c->user->belongs_to_council( $update->problem->council );
+ if $params{state} eq 'fixed' && $c->user && $c->user->belongs_to_body( $update->problem->bodies_str );
$update->problem_state( $params{state} );
} else {
# we do this so we have a record of the state of the problem at this point
@@ -223,7 +223,7 @@ sub process_update : Private {
my @extra; # Next function fills this, but we don't need it here.
# This is just so that the error checkign for these extra fields runs.
# TODO Use extra here as it is used on reports.
- $c->cobrand->process_extras( $c, $update->problem->council, \@extra );
+ $c->cobrand->process_extras( $c, $update->problem->bodies_str, \@extra );
if ( $c->req->param('fms_extra_title') ) {
my %extras = ();
@@ -261,7 +261,7 @@ sub check_for_errors : Private {
# they have to be an authority user to update the state
if ( $c->req->param('state') ) {
my $error = 0;
- $error = 1 unless $c->user && $c->user->belongs_to_council( $c->stash->{update}->problem->council );
+ $error = 1 unless $c->user && $c->user->belongs_to_body( $c->stash->{update}->problem->bodies_str );
my $state = $c->req->param('state');
$state = 'fixed - council' if $state eq 'fixed';
diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm
index 1fcbfbd72..781dee698 100644
--- a/perllib/FixMyStreet/App/Controller/Reports.pm
+++ b/perllib/FixMyStreet/App/Controller/Reports.pm
@@ -5,6 +5,7 @@ use namespace::autoclean;
use File::Slurp;
use List::MoreUtils qw(zip);
use POSIX qw(strcoll);
+use RABX;
use mySociety::MaPit;
BEGIN { extends 'Catalyst::Controller'; }
@@ -30,34 +31,26 @@ Show the summary page of all reports.
sub index : Path : Args(0) {
my ( $self, $c ) = @_;
- # Fetch all areas of the types we're interested in
- my $areas_info;
- eval {
- my $area_types = $c->cobrand->area_types;
- $areas_info = mySociety::MaPit::call('areas', $area_types,
- min_generation => $c->cobrand->area_min_generation
+ # Zurich goes straight to map page, with all reports
+ if ( $c->cobrand->moniker eq 'zurich' ) {
+ $c->forward( 'load_and_group_problems' );
+ my $pins = $c->stash->{pins};
+ $c->stash->{page} = 'reports';
+ FixMyStreet::Map::display_map(
+ $c,
+ latitude => @$pins ? $pins->[0]{latitude} : 0,
+ longitude => @$pins ? $pins->[0]{longitude} : 0,
+ area => 274456,
+ pins => $pins,
+ any_zoom => 1,
);
- };
- if ($@) {
- $c->stash->{message} = _("Unable to look up areas in MaPit. Please try again later.") . ' ' .
- sprintf(_('The error was: %s'), $@);
- $c->stash->{template} = 'errors/generic.html';
- return;
+ return 1;
}
- # For each area, add its link and perhaps alter its name if we need to for
- # places with the same name.
- foreach (values %$areas_info) {
- $_->{url} = $c->uri_for( '/reports/' . $c->cobrand->short_name( $_, $areas_info ) );
- if ($_->{parent_area} && $_->{url} =~ /,|%2C/) {
- $_->{name} .= ', ' . $areas_info->{$_->{parent_area}}{name};
- }
- }
-
- $c->stash->{areas_info} = $areas_info;
- my @keys = sort { strcoll($areas_info->{$a}{name}, $areas_info->{$b}{name}) } keys %$areas_info;
- @keys = $c->cobrand->filter_all_council_ids_list( @keys );
- $c->stash->{areas_info_sorted} = [ map { $areas_info->{$_} } @keys ];
+ # Fetch all areas of the types we're interested in
+ my @bodies = $c->model('DB::Body')->all;
+ @bodies = sort { strcoll($a->name, $b->name) } @bodies;
+ $c->stash->{bodies} = \@bodies;
eval {
my $data = File::Slurp::read_file(
@@ -99,21 +92,20 @@ Show the summary page for a particular ward.
=cut
sub ward : Path : Args(2) {
- my ( $self, $c, $council, $ward ) = @_;
+ my ( $self, $c, $body, $ward ) = @_;
- $c->forward( 'body_check', [ $council ] );
+ $c->forward( 'body_check', [ $body ] );
$c->forward( 'ward_check', [ $ward ] )
if $ward;
- $c->forward( 'load_parent' );
- $c->forward( 'check_canonical_url', [ $council ] );
+ $c->forward( 'check_canonical_url', [ $body ] );
$c->forward( 'load_and_group_problems' );
- my $council_short = $c->cobrand->short_name( $c->stash->{council}, $c->stash->{areas_info} );
- $c->stash->{rss_url} = '/rss/reports/' . $council_short;
+ my $body_short = $c->cobrand->short_name( $c->stash->{body} );
+ $c->stash->{rss_url} = '/rss/reports/' . $body_short;
$c->stash->{rss_url} .= '/' . $c->cobrand->short_name( $c->stash->{ward} )
if $c->stash->{ward};
- $c->stash->{council_url} = '/reports/' . $council_short;
+ $c->stash->{body_url} = '/reports/' . $body_short;
$c->stash->{stats} = $c->cobrand->get_report_stats();
@@ -123,7 +115,7 @@ sub ward : Path : Args(2) {
my %map_params = (
latitude => @$pins ? $pins->[0]{latitude} : 0,
longitude => @$pins ? $pins->[0]{longitude} : 0,
- area => $c->stash->{ward} ? $c->stash->{ward}->{id} : $c->stash->{council}->{id},
+ area => $c->stash->{ward} ? $c->stash->{ward}->{id} : [ keys %{$c->stash->{body}->areas} ],
any_zoom => 1,
);
if ( $c->cobrand->moniker eq 'emptyhomes' ) {
@@ -139,64 +131,121 @@ sub ward : Path : Args(2) {
$c->cobrand->tweak_all_reports_map( $c );
# List of wards
- # 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} ],
+ # Ignore external_body special body thing
+ unless ($c->stash->{ward} || !$c->stash->{body}->id) {
+ my $children = mySociety::MaPit::call('area/children', [ $c->stash->{body}->body_areas->first->area_id ],
type => $c->cobrand->area_types_children,
);
- foreach (values %$children) {
- $_->{url} = $c->uri_for( $c->stash->{council_url}
- . '/' . $c->cobrand->short_name( $_ )
- );
+ unless ($children->{error}) {
+ foreach (values %$children) {
+ $_->{url} = $c->uri_for( $c->stash->{body_url}
+ . '/' . $c->cobrand->short_name( $_ )
+ );
+ }
+ $c->stash->{children} = $children;
}
- $c->stash->{children} = $children;
}
}
-sub rss_body : Regex('^rss/(reports|area)$') : Args(1) {
- my ( $self, $c, $body ) = @_;
- $c->detach( 'rss_ward', [ $body ] );
+sub rss_area : Path('/rss/area') : Args(1) {
+ my ( $self, $c, $area ) = @_;
+ $c->detach( 'rss_area_ward', [ $area ] );
}
-sub rss_ward : Regex('^rss/(reports|area)$') : Args(2) {
- my ( $self, $c, $council, $ward ) = @_;
-
- my ( $rss ) = $c->req->captures->[0];
+sub rss_area_ward : Path('/rss/area') : Args(2) {
+ my ( $self, $c, $area, $ward ) = @_;
$c->stash->{rss} = 1;
- $c->forward( 'body_check', [ $council ] );
- $c->forward( 'ward_check', [ $ward ] ) if $ward;
+ # area_check
+
+ $area =~ s/\+/ /g;
+ $area =~ s/\.html//;
- 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
- $c->detach( 'redirect_area' );
+ # 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
+ if ($area =~ /^\d+$/) {
+ my $council = mySociety::MaPit::call('area', $area);
+ $c->detach( 'redirect_index') if $council->{error};
+ $c->stash->{body} = $council;
+ $c->detach( 'redirect_body' );
+ }
+
+ # We must now have a string to check on mapit
+ my $areas = mySociety::MaPit::call( 'areas', $area,
+ type => $c->cobrand->area_types,
+ );
+
+ if (keys %$areas == 1) {
+ ($c->stash->{area}) = values %$areas;
+ } else {
+ foreach (keys %$areas) {
+ if (lc($areas->{$_}->{name}) eq lc($area) || $areas->{$_}->{name} =~ /^\Q$area\E (Borough|City|District|County) Council$/i) {
+ $c->stash->{area} = $areas->{$_};
+ }
+ }
}
- my $url = $c->cobrand->short_name( $c->stash->{council} );
- $url .= '/' . $c->cobrand->short_name( $c->stash->{ward} ) if $c->stash->{ward};
+ $c->forward( 'ward_check', [ $ward ] ) if $ward;
+
+ my $url = $c->cobrand->short_name( $c->stash->{area} );
+ $url .= '/' . $c->cobrand->short_name( $c->stash->{ward} ) if $c->stash->{ward};
$c->stash->{qs} = "/$url";
- if ( $rss eq 'area' && $c->stash->{ward} ) {
+ if ($c->stash->{area}{type} ne 'DIS' && $c->stash->{area}{type} ne 'CTY') {
+ # UK-specific types - two possibilites are the same for one-tier councils, so redirect one to the other
+ # With bodies, this should presumably redirect if only one body covers
+ # the area, and then it will need that body's name (rather than
+ # assuming as now it is the same as the area)
+ $c->stash->{body} = $c->stash->{area};
+ $c->detach( 'redirect_body' );
+ }
+
+ $c->stash->{type} = 'area_problems';
+ if ( $c->stash->{ward} ) {
# All problems within a particular ward
- $c->stash->{type} = 'area_problems';
$c->stash->{title_params} = { NAME => $c->stash->{ward}{name} };
$c->stash->{db_params} = [ $c->stash->{ward}->{id} ];
- } elsif ( $rss eq 'area' ) {
- # Problems within a particular council
- $c->stash->{type} = 'area_problems';
- $c->stash->{title_params} = { NAME => $c->stash->{council}{name} };
- $c->stash->{db_params} = [ $c->stash->{council}->{id} ];
- } elsif ($c->stash->{ward}) {
+ } else {
+ # Problems within a particular area
+ $c->stash->{title_params} = { NAME => $c->stash->{area}->{name} };
+ $c->stash->{db_params} = [ $c->stash->{area}->{id} ];
+ }
+
+ # Send on to the RSS generation
+ $c->forward( '/rss/output' );
+
+}
+
+sub rss_body : Path('/rss/reports') : Args(1) {
+ my ( $self, $c, $body ) = @_;
+ $c->detach( 'rss_ward', [ $body ] );
+}
+
+sub rss_ward : Path('/rss/reports') : Args(2) {
+ my ( $self, $c, $body, $ward ) = @_;
+
+ $c->stash->{rss} = 1;
+
+ $c->forward( 'body_check', [ $body ] );
+ $c->forward( 'ward_check', [ $ward ] ) if $ward;
+
+ my $url = $c->cobrand->short_name( $c->stash->{body} );
+ $url .= '/' . $c->cobrand->short_name( $c->stash->{ward} ) if $c->stash->{ward};
+ $c->stash->{qs} = "/$url";
+
+ if ($c->stash->{ward}) {
# Problems sent to a council, restricted to a ward
$c->stash->{type} = 'ward_problems';
- $c->stash->{title_params} = { COUNCIL => $c->stash->{council}{name}, WARD => $c->stash->{ward}{name} };
- $c->stash->{db_params} = [ $c->stash->{council}->{id}, $c->stash->{ward}->{id} ];
+ $c->stash->{title_params} = { COUNCIL => $c->stash->{body}->name, WARD => $c->stash->{ward}{name} };
+ $c->stash->{db_params} = [ $c->stash->{body}->id, $c->stash->{ward}->{id} ];
} else {
# Problems sent to a council
$c->stash->{type} = 'council_problems';
- $c->stash->{title_params} = { COUNCIL => $c->stash->{council}{name} };
- $c->stash->{db_params} = [ $c->stash->{council}->{id}, $c->stash->{council}->{id} ];
+ $c->stash->{title_params} = { COUNCIL => $c->stash->{body}->name };
+ # XXX This looks up in both bodies_str and areas, but is only using body ID.
+ # This will not work properly in any install where body IDs are not === area IDs.
+ $c->stash->{db_params} = [ $c->stash->{body}->id, $c->stash->{body}->id ];
}
# Send on to the RSS generation
@@ -205,60 +254,56 @@ sub rss_ward : Regex('^rss/(reports|area)$') : Args(2) {
=head2 body_check
-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.
+This action checks the body name (or code) given in a URI exists, is valid and
+so on. If it is, it stores the body in the stash, otherwise it redirects to the
+all reports page.
=cut
sub body_check : Private {
- my ( $self, $c, $q_council ) = @_;
+ my ( $self, $c, $q_body ) = @_;
- $q_council =~ s/\+/ /g;
- $q_council =~ s/\.html//;
+ $q_body =~ s/\+/ /g;
+ $q_body =~ s/\.html//;
# Check cobrand specific incantations - e.g. ONS codes for UK,
# Oslo/ kommunes sharing a name in Norway
- return if $c->cobrand->reports_body_check( $c, $q_council );
+ return if $c->cobrand->reports_body_check( $c, $q_body );
# 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
- if ($q_council =~ /^\d+$/) {
- my $council = mySociety::MaPit::call('area', $q_council);
- $c->detach( 'redirect_index') if $council->{error};
- $c->stash->{council} = $council;
- $c->detach( 'redirect_area' );
+ if ($q_body =~ /^\d+$/) {
+ my $area = mySociety::MaPit::call('area', $q_body);
+ $c->detach( 'redirect_index') if $area->{error};
+ $c->stash->{body} = $area;
+ $c->detach( 'redirect_body' );
}
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;
+ my $problem = $c->cobrand->problems->search({ 'lower(me.external_body)' => lc $q_body }, { 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 };
+ # If external_body, put as a body with ID 0 for the moment.
+ $c->stash->{body} = $c->model('DB::Body')->new( { 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
- );
+ my @bodies = $c->model('DB::Body')->search( { name => { -like => "$q_body%" } } )->all;
- if (keys %$areas == 1) {
- ($c->stash->{council}) = values %$areas;
+ if (@bodies == 1) {
+ $c->stash->{body} = $bodies[0];
return;
} else {
- foreach (keys %$areas) {
- if (lc($areas->{$_}->{name}) eq lc($q_council) || $areas->{$_}->{name} =~ /^\Q$q_council\E (Borough|City|District|County) Council$/i) {
- $c->stash->{council} = $areas->{$_};
+ foreach (@bodies) {
+ if (lc($_->name) eq lc($q_body) || $_->name =~ /^\Q$q_body\E (Borough|City|District|County) Council$/i) {
+ $c->stash->{body} = $_;
return;
}
}
}
- # No result, bad council name.
+ # No result, bad body name.
$c->detach( 'redirect_index' );
}
@@ -266,7 +311,7 @@ sub body_check : Private {
This action checks the ward name from a URI exists and is part of the right
parent, already found with body_check. It either stores the ward Area if
-okay, or redirects to the council page if bad.
+okay, or redirects to the body page if bad.
=cut
@@ -277,48 +322,41 @@ sub ward_check : Private {
$ward =~ s/\.html//;
$ward =~ s{_}{/}g;
- my $council = $c->stash->{council};
+ # Could be from RSS area, or body...
+ my $parent_id;
+ if ( $c->stash->{body} ) {
+ $parent_id = $c->stash->{body}->body_areas->first->area_id;
+ } else {
+ $parent_id = $c->stash->{area}->{id};
+ }
my $qw = mySociety::MaPit::call('areas', $ward,
type => $c->cobrand->area_types_children,
- min_generation => $c->cobrand->area_min_generation
);
foreach my $area (sort { $a->{name} cmp $b->{name} } values %$qw) {
- if ($area->{parent_area} == $council->{id}) {
+ if ($area->{parent_area} == $parent_id) {
$c->stash->{ward} = $area;
return;
}
}
# Given a false ward name
- $c->detach( 'redirect_area' );
-}
-
-sub load_parent : Private {
- my ( $self, $c ) = @_;
-
- my $council = $c->stash->{council};
- my $areas_info;
- if ($council->{parent_area}) {
- $c->stash->{areas_info} = mySociety::MaPit::call('areas', [ $council->{id}, $council->{parent_area} ])
- } else {
- $c->stash->{areas_info} = { $council->{id} => $council };
- }
+ $c->detach( 'redirect_body' );
}
=head2 check_canonical_url
-Given an already found (case-insensitively) council, check what URL
+Given an already found (case-insensitively) body, check what URL
we are at and redirect accordingly if different.
=cut
sub check_canonical_url : Private {
- my ( $self, $c, $q_council ) = @_;
+ my ( $self, $c, $q_body ) = @_;
- my $council_short = $c->cobrand->short_name( $c->stash->{council}, $c->stash->{areas_info} );
- my $url_short = URI::Escape::uri_escape_utf8($q_council);
+ my $body_short = $c->cobrand->short_name( $c->stash->{body} );
+ my $url_short = URI::Escape::uri_escape_utf8($q_body);
$url_short =~ s/%2B/+/g;
- $c->detach( 'redirect_area' ) unless $council_short eq $url_short;
+ $c->detach( 'redirect_body' ) unless $body_short eq $url_short;
}
sub load_and_group_problems : Private {
@@ -332,69 +370,57 @@ sub load_and_group_problems : Private {
};
if ($c->stash->{ward}) {
$where->{areas} = { 'like', '%,' . $c->stash->{ward}->{id} . ',%' };
- $where->{council} = [
+ $where->{bodies_str} = [
undef,
- $c->stash->{council}->{id},
- { 'like', $c->stash->{council}->{id} . ',%' },
- { 'like', '%,' . $c->stash->{council}->{id} },
+ $c->stash->{body}->id,
+ { 'like', $c->stash->{body}->id . ',%' },
+ { 'like', '%,' . $c->stash->{body}->id },
];
- } elsif ($c->stash->{council} && $c->stash->{council}->{id} == 0) {
+ } elsif ($c->stash->{body} && $c->stash->{body}->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} = [
- undef,
- $c->stash->{council}->{id},
- { 'like', $c->stash->{council}->{id} . ',%' },
- { 'like', '%,' . $c->stash->{council}->{id} },
+ $where->{'lower(external_body)'} = lc $c->stash->{body}->name;
+ } elsif ($c->stash->{body}) {
+ # XXX FixMyStreet used to have the following line so that reports not
+ # currently sent anywhere could still be listed in the appropriate
+ # (body/area), as they were the same. Now they're not, not sure if
+ # there's a way to do this easily.
+ #$where->{areas} = { 'like', '%,' . $c->stash->{body}->id . ',%' };
+ $where->{bodies_str} = [
+ # undef,
+ $c->stash->{body}->id,
+ { 'like', $c->stash->{body}->id . ',%' },
+ { 'like', '%,' . $c->stash->{body}->id },
];
}
my $problems = $c->cobrand->problems->search(
$where,
{
- columns => [
- 'id', 'council', 'state', 'areas', 'latitude', 'longitude', 'title', 'cobrand',
- #{ duration => { extract => "epoch from current_timestamp-lastupdate" } },
- #{ age => { extract => "epoch from current_timestamp-confirmed" } },
- { confirmed => { extract => 'epoch from confirmed' } },
- { whensent => { extract => 'epoch from whensent' } },
- { lastupdate => { extract => 'epoch from lastupdate' } },
- { photo => 'photo is not null' },
- ],
order_by => { -desc => 'lastupdate' },
rows => $c->cobrand->reports_per_page,
}
)->page( $page );
$c->stash->{pager} = $problems->pager;
- $problems = $problems->cursor; # Raw DB cursor for speed
my ( %problems, @pins );
- my $re_councils = join('|', keys %{$c->stash->{areas_info}});
- my @cols = ( 'id', 'council', 'state', 'areas', 'latitude', 'longitude', 'title', 'cobrand', 'confirmed', 'whensent', 'lastupdate', 'photo' );
- while ( my @problem = $problems->next ) {
- 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} ) {
+ while ( my $problem = $problems->next ) {
+ $c->log->debug( $problem->cobrand . ', cobrand is ' . $c->cobrand->moniker );
+ if ( !$c->stash->{body} || !$c->stash->{body}->id ) {
# An external_body entry
- add_row( \%problem, 0, \%problems, \@pins );
+ add_row( $c, $problem, 0, \%problems, \@pins );
next;
}
- if ( !$problem{council} ) {
- # Problem was not sent to any council, add to possible councils
- $problem{councils} = 0;
- while ($problem{areas} =~ /,($re_councils)(?=,)/g) {
- add_row( \%problem, $1, \%problems, \@pins );
+ if ( !$problem->bodies_str ) {
+ # Problem was not sent to any body, add to all possible areas XXX
+ while ($problem->areas =~ /,(\d+)(?=,)/g) {
+ add_row( $c, $problem, $1, \%problems, \@pins );
}
} else {
- # Add to councils it was sent to
- (my $council = $problem{council}) =~ s/\|.*$//;
- my @council = split( /,/, $council );
- $problem{councils} = scalar @council;
- foreach ( @council ) {
- next if $_ != $c->stash->{council}->{id};
- add_row( \%problem, $_, \%problems, \@pins );
+ # Add to bodies it was sent to
+ # XXX Assumes body ID matches "council ID"
+ my $bodies = $problem->bodies_str_ids;
+ foreach ( @$bodies ) {
+ next if $_ != $c->stash->{body}->id;
+ add_row( $c, $problem, $_, \%problems, \@pins );
}
}
}
@@ -413,26 +439,26 @@ sub redirect_index : Private {
$c->res->redirect( $c->uri_for($url) );
}
-sub redirect_area : Private {
+sub redirect_body : Private {
my ( $self, $c ) = @_;
my $url = '';
$url .= "/rss" if $c->stash->{rss};
$url .= '/reports';
- $url .= '/' . $c->cobrand->short_name( $c->stash->{council}, $c->stash->{areas_info} );
+ $url .= '/' . $c->cobrand->short_name( $c->stash->{body} );
$url .= '/' . $c->cobrand->short_name( $c->stash->{ward} )
if $c->stash->{ward};
$c->res->redirect( $c->uri_for($url) );
}
sub add_row {
- my ( $problem, $council, $problems, $pins ) = @_;
- push @{$problems->{$council}}, $problem;
+ my ( $c, $problem, $body, $problems, $pins ) = @_;
+ push @{$problems->{$body}}, $problem;
push @$pins, {
- latitude => $problem->{latitude},
- longitude => $problem->{longitude},
- colour => 'yellow', # FixMyStreet::DB::Result::Problem->fixed_states()->{$problem->{state}} ? 'green' : 'red',
- id => $problem->{id},
- title => $problem->{title},
+ latitude => $problem->latitude,
+ longitude => $problem->longitude,
+ colour => $c->cobrand->pin_colour( $problem, 'reports' ),
+ id => $problem->id,
+ title => $problem->title_safe,
};
}
diff --git a/perllib/FixMyStreet/App/Controller/Rss.pm b/perllib/FixMyStreet/App/Controller/Rss.pm
index baaa3b927..90ab7ad41 100755
--- a/perllib/FixMyStreet/App/Controller/Rss.pm
+++ b/perllib/FixMyStreet/App/Controller/Rss.pm
@@ -241,6 +241,15 @@ sub add_row : Private {
$row->{name} = 'anonymous' if $row->{anonymous} || !$row->{name};
my $pubDate;
+ if ($row->{created}) {
+ $row->{created} =~ /^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/;
+ $pubDate = mySociety::Locale::in_gb_locale {
+ strftime("%a, %d %b %Y %H:%M:%S %z", $6, $5, $4, $3, $2-1, $1-1900, -1, -1, 0)
+ };
+ $row->{created} = strftime("%e %B", $6, $5, $4, $3, $2-1, $1-1900, -1, -1, 0);
+ $row->{created} =~ s/^\s+//;
+ $row->{created} =~ s/^(\d+)/ordinal($1)/e if $c->stash->{lang_code} eq 'en-gb';
+ }
if ($row->{confirmed}) {
$row->{confirmed} =~ /^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/;
$pubDate = mySociety::Locale::in_gb_locale {
@@ -257,7 +266,7 @@ sub add_row : Private {
my $hashref_restriction = $c->cobrand->site_restriction;
my $base_url = $c->cobrand->base_url;
- if ( $hashref_restriction && $hashref_restriction->{council} && $row->{council} && $row->{council} ne $hashref_restriction->{council} ) {
+ if ( $hashref_restriction && $hashref_restriction->{bodies_str} && $row->{bodies_str} && $row->{bodies_str} ne $hashref_restriction->{bodies_str} ) {
$base_url = $c->config->{BASE_URL};
}
my $url = $base_url . $link;
diff --git a/perllib/FixMyStreet/App/Controller/Tokens.pm b/perllib/FixMyStreet/App/Controller/Tokens.pm
index 03dc69b00..740822876 100644
--- a/perllib/FixMyStreet/App/Controller/Tokens.pm
+++ b/perllib/FixMyStreet/App/Controller/Tokens.pm
@@ -53,6 +53,28 @@ sub confirm_problem : Path('/P') {
return;
}
+ # For Zurich, email confirmation simply sets a flag, it does not change the
+ # problem state, log in, or anything else
+ if ($c->cobrand->moniker eq 'zurich') {
+ my $extra = { %{ $problem->extra || {} } };
+ $extra->{email_confirmed} = 1;
+ $problem->update( {
+ extra => $extra,
+ confirmed => \'ms_current_timestamp()',
+ } );
+
+ $c->stash->{report} = $c->stash->{problem};
+ $c->forward( '/report/new/create_reporter_alert' );
+
+ if ( ref($data) && ( $data->{name} || $data->{password} ) ) {
+ $problem->user->name( $data->{name} ) if $data->{name};
+ $problem->user->phone( $data->{phone} ) if $data->{phone};
+ $problem->user->update;
+ }
+
+ return 1;
+ }
+
# We have a problem - confirm it if needed!
my $old_state = $problem->state;
$problem->update(
diff --git a/perllib/FixMyStreet/App/View/Web.pm b/perllib/FixMyStreet/App/View/Web.pm
index 42878be37..febeaf3c1 100644
--- a/perllib/FixMyStreet/App/View/Web.pm
+++ b/perllib/FixMyStreet/App/View/Web.pm
@@ -18,7 +18,7 @@ __PACKAGE__->config(
ENCODING => 'utf8',
render_die => 1,
expose_methods => [
- 'loc', 'nget', 'tprintf', 'display_crosssell_advert', 'prettify_epoch',
+ 'loc', 'nget', 'tprintf', 'display_crosssell_advert', 'prettify_dt',
'add_links', 'version',
],
FILTERS => {
@@ -92,20 +92,20 @@ sub display_crosssell_advert {
return CrossSell::display_advert( $c, $email, $name, %data );
}
-=head2 Utils::prettify_epoch
+=head2 Utils::prettify_dt
- [% pretty = prettify_epoch( $epoch, $short_bool ) %]
+ [% pretty = prettify_dt( $dt, $short_bool ) %]
-Return a pretty version of the epoch.
+Return a pretty version of the DateTime object.
$short_bool = 1; # 16:02, 29 Mar 2011
$short_bool = 0; # 16:02, Tuesday 29 March 2011
=cut
-sub prettify_epoch {
+sub prettify_dt {
my ( $self, $c, $epoch, $short_bool ) = @_;
- return Utils::prettify_epoch( $epoch, $short_bool );
+ return Utils::prettify_dt( $epoch, $short_bool );
}
=head2 add_links
diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm
index 11851c5a1..963c8a6ad 100644
--- a/perllib/FixMyStreet/Cobrand/Default.pm
+++ b/perllib/FixMyStreet/Cobrand/Default.pm
@@ -476,14 +476,14 @@ sub format_postcode {
return $postcode;
}
-=head2 council_check
+=head2 area_check
-Paramters are COUNCILS, QUERY, CONTEXT. Return a boolean indicating whether
-COUNCILS pass any extra checks. CONTEXT is where we are on the site.
+Paramters are AREAS, QUERY, CONTEXT. Return a boolean indicating whether
+AREAS pass any extra checks. CONTEXT is where we are on the site.
=cut
-sub council_check { return ( 1, '' ); }
+sub area_check { return ( 1, '' ); }
=head2 all_councils_report
@@ -526,7 +526,7 @@ Show the problem creation graph in the admin interface
sub admin_show_creation_graph { 1 }
-=head2 area_types, area_min_generation
+=head2 area_types
The MaPit types this site handles
@@ -534,7 +534,6 @@ The MaPit types this site handles
sub area_types { FixMyStreet->config('MAPIT_TYPES') || [ 'ZZZ' ] }
sub area_types_children { FixMyStreet->config('MAPIT_TYPES_CHILDREN') || [] }
-sub area_min_generation { '' }
=head2 contact_name, contact_email
@@ -556,39 +555,28 @@ sub email_host {
return 1;
}
-=item remove_redundant_councils
+=item remove_redundant_areas
-Remove councils whose reports go to another council
+Remove areas whose reports go to another area (XXX)
=cut
-sub remove_redundant_councils {
+sub remove_redundant_areas {
my $self = shift;
- my $all_councils = shift;
-}
-
-=item filter_all_council_ids_list
-
-Removes any council IDs that we don't need from an array and returns the
-filtered array
-
-=cut
-
-sub filter_all_council_ids_list {
- my $self = shift;
- return @_;
+ my $all_areas = shift;
}
=item short_name
-Remove extra information from council names for tidy URIs
+Remove extra information from body names for tidy URIs
=cut
sub short_name {
my $self = shift;
- my ($area, $info) = @_;
- my $name = $area->{name};
+ my ($area) = @_;
+
+ my $name = $area->{name} || $area->name;
$name = URI::Escape::uri_escape_utf8($name);
$name =~ s/%20/+/g;
return $name;
@@ -615,10 +603,10 @@ Generate a set of options for council rss alerts.
=cut
sub council_rss_alert_options {
- my ( $self, $all_councils, $c ) = @_;
+ my ( $self, $all_areas, $c ) = @_;
my ( @options, @reported_to_options );
- foreach (values %$all_councils) {
+ foreach (values %$all_areas) {
$_->{short_name} = $self->short_name( $_ );
( $_->{id_name} = $_->{short_name} ) =~ tr/+/_/;
push @options, {
@@ -662,31 +650,26 @@ Get stats to display on the council reports page
sub get_report_stats { return 0; }
-sub get_council_sender {
- my ( $self, $area_id, $area_info, $category ) = @_;
+sub get_body_sender {
+ my ( $self, $body, $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 ) {
+ if ( $body->can_be_devolved ) {
# look up via category
- my $config = FixMyStreet::App->model("DB::Contact")->search( { area_id => $area_id, category => $category } )->first;
+ my $config = FixMyStreet::App->model("DB::Contact")->search( { body_id => $body->id, category => $category } )->first;
if ( $config->send_method ) {
return { method => $config->send_method, config => $config };
} else {
- return { method => $send_method, config => $council_config };
+ return { method => $body->send_method, config => $body };
}
- } elsif ( $send_method ) {
- return { method => $send_method, config => $council_config };
+ } elsif ( $body->send_method ) {
+ return { method => $body->send_method, config => $body };
}
- return $self->_fallback_council_sender( $area_id, $area_info, $category );
+ return $self->_fallback_body_sender( $body, $category );
}
-sub _fallback_council_sender {
- my ( $self, $area_id, $area_info, $category ) = @_;
+sub _fallback_body_sender {
+ my ( $self, $body, $category ) = @_;
return { method => 'Email' };
};
@@ -699,7 +682,7 @@ sub example_places {
=head2 only_authed_can_create
-If true, only users with the from_council flag set are able to create reports.
+If true, only users with the from_body flag set are able to create reports.
=cut
@@ -810,5 +793,16 @@ a name key
sub anonymous_account { undef; }
+=head2 show_unconfirmed_reports
+
+Whether reports in state 'unconfirmed' should still be shown on the public site.
+(They're always included in the admin interface.)
+
+=cut
+
+sub show_unconfirmed_reports {
+ 0;
+}
+
1;
diff --git a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
index 6bec115dd..5e90db038 100644
--- a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
+++ b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
@@ -100,33 +100,26 @@ sub guess_road_operator {
return '';
}
-sub remove_redundant_councils {
+sub remove_redundant_areas {
my $self = shift;
- my $all_councils = shift;
+ my $all_areas = shift;
# Oslo is both a kommune and a fylke, we only want to show it once
- delete $all_councils->{301} #
- if $all_councils->{3};
-}
-
-sub filter_all_council_ids_list {
- my $self = shift;
- my @all_councils_ids = @_;
-
- # as above we only want to show Oslo once
- return grep { $_ != 301 } @all_councils_ids;
+ delete $all_areas->{301}
+ if $all_areas->{3};
}
sub short_name {
my $self = shift;
my ($area, $info) = @_;
- if ($area->{name} =~ /^(Os|Nes|V\xe5ler|Sande|B\xf8|Her\xf8y)$/) {
+ my $name = $area->{name} || $area->name;
+
+ if ($name =~ /^(Os|Nes|V\xe5ler|Sande|B\xf8|Her\xf8y)$/) {
my $parent = $info->{$area->{parent_area}}->{name};
- return URI::Escape::uri_escape_utf8("$area->{name}, $parent");
+ return URI::Escape::uri_escape_utf8("$name, $parent");
}
- my $name = $area->{name};
$name =~ s/ & / and /;
$name = URI::Escape::uri_escape_utf8($name);
$name =~ s/%20/+/g;
diff --git a/perllib/FixMyStreet/Cobrand/LichfieldDC.pm b/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
index 31d5bf987..6a534fc18 100644
--- a/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
+++ b/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
@@ -13,7 +13,7 @@ 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.
sub problems_clause {
- return { council => { like => '%2434%' } };
+ return { bodies_str => { like => '%2434%' } };
}
# FIXME - need to double check this is all correct
diff --git a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
index 9aa054020..62550e626 100644
--- a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
+++ b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
@@ -18,7 +18,7 @@ sub base_url {
# 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%' } };
+ return { bodies_str => { like => '%2237%' } };
}
sub path_to_web_templates {
diff --git a/perllib/FixMyStreet/Cobrand/SeeSomething.pm b/perllib/FixMyStreet/Cobrand/SeeSomething.pm
index dc28156dc..88d5f6b78 100644
--- a/perllib/FixMyStreet/Cobrand/SeeSomething.pm
+++ b/perllib/FixMyStreet/Cobrand/SeeSomething.pm
@@ -14,12 +14,12 @@ sub site_title { return 'See Something, Say Something'; }
sub site_restriction {
my $self = shift;
- return { council => { IN => $self->council_id } };
+ return { bodies_str => { IN => $self->council_id } };
}
sub problems_clause {
my $self = shift;
- return { council => { IN => $self->council_id } };
+ return { bodies_str => { IN => $self->council_id } };
}
sub path_to_web_templates {
@@ -30,10 +30,10 @@ sub path_to_web_templates {
];
}
-sub council_check {
+sub area_check {
my ( $self, $params, $context ) = @_;
- my $councils = $params->{all_councils};
+ my $councils = $params->{all_areas};
my $council_match = grep { $councils->{$_} } @{ $self->council_id };
if ($council_match) {
diff --git a/perllib/FixMyStreet/Cobrand/UK.pm b/perllib/FixMyStreet/Cobrand/UK.pm
index 4eee1869e..ff613ffa8 100644
--- a/perllib/FixMyStreet/Cobrand/UK.pm
+++ b/perllib/FixMyStreet/Cobrand/UK.pm
@@ -1,6 +1,7 @@
package FixMyStreet::Cobrand::UK;
use base 'FixMyStreet::Cobrand::Default';
+use mySociety::MaPit;
use mySociety::VotingArea;
sub path_to_web_templates {
@@ -11,7 +12,6 @@ sub path_to_web_templates {
sub country { return 'GB'; }
sub area_types { [ 'DIS', 'LBO', 'MTD', 'UTA', 'CTY', 'COI', 'LGD' ] }
sub area_types_children { $mySociety::VotingArea::council_child_types }
-sub area_min_generation { 10 }
sub enter_postcode_text {
my ( $self ) = @_;
@@ -31,8 +31,11 @@ sub disambiguate_location {
};
}
-sub _fallback_council_sender {
- my ( $self, $area_id, $area_info, $category ) = @_;
+sub _fallback_body_sender {
+ my ( $self, $body, $category ) = @_;
+
+ my $first_area = $body->body_areas->first->area_id;
+ my $area_info = mySociety::MaPit::call('area', $first_area);
return { method => 'London' } if $area_info->{type} eq 'LBO';
return { method => 'NI' } if $area_info->{type} eq 'LGD';
return { method => 'Email' };
@@ -41,11 +44,12 @@ sub _fallback_council_sender {
sub process_extras {
my $self = shift;
my $ctx = shift;
- my $area_id = shift;
+ my $body_id = shift;
my $extra = shift;
my $fields = shift || [];
- if ( $area_id eq '2482' ) {
+ # XXX Hardcoded body ID matching mapit area ID
+ if ( $body_id eq '2482' ) {
my @fields = ( 'fms_extra_title', @$fields );
for my $field ( @fields ) {
my $value = $ctx->request->param( $field );
@@ -97,46 +101,38 @@ sub geocode_postcode {
return {};
}
-sub remove_redundant_councils {
+sub remove_redundant_areas {
my $self = shift;
- my $all_councils = shift;
+ my $all_areas = shift;
# Ipswich & St Edmundsbury are responsible for everything in their
# areas, not Suffolk
- delete $all_councils->{2241}
- if $all_councils->{2446} #
- || $all_councils->{2443};
+ delete $all_areas->{2241}
+ if $all_areas->{2446} #
+ || $all_areas->{2443};
# Norwich is responsible for everything in its areas, not Norfolk
- delete $all_councils->{2233} #
- if $all_councils->{2391};
+ delete $all_areas->{2233} #
+ if $all_areas->{2391};
}
-sub filter_all_council_ids_list {
+sub short_name {
my $self = shift;
- my @all_councils_ids = @_;
+ my ($area) = @_;
- # Ignore the four council areas introduced because of generation 15
- # (where we put the new boundaries under the old IDs)
- return grep { $_ < 141648 || $_ > 141651 } @all_councils_ids;
-}
+ my $name = $area->{name} || $area->name;
-sub short_name {
- my $self = shift;
- my ($area, $info) = @_;
- # Special case Durham as it's the only place with two councils of the same name
- return 'Durham+County' if $area->{name} eq 'Durham County Council';
- return 'Durham+City' if $area->{name} eq 'Durham City Council';
-
- my $name = $area->{name};
- $name =~ s/ (Borough|City|District|County) Council$//;
- $name =~ s/ Council$//;
- $name =~ s/ & / and /;
- $name =~ s{/}{_}g;
- $name = URI::Escape::uri_escape_utf8($name);
- $name =~ s/%20/+/g;
- return $name;
+ # Special case Durham as it's the only place with two councils of the same name
+ return 'Durham+County' if $name eq 'Durham County Council';
+ return 'Durham+City' if $name eq 'Durham City Council';
+ $name =~ s/ (Borough|City|District|County) Council$//;
+ $name =~ s/ Council$//;
+ $name =~ s/ & / and /;
+ $name =~ s{/}{_}g;
+ $name = URI::Escape::uri_escape_utf8($name);
+ $name =~ s/%20/+/g;
+ return $name;
}
sub find_closest {
@@ -174,11 +170,11 @@ sub reports_body_check {
if (length($code) == 6) {
my $council = mySociety::MaPit::call( 'area', $area->{parent_area} );
$c->stash->{ward} = $area;
- $c->stash->{council} = $council;
+ $c->stash->{body} = $council;
} else {
- $c->stash->{council} = $area;
+ $c->stash->{body} = $area;
}
- $c->detach( 'redirect_area' );
+ $c->detach( 'redirect_body' );
}
# New ONS codes
@@ -188,11 +184,11 @@ sub reports_body_check {
if ($code =~ /^(E05|W05|S13)/) {
my $council = mySociety::MaPit::call( 'area', $area->{parent_area} );
$c->stash->{ward} = $area;
- $c->stash->{council} = $council;
- $c->detach( 'redirect_area' );
+ $c->stash->{body} = $council;
+ $c->detach( 'redirect_body' );
} elsif ($code =~ /^(W06|S12|E0[6-9]|E10)/) {
- $c->stash->{council} = $area;
- $c->detach( 'redirect_area' );
+ $c->stash->{body} = $area;
+ $c->detach( 'redirect_body' );
}
}
@@ -200,17 +196,17 @@ sub reports_body_check {
sub council_rss_alert_options {
my $self = shift;
- my $all_councils = shift;
- my $c = shift;
+ my $all_areas = shift;
+ my $c = shift;
my %councils = map { $_ => 1 } @{$self->area_types};
- my $num_councils = scalar keys %$all_councils;
+ my $num_councils = scalar keys %$all_areas;
my ( @options, @reported_to_options );
if ( $num_councils == 1 or $num_councils == 2 ) {
my ($council, $ward);
- foreach (values %$all_councils) {
+ foreach (values %$all_areas) {
if ($councils{$_->{type}}) {
$council = $_;
$council->{short_name} = $self->short_name( $council );
@@ -249,7 +245,7 @@ sub council_rss_alert_options {
} elsif ( $num_councils == 4 ) {
# Two-tier council
my ($county, $district, $c_ward, $d_ward);
- foreach (values %$all_councils) {
+ foreach (values %$all_areas) {
$_->{short_name} = $self->short_name( $_ );
( $_->{id_name} = $_->{short_name} ) =~ tr/+/_/;
if ($_->{type} eq 'CTY') {
@@ -320,7 +316,7 @@ sub council_rss_alert_options {
};
} else {
- throw Error::Simple('An area with three tiers of council? Impossible! '. join('|',keys %$all_councils));
+ throw Error::Simple('An area with three tiers of council? Impossible! '. join('|',keys %$all_areas));
}
return ( \@options, @reported_to_options ? \@reported_to_options : undef );
diff --git a/perllib/FixMyStreet/Cobrand/UKCouncils.pm b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
index 4c80da4f3..354b1b72a 100644
--- a/perllib/FixMyStreet/Cobrand/UKCouncils.pm
+++ b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
@@ -13,7 +13,7 @@ sub is_council {
sub site_restriction {
my $self = shift;
- return { council => sprintf('%d', $self->council_id) };
+ return { bodies_str => sprintf('%d', $self->council_id) };
}
sub site_key {
my $self = shift;
@@ -27,7 +27,7 @@ sub restriction {
# Different function to site_restriction due to two-tier use
sub problems_clause {
my $self = shift;
- return { council => sprintf('%d', $self->council_id) };
+ return { bodies_str => sprintf('%d', $self->council_id) };
}
sub problems {
@@ -51,10 +51,10 @@ sub enter_postcode_text {
return 'Enter a ' . $self->council_area . ' postcode, or street name and area';
}
-sub council_check {
+sub area_check {
my ( $self, $params, $context ) = @_;
- my $councils = $params->{all_councils};
+ my $councils = $params->{all_areas};
my $council_match = defined $councils->{$self->council_id};
if ($council_match) {
return 1;
@@ -86,11 +86,13 @@ sub recent_photos {
return $self->problems->recent_photos( $num, $lat, $lon, $dist );
}
+# If we ever link to a county problem report, needs to be to main FixMyStreet
sub base_url_for_report {
my ( $self, $report ) = @_;
if ( $self->is_two_tier ) {
- my %councils = map { $_ => 1 } @{$report->councils};
- if ( $councils{$self->council_id} ) {
+ my $bodies = $report->bodies;
+ my %areas = map { %{$_->areas} } values %$bodies;
+ if ( $areas{$self->council_id} ) {
return $self->base_url;
} else {
return FixMyStreet->config('BASE_URL');
diff --git a/perllib/FixMyStreet/Cobrand/Zurich.pm b/perllib/FixMyStreet/Cobrand/Zurich.pm
index e5d646c8b..ec65ec8f0 100644
--- a/perllib/FixMyStreet/Cobrand/Zurich.pm
+++ b/perllib/FixMyStreet/Cobrand/Zurich.pm
@@ -1,9 +1,29 @@
package FixMyStreet::Cobrand::Zurich;
use base 'FixMyStreet::Cobrand::Default';
+use DateTime;
+use POSIX qw(strcoll);
+
use strict;
use warnings;
+sub shorten_recency_if_new_greater_than_fixed {
+ return 0;
+}
+
+sub pin_colour {
+ my ( $self, $p, $context ) = @_;
+ return 'green' if $p->is_fixed || $p->is_closed;
+ return 'red' if $p->state eq 'unconfirmed' || $p->state eq 'confirmed';
+ return 'yellow';
+}
+
+# This isn't used
+sub find_closest {
+ my ( $self, $latitude, $longitude, $problem ) = @_;
+ return '';
+}
+
sub enter_postcode_text {
my ( $self ) = @_;
return _('Enter a Z&uuml;rich street name');
@@ -13,4 +33,428 @@ sub example_places {
return [ 'Langstrasse', 'Basteiplatz' ];
}
+sub languages { [ 'de-ch,Deutsch,de_CH', 'en-gb,English,en_GB' ] };
+
+# If lat/lon are in the URI, we must have zoom as well, otherwise OpenLayers defaults to 0.
+sub uri {
+ my ( $self, $uri ) = @_;
+
+ $uri->query_param( zoom => 7 )
+ if $uri->query_param('lat') && !$uri->query_param('zoom');
+ return $uri;
+}
+
+sub remove_redundant_areas {
+ my $self = shift;
+ my $all_areas = shift;
+
+ # Remove all except Zurich
+ foreach (keys %$all_areas) {
+ delete $all_areas->{$_} unless $_ eq 274456;
+ }
+}
+
+sub show_unconfirmed_reports {
+ 1;
+}
+
+sub get_body_sender {
+ my ( $self, $body, $category ) = @_;
+ return { method => 'Zurich' };
+}
+
+# Report overdue functions
+
+my %public_holidays = map { $_ => 1 } (
+ '2013-01-01', '2013-01-02', '2013-03-29', '2013-04-01',
+ '2013-04-15', '2013-05-01', '2013-05-09', '2013-05-20',
+ '2013-08-01', '2013-09-09', '2013-12-25', '2013-12-26',
+ '2014-01-01', '2014-01-02', '2014-04-18', '2014-04-21',
+ '2014-04-28', '2014-05-01', '2014-05-29', '2014-06-09',
+ '2014-08-01', '2014-09-15', '2014-12-25', '2014-12-26',
+);
+
+sub is_public_holiday {
+ my $dt = shift;
+ return $public_holidays{$dt->ymd};
+}
+
+sub is_weekend {
+ my $dt = shift;
+ return $dt->dow > 5;
+}
+
+sub add_days {
+ my ( $dt, $days ) = @_;
+ $dt = $dt->clone;
+ while ( $days > 0 ) {
+ $dt->add ( days => 1 );
+ next if is_public_holiday($dt) or is_weekend($dt);
+ $days--;
+ }
+ return $dt;
+}
+
+sub sub_days {
+ my ( $dt, $days ) = @_;
+ $dt = $dt->clone;
+ while ( $days > 0 ) {
+ $dt->subtract ( days => 1 );
+ next if is_public_holiday($dt) or is_weekend($dt);
+ $days--;
+ }
+ return $dt;
+}
+
+sub overdue {
+ my ( $self, $problem ) = @_;
+
+ my $w = $problem->whensent;
+ return 0 unless $w;
+
+ if ( $problem->state eq 'unconfirmed' || $problem->state eq 'confirmed' ) {
+ # One working day
+ $w = add_days( $w, 1 );
+ return $w < DateTime->now();
+ } elsif ( $problem->state eq 'in progress' ) {
+ # Five working days
+ $w = add_days( $w, 5 );
+ return $w < DateTime->now();
+ } else {
+ return 0;
+ }
+}
+
+# Specific administrative displays
+
+sub admin_pages {
+ my $self = shift;
+ my $c = $self->{c};
+
+ my $type = $c->stash->{admin_type};
+ my $pages = {
+ 'summary' => [_('Summary'), 0],
+ 'reports' => [_('Reports'), 2],
+ 'report_edit' => [undef, undef],
+ 'update_edit' => [undef, undef],
+ };
+ return $pages if $type eq 'sdm';
+
+ $pages = { %$pages,
+ 'bodies' => [_('Bodies'), 1],
+ 'body' => [undef, undef],
+ 'body_edit' => [undef, undef],
+ };
+ return $pages if $type eq 'dm';
+
+ $pages = { %$pages,
+ 'users' => [_('Users'), 3],
+ 'user_edit' => [undef, undef],
+ };
+ return $pages if $type eq 'super';
+}
+
+sub admin_type {
+ my $self = shift;
+ my $c = $self->{c};
+ my $body = $c->user->from_body;
+ $c->stash->{body} = $body;
+
+ my $parent = $body->parent;
+ my $children = $body->bodies->count;
+
+ my $type;
+ if (!$parent) {
+ $type = 'super';
+ } elsif ($parent && $children) {
+ $type = 'dm';
+ } elsif ($parent) {
+ $type = 'sdm';
+ }
+
+ $c->stash->{admin_type} = $type;
+ return $type;
+}
+
+sub admin {
+ my $self = shift;
+ my $c = $self->{c};
+ my $type = $c->stash->{admin_type};
+
+ if ($type eq 'dm') {
+ $c->stash->{template} = 'admin/index-dm.html';
+
+ my $body = $c->stash->{body};
+ my @children = map { $_->id } $body->bodies->all;
+ my @all = (@children, $body->id);
+
+ # XXX No multiples or missing bodies
+ $c->stash->{unconfirmed} = $c->cobrand->problems->search({
+ state => [ 'unconfirmed', 'confirmed' ],
+ bodies_str => $c->stash->{body}->id,
+ });
+ $c->stash->{approval} = $c->cobrand->problems->search({
+ state => 'planned',
+ bodies_str => $c->stash->{body}->id,
+ });
+ $c->stash->{other} = $c->cobrand->problems->search({
+ state => { -not_in => [ 'unconfirmed', 'confirmed', 'planned' ] },
+ bodies_str => \@all,
+ });
+ } elsif ($type eq 'sdm') {
+ $c->stash->{template} = 'admin/index-sdm.html';
+
+ my $body = $c->stash->{body};
+
+ # XXX No multiples or missing bodies
+ $c->stash->{reports_new} = $c->cobrand->problems->search( {
+ state => 'in progress',
+ bodies_str => $body->id,
+ } );
+ $c->stash->{reports_unpublished} = $c->cobrand->problems->search( {
+ state => 'planned',
+ bodies_str => $body->parent->id,
+ } );
+ $c->stash->{reports_published} = $c->cobrand->problems->search( {
+ state => 'fixed - council',
+ bodies_str => $body->parent->id,
+ } );
+ }
+}
+
+sub admin_report_edit {
+ my $self = shift;
+ my $c = $self->{c};
+ my $type = $c->stash->{admin_type};
+
+ my $problem = $c->stash->{problem};
+ my $body = $c->stash->{body};
+
+ if ($type ne 'super') {
+ my %allowed_bodies = map { $_->id => 1 } ( $body->bodies->all, $body );
+ $c->detach( '/page_error_404_not_found' )
+ unless $allowed_bodies{$problem->bodies_str};
+ }
+
+ if ($type eq 'super') {
+
+ my @bodies = $c->model('DB::Body')->all();
+ @bodies = sort { strcoll($a->name, $b->name) } @bodies;
+ $c->stash->{bodies} = \@bodies;
+
+ # Can change category to any other
+ my @categories = $c->model('DB::Contact')->not_deleted->all;
+ $c->stash->{categories} = [ map { $_->category } @categories ];
+
+ } elsif ($type eq 'dm') {
+
+ # Can assign to:
+ my @bodies = $c->model('DB::Body')->search( [
+ { 'me.parent' => $body->parent->id }, # Other DMs on the same level
+ { 'me.parent' => $body->id }, # Their subdivisions
+ { 'me.parent' => undef, 'bodies.id' => undef }, # External bodies
+ ], { join => 'bodies', distinct => 1 } );
+ @bodies = sort { strcoll($a->name, $b->name) } @bodies;
+ $c->stash->{bodies} = \@bodies;
+
+ # Can change category to any other
+ my @categories = $c->model('DB::Contact')->not_deleted->all;
+ $c->stash->{categories} = [ map { $_->category } @categories ];
+
+ }
+
+ # Problem updates upon submission
+ if ( ($type eq 'super' || $type eq 'dm') && $c->req->param('submit') ) {
+ $c->forward('check_token');
+
+ # Predefine the hash so it's there for lookups
+ # XXX Note you need to shallow copy each time you set it, due to a bug? in FilterColumn.
+ my $extra = $problem->extra || {};
+ $extra->{internal_notes} = $c->req->param('internal_notes');
+ $extra->{publish_photo} = $c->req->params->{publish_photo} || 0;
+ $extra->{third_personal} = $c->req->params->{third_personal} || 0;
+ # Make sure we have a copy of the original detail field
+ $extra->{original_detail} = $problem->detail unless $extra->{original_detail};
+ $problem->extra( { %$extra } );
+
+ # Workflow things
+ my $redirect = 0;
+ my $new_cat = $c->req->params->{category};
+ if ( $new_cat && $new_cat ne $problem->category ) {
+ my $cat = $c->model('DB::Contact')->search( { category => $c->req->params->{category} } )->first;
+ $problem->category( $new_cat );
+ $problem->external_body( undef );
+ $problem->bodies_str( $cat->body_id );
+ $problem->whensent( undef );
+ $redirect = 1 if $cat->body_id ne $body->id;
+ } elsif ( my $subdiv = $c->req->params->{body_subdivision} ) {
+ $problem->state( 'in progress' );
+ $problem->external_body( undef );
+ $problem->bodies_str( $subdiv );
+ $problem->whensent( undef );
+ $redirect = 1;
+ } elsif ( my $external = $c->req->params->{body_external} ) {
+ $problem->state( 'closed' );
+ $problem->external_body( $external );
+ $problem->whensent( undef );
+ _admin_send_email( $c, 'problem-external.txt', $problem );
+ $redirect = 1;
+ } else {
+ $problem->state( $c->req->params->{state} ) if $c->req->params->{state};
+ if ( $problem->state eq 'hidden' ) {
+ _admin_send_email( $c, 'problem-rejected.txt', $problem );
+ }
+ }
+
+ $problem->title( $c->req->param('title') );
+ $problem->detail( $c->req->param('detail') );
+
+ # Final, public, Update from DM
+ if (my $update = $c->req->param('status_update')) {
+ $extra->{public_response} = $update;
+ $problem->extra( { %$extra } );
+ if ($c->req->params->{publish_response}) {
+ $problem->state( 'fixed - council' );
+ _admin_send_email( $c, 'problem-closed.txt', $problem );
+ }
+ }
+
+ $problem->lastupdate( \'ms_current_timestamp()' );
+ $problem->update;
+
+ $c->stash->{status_message} =
+ '<p><em>' . _('Updated!') . '</em></p>';
+
+ # do this here otherwise lastupdate and confirmed times
+ # do not display correctly
+ $problem->discard_changes;
+
+ if ( $redirect ) {
+ $c->detach('index');
+ }
+
+ $c->stash->{updates} = [ $c->model('DB::Comment')
+ ->search( { problem_id => $problem->id }, { order_by => 'created' } )
+ ->all ];
+
+ return 1;
+ }
+
+ if ($type eq 'sdm') {
+
+ # Has cut-down edit template for adding update and sending back up only
+ $c->stash->{template} = 'admin/report_edit-sdm.html';
+
+ if ($c->req->param('send_back')) {
+ $c->forward('check_token');
+
+ $problem->bodies_str( $body->parent->id );
+ $problem->state( 'confirmed' );
+ $problem->update;
+ # log here
+ $c->res->redirect( '/admin/summary' );
+
+ } elsif ($c->req->param('submit')) {
+ $c->forward('check_token');
+
+ my $extra = $problem->extra || {};
+ $extra->{internal_notes} ||= '';
+ if ($c->req->param('internal_notes') && $c->req->param('internal_notes') ne $extra->{internal_notes}) {
+ $extra->{internal_notes} = $c->req->param('internal_notes');
+ $problem->extra( { %$extra } );
+ $problem->update;
+ }
+
+ # Add new update from status_update
+ if (my $update = $c->req->param('status_update')) {
+ FixMyStreet::App->model('DB::Comment')->create( {
+ text => $update,
+ user => $c->user->obj,
+ state => 'unconfirmed',
+ problem => $problem,
+ mark_fixed => 0,
+ problem_state => 'fixed - council',
+ anonymous => 1,
+ } );
+ }
+
+ $c->stash->{status_message} = '<p><em>' . _('Updated!') . '</em></p>';
+
+ # If they clicked the no more updates button, we're done.
+ if ($c->req->param('no_more_updates')) {
+ $problem->bodies_str( $body->parent->id );
+ $problem->whensent( undef );
+ $problem->state( 'planned' );
+ $problem->update;
+ # log here
+ $c->res->redirect( '/admin/summary' );
+ }
+ }
+
+ $c->stash->{updates} = [ $c->model('DB::Comment')
+ ->search( { problem_id => $problem->id }, { order_by => 'created' } )
+ ->all ];
+
+ return 1;
+
+ }
+
+ return 0;
+
+}
+
+sub _admin_send_email {
+ my ( $c, $template, $problem ) = @_;
+
+ return unless $problem->extra && $problem->extra->{email_confirmed};
+
+ my $to = $problem->name
+ ? [ $problem->user->email, $problem->name ]
+ : $problem->user->email;
+
+ $c->send_email( $template, {
+ to => [ $to ],
+ url => $c->uri_for_email( $problem->url ),
+ } );
+}
+
+sub admin_fetch_all_bodies {
+ my ( $self, @bodies ) = @_;
+
+ sub tree_sort {
+ my ( $level, $id, $sorted, $out ) = @_;
+
+ my @sorted;
+ my $array = $sorted->{$id};
+ if ( $level == 0 ) {
+ @sorted = sort {
+ # Want Zurich itself at the top.
+ return -1 if $sorted->{$a->id};
+ return 1 if $sorted->{$b->id};
+ # Otherwise, by name
+ strcoll($a->name, $b->name)
+ } @$array;
+ } else {
+ @sorted = sort { strcoll($a->name, $b->name) } @$array;
+ }
+ foreach ( @sorted ) {
+ $_->api_key( $level ); # Misuse
+ push @$out, $_;
+ if ($sorted->{$_->id}) {
+ tree_sort( $level+1, $_->id, $sorted, $out );
+ }
+ }
+ }
+
+ my %sorted;
+ foreach (@bodies) {
+ my $p = $_->parent ? $_->parent->id : 0;
+ push @{$sorted{$p}}, $_;
+ }
+
+ my @out;
+ tree_sort( 0, 0, \%sorted, \@out );
+ return @out;
+}
+
1;
diff --git a/perllib/FixMyStreet/DB/Result/Body.pm b/perllib/FixMyStreet/DB/Result/Body.pm
new file mode 100644
index 000000000..83704563a
--- /dev/null
+++ b/perllib/FixMyStreet/DB/Result/Body.pm
@@ -0,0 +1,108 @@
+use utf8;
+package FixMyStreet::DB::Result::Body;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+__PACKAGE__->load_components("FilterColumn", "InflateColumn::DateTime", "EncodedColumn");
+__PACKAGE__->table("body");
+__PACKAGE__->add_columns(
+ "id",
+ {
+ data_type => "integer",
+ is_auto_increment => 1,
+ is_nullable => 0,
+ sequence => "body_id_seq",
+ },
+ "name",
+ { data_type => "text", is_nullable => 0 },
+ "endpoint",
+ { data_type => "text", is_nullable => 1 },
+ "jurisdiction",
+ { data_type => "text", is_nullable => 1 },
+ "api_key",
+ { data_type => "text", is_nullable => 1 },
+ "send_method",
+ { data_type => "text", is_nullable => 1 },
+ "send_comments",
+ { data_type => "boolean", default_value => \"false", is_nullable => 0 },
+ "comment_user_id",
+ { 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 },
+ "parent",
+ { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
+);
+__PACKAGE__->set_primary_key("id");
+__PACKAGE__->has_many(
+ "bodies",
+ "FixMyStreet::DB::Result::Body",
+ { "foreign.parent" => "self.id" },
+ { cascade_copy => 0, cascade_delete => 0 },
+);
+__PACKAGE__->has_many(
+ "body_areas",
+ "FixMyStreet::DB::Result::BodyArea",
+ { "foreign.body_id" => "self.id" },
+ { cascade_copy => 0, cascade_delete => 0 },
+);
+__PACKAGE__->belongs_to(
+ "comment_user",
+ "FixMyStreet::DB::Result::User",
+ { id => "comment_user_id" },
+ {
+ is_deferrable => 1,
+ join_type => "LEFT",
+ on_delete => "CASCADE",
+ on_update => "CASCADE",
+ },
+);
+__PACKAGE__->has_many(
+ "contacts",
+ "FixMyStreet::DB::Result::Contact",
+ { "foreign.body_id" => "self.id" },
+ { cascade_copy => 0, cascade_delete => 0 },
+);
+__PACKAGE__->belongs_to(
+ "parent",
+ "FixMyStreet::DB::Result::Body",
+ { id => "parent" },
+ {
+ is_deferrable => 1,
+ join_type => "LEFT",
+ on_delete => "CASCADE",
+ on_update => "CASCADE",
+ },
+);
+__PACKAGE__->has_many(
+ "users",
+ "FixMyStreet::DB::Result::User",
+ { "foreign.from_body" => "self.id" },
+ { cascade_copy => 0, cascade_delete => 0 },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-12-19 12:47:10
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:DdtXjMWRpz20ZHjtY3oP2w
+
+sub url {
+ my ( $self, $c ) = @_;
+ # XXX $areas_info was used here for Norway parent - needs body parents, I guess
+ return $c->uri_for( '/reports/' . $c->cobrand->short_name( $self ) );
+}
+
+sub areas {
+ my $self = shift;
+ my %ids = map { $_->area_id => 1 } $self->body_areas->all;
+ return \%ids;
+}
+
+1;
diff --git a/perllib/FixMyStreet/DB/Result/BodyArea.pm b/perllib/FixMyStreet/DB/Result/BodyArea.pm
new file mode 100644
index 000000000..844a3277d
--- /dev/null
+++ b/perllib/FixMyStreet/DB/Result/BodyArea.pm
@@ -0,0 +1,33 @@
+use utf8;
+package FixMyStreet::DB::Result::BodyArea;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+__PACKAGE__->load_components("FilterColumn", "InflateColumn::DateTime", "EncodedColumn");
+__PACKAGE__->table("body_areas");
+__PACKAGE__->add_columns(
+ "body_id",
+ { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+ "area_id",
+ { data_type => "integer", is_nullable => 0 },
+);
+__PACKAGE__->add_unique_constraint("body_areas_body_id_area_id_idx", ["body_id", "area_id"]);
+__PACKAGE__->belongs_to(
+ "body",
+ "FixMyStreet::DB::Result::Body",
+ { id => "body_id" },
+ { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-12-19 12:47:10
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:aAr+Nadyu8IckZlK6+PTNg
+
+ __PACKAGE__->set_primary_key(__PACKAGE__->columns);
+
+1;
diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm
index b551be9ef..33fbb9356 100644
--- a/perllib/FixMyStreet/DB/Result/Comment.pm
+++ b/perllib/FixMyStreet/DB/Result/Comment.pm
@@ -91,6 +91,7 @@ __PACKAGE__->filter_column(
my $self = shift;
my $ser = shift;
return undef unless defined $ser;
+ utf8::encode($ser) if utf8::is_utf8($ser);
my $h = new IO::String($ser);
return RABX::wire_rd($h);
},
@@ -146,8 +147,8 @@ sub check_for_errors {
$errors{update} = _('Please enter a message')
unless $self->text =~ m/\S/;
- if ( $self->text && $self->problem && $self->problem->council
- && $self->problem->council eq '2482' && length($self->text) > 2000 ) {
+ if ( $self->text && $self->problem && $self->problem->bodies_str
+ && $self->problem->bodies_str eq '2482' && length($self->text) > 2000 ) {
$errors{update} = _('Updates are limited to 2000 characters in length. Please shorten your update');
}
diff --git a/perllib/FixMyStreet/DB/Result/Contact.pm b/perllib/FixMyStreet/DB/Result/Contact.pm
index 993e3524b..551bcd019 100644
--- a/perllib/FixMyStreet/DB/Result/Contact.pm
+++ b/perllib/FixMyStreet/DB/Result/Contact.pm
@@ -18,8 +18,8 @@ __PACKAGE__->add_columns(
is_nullable => 0,
sequence => "contacts_id_seq",
},
- "area_id",
- { data_type => "integer", is_nullable => 0 },
+ "body_id",
+ { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
"category",
{ data_type => "text", default_value => "Other", is_nullable => 0 },
"email",
@@ -48,11 +48,17 @@ __PACKAGE__->add_columns(
{ data_type => "text", is_nullable => 1 },
);
__PACKAGE__->set_primary_key("id");
-__PACKAGE__->add_unique_constraint("contacts_area_id_category_idx", ["area_id", "category"]);
+__PACKAGE__->add_unique_constraint("contacts_body_id_category_idx", ["body_id", "category"]);
+__PACKAGE__->belongs_to(
+ "body",
+ "FixMyStreet::DB::Result::Body",
+ { id => "body_id" },
+ { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
+);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-08-31 10:29:17
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:t6yOPhZmedV/eH6AUvHI6w
+# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-12-13 12:34:33
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:imXq3EtrC0FrQwj+E2xfBw
__PACKAGE__->filter_column(
extra => {
@@ -60,6 +66,7 @@ __PACKAGE__->filter_column(
my $self = shift;
my $ser = shift;
return undef unless defined $ser;
+ utf8::encode($ser) if utf8::is_utf8($ser);
my $h = new IO::String($ser);
return RABX::wire_rd($h);
},
diff --git a/perllib/FixMyStreet/DB/Result/ContactsHistory.pm b/perllib/FixMyStreet/DB/Result/ContactsHistory.pm
index deb00fb95..7126d91c9 100644
--- a/perllib/FixMyStreet/DB/Result/ContactsHistory.pm
+++ b/perllib/FixMyStreet/DB/Result/ContactsHistory.pm
@@ -20,7 +20,7 @@ __PACKAGE__->add_columns(
},
"contact_id",
{ data_type => "integer", is_nullable => 0 },
- "area_id",
+ "body_id",
{ data_type => "integer", is_nullable => 0 },
"category",
{ data_type => "text", default_value => "Other", is_nullable => 0 },
@@ -40,8 +40,8 @@ __PACKAGE__->add_columns(
__PACKAGE__->set_primary_key("contacts_history_id");
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-03-08 17:19:55
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:dN2ueIDoP3d/+Mg1UDqsMw
+# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-12-12 16:37:16
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:sxflEBBn0Mn0s3MroWnWFA
# You can replace this text with custom code or comments, and it will be preserved on regeneration
diff --git a/perllib/FixMyStreet/DB/Result/Open311conf.pm b/perllib/FixMyStreet/DB/Result/Open311conf.pm
deleted file mode 100644
index f01a20dec..000000000
--- a/perllib/FixMyStreet/DB/Result/Open311conf.pm
+++ /dev/null
@@ -1,61 +0,0 @@
-use utf8;
-package FixMyStreet::DB::Result::Open311conf;
-
-# Created by DBIx::Class::Schema::Loader
-# DO NOT MODIFY THE FIRST PART OF THIS FILE
-
-use strict;
-use warnings;
-
-use base 'DBIx::Class::Core';
-__PACKAGE__->load_components("FilterColumn", "InflateColumn::DateTime", "EncodedColumn");
-__PACKAGE__->table("open311conf");
-__PACKAGE__->add_columns(
- "id",
- {
- data_type => "integer",
- is_auto_increment => 1,
- is_nullable => 0,
- sequence => "open311conf_id_seq",
- },
- "area_id",
- { data_type => "integer", is_nullable => 0 },
- "endpoint",
- { data_type => "text", is_nullable => 0 },
- "jurisdiction",
- { data_type => "text", is_nullable => 1 },
- "api_key",
- { data_type => "text", is_nullable => 1 },
- "send_method",
- { data_type => "text", is_nullable => 1 },
- "send_comments",
- { data_type => "boolean", default_value => \"false", is_nullable => 0 },
- "comment_user_id",
- { 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 },
-);
-__PACKAGE__->set_primary_key("id");
-__PACKAGE__->add_unique_constraint("open311conf_area_id_key", ["area_id"]);
-__PACKAGE__->belongs_to(
- "comment_user",
- "FixMyStreet::DB::Result::User",
- { id => "comment_user_id" },
- {
- is_deferrable => 1,
- join_type => "LEFT",
- on_delete => "CASCADE",
- on_update => "CASCADE",
- },
-);
-
-
-# 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 0238e3b09..d9a2a0273 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -24,7 +24,7 @@ __PACKAGE__->add_columns(
{ data_type => "double precision", is_nullable => 0 },
"longitude",
{ data_type => "double precision", is_nullable => 0 },
- "council",
+ "bodies_str",
{ data_type => "text", is_nullable => 1 },
"areas",
{ data_type => "text", is_nullable => 0 },
@@ -99,7 +99,7 @@ __PACKAGE__->add_columns(
"external_source_id",
{ data_type => "text", is_nullable => 1 },
"interest_count",
- { data_type => "integer", is_nullable => 1 },
+ { data_type => "integer", default_value => 0, is_nullable => 1 },
"subcategory",
{ data_type => "text", is_nullable => 1 },
);
@@ -124,8 +124,8 @@ __PACKAGE__->belongs_to(
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-12-03 17:48:10
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:xN/RB8Vx50CwyOeBjvJezQ
+# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-12-13 15:13:48
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:H2P3Og37G569nQdQA1IWaA
# Add fake relationship to stored procedure table
__PACKAGE__->has_one(
@@ -141,6 +141,7 @@ __PACKAGE__->filter_column(
my $self = shift;
my $ser = shift;
return undef unless defined $ser;
+ utf8::encode($ser) if utf8::is_utf8($ser);
my $h = new IO::String($ser);
return RABX::wire_rd($h);
},
@@ -161,6 +162,7 @@ __PACKAGE__->filter_column(
my $self = shift;
my $ser = shift;
return undef unless defined $ser;
+ utf8::encode($ser) if utf8::is_utf8($ser);
my $h = new IO::String($ser);
return RABX::wire_rd($h);
},
@@ -259,24 +261,26 @@ HASHREF.
=cut
+my $visible_states = {
+ 'confirmed' => 1,
+ 'investigating' => 1,
+ 'in progress' => 1,
+ 'planned' => 1,
+ 'action scheduled' => 1,
+ 'fixed' => 1,
+ 'fixed - council' => 1,
+ 'fixed - user' => 1,
+ 'unable to fix' => 1,
+ 'not responsible' => 1,
+ 'duplicate' => 1,
+ 'closed' => 1,
+ 'internal referral' => 1,
+};
sub visible_states {
- my $states = {
- 'confirmed' => 1,
- 'investigating' => 1,
- 'in progress' => 1,
- 'planned' => 1,
- 'action scheduled' => 1,
- 'fixed' => 1,
- 'fixed - council' => 1,
- 'fixed - user' => 1,
- 'unable to fix' => 1,
- 'not responsible' => 1,
- 'duplicate' => 1,
- 'closed' => 1,
- 'internal referral' => 1,
- };
-
- return wantarray ? keys %{$states} : $states;
+ return wantarray ? keys %{$visible_states} : $visible_states;
+}
+sub visible_states_add_unconfirmed {
+ $visible_states->{unconfirmed} = 1;
}
=head2
@@ -336,7 +340,6 @@ sub council_states {
return wantarray ? keys %{$states} : $states;
}
-
my $tz = DateTime::TimeZone->new( name => "local" );
sub confirmed_local {
@@ -378,6 +381,12 @@ around service => sub {
return $s;
};
+sub title_safe {
+ my $self = shift;
+ return _('Awaiting moderation') if $self->cobrand eq 'zurich' && $self->state eq 'unconfirmed';
+ return $self->title;
+}
+
=head2 check_for_errors
$error_hashref = $problem->check_for_errors();
@@ -402,9 +411,9 @@ sub check_for_errors {
$errors{detail} = _('Please enter some details')
unless $self->detail =~ m/\S/;
- $errors{council} = _('No council selected')
- unless $self->council
- && $self->council =~ m/^(?:-1|[\d,]+(?:\|[\d,]+)?)$/;
+ $errors{bodies} = _('No council selected')
+ unless $self->bodies_str
+ && $self->bodies_str =~ m/^(?:-1|[\d,]+(?:\|[\d,]+)?)$/;
if ( !$self->name || $self->name !~ m/\S/ ) {
$errors{name} = _('Please enter your name');
@@ -431,8 +440,8 @@ sub check_for_errors {
$self->category(undef);
}
- if ( $self->council && $self->detail &&
- $self->council eq '2482' && length($self->detail) > 2000 ) {
+ if ( $self->bodies_str && $self->detail &&
+ $self->bodies_str eq '2482' && length($self->detail) > 2000 ) {
$errors{detail} = _('Reports are limited to 2000 characters in length. Please shorten your report');
}
@@ -462,18 +471,26 @@ sub confirm {
return 1;
}
-=head2 councils
+sub bodies_str_ids {
+ my $self = shift;
+ return unless $self->bodies_str;
+ (my $bodies = $self->bodies_str) =~ s/\|.*$//;
+ my @bodies = split( /,/, $bodies );
+ return \@bodies;
+}
+
+=head2 bodies
-Returns an arrayref of councils to which a report was sent.
+Returns an arrayref of bodies to which a report was sent.
=cut
-sub councils {
+sub bodies($) {
my $self = shift;
- return [] unless $self->council;
- (my $council = $self->council) =~ s/\|.*$//;
- my @council = split( /,/, $council );
- return \@council;
+ return {} unless $self->bodies_str;
+ my $bodies = $self->bodies_str_ids;
+ my @bodies = FixMyStreet::App->model('DB::Body')->search({ id => $bodies })->all;
+ return { map { $_->id => $_ } @bodies };
}
=head2 url
@@ -557,8 +574,7 @@ meta data about the report.
sub meta_line {
my ( $problem, $c ) = @_;
- my $date_time =
- Utils::prettify_epoch( $problem->confirmed_local->epoch );
+ my $date_time = Utils::prettify_dt( $problem->confirmed_local );
my $meta = '';
# FIXME Should be in cobrand
@@ -623,21 +639,22 @@ sub body {
my ( $problem, $c ) = @_;
my $body;
if ($problem->external_body) {
- $body = $problem->external_body;
+ if ($problem->cobrand eq 'zurich') {
+ $body = $c->model('DB::Body')->find({ id => $problem->external_body });
+ } else {
+ $body = $problem->external_body;
+ }
} else {
- my $councils = $problem->councils;
- my $areas_info = mySociety::MaPit::call('areas', $councils);
+ my $bodies = $problem->bodies;
$body = join( _(' and '),
map {
- my $name = $areas_info->{$_}->{name};
+ my $name = $_->name;
if (mySociety::Config::get('AREA_LINKS_FROM_PROBLEMS')) {
- '<a href="'
- . $c->uri_for( '/reports/' . $c->cobrand->short_name( $areas_info->{$_} ) )
- . '">' . $name . '</a>';
+ '<a href="' . $_->url($c) . '">' . $name . '</a>';
} else {
$name;
}
- } @$councils
+ } values %$bodies
);
}
return $body;
@@ -696,6 +713,14 @@ sub duration_string {
);
}
+sub local_coords {
+ my $self = shift;
+ if ($self->cobrand eq 'zurich') {
+ my ($x, $y) = Geo::Coordinates::CH1903::from_latlon($self->latitude, $self->longitude);
+ return ( int($x+0.5), int($y+0.5) );
+ }
+}
+
=head2 update_from_open311_service_request
$p->update_from_open311_service_request( $request, $council_details, $system_user );
@@ -789,6 +814,29 @@ sub update_send_failed {
} );
}
+sub as_hashref {
+ my $self = shift;
+ my $c = shift;
+
+ return {
+ id => $self->id,
+ title => $self->title,
+ category => $self->category,
+ detail => $self->detail,
+ latitude => $self->latitude,
+ longitude => $self->longitude,
+ postcode => $self->postcode,
+ state => $self->state,
+ state_t => _( $self->state ),
+ used_map => $self->used_map,
+ is_fixed => $self->fixed_states->{ $self->state } ? 1 : 0,
+ photo => $self->get_photo_params,
+ meta => $self->confirmed ? $self->meta_line( $c ) : '',
+ confirmed_pp => $self->confirmed ? Utils::prettify_dt( $self->confirmed_local, 1 ): '',
+ created_pp => Utils::prettify_dt( $self->created_local, 1 ),
+ };
+}
+
# we need the inline_constructor bit as we don't inherit from Moose
__PACKAGE__->meta->make_immutable( inline_constructor => 0 );
diff --git a/perllib/FixMyStreet/DB/Result/Token.pm b/perllib/FixMyStreet/DB/Result/Token.pm
index b223ada3a..028300842 100644
--- a/perllib/FixMyStreet/DB/Result/Token.pm
+++ b/perllib/FixMyStreet/DB/Result/Token.pm
@@ -60,6 +60,7 @@ __PACKAGE__->filter_column(
my $self = shift;
my $ser = shift;
return undef unless defined $ser;
+ utf8::encode($ser) if utf8::is_utf8($ser);
my $h = new IO::String($ser);
return RABX::wire_rd($h);
},
diff --git a/perllib/FixMyStreet/DB/Result/User.pm b/perllib/FixMyStreet/DB/Result/User.pm
index 7f43d1a52..481b654c9 100644
--- a/perllib/FixMyStreet/DB/Result/User.pm
+++ b/perllib/FixMyStreet/DB/Result/User.pm
@@ -26,8 +26,8 @@ __PACKAGE__->add_columns(
{ data_type => "text", is_nullable => 1 },
"password",
{ data_type => "text", default_value => "", is_nullable => 0 },
- "from_council",
- { data_type => "integer", is_nullable => 1 },
+ "from_body",
+ { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
"flagged",
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
"title",
@@ -42,16 +42,27 @@ __PACKAGE__->has_many(
{ cascade_copy => 0, cascade_delete => 0 },
);
__PACKAGE__->has_many(
+ "bodies",
+ "FixMyStreet::DB::Result::Body",
+ { "foreign.comment_user_id" => "self.id" },
+ { cascade_copy => 0, cascade_delete => 0 },
+);
+__PACKAGE__->has_many(
"comments",
"FixMyStreet::DB::Result::Comment",
{ "foreign.user_id" => "self.id" },
{ cascade_copy => 0, cascade_delete => 0 },
);
-__PACKAGE__->has_many(
- "open311confs",
- "FixMyStreet::DB::Result::Open311conf",
- { "foreign.comment_user_id" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
+__PACKAGE__->belongs_to(
+ "from_body",
+ "FixMyStreet::DB::Result::Body",
+ { id => "from_body" },
+ {
+ is_deferrable => 1,
+ join_type => "LEFT",
+ on_delete => "CASCADE",
+ on_update => "CASCADE",
+ },
);
__PACKAGE__->has_many(
"problems",
@@ -61,8 +72,8 @@ __PACKAGE__->has_many(
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-05-01 16:20:29
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:LKi8u5IYnHW1+Mez64nvGg
+# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-12-14 09:23:59
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:aw374WQraL5ysOvUmUIU3w
__PACKAGE__->add_columns(
"password" => {
@@ -144,38 +155,27 @@ sub alert_for_problem {
} );
}
-sub council {
+sub body {
my $self = shift;
-
- return '' unless $self->from_council;
-
- my $key = 'council_name:' . $self->from_council;
- my $result = Memcached::get($key);
-
- unless ($result) {
- my $area_info = mySociety::MaPit::call('area', $self->from_council);
- $result = $area_info->{name};
- Memcached::set($key, $result, 86400);
- }
-
- return $result;
+ return '' unless $self->from_body;
+ return $self->from_body->name;
}
-=head2 belongs_to_council
+=head2 belongs_to_body
- $belongs_to_council = $user->belongs_to_council( $council_list );
+ $belongs_to_body = $user->belongs_to_body( $bodies );
-Returns true if the user belongs to the comma seperated list of council ids passed in
+Returns true if the user belongs to the comma seperated list of body ids passed in
=cut
-sub belongs_to_council {
+sub belongs_to_body {
my $self = shift;
- my $council = shift;
+ my $bodies = shift;
- my %councils = map { $_ => 1 } split ',', $council;
+ my %bodies = map { $_ => 1 } split ',', $bodies;
- return 1 if $self->from_council && $councils{ $self->from_council };
+ return 1 if $self->from_body && $bodies{ $self->from_body->id };
return 0;
}
diff --git a/perllib/FixMyStreet/DB/ResultSet/AlertType.pm b/perllib/FixMyStreet/DB/ResultSet/AlertType.pm
index d903f8eb2..8e9b3d17e 100644
--- a/perllib/FixMyStreet/DB/ResultSet/AlertType.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/AlertType.pm
@@ -89,13 +89,14 @@ sub email_alerts ($) {
}
my $url = $cobrand->base_url( $row->{alert_cobrand_data} );
- if ( $hashref_restriction && $hashref_restriction->{council} && $row->{council} ne $hashref_restriction->{council} ) {
+ if ( $hashref_restriction && $hashref_restriction->{bodies_str} && $row->{bodies_str} ne $hashref_restriction->{bodies_str} ) {
$url = mySociety::Config::get('BASE_URL');
}
# this is currently only for new_updates
if ($row->{item_text}) {
- if ( $row->{alert_user_id} == $row->{user_id} ) {
+ if ( $cobrand->moniker ne 'zurich' && $row->{alert_user_id} == $row->{user_id} ) {
# This is an alert to the same user who made the report - make this a login link
+ # Don't bother with Zurich which has no accounts
my $user = FixMyStreet::App->model('DB::User')->find( {
id => $row->{alert_user_id}
} );
@@ -166,7 +167,7 @@ sub email_alerts ($) {
};
my $states = "'" . join( "', '", FixMyStreet::DB::Result::Problem::visible_states() ) . "'";
my %data = ( template => $template, data => '', alert_id => $alert->id, alert_email => $alert->user->email, lang => $alert->lang, cobrand => $alert->cobrand, cobrand_data => $alert->cobrand_data );
- my $q = "select problem.id, problem.council, problem.postcode, problem.geocode, problem.title from problem_find_nearby(?, ?, ?) as nearby, problem, users
+ my $q = "select problem.id, problem.bodies_str, problem.postcode, problem.geocode, problem.title from problem_find_nearby(?, ?, ?) as nearby, problem, users
where nearby.problem_id = problem.id
and problem.user_id = users.id
and problem.state in ($states)
@@ -183,7 +184,7 @@ sub email_alerts ($) {
parameter => $row->{id},
} );
my $url = $cobrand->base_url( $alert->cobrand_data );
- if ( $hashref_restriction && $hashref_restriction->{council} && $row->{council} ne $hashref_restriction->{council} ) {
+ if ( $hashref_restriction && $hashref_restriction->{bodies_str} && $row->{bodies_str} ne $hashref_restriction->{bodies_str} ) {
$url = mySociety::Config::get('BASE_URL');
}
$data{data} .= $url . "/report/" . $row->{id} . " - $row->{title}\n\n";
@@ -254,6 +255,7 @@ sub _get_address_from_gecode {
my $geocode = shift;
return '' unless defined $geocode;
+ utf8::encode($geocode) if utf8::is_utf8($geocode);
my $h = new IO::String($geocode);
my $data = RABX::wire_rd($h);
diff --git a/perllib/FixMyStreet/DB/ResultSet/Body.pm b/perllib/FixMyStreet/DB/ResultSet/Body.pm
new file mode 100644
index 000000000..6802ed604
--- /dev/null
+++ b/perllib/FixMyStreet/DB/ResultSet/Body.pm
@@ -0,0 +1,17 @@
+package FixMyStreet::DB::ResultSet::Body;
+use base 'DBIx::Class::ResultSet';
+
+use strict;
+use warnings;
+
+sub for_areas {
+ my ( $rs, @areas ) = @_;
+
+ my $result = $rs->search(
+ { 'body_areas.area_id' => \@areas },
+ { join => 'body_areas' }
+ );
+ return $result;
+}
+
+1;
diff --git a/perllib/FixMyStreet/DB/ResultSet/Nearby.pm b/perllib/FixMyStreet/DB/ResultSet/Nearby.pm
index 191223572..91c44d5f4 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Nearby.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Nearby.pm
@@ -21,12 +21,7 @@ sub nearby {
} if $c->cobrand->problems_clause;
my $attrs = {
- join => 'problem',
- columns => [
- 'problem.id', 'problem.title', 'problem.latitude',
- 'problem.longitude', 'distance', 'problem.state',
- 'problem.confirmed', { 'problem.photo' => 'problem.photo is not null' },
- ],
+ prefetch => 'problem',
bind => [ $mid_lat, $mid_lon, $dist ],
order_by => [ 'distance', { -desc => 'created' } ],
rows => $limit,
diff --git a/perllib/FixMyStreet/DB/ResultSet/Problem.pm b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
index faed3b8ac..078c78d0e 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Problem.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
@@ -84,15 +84,16 @@ sub _recent {
my $key = $photos ? 'recent_photos' : 'recent';
$key .= ":$site_key:$num";
+ # unconfirmed might be returned for e.g. Zurich, but would mean in moderation, so no photo
+ my @states = grep { $_ ne 'unconfirmed' } FixMyStreet::DB::Result::Problem->visible_states();
my $query = {
non_public => 0,
- state => [ FixMyStreet::DB::Result::Problem->visible_states() ],
+ state => \@states,
};
$query->{photo} = { '!=', undef } if $photos;
my $attrs = {
- columns => [ 'id', 'title', 'confirmed' ],
- order_by => { -desc => 'confirmed' },
+ order_by => { -desc => 'coalesce(confirmed, created)' },
rows => $num,
};
@@ -134,10 +135,6 @@ sub around_map {
my ( $rs, $min_lat, $max_lat, $min_lon, $max_lon, $interval, $limit ) = @_;
my $attr = {
order_by => { -desc => 'created' },
- columns => [
- 'id', 'title', 'latitude', 'longitude', 'state', 'confirmed',
- { photo => 'photo is not null' },
- ],
};
$attr->{rows} = $limit if $limit;
@@ -220,15 +217,19 @@ sub categories_summary {
}
sub send_reports {
+ my ( $rs, $site_override ) = @_;
+
# Set up site, language etc.
my ($verbose, $nomail) = CronFns::options();
my $base_url = mySociety::Config::get('BASE_URL');
- my $site = CronFns::site($base_url);
+ my $site = $site_override || CronFns::site($base_url);
+ my $states = [ 'confirmed', 'fixed' ];
+ $states = [ 'unconfirmed', 'confirmed', 'in progress', 'planned', 'closed' ] if $site eq 'zurich';
my $unsent = FixMyStreet::App->model("DB::Problem")->search( {
- state => [ 'confirmed', 'fixed' ],
+ state => $states,
whensent => undef,
- council => { '!=', undef },
+ bodies_str => { '!=', undef },
} );
my (%notgot, %note);
@@ -255,10 +256,12 @@ sub send_reports {
my $email_base_url = $cobrand->base_url_for_report($row);
my %h = map { $_ => $row->$_ } qw/id title detail name category latitude longitude used_map/;
map { $h{$_} = $row->user->$_ } qw/email phone/;
- $h{confirmed} = DateTime::Format::Pg->format_datetime( $row->confirmed->truncate (to => 'second' ) );
+ $h{confirmed} = DateTime::Format::Pg->format_datetime( $row->confirmed->truncate (to => 'second' ) )
+ if $row->confirmed;
$h{query} = $row->postcode;
$h{url} = $email_base_url . $row->url;
+ $h{admin_url} = $cobrand->admin_base_url . 'report_edit/' . $row->id;
$h{phone_line} = $h{phone} ? _('Phone:') . " $h{phone}\n\n" : '';
if ($row->photo) {
$h{has_photo} = _("This web page also contains a photo of the problem, provided by the user.") . "\n\n";
@@ -302,29 +305,28 @@ sub send_reports {
my ( $sender_count );
if ($site eq 'emptyhomes') {
- my $council = $row->council;
- my $areas_info = mySociety::MaPit::call('areas', $council);
+ my $body = $row->bodies_str;
+ $body = FixMyStreet::App->model("DB::Body")->find($body);
my $sender = "FixMyStreet::SendReport::EmptyHomes";
$reporters{ $sender } = $sender->new() unless $reporters{$sender};
- $reporters{ $sender }->add_council( $council, $areas_info->{$council} );
+ $reporters{ $sender }->add_body( $body );
} else {
# XXX Needs locks!
- my @all_councils = split /,|\|/, $row->council;
- my ($councils, $missing) = $row->council =~ /^([\d,]+)(?:\|([\d,]+))?/;
- my @councils = split(/,/, $councils);
- my $areas_info = mySociety::MaPit::call('areas', \@all_councils);
+ # XXX Only copes with at most one missing body
+ my ($bodies, $missing) = $row->bodies_str =~ /^([\d,]+)(?:\|(\d+))?/;
+ my @bodies = split(/,/, $bodies);
+ $bodies = FixMyStreet::App->model("DB::Body")->search({ id => \@bodies });
+ $missing = FixMyStreet::App->model("DB::Body")->find($missing) if $missing;
my @dear;
- foreach my $council (@councils) {
- my $name = $areas_info->{$council}->{name};
-
- my $sender_info = $cobrand->get_council_sender( $council, $areas_info->{$council}, $row->category );
+ while (my $body = $bodies->next) {
+ my $sender_info = $cobrand->get_body_sender( $body, $row->category );
my $sender = "FixMyStreet::SendReport::" . $sender_info->{method};
if ( ! exists $senders->{ $sender } ) {
- warn "No such sender [ $sender ] for council $name ( $council )";
+ warn "No such sender [ $sender ] for body $body->name ( $body->id )";
next;
}
$reporters{ $sender } ||= $sender->new();
@@ -333,8 +335,8 @@ sub send_reports {
$sending_skipped_by_method{ $sender }++ if
$reporters{ $sender }->skipped;
} else {
- push @dear, $name;
- $reporters{ $sender }->add_council( $council, $areas_info->{$council}, $sender_info->{config} );
+ push @dear, $body->name;
+ $reporters{ $sender }->add_body( $body, $sender_info->{config} );
}
}
@@ -350,7 +352,7 @@ sub send_reports {
$h{subcategory_line} = sprintf(_("Subcategory: %s"), $row->subcategory) . "\n\n";
}
- $h{councils_name} = join(_(' and '), @dear);
+ $h{bodies_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"
: '';
@@ -360,9 +362,8 @@ sub send_reports {
}
$h{missing} = '';
if ($missing) {
- my $name = $areas_info->{$missing}->{name};
$h{missing} = '[ '
- . sprintf(_('We realise this problem might be the responsibility of %s; however, we don\'t currently have any contact details for them. If you know of an appropriate contact address, please do get in touch.'), $name)
+ . sprintf(_('We realise this problem might be the responsibility of %s; however, we don\'t currently have any contact details for them. If you know of an appropriate contact address, please do get in touch.'), $missing->name)
. " ]\n\n";
}
@@ -375,39 +376,11 @@ sub send_reports {
next unless $sender_count;
- if (mySociety::Config::get('STAGING_SITE')) {
- # on a staging server send emails to ourselves rather than the 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() );
- }
+ if (mySociety::Config::get('STAGING_SITE') && !mySociety::Config::get('SEND_REPORTS_ON_STAGING')) {
+ # on a staging server send emails to ourselves rather than the bodies
+ %reporters = map { $_ => $reporters{$_} } grep { /FixMyStreet::SendReport::(Email|NI)/ } keys %reporters;
+ unless (%reporters) {
+ %reporters = ( 'FixMyStreet::SendReport::Email' => FixMyStreet::SendReport::Email->new() );
}
}
@@ -468,7 +441,7 @@ sub send_reports {
my $unsent = FixMyStreet::App->model("DB::Problem")->search( {
state => [ 'confirmed', 'fixed' ],
whensent => undef,
- council => { '!=', undef },
+ bodies_str => { '!=', undef },
send_fail_count => { '>', 0 }
} );
while (my $row = $unsent->next) {
diff --git a/perllib/FixMyStreet/Geocode.pm b/perllib/FixMyStreet/Geocode.pm
index 6cfd960ed..61c398985 100644
--- a/perllib/FixMyStreet/Geocode.pm
+++ b/perllib/FixMyStreet/Geocode.pm
@@ -31,7 +31,7 @@ sub lookup {
}
# string STRING CONTEXT
-# Canonicalises, and then passes to some external API to look stuff up.
+# Passes the string to some external API to look stuff up.
sub string {
my ($s, $c) = @_;
diff --git a/perllib/FixMyStreet/Geocode/Zurich.pm b/perllib/FixMyStreet/Geocode/Zurich.pm
index 5aaca2c8e..0fc84c0ef 100644
--- a/perllib/FixMyStreet/Geocode/Zurich.pm
+++ b/perllib/FixMyStreet/Geocode/Zurich.pm
@@ -52,8 +52,13 @@ sub setup_soap {
# 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.
+# an array of matches if there are more than one.
+# If there is no ambiguity, returns only a {lat,long} hash, unless allow_single_match_string is true
+# (because the auto-complete use of this (in /around) should send the matched name even though it's not ambiguous).
+#
+# The information in the query may be used to disambiguate the location in cobranded
+# versions of the site.
+
sub string {
my ( $s, $c ) = @_;
@@ -98,8 +103,9 @@ sub string {
push (@valid_locations, $_);
last if lc($_->{text}) eq lc($s);
}
-
- return { latitude => $latitude, longitude => $longitude } if scalar @valid_locations == 1;
+ if (scalar @valid_locations == 1 && ! $c->stash->{allow_single_geocode_match_strings} ) {
+ return { latitude => $latitude, longitude => $longitude };
+ }
return { error => $error };
}
diff --git a/perllib/FixMyStreet/Map.pm b/perllib/FixMyStreet/Map.pm
index a1876e150..f2dd0da6d 100644
--- a/perllib/FixMyStreet/Map.pm
+++ b/perllib/FixMyStreet/Map.pm
@@ -129,7 +129,7 @@ sub map_pins {
my $colour = $c->cobrand->pin_colour( $p, 'around' );
[ $p->latitude, $p->longitude,
$colour,
- $p->id, $p->title
+ $p->id, $p->title_safe
]
} @$around_map, @$nearby;
diff --git a/perllib/FixMyStreet/Map/Zurich.pm b/perllib/FixMyStreet/Map/Zurich.pm
index d2f7a35af..262b6e229 100644
--- a/perllib/FixMyStreet/Map/Zurich.pm
+++ b/perllib/FixMyStreet/Map/Zurich.pm
@@ -13,8 +13,8 @@ use Geo::Coordinates::CH1903;
use Math::Trig;
use Utils;
-use constant ZOOM_LEVELS => 10;
-use constant DEFAULT_ZOOM => 7;
+use constant ZOOM_LEVELS => 7;
+use constant DEFAULT_ZOOM => 5;
use constant MIN_ZOOM_LEVEL => 0;
sub map_tiles {
@@ -30,7 +30,7 @@ sub map_tiles {
}
sub base_tile_url {
- return 'http://www.wmts.stadt-zuerich.ch/Luftbild/MapServer/WMTS/tile/1.0.0/Luftbild/default/nativeTileMatrixSet';
+ return 'http://www.wmts.stadt-zuerich.ch/Hybrid/MapServer/WMTS/tile/1.0.0/Hybrid/default/nativeTileMatrixSet';
}
sub copyright {
@@ -90,10 +90,10 @@ sub latlon_to_tile($$$) {
my ($x, $y) = Geo::Coordinates::CH1903::from_latlon($lat, $lon);
- my $matrix_id = $zoom - 1;
+ my $matrix_id = $zoom;
$matrix_id = 0 if $matrix_id < 0;
- my @scales = ( '250000', '125000', '64000', '32000', '16000', '8000', '4000', '2000', '1000', '500' );
+ my @scales = ( '250000', '125000', '64000', '32000', '16000', '8000', '4000', '2000', '1000' );
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
diff --git a/perllib/FixMyStreet/SendReport.pm b/perllib/FixMyStreet/SendReport.pm
index f679d826e..f8901c6f8 100644
--- a/perllib/FixMyStreet/SendReport.pm
+++ b/perllib/FixMyStreet/SendReport.pm
@@ -7,7 +7,8 @@ use Module::Pluggable
search_path => __PACKAGE__,
require => 1;
-has 'councils' => ( is => 'rw', isa => 'HashRef', default => sub { {} } );
+has 'body_config' => ( is => 'rw', isa => 'HashRef', default => sub { {} } );
+has 'bodies' => ( is => 'rw', isa => 'ArrayRef', default => sub { [] } );
has 'to' => ( is => 'rw', isa => 'ArrayRef', default => sub { [] } );
has 'success' => ( is => 'rw', isa => 'Bool', default => 0 );
has 'error' => ( is => 'rw', isa => 'Str', default => '' );
@@ -31,25 +32,18 @@ sub get_senders {
sub reset {
my $self = shift;
- $self->councils( {} );
+ $self->bodies( [] );
+ $self->body_config( {} );
$self->to( [] );
}
-sub add_council {
+sub add_body {
my $self = shift;
- my $council = shift;
- my $info = shift;
+ my $body = shift;
my $config = shift;
- $self->councils->{ $council } = { info => $info, config => $config };
+ push @{$self->bodies}, $body;
+ $self->body_config->{ $body->id } = $config;
}
-sub delete_council {
- my $self = shift;
- my $council = shift;
-
- delete $self->councils->{$council};
-}
-
-
1;
diff --git a/perllib/FixMyStreet/SendReport/Barnet.pm b/perllib/FixMyStreet/SendReport/Barnet.pm
index 9a92686ec..05ca20809 100644
--- a/perllib/FixMyStreet/SendReport/Barnet.pm
+++ b/perllib/FixMyStreet/SendReport/Barnet.pm
@@ -80,9 +80,9 @@ sub send {
? $h{query} : $nearest_postcode; # use given postcode if available
# note: endpoint can be of form 'https://username:password@url'
- my $council_config = FixMyStreet::App->model("DB::Open311conf")->search( { area_id => COUNCIL_ID_BARNET} )->first;
- if ($council_config and $council_config->endpoint) {
- $interface->set_proxy($council_config->endpoint);
+ my $body = FixMyStreet::App->model("DB::Body")->search( { 'body_areas.area_id' => COUNCIL_ID_BARNET }, { join => "body_areas" } )->first;
+ if ($body and $body->endpoint) {
+ $interface->set_proxy($body->endpoint);
# Barnet web service doesn't like namespaces in the elements so use a prefix
$interface->set_prefix('urn');
# uncomment these lines to print XML that will be sent rather
@@ -90,7 +90,7 @@ sub send {
#$interface->outputxml(1);
#$interface->no_dispatch(1);
} else {
- die "Barnet webservice FAIL: looks like you're missing some config data: no endpoint (URL) found for area_id=" . COUNCIL_ID_BARNET;
+ die "Barnet webservice FAIL: looks like you're missing some config data: no endpoint (URL) found for area ID " . COUNCIL_ID_BARNET;
}
eval {
diff --git a/perllib/FixMyStreet/SendReport/Email.pm b/perllib/FixMyStreet/SendReport/Email.pm
index f26116bc4..1ff476da3 100644
--- a/perllib/FixMyStreet/SendReport/Email.pm
+++ b/perllib/FixMyStreet/SendReport/Email.pm
@@ -11,36 +11,36 @@ sub build_recipient_list {
my %recips;
my $all_confirmed = 1;
- foreach my $council ( keys %{ $self->councils } ) {
+ foreach my $body ( @{ $self->bodies } ) {
my $contact = FixMyStreet::App->model("DB::Contact")->find( {
deleted => 0,
- area_id => $council,
+ body_id => $body->id,
category => $row->category
} );
- my ($council_email, $confirmed, $note) = ( $contact->email, $contact->confirmed, $contact->note );
+ my ($body_email, $confirmed, $note) = ( $contact->email, $contact->confirmed, $contact->note );
- $council_email = essex_contact($row->latitude, $row->longitude) if $council == 2225;
- $council_email = oxfordshire_contact($row->latitude, $row->longitude) if $council == 2237 && $council_email eq 'SPECIAL';
+ $body_email = essex_contact($row->latitude, $row->longitude) if $body->areas->{2225};
+ $body_email = oxfordshire_contact($row->latitude, $row->longitude) if $body->areas->{2237} && $body_email eq 'SPECIAL';
unless ($confirmed) {
$all_confirmed = 0;
- $note = 'Council ' . $row->council . ' deleted'
+ $note = 'Body ' . $row->bodies_str . ' deleted'
unless $note;
- $council_email = 'N/A' unless $council_email;
- $self->unconfirmed_counts->{$council_email}{$row->category}++;
- $self->unconfirmed_notes->{$council_email}{$row->category} = $note;
+ $body_email = 'N/A' unless $body_email;
+ $self->unconfirmed_counts->{$body_email}{$row->category}++;
+ $self->unconfirmed_notes->{$body_email}{$row->category} = $note;
}
# 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' ];
+ push @{ $self->to }, [ $body_email, 'See Something, Say Something' ];
} else {
- push @{ $self->to }, [ $council_email, $self->councils->{ $council }->{info}->{name} ];
+ push @{ $self->to }, [ $body_email, $body->name ];
}
- $recips{$council_email} = 1;
+ $recips{$body_email} = 1;
}
return () unless $all_confirmed;
@@ -51,7 +51,7 @@ sub get_template {
my ( $self, $row ) = @_;
my $template = 'submit.txt';
- $template = 'submit-brent.txt' if $row->council eq 2488 || $row->council eq 2237;
+ $template = 'submit-brent.txt' if $row->bodies_str eq 2488 || $row->bodies_str eq 2237;
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;
@@ -61,14 +61,19 @@ sub get_template {
return $template;
}
+sub send_from {
+ my ( $self, $row ) = @_;
+ return [ $row->user->email, $row->name ];
+}
+
sub send {
my $self = shift;
my ( $row, $h ) = @_;
my @recips = $self->build_recipient_list( $row, $h );
- # on a staging server send emails to ourselves rather than the councils
- if (mySociety::Config::get('STAGING_SITE') && !FixMyStreet->test_mode) {
+ # on a staging server send emails to ourselves rather than the bodies
+ if (mySociety::Config::get('STAGING_SITE') && !mySociety::Config::get('SEND_REPORTS_ON_STAGING') && !FixMyStreet->test_mode) {
@recips = ( mySociety::Config::get('CONTACT_EMAIL') );
}
@@ -83,7 +88,7 @@ sub send {
_template_ => $self->get_template( $row ),
_parameters_ => $h,
To => $self->to,
- From => [ $row->user->email, $row->name ],
+ From => $self->send_from( $row ),
},
mySociety::Config::get('CONTACT_EMAIL'),
\@recips,
diff --git a/perllib/FixMyStreet/SendReport/EmptyHomes.pm b/perllib/FixMyStreet/SendReport/EmptyHomes.pm
index 4a6f058fe..b29c1fd3c 100644
--- a/perllib/FixMyStreet/SendReport/EmptyHomes.pm
+++ b/perllib/FixMyStreet/SendReport/EmptyHomes.pm
@@ -3,6 +3,8 @@ package FixMyStreet::SendReport::EmptyHomes;
use Moose;
use namespace::autoclean;
+use mySociety::MaPit;
+
BEGIN { extends 'FixMyStreet::SendReport::Email'; }
sub build_recipient_list {
@@ -10,28 +12,29 @@ sub build_recipient_list {
my %recips;
my $all_confirmed = 1;
- foreach my $council ( keys %{ $self->councils } ) {
+ foreach my $body ( @{ $self->bodies } ) {
my $contact = FixMyStreet::App->model("DB::Contact")->find( {
deleted => 0,
- area_id => $council,
+ body_id => $body->id,
category => 'Empty property',
} );
- my ($council_email, $confirmed, $note) = ( $contact->email, $contact->confirmed, $contact->note );
+ my ($body_email, $confirmed, $note) = ( $contact->email, $contact->confirmed, $contact->note );
unless ($confirmed) {
$all_confirmed = 0;
- #$note = 'Council ' . $row->council . ' deleted'
+ #$note = 'Council ' . $row->body . ' deleted'
#unless $note;
- $council_email = 'N/A' unless $council_email;
- #$notgot{$council_email}{$row->category}++;
- #$note{$council_email}{$row->category} = $note;
+ $body_email = 'N/A' unless $body_email;
+ #$notgot{$body_email}{$row->category}++;
+ #$note{$body_email}{$row->category} = $note;
}
- push @{ $self->to }, [ $council_email, $self->councils->{ $council }->{ info }->{name} ];
- $recips{$council_email} = 1;
+ push @{ $self->to }, [ $body_email, $body->name ];
+ $recips{$body_email} = 1;
- my $country = $self->councils->{$council}->{country};
+ my $area_info = mySociety::MaPit::call('area', $body->area_id);
+ my $country = $area_info->{country};
if ($country eq 'W') {
$recips{ 'shelter@' . mySociety::Config::get('EMAIL_DOMAIN') } = 1;
} else {
diff --git a/perllib/FixMyStreet/SendReport/NI.pm b/perllib/FixMyStreet/SendReport/NI.pm
index 810ee60e2..e0ea24f9c 100644
--- a/perllib/FixMyStreet/SendReport/NI.pm
+++ b/perllib/FixMyStreet/SendReport/NI.pm
@@ -9,10 +9,10 @@ sub build_recipient_list {
my %recips;
my $all_confirmed = 1;
- foreach my $council ( keys %{ $self->councils } ) {
+ foreach my $body ( @{ $self->bodies } ) {
my $contact = FixMyStreet::App->model("DB::Contact")->find( {
deleted => 0,
- area_id => $council,
+ body_id => $body->id,
category => $row->category
} );
@@ -23,10 +23,10 @@ sub build_recipient_list {
$email = 'N/A' unless $email;
}
- my $name = $self->councils->{$council}->{info}->{name};
+ my $name = $body->name;
if ( $email =~ /^roads.([^@]*)\@drdni/ ) {
$name = "Roads Service (\u$1)";
- $h->{councils_name} = $name;
+ $h->{bodies_name} = $name;
$row->external_body( 'Roads Service' );
}
push @{ $self->to }, [ $email, $name ];
diff --git a/perllib/FixMyStreet/SendReport/Open311.pm b/perllib/FixMyStreet/SendReport/Open311.pm
index 93b96ce00..1b79bcc99 100644
--- a/perllib/FixMyStreet/SendReport/Open311.pm
+++ b/perllib/FixMyStreet/SendReport/Open311.pm
@@ -30,8 +30,8 @@ sub send {
my $result = -1;
- foreach my $council ( keys %{ $self->councils } ) {
- my $conf = $self->councils->{$council}->{config};
+ foreach my $body ( @{ $self->bodies } ) {
+ my $conf = $self->body_config->{ $body->id };
my $always_send_latlong = 1;
my $send_notpinpointed = 0;
@@ -39,8 +39,13 @@ sub send {
my $extended_desc = 1;
+ # To rollback temporary changes made by this function
+ my $revert = 0;
+
# Extra bromley fields
- if ( $row->council =~ /2482/ ) {
+ if ( $row->bodies_str == 2482 ) {
+
+ $revert = 1;
my $extra = $row->extra;
if ( $row->used_map || ( !$row->used_map && !$row->postcode ) ) {
@@ -88,7 +93,7 @@ sub send {
# FIXME: we've already looked this up before
my $contact = FixMyStreet::App->model("DB::Contact")->find( {
deleted => 0,
- area_id => $conf->area_id,
+ body_id => $body->id,
category => $row->category
} );
@@ -103,31 +108,32 @@ sub send {
);
# non standard west berks end points
- if ( $row->council =~ /2619/ ) {
+ if ( $row->bodies_str =~ /2619/ ) {
$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' } );
+ $revert = 1;
}
# required to get round issues with CRM constraints
- if ( $row->council =~ /2218/ ) {
+ if ( $row->bodies_str =~ /2218/ ) {
$row->user->name( $row->user->id . ' ' . $row->user->name );
+ $revert = 1;
}
if ($row->cobrand eq 'fixmybarangay') {
# FixMyBarangay endpoints expect external_id as an attribute, as do Oxfordshire
$row->extra( [ { 'name' => 'external_id', 'value' => $row->id } ] );
+ $revert = 1;
}
my $resp = $open311->send_service_request( $row, $h, $contact->email );
# make sure we don't save user changes from above
- if ( $row->council =~ /(2218|2482|$COUNCIL_ID_OXFORDSHIRE)/ || $row->cobrand eq 'fixmybarangay') {
- $row->discard_changes();
- }
+ $row->discard_changes() if $revert;
if ( $resp ) {
$row->external_id( $resp );
@@ -150,7 +156,7 @@ sub send {
} else {
$result *= 1;
# temporary fix to resolve some issues with west berks
- if ( $row->council =~ /2619/ ) {
+ if ( $row->bodies_str =~ /2619/ ) {
$result *= 0;
}
}
diff --git a/perllib/FixMyStreet/SendReport/Zurich.pm b/perllib/FixMyStreet/SendReport/Zurich.pm
new file mode 100644
index 000000000..e0c95283e
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport/Zurich.pm
@@ -0,0 +1,58 @@
+package FixMyStreet::SendReport::Zurich;
+
+use Moose;
+
+BEGIN { extends 'FixMyStreet::SendReport::Email'; }
+
+sub build_recipient_list {
+ my ( $self, $row, $h ) = @_;
+
+ # Only one body ever, most of the time with an email endpoint
+ my $body = @{ $self->bodies }[0];
+ $body = FixMyStreet::App->model("DB::Body")->find( { id => $row->external_body } )
+ if $row->external_body;
+ my $body_email = $body->endpoint;
+
+ my @bodies = $body->bodies;
+ if ($body->parent && @bodies) {
+ # Division, might have an individual contact email address
+ my $contact = FixMyStreet::App->model("DB::Contact")->find( {
+ body_id => $body->id,
+ category => $row->category
+ } );
+ $body_email = $contact->email if $contact && $contact->email;
+ }
+
+ push @{ $self->to }, [ $body_email, $body->name ];
+ return $body_email;
+}
+
+sub get_template {
+ my ( $self, $row ) = @_;
+
+ my $template;
+ if ( $row->state eq 'unconfirmed' || $row->state eq 'confirmed' ) {
+ $template = 'submit.txt';
+ } elsif ( $row->state eq 'in progress' ) {
+ $template = 'submit-in-progress.txt';
+ } elsif ( $row->state eq 'planned' ) {
+ $template = 'submit-feedback-pending.txt';
+ } elsif ( $row->state eq 'closed' ) {
+ $template = 'submit-external.txt';
+ if ( $row->extra->{third_personal} ) {
+ $template = 'submit-external-personal.txt';
+ }
+ }
+
+ my $template_path = FixMyStreet->path_to( "templates", "email", "zurich", $template )->stringify;
+ $template = Utils::read_file( $template_path );
+ return $template;
+}
+
+# Zurich emails come from the site itself
+sub send_from {
+ my ( $self, $row ) = @_;
+ return [ FixMyStreet->config('CONTACT_EMAIL'), FixMyStreet->config('CONTACT_NAME') ];
+}
+
+1;
diff --git a/perllib/FixMyStreet/TestMech.pm b/perllib/FixMyStreet/TestMech.pm
index 7f81c0fc2..addbb1752 100644
--- a/perllib/FixMyStreet/TestMech.pm
+++ b/perllib/FixMyStreet/TestMech.pm
@@ -519,11 +519,11 @@ sub get_ok_json {
return decode_json( $res->content );
}
-sub delete_problems_for_council {
+sub delete_problems_for_body {
my $mech = shift;
- my $council = shift;
+ my $body = shift;
- my $reports = FixMyStreet::App->model('DB::Problem')->search( { council => $council } );
+ my $reports = FixMyStreet::App->model('DB::Problem')->search( { bodies_str => $body } );
if ( $reports ) {
for my $r ( $reports->all ) {
$r->comments->delete;
@@ -532,8 +532,26 @@ sub delete_problems_for_council {
}
}
-sub create_problems_for_council {
- my ( $mech, $count, $council, $title, $params ) = @_;
+sub create_body_ok {
+ my $self = shift;
+ my ( $id, $name ) = @_;
+
+ my $params = { id => $id, name => $name };
+ my $body = FixMyStreet::App->model('DB::Body')->find_or_create($params);
+ $body->update($params); # Make sure
+ ok $body, "found/created user for $id $name";
+
+ FixMyStreet::App->model('DB::BodyArea')->find_or_create({
+ area_id => $id,
+ body_id => $id,
+ });
+
+ return $body;
+
+}
+
+sub create_problems_for_body {
+ my ( $mech, $count, $body, $title, $params ) = @_;
my $dt = $params->{dt} || DateTime->now();
@@ -549,11 +567,11 @@ sub create_problems_for_council {
while ($count) {
my $default_params = {
postcode => 'SW1A 1AA',
- council => $council,
+ bodies_str => $body,
areas => ',105255,11806,11828,2247,2504,',
category => 'Other',
- title => "$title Test $count for $council",
- detail => "$title Test $count for $council Detail",
+ title => "$title Test $count for $body",
+ detail => "$title Test $count for $body Detail",
used_map => 't',
name => 'Test User',
anonymous => 'f',