aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/App
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet/App')
-rwxr-xr-xperllib/FixMyStreet/App/Controller/About.pm14
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm269
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin/DefectTypes.pm8
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin/ExorDefects.pm199
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin/ReportExtraFields.pm55
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin/ResponsePriorities.pm7
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin/States.pm96
-rw-r--r--perllib/FixMyStreet/App/Controller/Around.pm129
-rw-r--r--perllib/FixMyStreet/App/Controller/Auth.pm22
-rw-r--r--perllib/FixMyStreet/App/Controller/Contact.pm28
-rw-r--r--perllib/FixMyStreet/App/Controller/Dashboard.pm22
-rw-r--r--perllib/FixMyStreet/App/Controller/JSON.pm7
-rw-r--r--perllib/FixMyStreet/App/Controller/Location.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Moderate.pm29
-rw-r--r--perllib/FixMyStreet/App/Controller/My.pm51
-rw-r--r--perllib/FixMyStreet/App/Controller/Open311.pm9
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm164
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm85
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/Update.pm43
-rw-r--r--perllib/FixMyStreet/App/Controller/Reports.pm96
-rw-r--r--perllib/FixMyStreet/App/Controller/Root.pm38
-rwxr-xr-xperllib/FixMyStreet/App/Controller/Rss.pm26
-rw-r--r--perllib/FixMyStreet/App/Model/DB.pm21
-rw-r--r--perllib/FixMyStreet/App/View/Web.pm7
24 files changed, 880 insertions, 547 deletions
diff --git a/perllib/FixMyStreet/App/Controller/About.pm b/perllib/FixMyStreet/App/Controller/About.pm
index 78e548c5f..233da25d3 100755
--- a/perllib/FixMyStreet/App/Controller/About.pm
+++ b/perllib/FixMyStreet/App/Controller/About.pm
@@ -34,22 +34,24 @@ sub index : Path("/about") : Args(0) {
sub find_template : Private {
my ( $self, $c, $page ) = @_;
- return $found{$page} if !FixMyStreet->config('STAGING_SITE') && exists $found{$page};
-
my $lang_code = $c->stash->{lang_code};
+
+ return $found{$lang_code}{$page} if !FixMyStreet->config('STAGING_SITE') &&
+ exists $found{$lang_code}{$page};
+
foreach my $dir_templates (@{$c->stash->{additional_template_paths}}, @{$c->view('Web')->paths}) {
foreach my $dir_static (static_dirs($page, $dir_templates)) {
foreach my $file ("$page-$lang_code.html", "$page.html") {
if (-e "$dir_templates/$dir_static/$file") {
- $found{$page} = "$dir_static/$file";
- return $found{$page};
+ $found{$lang_code}{$page} = "$dir_static/$file";
+ return $found{$lang_code}{$page};
}
}
}
}
# Cache that the page does not exist, so we don't look next time
- $found{$page} = undef;
- return $found{$page};
+ $found{$lang_code}{$page} = undef;
+ return $found{$lang_code}{$page};
}
sub static_dirs {
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm
index 1f3307710..ed40f4565 100644
--- a/perllib/FixMyStreet/App/Controller/Admin.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin.pm
@@ -8,9 +8,10 @@ use Path::Class;
use POSIX qw(strftime strcoll);
use Digest::SHA qw(sha1_hex);
use mySociety::EmailUtil qw(is_valid_email is_valid_email_list);
-use mySociety::ArrayUtils;
use DateTime::Format::Strptime;
use List::Util 'first';
+use List::MoreUtils 'uniq';
+use mySociety::ArrayUtils;
use FixMyStreet::SendReport;
@@ -26,7 +27,7 @@ Admin pages
=cut
-sub begin : Private {
+sub auto : Private {
my ( $self, $c ) = @_;
$c->uri_disposition('relative');
@@ -43,10 +44,6 @@ sub begin : Private {
if ( $c->cobrand->moniker eq 'zurich' ) {
$c->cobrand->admin_type();
}
-}
-
-sub auto : Private {
- my ( $self, $c ) = @_;
$c->forward('check_page_allowed');
}
@@ -97,11 +94,11 @@ sub index : Path : Args(0) {
my $contacts = $c->model('DB::Contact')->summary_count();
my %contact_counts =
- map { $_->confirmed => $_->get_column('confirmed_count') } $contacts->all;
+ map { $_->state => $_->get_column('state_count') } $contacts->all;
- $contact_counts{0} ||= 0;
- $contact_counts{1} ||= 0;
- $contact_counts{total} = $contact_counts{0} + $contact_counts{1};
+ $contact_counts{confirmed} ||= 0;
+ $contact_counts{unconfirmed} ||= 0;
+ $contact_counts{total} = $contact_counts{confirmed} + $contact_counts{unconfirmed};
$c->stash->{contacts} = \%contact_counts;
@@ -243,6 +240,9 @@ sub bodies : Path('bodies') : Args(0) {
$c->stash->{edit_activity} = $edit_activity;
+ $c->forward( 'fetch_languages' );
+ $c->forward( 'fetch_translations' );
+
my $posted = $c->get_param('posted') || '';
if ( $posted eq 'body' ) {
$c->forward('check_for_super_user');
@@ -256,6 +256,9 @@ sub bodies : Path('bodies') : Args(0) {
$c->model('DB::BodyArea')->create( { body => $body, area_id => $_ } );
}
+ $c->stash->{object} = $body;
+ $c->stash->{translation_col} = 'name';
+ $c->forward('update_translations');
$c->stash->{updated} = _('New body added');
}
}
@@ -265,8 +268,8 @@ sub bodies : Path('bodies') : Args(0) {
my $contacts = $c->model('DB::Contact')->search(
undef,
{
- select => [ 'body_id', { count => 'id' }, { count => \'case when deleted then 1 else null end' },
- { count => \'case when confirmed then 1 else null end' } ],
+ select => [ 'body_id', { count => 'id' }, { count => \'case when state = \'deleted\' then 1 else null end' },
+ { count => \'case when state = \'confirmed\' then 1 else null end' } ],
as => [qw/body_id c deleted confirmed/],
group_by => [ 'body_id' ],
result_class => 'DBIx::Class::ResultClass::HashRefInflator'
@@ -299,30 +302,6 @@ sub body_form_dropdowns : Private {
$c->stash->{send_methods} = \@methods;
}
-sub body : Path('body') : Args(1) {
- my ( $self, $c, $body_id ) = @_;
-
- $c->stash->{body_id} = $body_id;
-
- unless ($c->user->has_permission_to('category_edit', $body_id)) {
- $c->forward('check_for_super_user');
- }
-
- $c->forward( '/auth/get_csrf_token' );
- $c->forward( 'lookup_body' );
- $c->forward( 'fetch_all_bodies' );
- $c->forward( 'body_form_dropdowns' );
-
- if ( $c->get_param('posted') ) {
- $c->log->debug( 'posted' );
- $c->forward('update_contacts');
- }
-
- $c->forward('fetch_contacts');
-
- return 1;
-}
-
sub check_for_super_user : Private {
my ( $self, $c ) = @_;
@@ -365,8 +344,7 @@ sub update_contacts : Private {
}
$contact->email( $email );
- $contact->confirmed( $c->get_param('confirmed') ? 1 : 0 );
- $contact->deleted( $c->get_param('deleted') ? 1 : 0 );
+ $contact->state( $c->get_param('state') );
$contact->non_public( $c->get_param('non_public') ? 1 : 0 );
$contact->note( $c->get_param('note') );
$contact->whenedited( \'current_timestamp' );
@@ -393,6 +371,8 @@ sub update_contacts : Private {
$contact->set_extra_metadata( reputation_threshold => int($c->get_param('reputation_threshold')) );
}
+ $c->forward('update_extra_fields', [ $contact ]);
+
if ( %errors ) {
$c->stash->{updated} = _('Please correct the errors below');
$c->stash->{contact} = $contact;
@@ -407,6 +387,12 @@ sub update_contacts : Private {
$contact->insert;
}
+ unless ( %errors ) {
+ $c->stash->{translation_col} = 'category';
+ $c->stash->{object} = $contact;
+ $c->forward('update_translations');
+ }
+
} elsif ( $posted eq 'update' ) {
$c->forward('/auth/check_csrf_token');
@@ -421,7 +407,7 @@ sub update_contacts : Private {
$contacts->update(
{
- confirmed => 1,
+ state => 'confirmed',
whenedited => \'current_timestamp',
note => 'Confirmed',
editor => $editor,
@@ -446,11 +432,43 @@ sub update_contacts : Private {
# Remove any others
$c->stash->{body}->body_areas->search( { area_id => [ keys %current ] } )->delete;
+ $c->stash->{translation_col} = 'name';
+ $c->stash->{object} = $c->stash->{body};
+ $c->forward('update_translations');
+
$c->stash->{updated} = _('Values updated');
}
}
}
+sub update_translations : Private {
+ my ( $self, $c ) = @_;
+
+ foreach my $lang (keys(%{$c->stash->{languages}})) {
+ my $id = $c->get_param('translation_id_' . $lang);
+ my $text = $c->get_param('translation_' . $lang);
+ if ($id) {
+ my $translation = $c->model('DB::Translation')->find(
+ {
+ id => $id,
+ }
+ );
+
+ if ($text) {
+ $translation->msgstr($text);
+ $translation->update;
+ } else {
+ $translation->delete;
+ }
+ } elsif ($text) {
+ my $col = $c->stash->{translation_col};
+ $c->stash->{object}->add_translation_for(
+ $col, $lang, $text
+ );
+ }
+ }
+}
+
sub body_params : Private {
my ( $self, $c ) = @_;
@@ -485,8 +503,8 @@ sub fetch_contacts : Private {
my $contacts = $c->stash->{body}->contacts->search(undef, { order_by => [ 'category' ] } );
$c->stash->{contacts} = $contacts;
- $c->stash->{live_contacts} = $contacts->search({ deleted => 0 });
- $c->stash->{any_not_confirmed} = $contacts->search({ confirmed => 0 })->count;
+ $c->stash->{live_contacts} = $contacts->search({ state => { '!=' => 'deleted' } });
+ $c->stash->{any_not_confirmed} = $contacts->search({ state => 'unconfirmed' })->count;
if ( $c->get_param('text') && $c->get_param('text') eq '1' ) {
$c->stash->{template} = 'admin/council_contacts.txt';
@@ -497,10 +515,48 @@ sub fetch_contacts : Private {
return 1;
}
-sub lookup_body : Private {
+sub fetch_languages : Private {
my ( $self, $c ) = @_;
- my $body_id = $c->stash->{body_id};
+ my $lang_map = {};
+ foreach my $lang (@{$c->cobrand->languages}) {
+ my ($id, $name, $code) = split(',', $lang);
+ $lang_map->{$id} = { name => $name, code => $code };
+ }
+
+ $c->stash->{languages} = $lang_map;
+
+ return 1;
+}
+
+sub fetch_translations : Private {
+ my ( $self, $c ) = @_;
+
+ my $translations = {};
+ if ($c->get_param('posted')) {
+ foreach my $lang (keys %{$c->stash->{languages}}) {
+ if (my $msgstr = $c->get_param('translation_' . $lang)) {
+ $translations->{$lang} = { msgstr => $msgstr };
+ }
+ if (my $id = $c->get_param('translation_id_' . $lang)) {
+ $translations->{$lang}->{id} = $id;
+ }
+ }
+ } elsif ($c->stash->{object}) {
+ my @translations = $c->stash->{object}->translation_for($c->stash->{translation_col})->all;
+
+ foreach my $tx (@translations) {
+ $translations->{$tx->lang} = { id => $tx->id, msgstr => $tx->msgstr };
+ }
+ }
+
+ $c->stash->{translations} = $translations;
+}
+
+sub body : Chained('/') : PathPart('admin/body') : CaptureArgs(1) {
+ my ( $self, $c, $body_id ) = @_;
+
+ $c->stash->{body_id} = $body_id;
my $body = $c->model('DB::Body')->find($body_id);
$c->detach( '/page_error_404_not_found', [] )
unless $body;
@@ -512,39 +568,70 @@ sub lookup_body : Private {
$c->stash->{example_pc} = $example_postcode;
}
}
+}
+
+sub edit_body : Chained('body') : PathPart('') : Args(0) {
+ my ( $self, $c ) = @_;
+
+ unless ($c->user->has_permission_to('category_edit', $c->stash->{body_id})) {
+ $c->forward('check_for_super_user');
+ }
+
+ $c->forward( '/auth/get_csrf_token' );
+ $c->forward( 'fetch_all_bodies' );
+ $c->forward( 'body_form_dropdowns' );
+ $c->forward('fetch_languages');
+ if ( $c->get_param('posted') ) {
+ $c->forward('update_contacts');
+ }
+
+ $c->stash->{object} = $c->stash->{body};
+ $c->stash->{translation_col} = 'name';
+
+ # if there's a contact then it's because we're displaying error
+ # messages about adding a contact so grabbing translations will
+ # fetch the contact submitted translations. So grab them, stash
+ # them and then clear posted so we can fetch the body translations
+ if ($c->stash->{contact}) {
+ $c->forward('fetch_translations');
+ $c->stash->{contact_translations} = $c->stash->{translations};
+ }
+ $c->set_param('posted', '');
+
+ $c->forward('fetch_translations');
+ $c->forward('fetch_contacts');
+
+ $c->stash->{template} = 'admin/body.html';
return 1;
}
-# This is for if the category name contains a '/'
-sub category_edit_all : Path('body') {
- my ( $self, $c, $body_id, @category ) = @_;
+sub category : Chained('body') : PathPart('') {
+ my ( $self, $c, @category ) = @_;
my $category = join( '/', @category );
- $c->go( 'category_edit', [ $body_id, $category ] );
-}
-
-sub category_edit : Path('body') : Args(2) {
- my ( $self, $c, $body_id, $category ) = @_;
-
- $c->stash->{body_id} = $body_id;
$c->forward( '/auth/get_csrf_token' );
- $c->forward( 'lookup_body' );
+ $c->stash->{template} = 'admin/category_edit.html';
my $contact = $c->stash->{body}->contacts->search( { category => $category } )->first;
$c->stash->{contact} = $contact;
+ $c->stash->{translation_col} = 'category';
+ $c->stash->{object} = $c->stash->{contact};
+
+ $c->forward('fetch_languages');
+ $c->forward('fetch_translations');
+
my $history = $c->model('DB::ContactsHistory')->search(
{
- body_id => $body_id,
- category => $category
+ body_id => $c->stash->{body_id},
+ category => $c->stash->{contact}->category
},
{
order_by => ['contacts_history_id']
},
);
$c->stash->{history} = $history;
-
my @methods = map { $_ =~ s/FixMyStreet::SendReport:://; $_ } keys %{ FixMyStreet::SendReport->get_senders };
$c->stash->{send_methods} = \@methods;
@@ -844,10 +931,26 @@ sub report_edit_category : Private {
$problem->category($category);
my @contacts = grep { $_->category eq $problem->category } @{$c->stash->{contacts}};
my @new_body_ids = map { $_->body_id } @contacts;
- # If the report has changed bodies we need to resend it
- if (scalar @{mySociety::ArrayUtils::symmetric_diff($problem->bodies_str_ids, \@new_body_ids)}) {
+ # If the report has changed bodies (and not to a subset!) we need to resend it
+ my %old_map = map { $_ => 1 } @{$problem->bodies_str_ids};
+ if (grep !$old_map{$_}, @new_body_ids) {
+ $problem->whensent(undef);
+ }
+ # If the send methods of the old/new contacts differ we need to resend the report
+ my @old_contacts = grep { $_->category eq $category_old } @{$c->stash->{contacts}};
+ my @new_send_methods = uniq map {
+ ( $_->body->can_be_devolved && $_->send_method ) ?
+ $_->send_method : $_->body->send_method;
+ } @contacts;
+ my @old_send_methods = map {
+ ( $_->body->can_be_devolved && $_->send_method ) ?
+ $_->send_method : $_->body->send_method;
+ } @old_contacts;
+ if ( scalar @{ mySociety::ArrayUtils::symmetric_diff(\@old_send_methods, \@new_send_methods) } ) {
+ $c->log->debug("Report changed, resending");
$problem->whensent(undef);
}
+
$problem->bodies_str(join( ',', @new_body_ids ));
$problem->add_to_comments({
text => '*' . sprintf(_('Category changed from ā€˜%s’ to ā€˜%s’'), $category_old, $category) . '*',
@@ -909,8 +1012,8 @@ sub categories_for_point : Private {
# Remove the "Pick a category" option
shift @{$c->stash->{category_options}} if @{$c->stash->{category_options}};
- $c->stash->{categories} = $c->stash->{category_options};
- $c->stash->{categories_hash} = { map { $_ => 1 } @{$c->stash->{category_options}} };
+ $c->stash->{category_options_copy} = $c->stash->{category_options};
+ $c->stash->{categories_hash} = { map { $_->{name} => 1 } @{$c->stash->{category_options}} };
}
sub templates : Path('templates') : Args(0) {
@@ -966,7 +1069,7 @@ sub template_edit : Path('templates') : Args(2) {
my %active_contacts = map { $_->id => 1 } @contacts;
my @all_contacts = map { {
id => $_->id,
- category => $_->category,
+ category => $_->category_display,
active => $active_contacts{$_->id},
} } @live_contacts;
$c->stash->{contacts} = \@all_contacts;
@@ -1808,7 +1911,7 @@ sub check_page_allowed : Private {
sub fetch_all_bodies : Private {
my ($self, $c ) = @_;
- my @bodies = $c->model('DB::Body')->all;
+ my @bodies = $c->model('DB::Body')->all_translated;
if ( $c->cobrand->moniker eq 'zurich' ) {
@bodies = $c->cobrand->admin_fetch_all_bodies( @bodies );
} else {
@@ -1840,6 +1943,46 @@ sub fetch_body_areas : Private {
$c->stash->{fetched_areas_body_id} = $body->id;
}
+sub update_extra_fields : Private {
+ my ($self, $c, $object) = @_;
+
+ my @indices = grep { /^metadata\[\d+\]\.code/ } keys %{ $c->req->params };
+ @indices = sort map { /(\d+)/ } @indices;
+
+ my @extra_fields;
+ foreach my $i (@indices) {
+ my $meta = {};
+ $meta->{code} = $c->get_param("metadata[$i].code");
+ next unless $meta->{code};
+ $meta->{order} = int $c->get_param("metadata[$i].order");
+ $meta->{datatype} = $c->get_param("metadata[$i].datatype");
+ my $required = $c->get_param("metadata[$i].required") && $c->get_param("metadata[$i].required") eq 'on';
+ $meta->{required} = $required ? 'true' : 'false';
+ my $notice = $c->get_param("metadata[$i].notice") && $c->get_param("metadata[$i].notice") eq 'on';
+ $meta->{variable} = $notice ? 'false' : 'true';
+ $meta->{description} = $c->get_param("metadata[$i].description");
+ $meta->{datatype_description} = $c->get_param("metadata[$i].datatype_description");
+
+ if ( $meta->{datatype} eq "singlevaluelist" ) {
+ $meta->{values} = [];
+ my $re = qr{^metadata\[$i\]\.values\[\d+\]\.key};
+ my @vindices = grep { /$re/ } keys %{ $c->req->params };
+ @vindices = sort map { /values\[(\d+)\]/ } @vindices;
+ foreach my $j (@vindices) {
+ my $name = $c->get_param("metadata[$i].values[$j].name");
+ my $key = $c->get_param("metadata[$i].values[$j].key");
+ push(@{$meta->{values}}, {
+ name => $name,
+ key => $key,
+ }) if $name;
+ }
+ }
+ push @extra_fields, $meta;
+ }
+ @extra_fields = sort { $a->{order} <=> $b->{order} } @extra_fields;
+ $object->set_extra_fields(@extra_fields);
+}
+
sub trim {
my $self = shift;
my $e = shift;
diff --git a/perllib/FixMyStreet/App/Controller/Admin/DefectTypes.pm b/perllib/FixMyStreet/App/Controller/Admin/DefectTypes.pm
index bcfeb3dd8..5dab1da2c 100644
--- a/perllib/FixMyStreet/App/Controller/Admin/DefectTypes.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin/DefectTypes.pm
@@ -6,12 +6,6 @@ use mySociety::ArrayUtils;
BEGIN { extends 'Catalyst::Controller'; }
-sub begin : Private {
- my ( $self, $c ) = @_;
-
- $c->forward('/admin/begin');
-}
-
sub index : Path : Args(0) {
my ( $self, $c ) = @_;
@@ -62,7 +56,7 @@ sub edit : Path : Args(2) {
my %active_contacts = map { $_->id => 1 } @contacts;
my @all_contacts = map { {
id => $_->id,
- category => $_->category,
+ category => $_->category_display,
active => $active_contacts{$_->id},
} } @live_contacts;
$c->stash->{contacts} = \@all_contacts;
diff --git a/perllib/FixMyStreet/App/Controller/Admin/ExorDefects.pm b/perllib/FixMyStreet/App/Controller/Admin/ExorDefects.pm
index 201742c81..bdeecc1a3 100644
--- a/perllib/FixMyStreet/App/Controller/Admin/ExorDefects.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin/ExorDefects.pm
@@ -2,19 +2,13 @@ package FixMyStreet::App::Controller::Admin::ExorDefects;
use Moose;
use namespace::autoclean;
-use Text::CSV;
use DateTime;
-use mySociety::Random qw(random_bytes);
+use Try::Tiny;
+use FixMyStreet::Integrations::ExorRDI;
BEGIN { extends 'Catalyst::Controller'; }
-sub begin : Private {
- my ( $self, $c ) = @_;
-
- $c->forward('/admin/begin');
-}
-
sub index : Path : Args(0) {
my ( $self, $c ) = @_;
@@ -54,177 +48,32 @@ sub download : Path('download') : Args(0) {
my $end_date = $parser-> parse_datetime ( $c->get_param('end_date') ) ;
my $one_day = DateTime::Duration->new( days => 1 );
- my %params = (
- -and => [
- state => [ 'action scheduled' ],
- external_id => { '!=' => undef },
- 'admin_log_entries.action' => 'inspected',
- 'admin_log_entries.whenedited' => { '>=', $start_date },
- 'admin_log_entries.whenedited' => { '<=', $end_date + $one_day },
- ]
- );
-
- my $user;
- if ( $c->get_param('user_id') ) {
- my $uid = $c->get_param('user_id');
- $params{'admin_log_entries.user_id'} = $uid;
- $user = $c->model('DB::User')->find( { id => $uid } );
- }
-
- my $problems = $c->cobrand->problems->search(
- \%params,
- {
- join => 'admin_log_entries',
- distinct => 1,
- }
- );
-
- if ( !$problems->count ) {
- if ( defined $user ) {
+ my $params = {
+ start_date => $start_date,
+ inspection_date => $start_date,
+ end_date => $end_date + $one_day,
+ user => $c->get_param('user_id'),
+ mark_as_processed => 0,
+ };
+ my $rdi = FixMyStreet::Integrations::ExorRDI->new($params);
+
+ try {
+ my $out = $rdi->construct;
+ $c->res->content_type('text/csv; charset=utf-8');
+ $c->res->header('content-disposition' => "attachment; filename=" . $rdi->filename);
+ $c->res->body( $out );
+ } catch {
+ die $_ unless $_ =~ /FixMyStreet::Integrations::ExorRDI::Error/;
+ if ($params->{user}) {
$c->flash->{error_message} = _("No inspections by that inspector in the selected date range.");
} else {
$c->flash->{error_message} = _("No inspections in the selected date range.");
}
- $c->flash->{start_date} = $start_date;
- $c->flash->{end_date} = $end_date;
- $c->flash->{user_id} = $user->id if $user;
+ $c->flash->{start_date} = $params->{start_date};
+ $c->flash->{end_date} = $params->{end_date};
+ $c->flash->{user_id} = $params->{user};
$c->res->redirect( $c->uri_for( '' ) );
- }
-
- # A single RDI file might contain inspections from multiple inspectors, so
- # we need to group inspections by inspector within G records.
- my $inspectors = {};
- my $inspector_initials = {};
- while ( my $report = $problems->next ) {
- my $user = $report->inspection_log_entry->user;
- $inspectors->{$user->id} ||= [];
- push @{ $inspectors->{$user->id} }, $report;
- unless ( $inspector_initials->{$user->id} ) {
- $inspector_initials->{$user->id} = $user->get_extra_metadata('initials');
- }
- }
-
- my $csv = Text::CSV->new({ binary => 1, eol => "" });
-
- my $p_count = 0;
- my $link_id = $c->cobrand->exor_rdi_link_id;
-
- # RDI first line is always the same
- $csv->combine("1", "1.8", "1.0.0.0", "ENHN", "");
- my @body = ($csv->string);
-
- my $i = 0;
- foreach my $inspector_id (keys %$inspectors) {
- my $inspections = $inspectors->{$inspector_id};
- my $initials = $inspector_initials->{$inspector_id};
-
- $csv->combine(
- "G", # start of an area/sequence
- $link_id, # area/link id, fixed value for our purposes
- "","", # must be empty
- $initials || "XX", # inspector initials
- $start_date->strftime("%y%m%d"), # date of inspection yymmdd
- "0700", # time of inspection hhmm, set to static value for now
- "D", # inspection variant, should always be D
- "INS", # inspection type, always INS
- "N", # Area of the county - north (N) or south (S)
- "", "", "", "" # empty fields
- );
- push @body, $csv->string;
-
- $csv->combine(
- "H", # initial inspection type
- "MC" # minor carriageway (changes depending on activity code)
- );
- push @body, $csv->string;
-
- foreach my $report (@$inspections) {
- my ($eastings, $northings) = $report->local_coords;
- my $description = sprintf("%s %s", $report->external_id || "", $report->get_extra_metadata('detailed_information') || "");
- my $activity_code = $report->defect_type ?
- $report->defect_type->get_extra_metadata('activity_code')
- : 'MC';
- my $traffic_information = $report->get_extra_metadata('traffic_information') ?
- 'TM ' . $report->get_extra_metadata('traffic_information')
- : 'TM none';
-
- $csv->combine(
- "I", # beginning of defect record
- $activity_code, # activity code - minor carriageway, also FC (footway)
- "", # empty field, can also be A (seen on MC) or B (seen on FC)
- sprintf("%03d", ++$i), # randomised sequence number
- "${eastings}E ${northings}N", # defect location field, which we don't capture from inspectors
- $report->inspection_log_entry->whenedited->strftime("%H%M"), # defect time raised
- "","","","","","","", # empty fields
- $traffic_information,
- $description, # defect description
- );
- push @body, $csv->string;
-
- my $defect_type = $report->defect_type ?
- $report->defect_type->get_extra_metadata('defect_code')
- : 'SFP2';
- $csv->combine(
- "J", # georeferencing record
- $defect_type, # defect type - SFP2: sweep and fill <1m2, POT2 also seen
- $report->response_priority ?
- $report->response_priority->external_id :
- "2", # priority of defect
- "","", # empty fields
- $eastings, # eastings
- $northings, # northings
- "","","","","" # empty fields
- );
- push @body, $csv->string;
-
- $csv->combine(
- "M", # bill of quantities record
- "resolve", # permanent repair
- "","", # empty fields
- "/CMC", # /C + activity code
- "", "" # empty fields
- );
- push @body, $csv->string;
- }
-
- # end this group of defects with a P record
- $csv->combine(
- "P", # end of area/sequence
- 0, # always 0
- 999999, # charging code, always 999999 in OCC
- );
- push @body, $csv->string;
- $p_count++;
- }
-
- # end the RDI file with an X record
- my $record_count = $i;
- $csv->combine(
- "X", # end of inspection record
- $p_count,
- $p_count,
- $record_count, # number of I records
- $record_count, # number of J records
- 0, 0, 0, # always zero
- $record_count, # number of M records
- 0, # always zero
- $p_count,
- 0, 0, 0 # error counts, always zero
- );
- push @body, $csv->string;
-
- my $start = $start_date->strftime("%Y%m%d");
- my $end = $end_date->strftime("%Y%m%d");
- my $filename = sprintf("exor_defects-%s-%s.rdi", $start, $end);
- if ( $user ) {
- my $initials = $user->get_extra_metadata("initials") || "";
- $filename = sprintf("exor_defects-%s-%s-%s.rdi", $start, $end, $initials);
- }
- $c->res->content_type('text/csv; charset=utf-8');
- $c->res->header('content-disposition' => "attachment; filename=$filename");
- # The RDI format is very weird CSV - each line must be wrapped in
- # double quotes.
- $c->res->body( join "", map { "\"$_\"\r\n" } @body );
+ };
}
-1; \ No newline at end of file
+1;
diff --git a/perllib/FixMyStreet/App/Controller/Admin/ReportExtraFields.pm b/perllib/FixMyStreet/App/Controller/Admin/ReportExtraFields.pm
new file mode 100644
index 000000000..337fb4bed
--- /dev/null
+++ b/perllib/FixMyStreet/App/Controller/Admin/ReportExtraFields.pm
@@ -0,0 +1,55 @@
+package FixMyStreet::App::Controller::Admin::ReportExtraFields;
+use Moose;
+use namespace::autoclean;
+use List::MoreUtils qw(uniq);
+
+BEGIN { extends 'Catalyst::Controller'; }
+
+
+sub index : Path : Args(0) {
+ my ( $self, $c ) = @_;
+
+ my @extras = $c->model('DB::ReportExtraFields')->search(
+ undef,
+ {
+ order_by => 'name'
+ }
+ );
+
+ $c->stash->{extra_fields} = \@extras;
+}
+
+sub edit : Path : Args(1) {
+ my ( $self, $c, $extra_id ) = @_;
+
+ my $extra;
+ if ( $extra_id eq 'new' ) {
+ $extra = $c->model('DB::ReportExtraFields')->new({});
+ } else {
+ $extra = $c->model('DB::ReportExtraFields')->find( $extra_id )
+ or $c->detach( '/page_error_404_not_found' );
+ }
+
+ if ($c->req->method eq 'POST') {
+ $c->forward('/auth/check_csrf_token');
+
+ foreach (qw/name cobrand language/) {
+ $extra->$_($c->get_param($_));
+ }
+ $c->forward('/admin/update_extra_fields', [ $extra ]);
+
+ $extra->update_or_insert;
+ }
+
+ $c->forward('/auth/get_csrf_token');
+ $c->forward('/admin/fetch_languages');
+
+ my @cobrands = uniq sort map { $_->{moniker} } FixMyStreet::Cobrand->available_cobrand_classes;
+ $c->stash->{cobrands} = \@cobrands;
+
+ $c->stash->{extra} = $extra;
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
diff --git a/perllib/FixMyStreet/App/Controller/Admin/ResponsePriorities.pm b/perllib/FixMyStreet/App/Controller/Admin/ResponsePriorities.pm
index bae0f71a7..2613f6ae0 100644
--- a/perllib/FixMyStreet/App/Controller/Admin/ResponsePriorities.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin/ResponsePriorities.pm
@@ -5,12 +5,6 @@ use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller'; }
-sub begin : Private {
- my ( $self, $c ) = @_;
-
- $c->forward('/admin/begin');
-}
-
sub index : Path : Args(0) {
my ( $self, $c ) = @_;
@@ -71,6 +65,7 @@ sub edit : Path : Args(2) {
$priority->name( $c->get_param('name') );
$priority->description( $c->get_param('description') );
$priority->external_id( $c->get_param('external_id') );
+ $priority->is_default( $c->get_param('is_default') ? 1 : 0 );
$priority->update_or_insert;
my @live_contact_ids = map { $_->id } @live_contacts;
diff --git a/perllib/FixMyStreet/App/Controller/Admin/States.pm b/perllib/FixMyStreet/App/Controller/Admin/States.pm
new file mode 100644
index 000000000..938692af0
--- /dev/null
+++ b/perllib/FixMyStreet/App/Controller/Admin/States.pm
@@ -0,0 +1,96 @@
+package FixMyStreet::App::Controller::Admin::States;
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'Catalyst::Controller'; }
+
+sub index : Path : Args(0) {
+ my ( $self, $c ) = @_;
+
+ $c->forward('/auth/get_csrf_token');
+ $c->forward('/admin/fetch_languages');
+ my $rs = $c->model('DB::State');
+
+ if ($c->req->method eq 'POST') {
+ $c->forward('/auth/check_csrf_token');
+
+ $c->forward('process_new')
+ && $c->forward('delete')
+ && $c->forward('update');
+
+ $rs->clear;
+ }
+
+ $c->stash->{open_states} = $rs->open;
+ $c->stash->{closed_states} = $rs->closed;
+ $c->stash->{fixed_states} = $rs->fixed;
+}
+
+sub process_new : Private {
+ my ($self, $c) = @_;
+ if ($c->get_param('new_fixed')) {
+ $c->model('DB::State')->create({
+ label => 'fixed',
+ type => 'fixed',
+ name => _('Fixed'),
+ });
+ return 0;
+ }
+ return 1 unless $c->get_param('new');
+ my %params = map { $_ => $c->get_param($_) } qw/label type name/;
+ $c->model('DB::State')->create(\%params);
+ return 0;
+}
+
+sub delete : Private {
+ my ($self, $c) = @_;
+
+ my @params = keys %{ $c->req->params };
+ my ($to_delete) = map { /^delete:(.*)/ } grep { /^delete:/ } @params;
+ if ($to_delete) {
+ $c->model('DB::State')->search({ label => $to_delete })->delete;
+ return 0;
+ }
+ return 1;
+}
+
+sub update : Private {
+ my ($self, $c) = @_;
+
+ my $rs = $c->model('DB::State');
+ my %db_states = map { $_->label => $_ } @{$rs->states};
+ my @params = keys %{ $c->req->params };
+ my @states = map { /^type:(.*)/ } grep { /^type:/ } @params;
+
+ foreach my $state (@states) {
+ # If there is only one language, we still store confirmed/closed
+ # as translations, as that seems a sensible place to store them.
+ if ($state eq 'confirmed' or $state eq 'closed') {
+ if (my $name = $c->get_param("name:$state")) {
+ my ($lang) = keys %{$c->stash->{languages}};
+ $db_states{$state}->add_translation_for('name', $lang, $name);
+ }
+ } else {
+ $db_states{$state}->update({
+ type => $c->get_param("type:$state"),
+ name => $c->get_param("name:$state"),
+ });
+ }
+
+ foreach my $lang (keys(%{$c->stash->{languages}})) {
+ my $id = $c->get_param("translation_id:$state:$lang");
+ my $text = $c->get_param("translation:$state:$lang");
+ if ($text) {
+ $db_states{$state}->add_translation_for('name', $lang, $text);
+ } elsif ($id) {
+ $c->model('DB::Translation')->find({ id => $id })->delete;
+ }
+ }
+ }
+
+ return 1;
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm
index 1fe35d0a3..b872084ff 100644
--- a/perllib/FixMyStreet/App/Controller/Around.pm
+++ b/perllib/FixMyStreet/App/Controller/Around.pm
@@ -163,52 +163,20 @@ sub display_location : Private {
$c->forward('/auth/get_csrf_token');
- # get the lat,lng
- my $latitude = $c->stash->{latitude};
- my $longitude = $c->stash->{longitude};
-
- # Deal with pin hiding/age
- my $all_pins = $c->get_param('all_pins') ? 1 : undef;
- $c->stash->{all_pins} = $all_pins;
- my $interval = $all_pins ? undef : $c->cobrand->on_map_default_max_pin_age;
-
- $c->forward( '/reports/stash_report_filter_status' );
-
# Check the category to filter by, if any, is valid
$c->forward('check_and_stash_category');
- $c->forward( '/reports/stash_report_sort', [ 'created-desc' ]);
-
- # get the map features
- my ( $on_map_all, $on_map, $nearby, $distance ) =
- FixMyStreet::Map::map_features( $c,
- latitude => $latitude, longitude => $longitude,
- interval => $interval, categories => [ keys %{$c->stash->{filter_category}} ],
- states => $c->stash->{filter_problem_states},
- order => $c->stash->{sort_order},
- );
- # copy the found reports to the stash
- $c->stash->{on_map} = $on_map;
- $c->stash->{around_map} = $nearby;
- $c->stash->{distance} = $distance;
+ my $latitude = $c->stash->{latitude};
+ my $longitude = $c->stash->{longitude};
- # create a list of all the pins
- my @pins;
- unless ($c->get_param('no_pins')) {
- @pins = map {
- # Here we might have a DB::Problem or a DB::Nearby, we always want the problem.
- my $p = (ref $_ eq 'FixMyStreet::App::Model::DB::Nearby') ? $_->problem : $_;
- $p->pin_data($c, 'around');
- } @$on_map_all, @$nearby;
- }
+ $c->forward('map_features', [ { latitude => $latitude, longitude => $longitude } ] );
- $c->stash->{page} = 'around'; # So the map knows to make clickable pins, update on pan
FixMyStreet::Map::display_map(
$c,
latitude => $latitude,
longitude => $longitude,
clickable => 1,
- pins => \@pins,
+ pins => $c->stash->{pins},
area => $c->cobrand->areas_on_around,
);
@@ -259,7 +227,7 @@ sub check_and_stash_category : Private {
distinct => 1
}
)->all;
- my @categories = map { $_->category } @contacts;
+ my @categories = map { { name => $_->category, value => $_->category_display } } @contacts;
$c->stash->{filter_categories} = \@categories;
my %categories_mapped = map { $_ => 1 } @categories;
@@ -268,6 +236,44 @@ sub check_and_stash_category : Private {
$c->stash->{filter_category} = \%valid_categories;
}
+sub map_features : Private {
+ my ($self, $c, $extra) = @_;
+
+ $c->stash->{page} = 'around'; # Needed by _item.html / so the map knows to make clickable pins, update on pan
+
+ $c->forward( '/reports/stash_report_filter_status' );
+ $c->forward( '/reports/stash_report_sort', [ 'created-desc' ]);
+
+ # Deal with pin hiding/age
+ my $all_pins = $c->get_param('all_pins') ? 1 : undef;
+ $c->stash->{all_pins} = $all_pins;
+ my $interval = $all_pins ? undef : $c->cobrand->on_map_default_max_pin_age;
+
+ return if $c->get_param('js'); # JS will request the same (or more) data client side
+
+ my ( $on_map_all, $on_map_list, $nearby, $distance ) =
+ FixMyStreet::Map::map_features(
+ $c, interval => $interval, %$extra,
+ categories => [ keys %{$c->stash->{filter_category}} ],
+ states => $c->stash->{filter_problem_states},
+ order => $c->stash->{sort_order},
+ );
+
+ my @pins;
+ unless ($c->get_param('no_pins')) {
+ @pins = map {
+ # Here we might have a DB::Problem or a DB::Result::Nearby, we always want the problem.
+ my $p = (ref $_ eq 'FixMyStreet::DB::Result::Nearby') ? $_->problem : $_;
+ $p->pin_data($c, 'around');
+ } @$on_map_all, @$nearby;
+ }
+
+ $c->stash->{pins} = \@pins;
+ $c->stash->{on_map} = $on_map_list;
+ $c->stash->{around_map} = $nearby;
+ $c->stash->{distance} = $distance;
+}
+
=head2 /ajax
Handle the ajax calls that the map makes when it is dragged. The info returned
@@ -279,8 +285,6 @@ the map.
sub ajax : Path('/ajax') {
my ( $self, $c ) = @_;
- $c->res->content_type('application/json; charset=utf-8');
-
my $bbox = $c->get_param('bbox');
unless ($bbox) {
$c->res->status(404);
@@ -288,52 +292,13 @@ sub ajax : Path('/ajax') {
return;
}
- # assume this is not cacheable - may need to be more fine-grained later
- $c->res->header( 'Cache_Control' => 'max-age=0' );
-
- $c->stash->{page} = 'around'; # Needed by _item.html
-
- # how far back should we go?
- my $all_pins = $c->get_param('all_pins') ? 1 : undef;
- my $interval = $all_pins ? undef : $c->cobrand->on_map_default_max_pin_age;
-
- $c->forward( '/reports/stash_report_filter_status' );
- $c->forward( '/reports/stash_report_sort', [ 'created-desc' ]);
-
- # extract the data from the map
- my ( $on_map_all, $on_map_list, $nearby, $dist ) =
- FixMyStreet::Map::map_features($c,
- bbox => $bbox, interval => $interval,
- categories => [ $c->get_param_list('filter_category', 1) ],
- states => $c->stash->{filter_problem_states},
- order => $c->stash->{sort_order},
- );
-
- # create a list of all the pins
- my @pins = map {
- # Here we might have a DB::Problem or a DB::Nearby, we always want the problem.
- my $p = (ref $_ eq 'FixMyStreet::App::Model::DB::Nearby') ? $_->problem : $_;
- my $colour = $c->cobrand->pin_colour( $p, 'around' );
- [ $p->latitude, $p->longitude,
- $colour,
- $p->id, $p->title_safe
- ]
- } @$on_map_all, @$nearby;
-
- # render templates to get the html
- my $on_map_list_html = $c->render_fragment(
- 'around/on_map_list_items.html',
- { on_map => $on_map_list, around_map => $nearby }
- );
+ my %valid_categories = map { $_ => 1 } $c->get_param_list('filter_category', 1);
+ $c->stash->{filter_category} = \%valid_categories;
- # JSON encode the response
- my $json = { pins => \@pins };
- $json->{current} = $on_map_list_html if $on_map_list_html;
- my $body = encode_json($json);
- $c->res->body($body);
+ $c->forward('map_features', [ { bbox => $bbox } ]);
+ $c->forward('/reports/ajax', [ 'around/on_map_list_items.html' ]);
}
-
sub location_autocomplete : Path('/ajax/geocode') {
my ( $self, $c ) = @_;
$c->res->content_type('application/json; charset=utf-8');
diff --git a/perllib/FixMyStreet/App/Controller/Auth.pm b/perllib/FixMyStreet/App/Controller/Auth.pm
index 4efa7abb8..825066026 100644
--- a/perllib/FixMyStreet/App/Controller/Auth.pm
+++ b/perllib/FixMyStreet/App/Controller/Auth.pm
@@ -33,7 +33,7 @@ sub general : Path : Args(0) {
my ( $self, $c ) = @_;
$c->detach( 'redirect_on_signin', [ $c->get_param('r') ] )
- if $c->user && $c->get_param('r');
+ if $c->req->method eq 'GET' && $c->user && $c->get_param('r');
# all done unless we have a form posted to us
return unless $c->req->method eq 'POST';
@@ -128,6 +128,18 @@ sub email_sign_in : Private {
return;
}
+ # If user registration is disabled then bail out at this point
+ # if there's not already a user with this email address.
+ # NB this uses the same template as a successful sign in to stop
+ # enumeration of valid email addresses.
+ if ( FixMyStreet->config('SIGNUPS_DISABLED')
+ && !$c->model('DB::User')->search({ email => $good_email })->count
+ && !$c->stash->{current_user} # don't break the change email flow
+ ) {
+ $c->stash->{template} = 'auth/token.html';
+ return;
+ }
+
my $user_params = {};
$user_params->{password} = $c->get_param('password_register')
if $c->get_param('password_register');
@@ -199,6 +211,10 @@ sub token : Path('/M') : Args(1) {
my $user = $c->model('DB::User')->find_or_new({ email => $data->{email} });
+ # Bail out if this is a new user and SIGNUPS_DISABLED is set
+ $c->detach( '/page_error_403_access_denied', [] )
+ if FixMyStreet->config('SIGNUPS_DISABLED') && !$user->in_storage && !$data->{old_email};
+
if ($data->{old_email}) {
# Were logged in as old_email, want to switch to email ($user)
if ($user->in_storage) {
@@ -244,6 +260,8 @@ sub fb : Private {
sub facebook_sign_in : Private {
my ( $self, $c ) = @_;
+ $c->detach( '/page_error_403_access_denied', [] ) if FixMyStreet->config('SIGNUPS_DISABLED');
+
my $fb = $c->forward('/auth/fb');
my $url = $fb->get_authorization_url(scope => ['email']);
@@ -302,6 +320,8 @@ sub tw : Private {
sub twitter_sign_in : Private {
my ( $self, $c ) = @_;
+ $c->detach( '/page_error_403_access_denied', [] ) if FixMyStreet->config('SIGNUPS_DISABLED');
+
my $twitter = $c->forward('/auth/tw');
my $url = $twitter->get_authentication_url(callback => $c->uri_for('/auth/Twitter'));
diff --git a/perllib/FixMyStreet/App/Controller/Contact.pm b/perllib/FixMyStreet/App/Controller/Contact.pm
index b98bdbcc7..f2c3be47c 100644
--- a/perllib/FixMyStreet/App/Controller/Contact.pm
+++ b/perllib/FixMyStreet/App/Controller/Contact.pm
@@ -54,7 +54,8 @@ sub submit : Path('submit') : Args(0) {
&& $c->forward('determine_contact_type')
&& $c->forward('validate')
&& $c->forward('prepare_params_for_email')
- && $c->forward('send_email');
+ && $c->forward('send_email')
+ && $c->forward('redirect_on_success');
}
=head2 determine_contact_type
@@ -99,7 +100,7 @@ sub determine_contact_type : Private {
=head2 validate
-Validate the form submission parameters. Sets error messages and redirect
+Validate the form submission parameters. Sets error messages and redirect
to index page if errors.
=cut
@@ -168,8 +169,7 @@ sub prepare_params_for_email : Private {
if ( $c->stash->{update} ) {
- $c->stash->{problem_url} = $base_url . '/report/' . $c->stash->{update}->problem_id
- . '#update_' . $c->stash->{update}->id;
+ $c->stash->{problem_url} = $base_url . $c->stash->{update}->url;
$c->stash->{admin_url} = $admin_url . '/update_edit/' . $c->stash->{update}->id;
$c->stash->{complaint} = sprintf(
"Complaint about update %d on report %d",
@@ -258,10 +258,24 @@ sub send_email : Private {
$params->{from} = $from;
}
- $c->send_email('contact.txt', $params);
+ $c->stash->{success} = $c->send_email('contact.txt', $params);
- # above is always succesful :(
- $c->stash->{success} = 1;
+ return 1;
+}
+
+=head2 redirect_on_success
+
+Redirect to a custom URL if one was provided
+
+=cut
+
+sub redirect_on_success : Private {
+ my ( $self, $c ) = @_;
+
+ if (my $success_url = $c->get_param('success_url')) {
+ $c->res->redirect($success_url);
+ $c->detach;
+ }
return 1;
}
diff --git a/perllib/FixMyStreet/App/Controller/Dashboard.pm b/perllib/FixMyStreet/App/Controller/Dashboard.pm
index fbe5a2dc9..f961660c0 100644
--- a/perllib/FixMyStreet/App/Controller/Dashboard.pm
+++ b/perllib/FixMyStreet/App/Controller/Dashboard.pm
@@ -24,6 +24,8 @@ sub example : Local : Args(0) {
my ( $self, $c ) = @_;
$c->stash->{template} = 'dashboard/index.html';
+ $c->stash->{filter_states} = $c->cobrand->state_groups_inspect;
+
$c->stash->{children} = {};
for my $i (1..3) {
$c->stash->{children}{$i} = { id => $i, name => "Ward $i" };
@@ -93,6 +95,7 @@ sub index : Path : Args(0) {
$c->stash->{body} = $body;
# Set up the data for the dropdowns
+ $c->stash->{filter_states} = $c->cobrand->state_groups_inspect;
# Just take the first area ID we find
my $area_id = $body->body_areas->first->area_id;
@@ -145,12 +148,10 @@ sub index : Path : Args(0) {
# List of reports underneath summary table
$c->stash->{q_state} = $c->get_param('state') || '';
- if ( $c->stash->{q_state} eq 'fixed' ) {
+ if ( $c->stash->{q_state} eq 'fixed - council' ) {
$prob_where->{'me.state'} = [ FixMyStreet::DB::Result::Problem->fixed_states() ];
} elsif ( $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,
@@ -180,7 +181,7 @@ sub export_as_csv {
my ($self, $c, $problems_rs, $body) = @_;
require Text::CSV;
my $problems = $problems_rs->search(
- {}, { prefetch => 'comments' });
+ {}, { prefetch => 'comments', order_by => 'me.confirmed' });
my $filename = do {
my %where = (
@@ -211,6 +212,9 @@ sub export_as_csv {
'Status',
'Latitude', 'Longitude',
'Nearest Postcode',
+ 'Ward',
+ 'Easting',
+ 'Northing',
'Report URL',
);
my @body = ($csv->string);
@@ -242,6 +246,13 @@ sub export_as_csv {
}
}
+ my $wards = join ', ',
+ map { $c->stash->{children}->{$_}->{name} }
+ grep {$c->stash->{children}->{$_} }
+ split ',', $hashref->{areas};
+
+ my @local_coords = $report->local_coords;
+
$csv->combine(
@{$hashref}{
'id',
@@ -258,6 +269,9 @@ sub export_as_csv {
'latitude', 'longitude',
'postcode',
},
+ $wards,
+ $local_coords[0],
+ $local_coords[1],
(join '', $c->cobrand->base_url_for_report($report), $report->url),
);
diff --git a/perllib/FixMyStreet/App/Controller/JSON.pm b/perllib/FixMyStreet/App/Controller/JSON.pm
index d3cd33546..762e3c115 100644
--- a/perllib/FixMyStreet/App/Controller/JSON.pm
+++ b/perllib/FixMyStreet/App/Controller/JSON.pm
@@ -105,10 +105,9 @@ sub problems : Local {
foreach my $problem (@problems) {
$problem->name( '' ) if $problem->anonymous == 1;
$problem->service( 'Web interface' ) if $problem->service eq '';
- my $bodies = $problem->bodies;
- if (keys %$bodies) {
- my @body_names = map { $_->name } values %$bodies;
- $problem->bodies_str( join(' and ', @body_names) );
+ my $body_names = $problem->body_names;
+ if (@$body_names) {
+ $problem->bodies_str( join(' and ', @$body_names) );
}
}
diff --git a/perllib/FixMyStreet/App/Controller/Location.pm b/perllib/FixMyStreet/App/Controller/Location.pm
index 6a0f2c0ec..c457c8fce 100644
--- a/perllib/FixMyStreet/App/Controller/Location.pm
+++ b/perllib/FixMyStreet/App/Controller/Location.pm
@@ -31,8 +31,6 @@ sub determine_location_from_coords : Private {
my $latitude = $c->get_param('latitude') || $c->get_param('lat');
my $longitude = $c->get_param('longitude') || $c->get_param('lon');
- $c->log->debug($longitude);
- $c->log->debug($latitude);
if ( defined $latitude && defined $longitude ) {
($c->stash->{latitude}, $c->stash->{longitude}) =
diff --git a/perllib/FixMyStreet/App/Controller/Moderate.pm b/perllib/FixMyStreet/App/Controller/Moderate.pm
index 74f2e6b31..e2ab16b6b 100644
--- a/perllib/FixMyStreet/App/Controller/Moderate.pm
+++ b/perllib/FixMyStreet/App/Controller/Moderate.pm
@@ -146,7 +146,7 @@ sub report_moderate_title : Private {
my $title = $c->get_param('problem_revert_title') ?
$original_title
- : $self->diff($original_title, $c->get_param('problem_title'));
+ : $c->get_param('problem_title');
if ($title ne $old_title) {
$original->insert unless $original->in_storage;
@@ -167,7 +167,7 @@ sub report_moderate_detail : Private {
my $original_detail = $original->detail;
my $detail = $c->get_param('problem_revert_detail') ?
$original_detail
- : $self->diff($original_detail, $c->get_param('problem_detail'));
+ : $c->get_param('problem_detail');
if ($detail ne $old_detail) {
$original->insert unless $original->in_storage;
@@ -285,7 +285,7 @@ sub update_moderate_detail : Private {
my $original_detail = $original->detail;
my $detail = $c->get_param('update_revert_detail') ?
$original_detail
- : $self->diff($original_detail, $c->get_param('update_detail'));
+ : $c->get_param('update_detail');
if ($detail ne $old_detail) {
$original->insert unless $original->in_storage;
@@ -340,29 +340,6 @@ sub return_text : Private {
$c->res->body( $text // '' );
}
-sub diff {
- my ($self, $old, $new) = @_;
-
- $new =~s/\[\.{3}\]//g;
-
- my $diff = Algorithm::Diff->new( [ split //, $old ], [ split //, $new ] );
- my $string;
- while ($diff->Next) {
- my $d = $diff->Diff;
- if ($d & 1) {
- my $deleted = join '', $diff->Items(1);
- unless ($deleted =~/^\s*$/) {
- $string .= ' ' if $deleted =~/^ /;
- $string .= '[...]';
- $string .= ' ' if $deleted =~/ $/;
- }
- }
- $string .= join '', $diff->Items(2);
- }
- return $string;
-}
-
-
__PACKAGE__->meta->make_immutable;
1;
diff --git a/perllib/FixMyStreet/App/Controller/My.pm b/perllib/FixMyStreet/App/Controller/My.pm
index 77711f807..5b80a4a08 100644
--- a/perllib/FixMyStreet/App/Controller/My.pm
+++ b/perllib/FixMyStreet/App/Controller/My.pm
@@ -19,9 +19,10 @@ Catalyst Controller.
=cut
-sub begin : Private {
+sub auto : Private {
my ($self, $c) = @_;
$c->detach( '/auth/redirect' ) unless $c->user;
+ return 1;
}
=head2 index
@@ -162,7 +163,7 @@ sub setup_page_data : Private {
distinct => 1,
order_by => [ 'category' ],
} )->all;
- @categories = map { $_->category } @categories;
+ @categories = map { { name => $_->category, value => $_->category_display } } @categories;
$c->stash->{filter_categories} = \@categories;
$c->stash->{page} = 'my';
@@ -205,6 +206,20 @@ sub planned_change : Path('planned/change') {
}
}
+sub shortlist_multiple : Path('planned/change_multiple') {
+ my ($self, $c) = @_;
+ $c->forward('/auth/check_csrf_token');
+
+ my @ids = $c->get_param_list('ids[]');
+
+ foreach my $id (@ids) {
+ $c->forward( '/report/load_problem_or_display_error', [ $id ] );
+ $c->user->add_to_planned_reports($c->stash->{problem});
+ }
+
+ $c->res->body(encode_json({ outcome => 'add' }));
+}
+
sub by_shortlisted {
my $a_order = $a->get_extra_metadata('order') || 0;
my $b_order = $b->get_extra_metadata('order') || 0;
@@ -220,6 +235,38 @@ sub by_shortlisted {
}
}
+sub anonymize : Path('anonymize') {
+ my ($self, $c) = @_;
+ $c->forward('/auth/get_csrf_token');
+
+ my $object;
+ if (my $id = $c->get_param('problem')) {
+ $c->forward( '/report/load_problem_or_display_error', [ $id ] );
+ $object = $c->stash->{problem};
+ } elsif ($id = $c->get_param('update')) {
+ $c->stash->{update} = $object = $c->model('DB::Comment')->find({ id => $id });
+ $c->detach('/page_error_400_bad_request') unless $object;
+ } else {
+ $c->detach('/page_error_404_not_found');
+ }
+ $c->detach('/page_error_400_bad_request') unless $c->user->id == $object->user_id;
+ $c->detach('/page_error_400_bad_request') if $object->anonymous;
+
+ if ($c->get_param('hide') || $c->get_param('hide_everywhere')) {
+ $c->detach('/page_error_400_bad_request') unless $c->req->method eq 'POST';
+ $c->forward('/auth/check_csrf_token');
+ if ($c->get_param('hide')) {
+ $object->update({ anonymous => 1 });
+ $c->flash->{anonymized} = _('Your name has been hidden.');
+ } elsif ($c->get_param('hide_everywhere')) {
+ $c->user->problems->update({anonymous => 1});
+ $c->user->comments->update({anonymous => 1});
+ $c->flash->{anonymized} = _('Your name has been hidden from all your reports and updates.');
+ }
+ $c->res->redirect($object->url);
+ }
+}
+
__PACKAGE__->meta->make_immutable;
1;
diff --git a/perllib/FixMyStreet/App/Controller/Open311.pm b/perllib/FixMyStreet/App/Controller/Open311.pm
index bc08593de..95b29d116 100644
--- a/perllib/FixMyStreet/App/Controller/Open311.pm
+++ b/perllib/FixMyStreet/App/Controller/Open311.pm
@@ -160,7 +160,7 @@ sub get_services : Private {
my $lon = $c->get_param('long') || '';
# Look up categories for this council or councils
- my $categories = $c->model('DB::Contact')->not_deleted;
+ my $categories = $c->model('DB::Contact')->active;
if ($lat || $lon) {
my $area_types = $c->cobrand->area_types;
@@ -241,7 +241,8 @@ sub output_requests : Private {
'long' => $problem->longitude,
'status' => $problem->state,
# 'status_notes' => {},
- 'requested_datetime' => w3date($problem->confirmed),
+ # Zurich has visible unconfirmed reports
+ 'requested_datetime' => w3date($problem->confirmed || $problem->created),
'updated_datetime' => w3date($problem->lastupdate),
# 'expected_datetime' => {},
# 'address' => {},
@@ -258,8 +259,8 @@ sub output_requests : Private {
}
else {
# FIXME Not according to Open311 v2
- my @body_names = map { $_->name } values %{$problem->bodies};
- $request->{agency_responsible} = {'recipient' => [ @body_names ] };
+ my $body_names = $problem->body_names;
+ $request->{agency_responsible} = {'recipient' => $body_names };
}
if ( !$problem->anonymous ) {
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm
index ad2702460..e37e08698 100644
--- a/perllib/FixMyStreet/App/Controller/Report.pm
+++ b/perllib/FixMyStreet/App/Controller/Report.pm
@@ -28,14 +28,11 @@ Redirect to homepage unless C<id> parameter in query, in which case redirect to
sub index : Path('') : Args(0) {
my ( $self, $c ) = @_;
- my $id = $c->get_param('id');
-
- my $uri =
- $id
- ? $c->uri_for( '/report', $id )
- : $c->uri_for('/');
-
- $c->res->redirect($uri);
+ if ($c->stash->{homepage_template}) {
+ $c->stash->{template} = 'index.html';
+ } else {
+ $c->res->redirect('/');
+ }
}
=head2 report_display
@@ -124,7 +121,7 @@ sub load_problem_or_display_error : Private {
$c->detach( '/page_error_404_not_found', [ _('Unknown problem ID') ] )
unless $c->cobrand->show_unconfirmed_reports ;
}
- elsif ( $problem->hidden_states->{ $problem->state } or
+ elsif ( $problem->hidden_states->{ $problem->state } or
(($problem->get_extra_metadata('closure_status')||'') eq 'hidden')) {
$c->detach(
'/page_error_410_gone',
@@ -159,7 +156,7 @@ sub load_updates : Private {
my $updates = $c->model('DB::Comment')->search(
{ problem_id => $c->stash->{problem}->id, state => 'confirmed' },
- { order_by => 'confirmed' }
+ { order_by => [ 'confirmed', 'id' ] }
);
my $questionnaires = $c->model('DB::Questionnaire')->search(
@@ -181,8 +178,10 @@ sub load_updates : Private {
@combined = map { $_->[1] } sort { $a->[0] <=> $b->[0] } @combined;
$c->stash->{updates} = \@combined;
- if ($c->sessionid && $c->flash->{alert_to_reporter}) {
- $c->stash->{alert_to_reporter} = 1;
+ if ($c->sessionid) {
+ foreach (qw(alert_to_reporter anonymized)) {
+ $c->stash->{$_} = $c->flash->{$_} if $c->flash->{$_};
+ }
}
return 1;
@@ -201,7 +200,8 @@ sub format_problem_for_display : Private {
$c->stash->{add_alert} = 1;
}
- $c->stash->{extra_name_info} = $problem->bodies_str && $problem->bodies_str eq '2482' ? 1 : 0;
+ my $first_body = (values %{$problem->bodies})[0];
+ $c->stash->{extra_name_info} = $first_body && $first_body->name =~ /Bromley/ ? 1 : 0;
$c->forward('generate_map_tags');
@@ -309,38 +309,33 @@ sub inspect : Private {
$c->forward('/admin/categories_for_point');
$c->stash->{report_meta} = { map { $_->{name} => $_ } @{ $c->stash->{problem}->get_extra_fields() } };
- my %category_body = map { $_->category => $_->body_id } map { $_->contacts->all } values %{$problem->bodies};
-
- my @priorities = $c->model('DB::ResponsePriority')->for_bodies($problem->bodies_str_ids)->all;
- my $priorities_by_category = {};
- foreach my $pri (@priorities) {
- my $any = 0;
- foreach ($pri->contacts->all) {
- $any = 1;
- push @{$priorities_by_category->{$_->category}}, $pri->id . '=' . URI::Escape::uri_escape_utf8($pri->name);
- }
- if (!$any) {
- foreach (grep { $category_body{$_} == $pri->body_id } @{$c->stash->{categories}}) {
- push @{$priorities_by_category->{$_}}, $pri->id . '=' . URI::Escape::uri_escape_utf8($pri->name);
- }
- }
+ if ($c->cobrand->can('council_area_id')) {
+ my $priorities_by_category = FixMyStreet::App->model('DB::ResponsePriority')->by_categories($c->cobrand->council_area_id, @{$c->stash->{contacts}});
+ $c->stash->{priorities_by_category} = $priorities_by_category;
+ my $templates_by_category = FixMyStreet::App->model('DB::ResponseTemplate')->by_categories($c->cobrand->council_area_id, @{$c->stash->{contacts}});
+ $c->stash->{templates_by_category} = $templates_by_category;
}
- foreach (keys %{$priorities_by_category}) {
- $priorities_by_category->{$_} = join('&', @{$priorities_by_category->{$_}});
+
+ if ($c->user->has_body_permission_to('planned_reports')) {
+ $c->stash->{post_inspect_url} = $c->req->referer;
}
- $c->stash->{priorities_by_category} = $priorities_by_category;
+ if ($c->user->has_body_permission_to('report_edit_priority') or
+ $c->user->has_body_permission_to('report_inspect')
+ ) {
+ $c->stash->{has_default_priority} = scalar( grep { $_->is_default } $problem->response_priorities );
+ }
if ( $c->get_param('save') ) {
$c->forward('/auth/check_csrf_token');
my $valid = 1;
- my $update_text;
+ my $update_text = '';
my $reputation_change = 0;
my %update_params = ();
if ($permissions->{report_inspect}) {
- foreach (qw/detailed_information traffic_information duplicate_of/) {
+ foreach (qw/detailed_information traffic_information/) {
$problem->set_extra_metadata( $_ => $c->get_param($_) );
}
@@ -375,19 +370,35 @@ sub inspect : Private {
}
if ( $problem->state ne 'duplicate' ) {
$problem->unset_extra_metadata('duplicate_of');
+ } elsif (my $duplicate_of = $c->get_param('duplicate_of')) {
+ $problem->set_duplicate_of($duplicate_of);
}
+
if ( $problem->state ne $old_state ) {
$c->forward( '/admin/log_edit', [ $problem->id, 'problem', 'state_change' ] );
- # If the state has been changed by an inspector, consider the
- # report to be inspected.
- unless ($problem->get_extra_metadata('inspected')) {
- $problem->set_extra_metadata( inspected => 1 );
- $c->forward( '/admin/log_edit', [ $problem->id, 'problem', 'inspected' ] );
- my $state = $problem->state;
- $reputation_change = 1 if $c->cobrand->reputation_increment_states->{$state};
- $reputation_change = -1 if $c->cobrand->reputation_decrement_states->{$state};
- }
+ $update_params{problem_state} = $problem->state;
+
+ my $state = $problem->state;
+ $reputation_change = 1 if $c->cobrand->reputation_increment_states->{$state};
+ $reputation_change = -1 if $c->cobrand->reputation_decrement_states->{$state};
+
+ # If an inspector has changed the state, subscribe them to
+ # updates
+ my $options = {
+ cobrand => $c->cobrand->moniker,
+ cobrand_data => $problem->cobrand_data,
+ lang => $problem->lang,
+ };
+ $problem->user->create_alert($problem->id, $options);
+ }
+
+ # If the state has been changed to action scheduled and they've said
+ # they want to raise a defect, consider the report to be inspected.
+ if ($problem->state eq 'action scheduled' && $c->get_param('raise_defect') && !$problem->get_extra_metadata('inspected')) {
+ $update_params{extra} = { 'defect_raised' => 1 };
+ $problem->set_extra_metadata( inspected => 1 );
+ $c->forward( '/admin/log_edit', [ $problem->id, 'problem', 'inspected' ] );
}
}
@@ -421,39 +432,52 @@ sub inspect : Private {
}
$problem->lastupdate( \'current_timestamp' );
$problem->update;
- if ( defined($update_text) ) {
- my $timestamp = \'current_timestamp';
- if (my $saved_at = $c->get_param('saved_at')) {
- $timestamp = DateTime->from_epoch( epoch => $saved_at );
- }
- my $name = $c->user->from_body ? $c->user->from_body->name : $c->user->name;
- $problem->add_to_comments( {
- text => $update_text,
- created => $timestamp,
- confirmed => $timestamp,
- user_id => $c->user->id,
- name => $name,
- state => 'confirmed',
- mark_fixed => 0,
- anonymous => 0,
- %update_params,
- } );
+ my $timestamp = \'current_timestamp';
+ if (my $saved_at = $c->get_param('saved_at')) {
+ $timestamp = DateTime->from_epoch( epoch => $saved_at );
}
- # This problem might no longer be visible on the current cobrand,
- # if its body has changed (e.g. by virtue of the category changing)
- # so redirect to a cobrand where it can be seen if necessary
+ my $name = $c->user->from_body ? $c->user->from_body->name : $c->user->name;
+ $problem->add_to_comments( {
+ text => $update_text,
+ created => $timestamp,
+ confirmed => $timestamp,
+ user_id => $c->user->id,
+ name => $name,
+ state => 'confirmed',
+ mark_fixed => 0,
+ anonymous => 0,
+ %update_params,
+ } );
+
my $redirect_uri;
- if ( $c->cobrand->is_council && !$c->cobrand->owns_problem($problem) ) {
+ $problem->discard_changes;
+
+ # If inspector, redirect back to the map view they came from
+ # with the right filters. If that wasn't set, go to /around at this
+ # report's location.
+ # We go here rather than the shortlist because it makes it much
+ # simpler to inspect many reports in the same location. The
+ # shortlist is always a single click away, being on the main nav.
+ if ($c->user->has_body_permission_to('planned_reports')) {
+ unless ($redirect_uri = $c->get_param("post_inspect_url")) {
+ my $categories = join(',', @{ $c->user->categories });
+ my $params = {
+ lat => $problem->latitude,
+ lon => $problem->longitude,
+ };
+ $params->{filter_category} = $categories if $categories;
+ $params->{js} = 1 if $c->get_param('js');
+ $redirect_uri = $c->uri_for( "/around", $params );
+ }
+ } elsif ( $c->cobrand->is_council && !$c->cobrand->owns_problem($problem) ) {
+ # This problem might no longer be visible on the current cobrand,
+ # if its body has changed (e.g. by virtue of the category changing)
+ # so redirect to a cobrand where it can be seen if necessary
$redirect_uri = $c->cobrand->base_url_for_report( $problem ) . $problem->url;
} else {
$redirect_uri = $c->uri_for( $problem->url );
}
- # Or if inspector, redirect back to shortlist
- if ($c->user->has_body_permission_to('planned_reports')) {
- $redirect_uri = $c->uri_for_action('my/planned');
- }
-
$c->log->debug( "Redirecting to: " . $redirect_uri );
$c->res->redirect( $redirect_uri );
}
@@ -476,7 +500,7 @@ sub nearby_json : Private {
$c->forward( 'load_problem_or_display_error', [ $id ] );
my $p = $c->stash->{problem};
- my $dist = 1000;
+ my $dist = 1;
my $nearby = $c->model('DB::Nearby')->nearby(
$c, $dist, [ $p->id ], 5, $p->latitude, $p->longitude, undef, [ $p->category ], undef
@@ -496,7 +520,7 @@ sub nearby_json : Private {
);
my $json = { pins => \@pins };
- $json->{current} = $on_map_list_html if $on_map_list_html;
+ $json->{reports_list} = $on_map_list_html if $on_map_list_html;
my $body = encode_json($json);
$c->res->content_type('application/json; charset=utf-8');
$c->res->body($body);
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index 2a68b170e..f92a5cb22 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -99,12 +99,14 @@ 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_bodies');
+ $c->forward('setup_report_extra_fields');
$c->forward('generate_map');
$c->forward('check_for_category');
# deal with the user and report and check both are happy
return unless $c->forward('check_form_submitted');
+
$c->forward('/auth/check_csrf_token');
$c->forward('process_user');
$c->forward('process_report');
@@ -137,6 +139,7 @@ sub report_new_ajax : Path('mobile') : Args(0) {
}
$c->forward('setup_categories_and_bodies');
+ $c->forward('setup_report_extra_fields');
$c->forward('process_user');
$c->forward('process_report');
$c->forward('/photo/process_photo');
@@ -184,6 +187,7 @@ sub report_form_ajax : Path('ajax') : Args(0) {
}
$c->forward('setup_categories_and_bodies');
+ $c->forward('setup_report_extra_fields');
# render templates to get the html
my $category = $c->render_fragment( 'report/new/category.html');
@@ -200,8 +204,10 @@ sub report_form_ajax : Path('ajax') : Args(0) {
if ($c->user_exists) {
my @bodies = keys %{$c->stash->{bodies}};
my $ca_another_user = $c->user->has_permission_to('contribute_as_another_user', \@bodies);
- my $ca_body = $c->user->has_permission_to('contribute_as_body', \@bodies);
+ my $ca_anonymous_user = $c->user->has_permission_to('contribute_as_anonymous_user', \@bodies);
+ my $ca_body = $c->user->from_body && $c->user->has_permission_to('contribute_as_body', \@bodies);
$contribute_as->{another_user} = $ca_another_user if $ca_another_user;
+ $contribute_as->{anonymous_user} = $ca_anonymous_user if $ca_anonymous_user;
$contribute_as->{body} = $ca_body if $ca_body;
}
@@ -212,7 +218,6 @@ sub report_form_ajax : Path('ajax') : Args(0) {
category => $category,
extra_name_info => $extra_name_info,
titles_list => $extra_titles_list,
- categories => $c->stash->{category_options},
%$contribute_as ? (contribute_as => $contribute_as) : (),
$top_message ? (top_message => $top_message) : (),
}
@@ -233,6 +238,7 @@ sub category_extras_ajax : Path('category_extras') : Args(0) {
return 1;
}
$c->forward('setup_categories_and_bodies');
+ $c->forward('setup_report_extra_fields');
$c->forward('check_for_category');
my $category = $c->stash->{category} || "";
@@ -252,6 +258,9 @@ sub category_extras_ajax : Path('category_extras') : Args(0) {
if ($c->stash->{unresponsive}->{$category}) {
$generate = 1;
}
+ if ($c->stash->{report_extra_fields}) {
+ $generate = 1;
+ }
if ($generate) {
$category_extra = $c->render_fragment('report/new/category_extras.html', $vars);
}
@@ -493,7 +502,7 @@ Work out what the location of the report should be - either by using lat,lng or
a tile click or what's come in from a partial. Returns false if no location
could be found.
-=cut
+=cut
sub determine_location : Private {
my ( $self, $c ) = @_;
@@ -515,7 +524,7 @@ sub determine_location : Private {
Detect that the map tiles have been clicked on by looking for the tile
parameters.
-=cut
+=cut
sub determine_location_from_tile_click : Private {
my ( $self, $c ) = @_;
@@ -566,7 +575,7 @@ sub determine_location_from_tile_click : Private {
Use latitude and longitude stored in the report - this is probably result of a
partial report being loaded.
-=cut
+=cut
sub determine_location_from_report : Private {
my ( $self, $c ) = @_;
@@ -604,8 +613,8 @@ sub setup_categories_and_bodies : Private {
my $contacts #
= $c #
->model('DB::Contact') #
- ->not_deleted #
- ->search( { body_id => [ keys %bodies ] } );
+ ->active
+ ->search( { body_id => [ keys %bodies ] }, { prefetch => 'body' } );
my @contacts = $c->cobrand->categories_restriction($contacts)->all;
# variables to populate
@@ -632,13 +641,19 @@ sub setup_categories_and_bodies : Private {
# keysort does not appear to obey locale so use strcoll (see i18n.t)
@contacts = sort { strcoll( $a->category, $b->category ) } @contacts;
+ # Get defect types for inspectors
+ if ($c->cobrand->can('council_area_id')) {
+ my $category_defect_types = FixMyStreet::App->model('DB::DefectType')->by_categories($c->cobrand->council_area_id, @contacts);
+ $c->stash->{category_defect_types} = $category_defect_types;
+ }
+
my %seen;
foreach my $contact (@contacts) {
$bodies_to_list{ $contact->body_id } = $contact->body;
unless ( $seen{$contact->category} ) {
- push @category_options, $contact->category;
+ push @category_options, { name => $contact->category, value => $contact->category_display };
my $metas = $contact->get_metadata_for_input;
$category_extras{$contact->category} = $metas if @$metas;
@@ -650,13 +665,15 @@ sub setup_categories_and_bodies : Private {
$non_public_categories{ $contact->category } = 1 if $contact->non_public;
}
- $seen{$contact->category} = 1;
+ $seen{$contact->category} = $contact->category_display;
}
if (@category_options) {
# 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_options = (
+ { name => _('-- Pick a category --'), value => _('-- Pick a category --') },
+ grep { $_->{name} ne _('Other') } @category_options );
+ push @category_options, { name => _('Other'), value => $seen{_('Other')} } if $seen{_('Other')};
}
$c->cobrand->call_hook(munge_category_list => \@category_options, \@contacts, \%category_extras);
@@ -679,6 +696,15 @@ sub setup_categories_and_bodies : Private {
$c->stash->{missing_details_body_names} = \@missing_details_body_names;
}
+sub setup_report_extra_fields : Private {
+ my ( $self, $c ) = @_;
+
+ return unless $c->cobrand->allow_report_extra_fields;
+
+ my @extras = $c->model('DB::ReportExtraFields')->for_cobrand($c->cobrand)->for_language($c->stash->{lang_code})->all;
+ $c->stash->{report_extra_fields} = \@extras;
+}
+
=head2 check_form_submitted
$bool = $c->forward('check_form_submitted');
@@ -734,7 +760,8 @@ sub process_user : Private {
$user->title( $user_title ) if $user_title;
$report->user( $user );
- if ($c->stash->{contributing_as_body} = $user->contributing_as('body', $c, $c->stash->{bodies})) {
+ if ($c->stash->{contributing_as_body} = $user->contributing_as('body', $c, $c->stash->{bodies}) or
+ $c->stash->{contributing_as_anonymous_user} = $user->contributing_as('anonymous_user', $c, $c->stash->{bodies})) {
$report->name($user->from_body->name);
$user->name($user->from_body->name) unless $user->name;
$c->stash->{no_reporter_alert} = 1;
@@ -814,6 +841,8 @@ sub process_report : Private {
# set some simple bool values (note they get inverted)
if ($c->stash->{contributing_as_body}) {
$report->anonymous(0);
+ } elsif ($c->stash->{contributing_as_anonymous_user}) {
+ $report->anonymous(1);
} else {
$report->anonymous( $params{may_show_name} ? 0 : 1 );
}
@@ -933,7 +962,24 @@ sub set_report_extras : Private {
}
}
- $c->cobrand->process_open311_extras( $c, @$contacts[0]->body_id, \@extra )
+ foreach my $extra_fields (@{ $c->stash->{report_extra_fields} }) {
+ my $metas = $extra_fields->get_extra_fields;
+ $param_prefix = "extra[" . $extra_fields->id . "]";
+ foreach my $field ( @$metas ) {
+ if ( lc( $field->{required} ) eq 'true' && !$c->cobrand->category_extra_hidden($field->{code})) {
+ unless ( $c->get_param($param_prefix . $field->{code}) ) {
+ $c->stash->{field_errors}->{ $field->{code} } = _('This information is required');
+ }
+ }
+ push @extra, {
+ name => $field->{code},
+ description => $field->{description},
+ value => $c->get_param($param_prefix . $field->{code}) || '',
+ };
+ }
+ }
+
+ $c->cobrand->process_open311_extras( $c, @$contacts[0]->body, \@extra )
if ( scalar @$contacts );
if ( @extra ) {
@@ -1140,7 +1186,7 @@ sub save_user_and_report : Private {
sub created_as_someone_else : Private {
my ($self, $c, $bodies) = @_;
- return $c->stash->{contributing_as_another_user} || $c->stash->{contributing_as_body};
+ return $c->stash->{contributing_as_another_user} || $c->stash->{contributing_as_body} || $c->stash->{contributing_as_anonymous_user};
}
=head2 generate_map
@@ -1203,9 +1249,14 @@ sub redirect_or_confirm_creation : Private {
to => [ [ $report->user->email, $report->name ] ],
} );
}
- $c->log->info($report->user->id . ' was logged in, showing confirmation page for ' . $report->id);
- $c->stash->{created_report} = 'loggedin';
- $c->stash->{template} = 'tokens/confirm_problem.html';
+ if ($c->user_exists && $c->user->has_body_permission_to('planned_reports')) {
+ $c->log->info($report->user->id . ' is an inspector - redirecting straight to report page for ' . $report->id);
+ $c->res->redirect( '/report/'. $report->id );
+ } else {
+ $c->log->info($report->user->id . ' was logged in, showing confirmation page for ' . $report->id);
+ $c->stash->{created_report} = 'loggedin';
+ $c->stash->{template} = 'tokens/confirm_problem.html';
+ }
return 1;
}
diff --git a/perllib/FixMyStreet/App/Controller/Report/Update.pm b/perllib/FixMyStreet/App/Controller/Report/Update.pm
index 4c2d92d5e..033f5c017 100644
--- a/perllib/FixMyStreet/App/Controller/Report/Update.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/Update.pm
@@ -128,7 +128,7 @@ sub process_user : Private {
$update->user( $user );
# Just in case, make sure the user will have a name
- if ($c->stash->{contributing_as_body}) {
+ if ($c->stash->{contributing_as_body} or $c->stash->{contributing_as_anonymous_user}) {
$user->name($user->from_body->name) unless $user->name;
}
@@ -277,17 +277,19 @@ sub process_update : Private {
$update->mark_open($params{reopen} ? 1 : 0);
$c->stash->{contributing_as_body} = $c->user_exists && $c->user->contributing_as('body', $c, $update->problem->bodies_str_ids);
+ $c->stash->{contributing_as_anonymous_user} = $c->user_exists && $c->user->contributing_as('anonymous_user', $c, $update->problem->bodies_str_ids);
if ($c->stash->{contributing_as_body}) {
$update->name($c->user->from_body->name);
$update->anonymous(0);
+ } elsif ($c->stash->{contributing_as_anonymous_user}) {
+ $update->name($c->user->from_body->name);
+ $update->anonymous(1);
} else {
$update->name($name);
$update->anonymous($c->get_param('may_show_name') ? 0 : 1);
}
if ( $params{state} ) {
- $params{state} = 'fixed - 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
@@ -309,7 +311,8 @@ sub process_update : Private {
my @extra; # Next function fills this, but we don't need it here.
# This is just so that the error checking for these extra fields runs.
# TODO Use extra here as it is used on reports.
- $c->cobrand->process_open311_extras( $c, $update->problem->bodies_str, \@extra );
+ my $body = (values %{$update->problem->bodies})[0];
+ $c->cobrand->process_open311_extras( $c, $body, \@extra );
if ( $c->get_param('fms_extra_title') ) {
my %extras = ();
@@ -344,14 +347,11 @@ sub check_for_errors : Private {
my ( $self, $c ) = @_;
# they have to be an authority user to update the state
- if ( $c->get_param('state') ) {
+ my $state = $c->get_param('state');
+ if ( $state && $state ne $c->stash->{update}->problem->state ) {
my $error = 0;
$error = 1 unless $c->user && $c->user->belongs_to_body( $c->stash->{update}->problem->bodies_str );
-
- my $state = $c->get_param('state');
- $state = 'fixed - council' if $state eq 'fixed';
- $error = 1 unless ( grep { $state eq $_ } ( FixMyStreet::DB::Result::Problem->council_states() ) );
-
+ $error = 1 unless grep { $state eq $_ } FixMyStreet::DB::Result::Problem->visible_states();
if ( $error ) {
$c->stash->{errors} ||= [];
push @{ $c->stash->{errors} }, _('There was a problem with your update. Please try again.');
@@ -548,24 +548,17 @@ sub signup_for_alerts : Private {
my ( $self, $c ) = @_;
my $update = $c->stash->{update};
+ my $user = $update->user;
+ my $problem_id = $update->problem_id;
+
if ( $c->stash->{add_alert} ) {
my $options = {
- user => $update->user,
- alert_type => 'new_updates',
- parameter => $update->problem_id,
+ cobrand => $update->cobrand,
+ cobrand_data => $update->cobrand_data,
+ lang => $update->lang,
};
- my $alert = $c->model('DB::Alert')->find($options);
- unless ($alert) {
- $alert = $c->model('DB::Alert')->create({
- %$options,
- cobrand => $update->cobrand,
- cobrand_data => $update->cobrand_data,
- lang => $update->lang,
- });
- }
- $alert->confirm();
-
- } elsif ( my $alert = $update->user->alert_for_problem($update->problem_id) ) {
+ $user->create_alert($problem_id, $options);
+ } elsif ( my $alert = $user->alert_for_problem($problem_id) ) {
$alert->disable();
}
diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm
index ed851f71f..8f8205719 100644
--- a/perllib/FixMyStreet/App/Controller/Reports.pm
+++ b/perllib/FixMyStreet/App/Controller/Reports.pm
@@ -36,6 +36,12 @@ sub index : Path : Args(0) {
if ( $c->cobrand->moniker eq 'zurich' ) {
$c->forward( 'stash_report_filter_status' );
$c->forward( 'load_and_group_problems' );
+ $c->stash->{body} = { id => 0 }; # So template can fetch the list
+
+ if ($c->get_param('ajax')) {
+ $c->detach('ajax', [ 'reports/_problem-list.html' ]);
+ }
+
my $pins = $c->stash->{pins};
$c->stash->{page} = 'reports';
FixMyStreet::Map::display_map(
@@ -54,6 +60,15 @@ sub index : Path : Args(0) {
$c->detach( 'redirect_body' );
}
+ if (my $body = $c->get_param('body')) {
+ $body = $c->model('DB::Body')->find( { id => $body } );
+ if ($body) {
+ $body = $c->cobrand->short_name($body);
+ $c->res->redirect("/reports/$body");
+ $c->detach;
+ }
+ }
+
# Fetch all bodies
my @bodies = $c->model('DB::Body')->search({
deleted => 0,
@@ -67,15 +82,21 @@ sub index : Path : Args(0) {
$c->stash->{bodies} = \@bodies;
$c->stash->{any_empty_bodies} = any { $_->get_column('area_count') == 0 } @bodies;
- eval {
+ my $dashboard = eval {
+ my $data = File::Slurp::read_file(
+ FixMyStreet->path_to( '../data/all-reports-dashboard.json' )->stringify
+ );
+ $c->stash(decode_json($data));
+ return 1;
+ };
+ my $table = eval {
my $data = File::Slurp::read_file(
FixMyStreet->path_to( '../data/all-reports.json' )->stringify
);
- my $j = decode_json($data);
- $c->stash->{fixed} = $j->{fixed};
- $c->stash->{open} = $j->{open};
+ $c->stash(decode_json($data));
+ return 1;
};
- if ($@) {
+ if (!$dashboard && !$table) {
my $message = _("There was a problem showing the All Reports page. Please try again later.");
if ($c->config->{STAGING_SITE}) {
$message .= '</p><p>Perhaps the bin/update-all-reports script needs running. Use: bin/update-all-reports</p><p>'
@@ -88,7 +109,7 @@ sub index : Path : Args(0) {
$c->response->header('Cache-Control' => 'max-age=3600');
}
-=head2 index
+=head2 body
Show the summary page for a particular body.
@@ -99,7 +120,7 @@ sub body : Path : Args(1) {
$c->detach( 'ward', [ $body ] );
}
-=head2 index
+=head2 ward
Show the summary page for a particular ward.
@@ -135,7 +156,7 @@ sub ward : Path : Args(2) {
distinct => 1,
order_by => [ 'category' ],
} )->all;
- @categories = map { $_->category } @categories;
+ @categories = map { { name => $_->category, value => $_->category_display } } @categories;
$c->stash->{filter_categories} = \@categories;
$c->stash->{filter_category} = { map { $_ => 1 } $c->get_param_list('filter_category', 1) };
@@ -303,6 +324,19 @@ sub body_check : Private {
}
}
+ my @translations = $c->model('DB::Translation')->search( {
+ tbl => 'body',
+ col => 'name',
+ msgstr => $q_body
+ } )->all;
+
+ if (@translations == 1) {
+ if ( my $body = $c->model('DB::Body')->find( { id => $translations[0]->object_id } ) ) {
+ $c->stash->{body} = $body;
+ return;
+ }
+ }
+
# No result, bad body name.
$c->detach( 'redirect_index' );
}
@@ -369,8 +403,6 @@ sub load_and_group_problems : Private {
$c->forward('stash_report_sort', [ $c->cobrand->reports_ordering ]);
my $page = $c->get_param('p') || 1;
- # NB: If 't' is specified, it will override 'status'.
- my $type = $c->get_param('t') || 'all';
my $category = [ $c->get_param_list('filter_category', 1) ];
my $states = $c->stash->{filter_problem_states};
@@ -382,6 +414,18 @@ sub load_and_group_problems : Private {
order_by => $c->stash->{sort_order},
rows => $c->cobrand->reports_per_page,
};
+ if ($c->user_exists && $c->stash->{body}) {
+ my $bid = $c->stash->{body}->id;
+ my $prefetch = [];
+ if ($c->user->has_permission_to('planned_reports', $bid)) {
+ push @$prefetch, 'user_planned_reports';
+ }
+ if ($c->user->has_permission_to('report_edit_priority', $bid) || $c->user->has_permission_to('report_inspect', $bid)) {
+ push @$prefetch, 'response_priority';
+ }
+ $prefetch = $prefetch->[0] if @$prefetch == 1;
+ $filter->{prefetch} = $prefetch;
+ }
if (defined $c->stash->{filter_status}{shortlisted}) {
$where->{'me.id'} = { '=', \"user_planned_reports.report_id"};
@@ -398,25 +442,6 @@ sub load_and_group_problems : Private {
$where->{'me.id'} = { -not_in => $shortlisted_ids };
}
- my $not_open = [ FixMyStreet::DB::Result::Problem::fixed_states(), FixMyStreet::DB::Result::Problem::closed_states() ];
- if ( $type eq 'new' ) {
- $where->{confirmed} = { '>', \"current_timestamp - INTERVAL '4 week'" };
- $where->{state} = { 'IN', [ FixMyStreet::DB::Result::Problem::open_states() ] };
- } elsif ( $type eq 'older' ) {
- $where->{confirmed} = { '<', \"current_timestamp - INTERVAL '4 week'" };
- $where->{lastupdate} = { '>', \"current_timestamp - INTERVAL '8 week'" };
- $where->{state} = { 'IN', [ FixMyStreet::DB::Result::Problem::open_states() ] };
- } elsif ( $type eq 'unknown' ) {
- $where->{lastupdate} = { '<', \"current_timestamp - INTERVAL '8 week'" };
- $where->{state} = { 'IN', [ FixMyStreet::DB::Result::Problem::open_states() ] };
- } elsif ( $type eq 'fixed' ) {
- $where->{lastupdate} = { '>', \"current_timestamp - INTERVAL '8 week'" };
- $where->{state} = $not_open;
- } elsif ( $type eq 'older_fixed' ) {
- $where->{lastupdate} = { '<', \"current_timestamp - INTERVAL '8 week'" };
- $where->{state} = $not_open;
- }
-
if (@$category) {
$where->{category} = $category;
}
@@ -445,7 +470,6 @@ sub load_and_group_problems : Private {
my ( %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;
@@ -531,6 +555,18 @@ sub stash_report_filter_status : Private {
$filter_status{unshortlisted} = 1;
}
+ if ($c->user and ($c->user->is_superuser or (
+ $c->stash->{body} and $c->user->belongs_to_body($c->stash->{body}->id)
+ ))) {
+ $c->stash->{filter_states} = $c->cobrand->state_groups_inspect;
+ foreach my $state (FixMyStreet::DB::Result::Problem->visible_states()) {
+ if ($status{$state}) {
+ $filter_problem_states{$state} = 1;
+ $filter_status{$state} = 1;
+ }
+ }
+ }
+
if (keys %filter_problem_states == 0) {
my $s = FixMyStreet::DB::Result::Problem->open_states();
%filter_problem_states = (%filter_problem_states, %$s);
diff --git a/perllib/FixMyStreet/App/Controller/Root.pm b/perllib/FixMyStreet/App/Controller/Root.pm
index 4f098dfc3..7f70623ae 100644
--- a/perllib/FixMyStreet/App/Controller/Root.pm
+++ b/perllib/FixMyStreet/App/Controller/Root.pm
@@ -16,6 +16,18 @@ FixMyStreet::App::Controller::Root - Root Controller for FixMyStreet::App
=head1 METHODS
+=head2 begin
+
+Any pre-flight checking for all requests
+
+=cut
+sub begin : Private {
+ my ( $self, $c ) = @_;
+
+ $c->forward( 'check_login_required' );
+}
+
+
=head2 auto
Set up general things for this instance
@@ -58,6 +70,11 @@ sub index : Path : Args(0) {
return;
}
+ if ($c->stash->{homepage_template}) {
+ $c->stash->{template} = $c->stash->{homepage_template};
+ $c->detach;
+ }
+
$c->forward('/auth/get_csrf_token');
}
@@ -125,6 +142,27 @@ sub page_error : Private {
$c->response->status($code);
}
+sub check_login_required : Private {
+ my ($self, $c) = @_;
+
+ return if $c->user_exists || !FixMyStreet->config('LOGIN_REQUIRED');
+
+ # Whitelisted URL patterns are allowed without login
+ my $whitelist = qr{
+ ^auth(/|$)
+ | ^js/translation_strings\.(.*?)\.js
+ | ^[PACQM]/ # various tokens that log the user in
+ }x;
+ return if $c->request->path =~ $whitelist;
+
+ # Blacklisted URLs immediately 404
+ # This is primarily to work around a Safari bug where the appcache
+ # URL is requested in an infinite loop if it returns a 302 redirect.
+ $c->detach('/page_error_404_not_found', []) if $c->request->path =~ /^offline/;
+
+ $c->detach( '/auth/redirect' );
+}
+
=head2 end
Attempt to render a view, if needed.
diff --git a/perllib/FixMyStreet/App/Controller/Rss.pm b/perllib/FixMyStreet/App/Controller/Rss.pm
index 28f1aba43..3497ad0e1 100755
--- a/perllib/FixMyStreet/App/Controller/Rss.pm
+++ b/perllib/FixMyStreet/App/Controller/Rss.pm
@@ -3,6 +3,7 @@ package FixMyStreet::App::Controller::Rss;
use Moose;
use namespace::autoclean;
use POSIX qw(strftime);
+use HTML::Entities;
use URI::Escape;
use XML::RSS;
@@ -11,8 +12,7 @@ use FixMyStreet::App::Model::PhotoSet;
use FixMyStreet::Gaze;
use mySociety::Locale;
use mySociety::MaPit;
-use mySociety::Sundries qw(ordinal);
-use mySociety::Web qw(ent);
+use Lingua::EN::Inflect qw(ORD);
BEGIN { extends 'Catalyst::Controller'; }
@@ -250,7 +250,7 @@ sub add_row : Private {
};
$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';
+ $row->{created} =~ s/^(\d+)/ORD($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)/;
@@ -259,7 +259,7 @@ sub add_row : Private {
};
$row->{confirmed} = strftime("%e %B", $6, $5, $4, $3, $2-1, $1-1900, -1, -1, 0);
$row->{confirmed} =~ s/^\s+//;
- $row->{confirmed} =~ s/^(\d+)/ordinal($1)/e if $c->stash->{lang_code} eq 'en-gb';
+ $row->{confirmed} =~ s/^(\d+)/ORD($1)/e if $c->stash->{lang_code} eq 'en-gb';
}
(my $title = _($alert_type->item_title)) =~ s/\{\{(.*?)}}/$row->{$1}/g;
@@ -270,13 +270,13 @@ sub add_row : Private {
my $url = $base_url . $link;
my %item = (
- title => ent($title),
+ title => encode_entities($title),
link => $url,
guid => $url,
- description => ent(ent($desc)) # Yes, double-encoded, really.
+ description => encode_entities(encode_entities($desc)) # Yes, double-encoded, really.
);
$item{pubDate} = $pubDate if $pubDate;
- $item{category} = ent($row->{category}) if $row->{category};
+ $item{category} = encode_entities($row->{category}) if $row->{category};
if ($c->cobrand->allow_photo_display($row) && $row->{photo}) {
# Bit yucky as we don't have full objects here
@@ -285,16 +285,16 @@ sub add_row : Private {
my ($hash, $format) = split /\./, $first_fn;
my $cachebust = substr($hash, 0, 8);
my $key = $alert_type->item_table eq 'comment' ? 'c/' : '';
- $item{description} .= ent("\n<br><img src=\"". $base_url . "/photo/$key$row->{id}.0.$format?$cachebust\">");
+ $item{description} .= encode_entities("\n<br><img src=\"". $base_url . "/photo/$key$row->{id}.0.$format?$cachebust\">");
}
if ( $row->{used_map} ) {
- my $address = $c->cobrand->find_closest_address_for_rss( $row->{latitude}, $row->{longitude}, $row );
- $item{description} .= ent("\n<br>$address") if $address;
+ my $address = $c->cobrand->find_closest_address_for_rss($row);
+ $item{description} .= encode_entities("\n<br>$address") if $address;
}
my $recipient_name = $c->cobrand->contact_name;
- $item{description} .= ent("\n<br><a href='$url'>" .
+ $item{description} .= encode_entities("\n<br><a href='$url'>" .
sprintf(_("Report on %s"), $recipient_name) . "</a>");
if ($row->{latitude} || $row->{longitude}) {
@@ -329,9 +329,9 @@ sub add_parameters : Private {
(my $desc = _($alert_type->head_description)) =~ s/\{\{(.*?)}}/$row->{$1}/g;
$c->stash->{rss}->channel(
- title => ent($title),
+ title => encode_entities($title),
link => $c->uri_for($link) . ($c->stash->{qs} || ''),
- description => ent($desc),
+ description => encode_entities($desc),
language => 'en-gb',
);
}
diff --git a/perllib/FixMyStreet/App/Model/DB.pm b/perllib/FixMyStreet/App/Model/DB.pm
index ac1f98dc9..c116abffc 100644
--- a/perllib/FixMyStreet/App/Model/DB.pm
+++ b/perllib/FixMyStreet/App/Model/DB.pm
@@ -5,11 +5,26 @@ use strict;
use warnings;
use FixMyStreet;
+use Catalyst::Utils;
+use Moose;
+
+with 'Catalyst::Component::InstancePerContext';
__PACKAGE__->config(
- schema_class => 'FixMyStreet::DB',
- connect_info => sub { FixMyStreet::DB->storage->dbh },
+ schema_class => 'FixMyStreet::DB::Schema',
+ connect_info => sub { FixMyStreet::DB->schema->storage->dbh },
);
+__PACKAGE__->config(
+ traits => ['QueryLog::AdoptPlack'],
+)
+ if Catalyst::Utils::env_value( 'FixMyStreet::App', 'DEBUG' );
+
+sub build_per_context_instance {
+ my ( $self, $c ) = @_;
+ # $self->schema->cobrand($c->cobrand);
+ $self->schema->cache({});
+ return $self;
+}
=head1 NAME
@@ -17,7 +32,7 @@ FixMyStreet::App::Model::DB - Catalyst DBIC Schema Model
=head1 DESCRIPTION
-L<Catalyst::Model::DBIC::Schema> Model using schema L<FixMyStreet::DB>
+L<Catalyst::Model::DBIC::Schema> Model using schema L<FixMyStreet::DB::Schema>
=cut
diff --git a/perllib/FixMyStreet/App/View/Web.pm b/perllib/FixMyStreet/App/View/Web.pm
index 496463700..93aa0e2fb 100644
--- a/perllib/FixMyStreet/App/View/Web.pm
+++ b/perllib/FixMyStreet/App/View/Web.pm
@@ -18,6 +18,7 @@ __PACKAGE__->config(
expose_methods => [
'tprintf', 'prettify_dt',
'version', 'decode',
+ 'prettify_state',
],
FILTERS => {
add_links => \&add_links,
@@ -167,5 +168,11 @@ sub decode {
return $text;
}
+sub prettify_state {
+ my ($self, $c, $text, $single_fixed) = @_;
+
+ return FixMyStreet::DB->resultset("State")->display($text, $single_fixed);
+}
+
1;