aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/App/Controller
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet/App/Controller')
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm646
-rw-r--r--perllib/FixMyStreet/App/Controller/Alert.pm6
-rw-r--r--perllib/FixMyStreet/App/Controller/Around.pm81
-rw-r--r--perllib/FixMyStreet/App/Controller/Auth.pm9
-rw-r--r--perllib/FixMyStreet/App/Controller/Contact.pm16
-rw-r--r--perllib/FixMyStreet/App/Controller/Council.pm55
-rw-r--r--perllib/FixMyStreet/App/Controller/Dashboard.pm158
-rwxr-xr-xperllib/FixMyStreet/App/Controller/FakeMapit.pm4
-rwxr-xr-xperllib/FixMyStreet/App/Controller/JS.pm4
-rw-r--r--perllib/FixMyStreet/App/Controller/JSON.pm27
-rw-r--r--perllib/FixMyStreet/App/Controller/Location.pm6
-rw-r--r--perllib/FixMyStreet/App/Controller/My.pm3
-rw-r--r--perllib/FixMyStreet/App/Controller/Open311.pm46
-rw-r--r--perllib/FixMyStreet/App/Controller/Photo.pm23
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm49
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm180
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/Update.pm36
-rw-r--r--perllib/FixMyStreet/App/Controller/Reports.pm387
-rwxr-xr-xperllib/FixMyStreet/App/Controller/Rss.pm13
-rwxr-xr-xperllib/FixMyStreet/App/Controller/Static.pm9
-rw-r--r--perllib/FixMyStreet/App/Controller/Tokens.pm27
21 files changed, 1154 insertions, 631 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm
index 7a2790b31..cfe165f43 100644
--- a/perllib/FixMyStreet/App/Controller/Admin.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin.pm
@@ -4,10 +4,13 @@ use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller'; }
+use Path::Class;
use POSIX qw(strftime strcoll);
-use Digest::MD5 qw(md5_hex);
+use Digest::SHA qw(sha1_hex);
use mySociety::EmailUtil qw(is_valid_email);
use if !$ENV{TRAVIS}, 'Image::Magick';
+use DateTime::Format::Strptime;
+
use FixMyStreet::SendReport;
@@ -23,23 +26,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 +66,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();
@@ -65,11 +79,9 @@ sub index : Path : Args(0) {
%prob_counts =
map { $_ => $prob_counts{$_} || 0 }
- ('confirmed', 'investigating', 'in progress', 'closed', 'fixed - council',
- 'fixed - user', 'fixed', 'unconfirmed', 'hidden',
- 'partial', 'planned');
+ ( FixMyStreet::DB::Result::Problem->all_states() );
$c->stash->{problems} = \%prob_counts;
- $c->stash->{total_problems_live} += $prob_counts{$_}
+ $c->stash->{total_problems_live} += $prob_counts{$_} ? $prob_counts{$_} : 0
for ( FixMyStreet::DB::Result::Problem->visible_states() );
$c->stash->{total_problems_users} = $c->cobrand->problems->unique_users;
@@ -120,13 +132,23 @@ sub index : Path : Args(0) {
$c->stash->{categories} = $c->cobrand->problems->categories_summary();
+ $c->stash->{total_bodies} = $c->model('DB::Body')->count();
+
return 1;
}
-sub timeline : Path( 'timeline' ) : Args(0) {
+sub config_page : Path( 'config' ) : Args(0) {
my ($self, $c) = @_;
+ my $dir = $c->stash->{additional_template_paths}->[0];
+ my $git_version = `cd $dir && git describe --tags`;
+ chomp $git_version;
+ $c->stash(
+ git_version => $git_version,
+ );
+}
- $c->forward('check_page_allowed');
+sub timeline : Path( 'timeline' ) : Args(0) {
+ my ($self, $c) = @_;
my $site_restriction = $c->cobrand->site_restriction();
my %time;
@@ -137,34 +159,34 @@ sub timeline : Path( 'timeline' ) : Args(0) {
my $probs = $c->cobrand->problems->timeline;
foreach ($probs->all) {
- push @{$time{$_->created->epoch}}, { type => 'problemCreated', date => $_->created_local, obj => $_ };
- push @{$time{$_->confirmed->epoch}}, { type => 'problemConfirmed', date => $_->confirmed_local, obj => $_ } if $_->confirmed;
- push @{$time{$_->whensent->epoch}}, { type => 'problemSent', date => $_->whensent_local, obj => $_ } if $_->whensent;
+ push @{$time{$_->created->epoch}}, { type => 'problemCreated', date => $_->created, obj => $_ };
+ push @{$time{$_->confirmed->epoch}}, { type => 'problemConfirmed', date => $_->confirmed, obj => $_ } if $_->confirmed;
+ push @{$time{$_->whensent->epoch}}, { type => 'problemSent', date => $_->whensent, obj => $_ } if $_->whensent;
}
my $questionnaires = $c->model('DB::Questionnaire')->timeline( $c->cobrand->restriction );
foreach ($questionnaires->all) {
- push @{$time{$_->whensent->epoch}}, { type => 'quesSent', date => $_->whensent_local, obj => $_ };
- push @{$time{$_->whenanswered->epoch}}, { type => 'quesAnswered', date => $_->whenanswered_local, obj => $_ } if $_->whenanswered;
+ push @{$time{$_->whensent->epoch}}, { type => 'quesSent', date => $_->whensent, obj => $_ };
+ push @{$time{$_->whenanswered->epoch}}, { type => 'quesAnswered', date => $_->whenanswered, obj => $_ } if $_->whenanswered;
}
my $updates = $c->model('DB::Comment')->timeline( $site_restriction );
foreach ($updates->all) {
- push @{$time{$_->created->epoch}}, { type => 'update', date => $_->created_local, obj => $_} ;
+ push @{$time{$_->created->epoch}}, { type => 'update', date => $_->created, obj => $_} ;
}
my $alerts = $c->model('DB::Alert')->timeline_created( $c->cobrand->restriction );
foreach ($alerts->all) {
- push @{$time{$_->whensubscribed->epoch}}, { type => 'alertSub', date => $_->whensubscribed_local, obj => $_ };
+ push @{$time{$_->whensubscribed->epoch}}, { type => 'alertSub', date => $_->whensubscribed, obj => $_ };
}
$alerts = $c->model('DB::Alert')->timeline_disabled( $c->cobrand->restriction );
foreach ($alerts->all) {
- push @{$time{$_->whendisabled->epoch}}, { type => 'alertDel', date => $_->whendisabled_local, obj => $_ };
+ push @{$time{$_->whendisabled->epoch}}, { type => 'alertDel', date => $_->whendisabled, obj => $_ };
}
$c->model('DB')->schema->storage->sql_maker->quote_char( '' );
@@ -177,8 +199,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' ],
@@ -209,10 +229,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,
@@ -226,54 +246,78 @@ 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_for_super_user');
+ $c->forward('check_token');
+
+ 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');
+ }
- 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->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 @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;
+ my %council_info = map { $_->{body_id} => $_ } $contacts->all;
- $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;
+ my $whitelist = $c->config->{MAPIT_ID_WHITELIST};
- my $posted = $c->req->param('posted') || '';
- $c->stash->{area_id} = $area_id;
+ if ( $whitelist && ref $whitelist eq 'ARRAY' && @$whitelist ) {
+ $areas = mySociety::MaPit::call('areas', $whitelist);
+ } else {
+ $areas = mySociety::MaPit::call('areas', $c->cobrand->area_types);
+ }
+ $c->stash->{areas} = [ sort { strcoll($a->{name}, $b->{name}) } values %$areas ];
+
+ 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( 'check_for_super_user' );
$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');
}
@@ -283,11 +327,18 @@ sub council_contacts : Path('council_contacts') : Args(1) {
return 1;
}
+sub check_for_super_user : Private {
+ my ( $self, $c ) = @_;
+ if ( $c->cobrand->moniker eq 'zurich' && $c->stash->{admin_type} ne 'super' ) {
+ $c->detach('/page_error_404_not_found', []);
+ }
+}
+
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');
@@ -299,7 +350,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,
}
);
@@ -333,7 +384,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 },
}
);
@@ -348,67 +399,53 @@ sub update_contacts : Private {
);
$c->stash->{updated} = _('Values updated');
- } elsif ( $posted eq 'open311' ) {
+ } elsif ( $posted eq 'body' ) {
+ $c->forward('check_for_super_user');
$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 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->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->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 deleted/;
+ 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,
+ deleted => 0,
);
+ 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;
+ $c->stash->{live_contacts} = $contacts->search({ deleted => 0 });
if ( $c->req->param('text') && $c->req->param('text') == 1 ) {
$c->stash->{template} = 'admin/council_contacts.txt';
@@ -419,59 +456,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 +510,30 @@ 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');
+ my $query = {};
+ if ( $c->cobrand->moniker eq 'zurich' ) {
+ my $type = $c->stash->{admin_type};
+ my $body = $c->stash->{body};
+ if ( $type eq 'dm' ) {
+ my @children = map { $_->id } $body->bodies->all;
+ my @all = (@children, $body->id);
+ $query = { bodies_str => \@all };
+ } elsif ( $type eq 'sdm' ) {
+ $query = { bodies_str => $body->id };
+ }
+ }
+
+ my $order = $c->req->params->{o} || 'created';
+ my $dir = defined $c->req->params->{d} ? $c->req->params->{d} : 1;
+ $c->stash->{order} = $order;
+ $c->stash->{dir} = $dir;
+ $order .= ' desc' if $dir;
if (my $search = $c->req->param('search')) {
- $c->stash->{searched} = 1;
+ $c->stash->{searched} = $search;
my $site_restriction = $c->cobrand->site_restriction;
@@ -503,37 +550,40 @@ sub search_reports : Path('search_reports') {
$c->model('DB')->schema->storage->sql_maker->quote_char( '"' );
$c->model('DB')->schema->storage->sql_maker->name_sep( '.' );
- my $query;
if (is_valid_email($search)) {
- $query = [
+ $query->{'-or'} = [
'user.email' => { ilike => $like_search },
];
} elsif ($search =~ /^id:(\d+)$/) {
- $query = [
+ $query->{'-or'} = [
'me.id' => int($1),
];
} elsif ($search =~ /^area:(\d+)$/) {
- $query = [
+ $query->{'-or'} = [
'me.areas' => { like => "%,$1,%" }
];
+ } elsif ($search =~ /^ref:(\d+)$/) {
+ $query->{'-or'} = [
+ 'me.external_id' => { like => "%$1%" }
+ ];
} else {
- $query = [
+ $query->{'-or'} = [
'me.id' => $search_n,
'user.email' => { ilike => $like_search },
+ 'me.external_id' => { ilike => $like_search },
'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 },
];
}
+
my $problems = $c->cobrand->problems->search(
- {
- -or => $query,
- },
+ $query,
{
prefetch => 'user',
- order_by => [\"(state='hidden')",'created']
+ order_by => [ \"(state='hidden')", \$order ]
}
);
@@ -542,9 +592,6 @@ 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}});
-
if (is_valid_email($search)) {
$query = [
'user.email' => { ilike => $like_search },
@@ -574,9 +621,9 @@ 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']
+ order_by => [ \"(me.state='hidden')", \"(problem.state='hidden')", 'me.created' ]
}
);
$c->stash->{updates} = [ $updates->all ];
@@ -584,7 +631,20 @@ sub search_reports : Path('search_reports') {
# Switch quoting back off. See above for explanation of this.
$c->model('DB')->schema->storage->sql_maker->quote_char( '' );
+ } else {
+
+ my $page = $c->req->params->{p} || 1;
+ my $problems = $c->cobrand->problems->search(
+ $query,
+ { order_by => $order }
+ )->page( $page );
+ $c->stash->{problems} = [ $problems->all ];
+ $c->stash->{pager} = $problems->pager;
}
+
+ $c->stash->{edit_body_contacts} = 1
+ if ( grep {$_ eq 'body'} keys %{$c->stash->{allowed_pages}});
+
}
sub report_edit : Path('report_edit') : Args(1) {
@@ -592,11 +652,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 +660,34 @@ sub report_edit : Path('report_edit') : Args(1) {
$c->stash->{problem} = $problem;
$c->forward('get_token');
- $c->forward('check_page_allowed');
+
+ if ( $c->cobrand->moniker eq 'zurich' ) {
+ $c->stash->{page} = 'admin';
+ FixMyStreet::Map::display_map(
+ $c,
+ latitude => $problem->latitude,
+ longitude => $problem->longitude,
+ pins => $problem->used_map
+ ? [ {
+ latitude => $problem->latitude,
+ longitude => $problem->longitude,
+ colour => $c->cobrand->pin_colour($problem),
+ type => 'big',
+ } ]
+ : [],
+ );
+ }
+
+ if ( $c->req->param('rotate_photo') ) {
+ $c->forward('rotate_photo');
+ return 1;
+ }
+
+ if ( $c->cobrand->moniker eq 'zurich' ) {
+ my $done = $c->cobrand->admin_report_edit();
+ return if $done;
+ }
+
$c->forward('check_email_for_abuse', [ $problem->user->email ] );
$c->stash->{updates} =
@@ -633,9 +716,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 +744,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 +754,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 );
@@ -687,11 +770,16 @@ sub report_edit : Path('report_edit') : Args(1) {
$problem->user( $user );
}
+ # Deal with photos
if ( $c->req->param('remove_photo') ) {
$problem->photo(undef);
}
- if ( $new_state eq 'confirmed' and $old_state eq 'unconfirmed' ) {
+ if ( $c->req->param('remove_photo') || $new_state eq 'hidden' ) {
+ unlink glob FixMyStreet->path_to( 'web', 'photo', $problem->id . '.*' );
+ }
+
+ if ( $problem->is_visible() and $old_state eq 'unconfirmed' ) {
$problem->confirmed( \'ms_current_timestamp()' );
}
@@ -721,26 +809,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 +846,19 @@ sub search_users: Path('search_users') : Args(0) {
}
}
+ } else {
+ $c->forward('get_token');
+ $c->forward('fetch_all_bodies');
+
+ # Admin users by default
+ my $users = $c->model('DB::User')->search(
+ { from_body => { '!=', undef } },
+ { order_by => 'name' }
+ );
+ my @users = $users->all;
+ my %email2user = map { $_->email => $_ } @users;
+ $c->stash->{users} = \@users;
+
}
return 1;
@@ -782,7 +879,6 @@ sub update_edit : Path('update_edit') : Args(1) {
unless $update;
$c->forward('get_token');
- $c->forward('check_page_allowed');
$c->stash->{update} = $update;
@@ -821,10 +917,14 @@ sub update_edit : Path('update_edit') : Args(1) {
$update->photo(undef);
}
+ if ( $c->req->param('remove_photo') || $new_state eq 'hidden' ) {
+ unlink glob FixMyStreet->path_to( 'web', 'photo', 'c', $update->id . '.*' );
+ }
+
$update->name( $c->req->param('name') || '' );
$update->text( $c->req->param('text') );
$update->anonymous( $c->req->param('anonymous') );
- $update->state( $c->req->param('state') );
+ $update->state( $new_state );
if ( $c->req->param('email') ne $update->user->email ) {
my $user =
@@ -837,6 +937,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 +973,51 @@ 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');
+
+ if ( $c->cobrand->moniker eq 'zurich' and $c->req->param('email') eq '' ) {
+ $c->stash->{field_errors}->{email} = _('Please enter a valid email');
+ return 1;
+ }
+
+ return unless $c->req->param('name') && $c->req->param('email');
+
+ 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,14 +1026,21 @@ 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 );
+
+ if ( $c->cobrand->moniker eq 'zurich' and $user->email eq '' ) {
+ $c->stash->{field_errors}->{email} = _('Please enter a valid email');
+ return 1;
+ }
$user->update;
if ($edited) {
@@ -907,11 +1054,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
@@ -919,8 +1064,20 @@ sub list_flagged : Path('list_flagged') : Args(0) {
$c->stash->{problems} = [ $problems->all ];
my $users = $c->model('DB::User')->search( { flagged => 1 } );
+ my @users = $users->all;
+ my %email2user = map { $_->email => $_ } @users;
+ $c->stash->{users} = [ @users ];
- $c->stash->{users} = $users;
+ my @abuser_emails = $c->model('DB::Abuse')->all();
+
+ foreach my $email (@abuser_emails) {
+ # Slight abuse of the boolean flagged value
+ if ($email2user{$email->email}) {
+ $email2user{$email->email}->flagged( 2 );
+ } else {
+ push @{$c->stash->{users}}, { email => $email->email, flagged => 2 };
+ }
+ }
return 1;
}
@@ -928,37 +1085,24 @@ 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' ) {
+ if ( $c->cobrand->moniker eq 'seesomething' || $c->cobrand->moniker eq 'zurich' ) {
return $c->cobrand->admin_stats();
}
if ( $c->req->param('getcounts') ) {
my ( $start_date, $end_date, @errors );
+ my $parser = DateTime::Format::Strptime->new( pattern => '%d/%m/%Y' );
- eval {
- $start_date = DateTime->new(
- year => $c->req->param('start_date_year'),
- month => $c->req->param('start_date_month'),
- day => $c->req->param('start_date_day'),
- );
- };
+ $start_date = $parser-> parse_datetime ( $c->req->param('start_date') );
- push @errors, _('Invalid start date') if $@;
+ push @errors, _('Invalid start date') unless defined $start_date;
- eval {
- $end_date = DateTime->new(
- year => $c->req->param('end_date_year'),
- month => $c->req->param('end_date_month'),
- day => $c->req->param('end_date_day'),
- );
- };
+ $end_date = $parser-> parse_datetime ( $c->req->param('end_date') ) ;
- push @errors, _('Invalid end date') if $@;
+ push @errors, _('Invalid end date') unless defined $end_date;
$c->stash->{errors} = \@errors;
$c->stash->{start_date} = $start_date;
@@ -970,11 +1114,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 +1153,7 @@ sub stats : Path('stats') : Args(0) {
$field => { '>=', $start_date},
$field => { '<=', $end_date + $one_day },
],
- %council,
+ %body,
%dates,
},
\%select,
@@ -1038,16 +1182,17 @@ 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],
+ 'config' => [ undef, undef ],
'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 +1207,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 +1227,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 +1255,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 +1263,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 +1383,36 @@ sub rotate_photo : Private {
my ( $self, $c ) =@_;
my $direction = $c->req->param('rotate_photo');
+ return unless $direction eq _('Rotate Left') or $direction eq _('Rotate Right');
- 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 ) {
- $c->stash->{rotated} = 1;
- $c->stash->{problem}->photo( $photo );
- $c->stash->{problem}->update();
+ # If photo field contains a hash
+ if ( length($photo) == 40 ) {
+ $file = file( $c->config->{UPLOAD_DIR}, "$photo.jpeg" );
+ $photo = $file->slurp;
}
+ $photo = _rotate_image( $photo, $direction eq _('Rotate Left') ? -90 : 90 );
+ return unless $photo;
+
+ # Write out to new location
+ my $fileid = sha1_hex($photo);
+ $file = file( $c->config->{UPLOAD_DIR}, "$fileid.jpeg" );
+
+ my $fh = $file->open('w');
+ print $fh $photo;
+ close $fh;
+
+ unlink glob FixMyStreet->path_to( 'web', 'photo', $c->stash->{problem}->id . '.*' );
+
+ $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 +1436,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..41e0ad947 100644
--- a/perllib/FixMyStreet/App/Controller/Around.pm
+++ b/perllib/FixMyStreet/App/Controller/Around.pm
@@ -40,11 +40,12 @@ sub around_index : Path : Args(0) {
my $partial_report = $c->forward('load_partial');
# Try to create a location for whatever we have
- return
- unless $c->forward('/location/determine_location_from_coords')
- || $c->forward('/location/determine_location_from_pc');
+ my $ret = $c->forward('/location/determine_location_from_coords')
+ || $c->forward('/location/determine_location_from_pc');
+ return unless $ret;
+ return $c->res->redirect('/') if $ret == -1 && !$partial_report;
- # 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 +193,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 +213,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 +221,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 +282,66 @@ 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, @locations);
+
+ if ( $lat && $long ) {
+ $response = { latitude => $lat, longitude => $long };
+ } else {
+ if ( ref($suggestions) eq 'ARRAY' ) {
+ foreach (@$suggestions) {
+ push @addresses, decode_utf8($_->{address});
+ push @locations, { address => decode_utf8($_->{address}), lat => $_->{latitude}, long => $_->{longitude} };
+ }
+ $response = { suggestions => \@addresses, locations => \@locations };
+ } 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..5a4243fbf 100644
--- a/perllib/FixMyStreet/App/Controller/Auth.pm
+++ b/perllib/FixMyStreet/App/Controller/Auth.pm
@@ -157,11 +157,8 @@ sub token : Path('/M') : Args(1) {
# Sign out in case we are another user
$c->logout();
- # get the email and scrap the token
- my $data = $token_obj->data;
- $token_obj->delete;
-
# find or create the user related to the token.
+ my $data = $token_obj->data;
my $user = $c->model('DB::User')->find_or_create( { email => $data->{email} } );
$user->name( $data->{name} ) if $data->{name};
$user->password( $data->{password}, 1 ) if $data->{password};
@@ -182,6 +179,10 @@ Used after signing in to take the person back to where they were.
sub redirect_on_signin : Private {
my ( $self, $c, $redirect ) = @_;
$redirect = 'my' unless $redirect;
+ if ( $c->cobrand->moniker eq 'zurich' ) {
+ $redirect = 'my' if $redirect eq 'admin';
+ $redirect = 'admin' if $c->user->from_body;
+ }
$c->res->redirect( $c->uri_for( "/$redirect" ) );
}
diff --git a/perllib/FixMyStreet/App/Controller/Contact.pm b/perllib/FixMyStreet/App/Controller/Contact.pm
index 926a3f2a5..6bc6e90ef 100644
--- a/perllib/FixMyStreet/App/Controller/Contact.pm
+++ b/perllib/FixMyStreet/App/Controller/Contact.pm
@@ -108,11 +108,19 @@ sub validate : Private {
if !mySociety::EmailUtil::is_valid_email( $c->req->param('em') );
}
+ %field_errors = (
+ %field_errors,
+ $c->cobrand->extra_contact_validation($c)
+ );
+
push @errors, _('Illegal ID')
if $c->req->param('id') && $c->req->param('id') !~ /^[1-9]\d*$/
or $c->req->param('update_id')
&& $c->req->param('update_id') !~ /^[1-9]\d*$/;
+ push @errors, _('There was a problem showing this page. Please try again later.')
+ if $c->req->params->{message} && $c->req->params->{message} =~ /\[url=|<a/;
+
unshift @errors,
_('There were problems with your report. Please see below.')
if scalar keys %field_errors;
@@ -146,7 +154,7 @@ sub prepare_params_for_email : Private {
my $problem_url = $base_url . '/report/' . $c->stash->{update}->problem_id
. '#update_' . $c->stash->{update}->id;
- my $admin_url = " - $admin_url" . 'update_edit/' . $c->stash->{update}->id
+ my $admin_url = " - $admin_url" . '/update_edit/' . $c->stash->{update}->id
if $admin_url;
$c->stash->{message} .= sprintf(
" \n\n[ Complaint about update %d on report %d - %s%s ]",
@@ -158,7 +166,7 @@ sub prepare_params_for_email : Private {
elsif ( $c->stash->{problem} ) {
my $problem_url = $base_url . '/report/' . $c->stash->{problem}->id;
- $admin_url = " - $admin_url" . 'report_edit/' . $c->stash->{problem}->id
+ $admin_url = " - $admin_url" . '/report_edit/' . $c->stash->{problem}->id
if $admin_url;
$c->stash->{message} .= sprintf(
" \n\n[ Complaint about report %d - %s%s ]",
@@ -184,7 +192,7 @@ generally required to stash
sub setup_request : Private {
my ( $self, $c ) = @_;
- $c->stash->{contact_email} = $c->cobrand->contact_email( 'contact' );
+ $c->stash->{contact_email} = $c->cobrand->contact_email;
$c->stash->{contact_email} =~ s/\@/&#64;/;
for my $param (qw/em subject message/) {
@@ -206,7 +214,7 @@ Sends the email
sub send_email : Private {
my ( $self, $c ) = @_;
- my $recipient = $c->cobrand->contact_email( 'contact' );
+ my $recipient = $c->cobrand->contact_email;
my $recipient_name = $c->cobrand->contact_name();
$c->stash->{host} = $c->req->header('HOST');
diff --git a/perllib/FixMyStreet/App/Controller/Council.pm b/perllib/FixMyStreet/App/Controller/Council.pm
index cb9e78421..ceec04027 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,52 @@ 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_mapit_error} = 1;
+ $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_cobrand_check} = 1;
$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_no_areas} = 1;
$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 a5ba8ff07..25c6e1923 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} . ',%' }
@@ -118,16 +121,23 @@ sub index : Path : Args(0) {
if $c->stash->{category};
$c->stash->{where} = \%where;
my $prob_where = { %where };
- $prob_where->{state} = $prob_where->{'problem.state'};
+ $prob_where->{'me.state'} = $prob_where->{'problem.state'};
delete $prob_where->{'problem.state'};
$c->stash->{prob_where} = $prob_where;
+ my $dtf = $c->model('DB')->storage->datetime_parser;
+
my %counts;
- my $t = DateTime->today;
- $counts{wtd} = $c->forward( 'updates_search', [ $t->subtract( days => $t->dow - 1 ) ] );
- $counts{week} = $c->forward( 'updates_search', [ DateTime->now->subtract( weeks => 1 ) ] );
- $counts{weeks} = $c->forward( 'updates_search', [ DateTime->now->subtract( weeks => 4 ) ] );
- $counts{ytd} = $c->forward( 'updates_search', [ DateTime->today->set( day => 1, month => 1 ) ] );
+ my $now = DateTime->now( time_zone => 'local' );
+ my $t = $now->clone->truncate( to => 'day' );
+ $counts{wtd} = $c->forward( 'updates_search',
+ [ $dtf->format_datetime( $t->clone->subtract( days => $t->dow - 1 ) ) ] );
+ $counts{week} = $c->forward( 'updates_search',
+ [ $dtf->format_datetime( $now->clone->subtract( weeks => 1 ) ) ] );
+ $counts{weeks} = $c->forward( 'updates_search',
+ [ $dtf->format_datetime( $now->clone->subtract( weeks => 4 ) ) ] );
+ $counts{ytd} = $c->forward( 'updates_search',
+ [ $dtf->format_datetime( $t->clone->set( day => 1, month => 1 ) ) ] );
$c->stash->{problems} = \%counts;
@@ -135,26 +145,126 @@ sub index : Path : Args(0) {
$c->stash->{q_state} = $c->req->param('state') || '';
if ( $c->stash->{q_state} eq 'fixed' ) {
- $prob_where->{state} = [ FixMyStreet::DB::Result::Problem->fixed_states() ];
+ $prob_where->{'me.state'} = [ FixMyStreet::DB::Result::Problem->fixed_states() ];
} elsif ( $c->stash->{q_state} ) {
- $prob_where->{state} = $c->stash->{q_state};
+ $prob_where->{'me.state'} = $c->stash->{q_state};
+ $prob_where->{'me.state'} = { IN => [ 'planned', 'action scheduled' ] }
+ if $prob_where->{'me.state'} eq 'action scheduled';
}
my $params = {
%$prob_where,
- 'me.confirmed' => { '>=', DateTime->now->subtract( days => 30 ) },
+ 'me.confirmed' => { '>=', $dtf->format_datetime( $now->clone->subtract( days => 30 ) ) },
};
- my @problems = $c->cobrand->problems->search( $params )->all;
+ my $problems_rs = $c->cobrand->problems->search( $params );
+ my @problems = $problems_rs->all;
+
my %problems;
foreach (@problems) {
- if ($_->confirmed >= DateTime->now->subtract(days => 7)) {
+ if ($_->confirmed >= $now->clone->subtract(days => 7)) {
push @{$problems{1}}, $_;
- } elsif ($_->confirmed >= DateTime->now->subtract(days => 14)) {
+ } elsif ($_->confirmed >= $now->clone->subtract(days => 14)) {
push @{$problems{2}}, $_;
} else {
push @{$problems{3}}, $_;
}
}
$c->stash->{lists} = \%problems;
+
+ if ( $c->req->params->{export} ) {
+ $self->export_as_csv($c, $problems_rs, $body);
+ }
+}
+
+sub export_as_csv {
+ my ($self, $c, $problems_rs, $body) = @_;
+ require Text::CSV;
+ my $problems = $problems_rs->search(
+ {}, { prefetch => 'comments' });
+
+ my $filename = do {
+ my %where = (
+ body => $body->id,
+ category => $c->stash->{category},
+ state => $c->stash->{q_state},
+ ward => $c->stash->{ward},
+ );
+ join '-',
+ $c->req->uri->host,
+ map {
+ my $value = $where{$_};
+ (defined $value and length $value) ? ($_, $value) : ()
+ } sort keys %where };
+
+ my $csv = Text::CSV->new({ binary => 1, eol => "\n" });
+ $csv->combine(
+ 'Report ID',
+ 'Title',
+ 'Detail',
+ 'User Name',
+ 'Category',
+ 'Created',
+ 'Confirmed',
+ 'Acknowledged',
+ 'Fixed',
+ 'Closed',
+ 'Status',
+ 'Latitude', 'Longitude',
+ 'Nearest Postcode',
+ 'Report URL',
+ );
+ my @body = ($csv->string);
+
+ my $fixed_states = FixMyStreet::DB::Result::Problem->fixed_states;
+ my $closed_states = FixMyStreet::DB::Result::Problem->closed_states;
+
+ while ( my $report = $problems->next ) {
+ my $external_body;
+ my $body_name = "";
+ if ( $external_body = $report->body($c) ) {
+ # seems to be a zurich specific thing
+ $body_name = $external_body->name if ref $external_body;
+ }
+ my $hashref = $report->as_hashref($c);
+
+ $hashref->{user_name_display} = $report->anonymous?
+ '(anonymous)' : $report->user->name;
+
+ for my $comment ($report->comments) {
+ my $problem_state = $comment->problem_state or next;
+ next if $problem_state eq 'confirmed';
+ $hashref->{acknowledged_pp} //= $c->cobrand->prettify_dt( $comment->created );
+ $hashref->{fixed_pp} //= $fixed_states->{ $problem_state } ?
+ $c->cobrand->prettify_dt( $comment->created ): undef;
+ if ($closed_states->{ $problem_state }) {
+ $hashref->{closed_pp} = $c->cobrand->prettify_dt( $comment->created );
+ last;
+ }
+ }
+
+ $csv->combine(
+ @{$hashref}{
+ 'id',
+ 'title',
+ 'detail',
+ 'user_name_display',
+ 'category',
+ 'created_pp',
+ 'confirmed_pp',
+ 'acknowledged_pp',
+ 'fixed_pp',
+ 'closed_pp',
+ 'state',
+ 'latitude', 'longitude',
+ 'postcode',
+ },
+ (join '', $c->cobrand->base_url_for_report($report), $report->url),
+ );
+
+ push @body, $csv->string;
+ }
+ $c->res->content_type('text/csv; charset=utf-8');
+ $c->res->header('content-disposition' => "attachment; filename=${filename}.csv");
+ $c->res->body( join "", @body );
}
sub updates_search : Private {
@@ -181,11 +291,13 @@ sub updates_search : Private {
map { $_ => $counts{$_} || 0 }
('confirmed', 'investigating', 'in progress', 'closed', 'fixed - council',
'fixed - user', 'fixed', 'unconfirmed', 'hidden',
- 'partial', 'planned');
+ 'partial', 'action scheduled', 'planned');
+
+ $counts{'action scheduled'} += $counts{planned} || 0;
for my $vars (
[ 'time_to_fix', 'fixed - council' ],
- [ 'time_to_mark', 'in progress', 'planned', 'investigating', 'closed' ],
+ [ 'time_to_mark', 'in progress', 'action scheduled', 'investigating', 'closed' ],
) {
my $col = shift @$vars;
my $substmt = "select min(id) from comment where me.problem_id=comment.problem_id and problem_state in ('"
diff --git a/perllib/FixMyStreet/App/Controller/FakeMapit.pm b/perllib/FixMyStreet/App/Controller/FakeMapit.pm
index bc46df712..253c75ba4 100755
--- a/perllib/FixMyStreet/App/Controller/FakeMapit.pm
+++ b/perllib/FixMyStreet/App/Controller/FakeMapit.pm
@@ -12,13 +12,13 @@ FixMyStreet::App::Controller::FakeMapit - Catalyst Controller
A controller to fake mapit when we don't have it. If you set MAPIT_URL to
.../fakemapit/ it should all just work, with a mapit that assumes the whole
-world is one area, with ID 161 and name "Default Area".
+world is one area, with ID 161 and name "Everywhere".
=head1 METHODS
=cut
-my $area = { "name" => "Default Area", "type" => "ZZZ", "id" => 161 };
+my $area = { "name" => "Everywhere", "type" => "ZZZ", "id" => 161 };
sub output : Private {
my ( $self, $c, $data ) = @_;
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..17507a84b 100644
--- a/perllib/FixMyStreet/App/Controller/JSON.pm
+++ b/perllib/FixMyStreet/App/Controller/JSON.pm
@@ -8,6 +8,7 @@ use JSON;
use DateTime;
use DateTime::Format::ISO8601;
use List::MoreUtils 'uniq';
+use FixMyStreet::App;
=head1 NAME
@@ -80,11 +81,13 @@ sub problems : Local {
$date_col = 'lastupdate';
}
+ my $dt_parser = FixMyStreet::App->model('DB')->schema->storage->datetime_parser;
+
my $one_day = DateTime::Duration->new( days => 1 );
my $query = {
$date_col => {
- '>=' => $start_dt,
- '<=' => $end_dt + $one_day,
+ '>=' => $dt_parser->format_datetime($start_dt),
+ '<=' => $dt_parser->format_datetime($end_dt + $one_day),
},
state => [ @state ],
};
@@ -92,7 +95,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 +103,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/Location.pm b/perllib/FixMyStreet/App/Controller/Location.pm
index e8bf2cd1c..4312b6911 100644
--- a/perllib/FixMyStreet/App/Controller/Location.pm
+++ b/perllib/FixMyStreet/App/Controller/Location.pm
@@ -5,6 +5,7 @@ use namespace::autoclean;
BEGIN {extends 'Catalyst::Controller'; }
use Encode;
+use FixMyStreet::Geocode;
=head1 NAME
@@ -49,6 +50,8 @@ sub determine_location_from_coords : Private {
User has searched for a location - try to find it for them.
+Return -1 if nothing provided.
+
If one match is found returns true and lat/lng is set.
If several possible matches are found puts an array onto stash so that user can be prompted to pick one and returns false.
@@ -61,7 +64,7 @@ sub determine_location_from_pc : Private {
my ( $self, $c, $pc ) = @_;
# check for something to search
- $pc ||= $c->req->param('pc') || return;
+ $pc ||= $c->req->param('pc') || return -1;
$c->stash->{pc} = $pc; # for template
if ( $pc =~ /^(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)$/ ) {
@@ -100,6 +103,7 @@ sub determine_location_from_pc : Private {
}
# pass errors back to the template
+ $c->stash->{location_error_pc_lookup} = 1;
$c->stash->{location_error} = $error;
return;
}
diff --git a/perllib/FixMyStreet/App/Controller/My.pm b/perllib/FixMyStreet/App/Controller/My.pm
index c00264315..bbef1f8d8 100644
--- a/perllib/FixMyStreet/App/Controller/My.pm
+++ b/perllib/FixMyStreet/App/Controller/My.pm
@@ -45,6 +45,7 @@ sub my : Path : Args(0) {
} )->page( $p_page );
while ( my $problem = $rs->next ) {
+ $c->stash->{has_content}++;
push @$pins, {
latitude => $problem->latitude,
longitude => $problem->longitude,
@@ -64,7 +65,9 @@ sub my : Path : Args(0) {
order_by => { -desc => 'confirmed' },
rows => 50
} )->page( $u_page );
+
my @updates = $rs->all;
+ $c->stash->{has_content} += scalar @updates;
$c->stash->{updates} = \@updates;
$c->stash->{updates_pager} = $rs->pager;
diff --git a/perllib/FixMyStreet/App/Controller/Open311.pm b/perllib/FixMyStreet/App/Controller/Open311.pm
index 040b0d3e6..f3841acef 100644
--- a/perllib/FixMyStreet/App/Controller/Open311.pm
+++ b/perllib/FixMyStreet/App/Controller/Open311.pm
@@ -100,7 +100,7 @@ sub error : Private {
sub get_discovery : Private {
my ( $self, $c ) = @_;
- my $contact_email = $c->config->{CONTACT_EMAIL};
+ my $contact_email = $c->cobrand->contact_email;
my $prod_url = 'http://www.fiksgatami.no/open311';
my $test_url = 'http://fiksgatami-dev.nuug.no/open311';
my $prod_changeset = '2011-04-08T00:00:00Z';
@@ -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 =
@@ -248,19 +240,23 @@ sub output_requests : Private {
'long' => [ $problem->longitude ],
'status' => [ $problem->state ],
# 'status_notes' => [ {} ],
- 'requested_datetime' => [ w3date($problem->confirmed_local) ],
- 'updated_datetime' => [ w3date($problem->lastupdate_local) ],
+ 'requested_datetime' => [ w3date($problem->confirmed) ],
+ 'updated_datetime' => [ w3date($problem->lastupdate) ],
# 'expected_datetime' => [ {} ],
# 'address' => [ {} ],
# 'address_id' => [ {} ],
'service_code' => [ $problem->category ],
'service_name' => [ $problem->category ],
# 'service_notice' => [ {} ],
- 'agency_responsible' => $problem->council , # FIXME Not according to Open311 v2
# 'zipcode' => [ {} ],
'interface_used' => [ $problem->service ], # Not in Open311 v2
};
+ if ( $c->cobrand->moniker ne 'zurich' ) { # XXX
+ # FIXME Not according to Open311 v2
+ $request->{agency_responsible} = $problem->bodies;
+ }
+
if ( !$problem->anonymous ) {
# Not in Open311 v2
$request->{'requestor_name'} = [ $problem->name ];
@@ -268,7 +264,7 @@ sub output_requests : Private {
if ( $problem->whensent ) {
# Not in Open311 v2
$request->{'agency_sent_datetime'} =
- [ w3date($problem->whensent_local) ];
+ [ w3date($problem->whensent) ];
}
# Extract number of updates
@@ -280,7 +276,7 @@ sub output_requests : Private {
$request->{'comment_count'} = [ $updates ];
}
- my $display_photos = $c->cobrand->allow_photo_display;
+ my $display_photos = $c->cobrand->allow_photo_display($problem);
if ($display_photos && $problem->photo) {
my $url = $c->cobrand->base_url();
my $imgurl = $url . "/photo/$id.full.jpeg";
@@ -288,12 +284,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', [ {
@@ -311,15 +307,17 @@ sub get_requests : Private {
my $max_requests = $c->req->param('max_requests') || 0;
# Only provide access to the published reports
+ my $states = FixMyStreet::DB::Result::Problem->visible_states();
+ delete $states->{unconfirmed};
my $criteria = {
- state => [ FixMyStreet::DB::Result::Problem->visible_states() ]
+ state => [ keys %$states ]
};
my %rules = (
service_request_id => [ '=', 'id' ],
service_code => [ '=', 'category' ],
status => [ 'IN', 'state' ],
- agency_responsible => [ '~', 'council' ],
+ agency_responsible => [ '~', 'bodies_str' ],
interface_used => [ '=', 'service' ],
has_photo => [ '=', 'photo' ],
);
@@ -411,8 +409,10 @@ sub get_request : Private {
return;
}
+ my $states = FixMyStreet::DB::Result::Problem->visible_states();
+ delete $states->{unconfirmed};
my $criteria = {
- state => [ FixMyStreet::DB::Result::Problem->visible_states() ],
+ state => [ keys %$states ],
id => $id,
};
$c->forward( 'output_requests', [ $criteria ] );
diff --git a/perllib/FixMyStreet/App/Controller/Photo.pm b/perllib/FixMyStreet/App/Controller/Photo.pm
index fa4baf045..09afabecf 100644
--- a/perllib/FixMyStreet/App/Controller/Photo.pm
+++ b/perllib/FixMyStreet/App/Controller/Photo.pm
@@ -5,7 +5,7 @@ use namespace::autoclean;
BEGIN {extends 'Catalyst::Controller'; }
use DateTime::Format::HTTP;
-use Digest::SHA1 qw(sha1_hex);
+use Digest::SHA qw(sha1_hex);
use File::Path;
use File::Slurp;
use Path::Class;
@@ -30,17 +30,19 @@ Display a photo
=cut
-sub during :LocalRegex('^([0-9a-f]{40})\.temp\.jpeg$') {
+sub during :LocalRegex('^([0-9a-f]{40})\.(temp|fulltemp)\.jpeg$') {
my ( $self, $c ) = @_;
- my ( $hash ) = @{ $c->req->captures };
+ my ( $hash, $size ) = @{ $c->req->captures };
my $file = file( $c->config->{UPLOAD_DIR}, "$hash.jpeg" );
my $photo = $file->slurp;
- if ( $c->cobrand->default_photo_resize ) {
- $photo = _shrink( $photo, $c->cobrand->default_photo_resize );
- } else {
- $photo = _shrink( $photo, '250x250' );
+ if ( $size eq 'temp' ) {
+ if ( $c->cobrand->default_photo_resize ) {
+ $photo = _shrink( $photo, $c->cobrand->default_photo_resize );
+ } else {
+ $photo = _shrink( $photo, '250x250' );
+ }
}
$c->forward( 'output', [ $photo ] );
@@ -73,7 +75,9 @@ sub index :LocalRegex('^(c/)?(\d+)(?:\.(full|tn|fp))?\.jpeg$') {
$c->detach( 'no_photo' ) unless @photo;
- my $photo = $photo[0]->photo;
+ my $item = $photo[0];
+ $c->detach( 'no_photo' ) unless $c->cobrand->allow_photo_display($item); # Should only be for reports, not updates
+ my $photo = $item->photo;
# If photo field contains a hash
if (length($photo) == 40) {
@@ -102,10 +106,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..13a347a90 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,25 @@ 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;
+ if ( $c->sessionid && $c->flash->{created_report} ) {
+ $c->stash->{created_report} = $c->flash->{created_report};
+ }
$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(
+ {
+ report => $c->cobrand->problem_as_hashref( $problem, $c ),
+ updates => $c->cobrand->updates_as_hashref( $problem, $c ),
+ }
+ );
+ $c->res->body( $content );
+ return 1;
+ }
+
return 1;
}
@@ -168,7 +202,7 @@ sub generate_map_tags : Private {
? [ {
latitude => $problem->latitude,
longitude => $problem->longitude,
- colour => 'yellow',
+ colour => $c->cobrand->pin_colour($problem, 'report'),
type => 'big',
} ]
: [],
@@ -187,11 +221,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->id};
$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 169c3d152..1e9f83aec 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -4,7 +4,6 @@ use Moose;
use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller'; }
-use FixMyStreet::Geocode;
use Encode;
use List::MoreUtils qw(uniq);
use POSIX 'strcoll';
@@ -90,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');
@@ -120,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');
@@ -148,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 };
}
@@ -181,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');
@@ -190,11 +189,14 @@ sub report_form_ajax : Path('ajax') : Args(0) {
? $c->render_fragment('report/new/extra_name.html')
: '';
+ my $extra_titles_list = $c->cobrand->title_list($c->stash->{all_areas});
+
my $body = JSON->new->utf8(1)->encode(
{
councils_text => $councils_text,
category => $category,
extra_name_info => $extra_name_info,
+ titles_list => $extra_titles_list,
categories => $c->stash->{category_options},
}
);
@@ -217,7 +219,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 ) {
@@ -570,29 +572,35 @@ 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 ], deleted => 0 },
+ { 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
my %non_public_categories =
(); # categories for which the reports are not public
@@ -600,9 +608,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
@@ -615,22 +623,18 @@ sub setup_categories_and_councils : Private {
_('Empty pub or bar'),
_('Empty public building - school, hospital, etc.')
);
- $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->{id} != COUNCIL_ID_BARNET
+ && $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) {
- @local_categories = sort keys %{ Utils::barnet_categories() }
- } else {
- @local_categories = sort keys %{ Utils::london_categories() }
- }
+ @local_categories = sort keys %{ Utils::london_categories() };
@category_options = (
_('-- Pick a category --'),
@local_categories
);
- $category_label = _('Category');
} else {
@@ -640,7 +644,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;
@@ -657,29 +661,34 @@ sub setup_categories_and_councils : Private {
# If there's an Other category present, put it at the bottom
@category_options = ( _('-- Pick a category --'), grep { $_ ne _('Other') } @category_options );
push @category_options, _('Other') if $seen{_('Other')};
- $category_label = _('Category');
}
}
+ if ($c->cobrand->can('hidden_categories')) {
+ my %hidden_categories = map { $_ => 1 }
+ $c->cobrand->hidden_categories;
+
+ @category_options = grep {
+ !$hidden_categories{$_}
+ } @category_options;
+ }
+
# put results onto stash for display
- $c->stash->{area_ids_to_list} = [ keys %area_ids_to_list ];
- $c->stash->{category_label} = $category_label;
+ $c->stash->{bodies} = \%bodies;
+ $c->stash->{all_body_names} = [ map { $_->name } values %bodies ];
+ $c->stash->{all_body_urls} = [ map { $_->external_url } values %bodies ];
+ $c->stash->{bodies_to_list} = [ keys %bodies_to_list ];
$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;
+ $c->stash->{extra_name_info} = $first_area->{id} == COUNCIL_ID_BROMLEY ? 1 : 0;
- my @missing_details_councils =
- grep { !$area_ids_to_list{$_} } #
- keys %$all_councils;
+ my @missing_details_bodies = grep { !$bodies_to_list{$_->id} } values %bodies;
+ my @missing_details_body_names = map { $_->name } @missing_details_bodies;
- my @missing_details_council_names =
- map { $all_councils->{$_}->{name} } #
- @missing_details_councils;
-
- $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
@@ -788,6 +797,7 @@ sub process_report : Private {
'category', #
'subcategory', #
'partial', #
+ 'service', #
);
# load the report
@@ -797,6 +807,7 @@ sub process_report : Private {
$report->postcode( $params{pc} );
$report->latitude( $c->stash->{latitude} );
$report->longitude( $c->stash->{longitude} );
+ $report->send_questionnaire( $c->cobrand->send_questionnaires() );
# set some simple bool values (note they get inverted)
$report->anonymous( $params{may_show_name} ? 0 : 1 );
@@ -812,65 +823,71 @@ sub process_report : Private {
}
$report->detail( $detail );
+ # mobile device type
+ $report->service( $params{service} ) if $params{service};
+
# set these straight from the params
$report->category( _ $params{category} ) if $params{category};
$report->subcategory( $params{subcategory} );
- my $areas = $c->stash->{all_areas};
+ 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 ) {
-
- unless ( exists Utils::barnet_categories()->{ $report->category } ) {
- $c->stash->{field_errors}->{category} = _('Please choose a category');
+ my %extra;
+ $c->cobrand->process_extras( $c, undef, \%extra );
+ if ( %extra ) {
+ $report->extra( \%extra );
}
- $report->council( $first_council->{id} );
-
- } elsif ( $first_council->{id} != COUNCIL_ID_BROMLEY && $first_council->{type} eq 'LBO') {
-
+
+ } elsif ($first_area->{id} != COUNCIL_ID_BROMLEY
+ && $first_area->{id} != COUNCIL_ID_BARNET
+ && $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;
@@ -892,13 +909,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');
@@ -907,7 +924,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 );
}
@@ -936,6 +953,22 @@ sub check_for_errors : Private {
$c->stash->{field_errors} ||= {};
my %field_errors = $c->cobrand->report_check_for_errors( $c );
+ # Zurich, we don't care about title or name
+ # There is no title, and name is optional
+ if ( $c->cobrand->moniker eq 'zurich' ) {
+ delete $field_errors{title};
+ delete $field_errors{name};
+ my $report = $c->stash->{report};
+ $report->title( Utils::cleanup_text( substr($report->detail, 0, 25) ) );
+
+ # We only want to validate the phone number web requests (where the
+ # service parameter is blank) because previous versions of the mobile
+ # apps don't validate the presence of a phone number.
+ if ( ! $c->req->param('phone') and ! $c->req->param('service') ) {
+ $field_errors{phone} = _("This information is required");
+ }
+ }
+
# FIXME: need to check for required bromley fields here
# if they're got the login details wrong when signing in then
@@ -996,8 +1029,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 {
@@ -1022,7 +1057,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+$/) {
@@ -1103,7 +1138,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');
@@ -1113,6 +1148,9 @@ sub redirect_or_confirm_creation : Private {
$report_uri = $c->cobrand->base_url_for_report( $report ) . $report->url;
}
$c->log->info($report->user->id . ' was logged in, redirecting to /report/' . $report->id);
+ if ( $c->sessionid ) {
+ $c->flash->{created_report} = 'loggedin';
+ }
$c->res->redirect($report_uri);
$c->detach;
}
@@ -1128,7 +1166,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 da4cc33ca..bc79cafd3 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,14 +201,29 @@ 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
+ # for use when sending updates to external parties
+ if ( $update->mark_fixed ) {
+ $update->problem_state( 'fixed - user' );
+ } elsif ( $update->mark_open ) {
+ $update->problem_state( 'confirmed' );
+ # if there is not state param and neither of the above conditions apply
+ # then we are not changing the state of the problem so can use the current
+ # problem state
+ } else {
+ my $problem = $c->stash->{problem} || $update->problem;
+ $update->problem_state( $problem->state );
+ }
}
+
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 = ();
@@ -246,10 +261,11 @@ 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');
- $error = 1 unless ( grep { $state eq $_ } ( qw/confirmed closed fixed investigating planned/, 'in progress', 'fixed', 'fixed - user', 'fixed - council' ) );
+ $state = 'fixed - council' if $state eq 'fixed';
+ $error = 1 unless ( grep { $state eq $_ } ( FixMyStreet::DB::Result::Problem->council_states() ) );
if ( $error ) {
$c->stash->{errors} ||= [];
@@ -296,7 +312,14 @@ sub save_update : Private {
my $update = $c->stash->{update};
- if ( !$update->user->in_storage ) {
+ if ( $c->cobrand->never_confirm_updates ) {
+ if ( $update->user->in_storage() ) {
+ $update->user->update();
+ } else {
+ $update->user->insert();
+ }
+ $update->confirm();
+ } elsif ( !$update->user->in_storage ) {
# User does not exist.
# Store changes in token for when token is validated.
$c->stash->{token_data} = {
@@ -354,6 +377,7 @@ sub redirect_or_confirm_creation : Private {
$c->forward( 'signup_for_alerts' );
my $report_uri = $c->cobrand->base_url_for_report( $update->problem ) . $update->problem->url;
+ $c->flash->{comment_created} = 1;
$c->res->redirect($report_uri);
$c->detach;
}
diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm
index ec41dc17f..7e0cccc7b 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,31 @@ 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};
- }
+ if ( my $body = $c->cobrand->all_reports_single_body ) {
+ $c->stash->{body} = $body;
+ $c->detach( 'redirect_body' );
}
- $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,97 +97,165 @@ 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();
my $pins = $c->stash->{pins};
$c->stash->{page} = 'reports'; # So the map knows to make clickable pins
- FixMyStreet::Map::display_map(
- $c,
+ 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},
- pins => $pins,
+ area => $c->stash->{ward} ? $c->stash->{ward}->{id} : [ keys %{$c->stash->{body}->areas} ],
any_zoom => 1,
);
+ if ( $c->cobrand->moniker eq 'emptyhomes' ) {
+ FixMyStreet::Map::display_map(
+ $c, %map_params, latitude => 0, longitude => 0,
+ );
+ } else {
+ FixMyStreet::Map::display_map(
+ $c, %map_params, pins => $pins,
+ );
+ }
$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} ],
+ if ( !$c->stash->{ward} && $c->stash->{body}->id && $c->stash->{body}->body_areas->first ) {
+ 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' );
+ # XXX Currently body/area overlaps here are a bit muddy.
+ # We're checking an area here, but this function is currently doing that.
+ return if $c->cobrand->reports_body_check( $c, $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->detach( 'redirect_index' ) unless $c->stash->{area};
+
+ $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
@@ -198,60 +264,47 @@ 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 ( $c->cobrand->reports_by_body ) {
- my $problem = $c->cobrand->problems->search({ 'lower(me.external_body)' => lc $q_council }, { columns => [ 'external_body' ], rows => 1 })->single;
- if ( $problem ) {
- # If external_body, put as a council with ID 0 for the moment.
- $c->stash->{council} = { id => 0, name => $problem->external_body };
- return;
- }
+ 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' );
}
# 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' );
}
@@ -259,7 +312,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
@@ -270,48 +323,45 @@ 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;
+ $c->detach( 'redirect_body' ) unless $parent_id;
+ $parent_id = $parent_id->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->stash->{body} = $c->stash->{area}
+ unless $c->stash->{body};
+ $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 {
@@ -325,69 +375,54 @@ 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) {
- # 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} },
+ } 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} ) {
- # An external_body entry
- add_row( \%problem, 0, \%problems, \@pins );
+ while ( my $problem = $problems->next ) {
+ $c->log->debug( $problem->cobrand . ', cobrand is ' . $c->cobrand->moniker );
+ if ( !$c->stash->{body} ) {
+ 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
+ my $a = $problem->areas; # Store, as otherwise is looked up every iteration.
+ while ($a =~ /,(\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 );
}
}
}
@@ -406,26 +441,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..ed47f6f87 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;
@@ -271,7 +280,7 @@ sub add_row : Private {
$item{pubDate} = $pubDate if $pubDate;
$item{category} = $row->{category} if $row->{category};
- if ($c->cobrand->allow_photo_display && $row->{photo}) {
+ if ($c->cobrand->allow_photo_display($row) && $row->{photo}) {
my $key = $alert_type->item_table eq 'comment' ? 'c/' : '';
$item{description} .= ent("\n<br><img src=\"". $base_url . "/photo/$key$row->{id}.jpeg\">");
}
diff --git a/perllib/FixMyStreet/App/Controller/Static.pm b/perllib/FixMyStreet/App/Controller/Static.pm
index 723f0f2e1..40e2431ea 100755
--- a/perllib/FixMyStreet/App/Controller/Static.pm
+++ b/perllib/FixMyStreet/App/Controller/Static.pm
@@ -19,7 +19,10 @@ template depending on language, will need extending at some point.
sub about : Global : Args(0) {
my ( $self, $c ) = @_;
- # don't need to do anything here - should just pass through.
+
+ my $lang_code = $c->stash->{lang_code};
+ my $template = "static/about-$lang_code.html";
+ $c->stash->{template} = $template;
}
sub privacy : Global : Args(0) {
@@ -54,6 +57,10 @@ sub iphone : Global : Args(0) {
my ( $self, $c ) = @_;
}
+sub council : Global : Args(0) {
+ my ( $self, $c ) = @_;
+}
+
__PACKAGE__->meta->make_immutable;
1;
diff --git a/perllib/FixMyStreet/App/Controller/Tokens.pm b/perllib/FixMyStreet/App/Controller/Tokens.pm
index 03dc69b00..44cb2429d 100644
--- a/perllib/FixMyStreet/App/Controller/Tokens.pm
+++ b/perllib/FixMyStreet/App/Controller/Tokens.pm
@@ -53,6 +53,25 @@ 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()',
+ } );
+
+ 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(
@@ -83,6 +102,7 @@ sub confirm_problem : Path('/P') {
$c->res->redirect($report_uri);
}
+ $c->stash->{created_report} = 'fromemail';
return 1;
}
@@ -176,7 +196,12 @@ sub confirm_update : Path('/C') {
$c->authenticate( { email => $comment->user->email }, 'no_password' );
$c->set_session_cookie_expire(0);
- $c->forward('/report/update/confirm');
+ if ( $comment->confirmed ) {
+ my $report_uri = $c->cobrand->base_url_for_report( $comment->problem ) . $comment->problem->url;
+ $c->res->redirect($report_uri);
+ } else {
+ $c->forward('/report/update/confirm');
+ }
return 1;
}