aboutsummaryrefslogtreecommitdiffstats
path: root/perllib
diff options
context:
space:
mode:
Diffstat (limited to 'perllib')
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm3
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin/Triage.pm163
-rw-r--r--perllib/FixMyStreet/App/Controller/Around.pm14
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm11
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm19
-rw-r--r--perllib/FixMyStreet/App/Controller/Reports.pm5
-rw-r--r--perllib/FixMyStreet/Cobrand/FixMyStreet.pm112
-rw-r--r--perllib/FixMyStreet/Cobrand/IsleOfWight.pm236
-rw-r--r--perllib/FixMyStreet/Cobrand/UKCouncils.pm6
-rw-r--r--perllib/FixMyStreet/DB/Result/Comment.pm2
-rw-r--r--perllib/FixMyStreet/DB/Result/Problem.pm2
-rw-r--r--perllib/FixMyStreet/DB/Result/User.pm6
-rw-r--r--perllib/FixMyStreet/Map/IsleOfWight.pm63
-rw-r--r--perllib/FixMyStreet/SendReport/Triage.pm20
-rwxr-xr-xperllib/Open311/PostServiceRequestUpdates.pm10
15 files changed, 648 insertions, 24 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm
index 5373220a7..c2c4e7588 100644
--- a/perllib/FixMyStreet/App/Controller/Admin.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin.pm
@@ -678,6 +678,9 @@ sub categories_for_point : Private {
shift @{$c->stash->{category_options}} if @{$c->stash->{category_options}};
$c->stash->{categories_hash} = { map { $_->category => 1 } @{$c->stash->{category_options}} };
+
+ $c->forward('/admin/triage/setup_categories');
+
}
sub alerts_for_report : Private {
diff --git a/perllib/FixMyStreet/App/Controller/Admin/Triage.pm b/perllib/FixMyStreet/App/Controller/Admin/Triage.pm
new file mode 100644
index 000000000..385248cd1
--- /dev/null
+++ b/perllib/FixMyStreet/App/Controller/Admin/Triage.pm
@@ -0,0 +1,163 @@
+package FixMyStreet::App::Controller::Admin::Triage;
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'Catalyst::Controller'; }
+
+=head1 NAME
+
+FixMyStreet::App::Controller::Admin::Triage - Catalyst Controller
+
+=head1 DESCRIPTION
+
+Admin pages for triaging reports.
+
+This allows reports to be triaged before being sent to the council. It works
+by having a set of categories with a send_method of Triage which sets the report
+state to 'for_triage'. Any reports with the state are then show on '/admin/triage'
+which is available to users with the 'triage' permission.
+
+Clicking on reports on this list will then allow a user to change the category of
+the report to one that has an alternative send method, which will trigger the report
+to be resent.
+
+In order for this to work additional work needs to be done to the cobrand to only
+display triageable categories to the user.
+
+=head1 METHODS
+
+=cut
+
+sub auto : Private {
+ my ( $self, $c ) = @_;
+
+ unless ( $c->user->has_body_permission_to('triage') ) {
+ $c->detach('/page_error_403_access_denied', []);
+ }
+}
+
+sub index : Path : Args(0) {
+ my ( $self, $c ) = @_;
+
+ # default sort to oldest
+ unless ( $c->get_param('sort') ) {
+ $c->set_param('sort', 'created-asc');
+ }
+ $c->stash->{body} = $c->forward('/reports/body_find', [ $c->cobrand->council_area ]);
+ $c->forward( 'stash_report_filter_status' );
+ $c->forward( '/reports/load_and_group_problems' );
+ $c->stash->{page} = 'reports'; # So the map knows to make clickable pins
+
+ if ($c->get_param('ajax')) {
+ my $ajax_template = $c->stash->{ajax_template} || 'reports/_problem-list.html';
+ $c->detach('/reports/ajax', [ $ajax_template ]);
+ }
+
+ my @categories = $c->stash->{body}->contacts->not_deleted->search( undef, {
+ columns => [ 'id', 'category', 'extra' ],
+ distinct => 1,
+ order_by => [ 'category' ],
+ } )->all;
+ $c->stash->{filter_categories} = \@categories;
+ $c->stash->{filter_category} = { map { $_ => 1 } $c->get_param_list('filter_category', 1) };
+ my $pins = $c->stash->{pins} || [];
+
+ my %map_params = (
+ latitude => @$pins ? $pins->[0]{latitude} : 0,
+ longitude => @$pins ? $pins->[0]{longitude} : 0,
+ area => [ $c->stash->{wards} ? map { $_->{id} } @{$c->stash->{wards}} : keys %{$c->stash->{body}->areas} ],
+ any_zoom => 1,
+ );
+ FixMyStreet::Map::display_map(
+ $c, %map_params, pins => $pins,
+ );
+}
+
+sub stash_report_filter_status : Private {
+ my ( $self, $c ) = @_;
+ $c->stash->{filter_problem_states} = { 'for triage' => 1 };
+ return 1;
+}
+
+sub setup_categories : Private {
+ my ( $self, $c ) = @_;
+
+ if ( $c->stash->{problem}->state eq 'for triage' ) {
+ $c->stash->{holding_options} = [ grep { $_->send_method && $_->send_method eq 'Triage' } @{$c->stash->{category_options}} ];
+ $c->stash->{holding_categories} = { map { $_->category => 1 } @{$c->stash->{holding_options}} };
+ $c->stash->{end_options} = [ grep { !$_->send_method || $_->send_method ne 'Triage' } @{$c->stash->{category_options}} ];
+ $c->stash->{end_categories} = { map { $_->category => 1 } @{$c->stash->{end_options}} };
+ delete $c->stash->{categories_hash};
+ my %category_groups = ();
+ for my $category (@{$c->stash->{end_options}}) {
+ my $group = $category->{group} // $category->get_extra_metadata('group') // [''];
+ # this could be an array ref or a string
+ my @groups = ref $group eq 'ARRAY' ? @$group : ($group);
+ push( @{$category_groups{$_}}, $category ) for @groups;
+ }
+ my @category_groups = ();
+ for my $group ( grep { $_ ne _('Other') } sort keys %category_groups ) {
+ push @category_groups, { name => $group, categories => $category_groups{$group} };
+ }
+ $c->stash->{end_groups} = \@category_groups;
+ }
+
+ return 1;
+}
+
+sub update : Private {
+ my ($self, $c) = @_;
+
+ my $problem = $c->stash->{problem};
+
+ my $current_category = $problem->category;
+ my $new_category = $c->get_param('category');
+
+ my $changed = $c->forward('/admin/report_edit_category', [ $problem, 1 ] );
+
+ if ( $changed ) {
+ $c->stash->{problem}->update( { state => 'confirmed' } );
+ $c->forward( '/admin/log_edit', [ $problem->id, 'problem', 'triage' ] );
+
+ my $name = $c->user->moderating_user_name;
+ my $extra = { is_superuser => 1 };
+ if ($c->user->from_body) {
+ delete $extra->{is_superuser};
+ $extra->{is_body_user} = $c->user->from_body->id;
+ }
+
+ $extra->{triage_report} = 1;
+ $extra->{holding_category} = $current_category;
+ $extra->{new_category} = $new_category;
+
+ my $timestamp = \'current_timestamp';
+ my $comment = $problem->add_to_comments( {
+ text => "Report triaged from $current_category to $new_category",
+ created => $timestamp,
+ confirmed => $timestamp,
+ user_id => $c->user->id,
+ name => $name,
+ mark_fixed => 0,
+ anonymous => 0,
+ state => 'confirmed',
+ problem_state => $problem->state,
+ extra => $extra,
+ whensent => \'current_timestamp',
+ } );
+
+ my @alerts = FixMyStreet::DB->resultset('Alert')->search( {
+ alert_type => 'new_updates',
+ parameter => $problem->id,
+ confirmed => 1,
+ } );
+
+ for my $alert (@alerts) {
+ my $alerts_sent = FixMyStreet::DB->resultset('AlertSent')->find_or_create( {
+ alert_id => $alert->id,
+ parameter => $comment->id,
+ } );
+ }
+ }
+}
+
+1;
diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm
index 203296c4d..ebb3d4839 100644
--- a/perllib/FixMyStreet/App/Controller/Around.pm
+++ b/perllib/FixMyStreet/App/Controller/Around.pm
@@ -234,12 +234,18 @@ sub check_and_stash_category : Private {
my @list_of_names = map { $_->name } values %bodies;
my $csv = Text::CSV->new();
$csv->combine(@list_of_names);
+ $c->stash->{bodies} = \@bodies;
$c->{stash}->{list_of_names_as_string} = $csv->string;
+ my $where = { body_id => [ keys %bodies ], };
+
+ my $cobrand_where = $c->cobrand->call_hook('munge_around_category_where', $where );
+ if ( $cobrand_where ) {
+ $where = $cobrand_where;
+ }
+
my @categories = $c->model('DB::Contact')->not_deleted->search(
- {
- body_id => [ keys %bodies ],
- },
+ $where,
{
columns => [ 'category', 'extra' ],
order_by => [ 'category' ],
@@ -252,6 +258,7 @@ sub check_and_stash_category : Private {
my $categories = [ $c->get_param_list('filter_category', 1) ];
my %valid_categories = map { $_ => 1 } grep { $_ && $categories_mapped{$_} } @$categories;
$c->stash->{filter_category} = \%valid_categories;
+ $c->cobrand->call_hook('munge_around_filter_category_list');
}
sub map_features : Private {
@@ -312,6 +319,7 @@ sub ajax : Path('/ajax') {
my %valid_categories = map { $_ => 1 } $c->get_param_list('filter_category', 1);
$c->stash->{filter_category} = \%valid_categories;
+ $c->cobrand->call_hook('munge_around_filter_category_list');
$c->forward('map_features', [ { bbox => $c->stash->{bbox} } ]);
$c->forward('/reports/ajax', [ 'around/on_map_list_items.html' ]);
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm
index 9b90da161..eb6050fde 100644
--- a/perllib/FixMyStreet/App/Controller/Report.pm
+++ b/perllib/FixMyStreet/App/Controller/Report.pm
@@ -86,7 +86,7 @@ sub display :PathPart('') :Chained('id') :Args(0) {
$c->forward( 'format_problem_for_display' );
my $permissions = $c->stash->{_permissions} ||= $c->forward( 'check_has_permission_to',
- [ qw/report_inspect report_edit_category report_edit_priority report_mark_private/ ] );
+ [ qw/report_inspect report_edit_category report_edit_priority report_mark_private triage/ ] );
if (any { $_ } values %$permissions) {
$c->stash->{template} = 'report/inspect.html';
$c->forward('inspect');
@@ -396,7 +396,14 @@ sub inspect : Private {
$c->stash->{max_detailed_info_length} = $c->cobrand->max_detailed_info_length;
- if ( $c->get_param('save') ) {
+ if ( $c->get_param('triage') ) {
+ $c->forward('/auth/check_csrf_token');
+ $c->forward('/admin/triage/update');
+ my $redirect_uri = $c->uri_for( '/admin/triage' );
+ $c->log->debug( "Redirecting to: " . $redirect_uri );
+ $c->res->redirect( $redirect_uri );
+ }
+ elsif ( $c->get_param('save') ) {
$c->forward('/auth/check_csrf_token');
my $valid = 1;
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index 554fbc3b7..9b7a925b8 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -261,15 +261,20 @@ sub category_extras_ajax : Path('category_extras') : Args(0) {
sub by_category_ajax_data : Private {
my ($self, $c, $type, $category) = @_;
- my $bodies = $c->forward('contacts_to_bodies', [ $category ]);
- my $list_of_names = [ map { $_->name } ($category ? @$bodies : values %{$c->stash->{bodies_to_list}}) ];
- my $vars = {
- $category ? (list_of_names => $list_of_names) : (),
- };
+ my @bodies;
+ my $bodies = [];
+ my $vars = {};
+ if ($category) {
+ $bodies = $c->forward('contacts_to_bodies', [ $category ]);
+ @bodies = @$bodies;
+ $vars->{list_of_names} = [ map { $_->cobrand_name } @bodies ];
+ } else {
+ @bodies = values %{$c->stash->{bodies_to_list}};
+ }
my $non_public = $c->stash->{non_public_categories}->{$category};
my $body = {
- bodies => $list_of_names,
+ bodies => [ map { $_->name } @bodies ],
$non_public ? ( non_public => JSON->true ) : (),
};
@@ -743,7 +748,7 @@ sub setup_categories_and_bodies : Private {
push @category_options, $seen{_('Other')} if $seen{_('Other')};
}
- $c->cobrand->call_hook(munge_category_list => \@category_options, \@contacts, \%category_extras);
+ $c->cobrand->call_hook(munge_report_new_category_list => \@category_options, \@contacts, \%category_extras);
# put results onto stash for display
$c->stash->{bodies} = \%bodies;
diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm
index d8d52a2d9..741cbb60f 100644
--- a/perllib/FixMyStreet/App/Controller/Reports.pm
+++ b/perllib/FixMyStreet/App/Controller/Reports.pm
@@ -165,10 +165,13 @@ sub ward : Path : Args(2) {
$c->stash->{stats} = $c->cobrand->get_report_stats();
my @categories = $c->stash->{body}->contacts->not_deleted->search( undef, {
- columns => [ 'id', 'category', 'extra' ],
+ columns => [ 'id', 'category', 'extra', 'body_id', 'send_method' ],
distinct => 1,
order_by => [ 'category' ],
} )->all;
+
+ $c->cobrand->call_hook('munge_reports_category_list', \@categories);
+
$c->stash->{filter_categories} = \@categories;
$c->stash->{filter_category} = { map { $_ => 1 } $c->get_param_list('filter_category', 1) };
diff --git a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm
index e5327b084..38e9e09a0 100644
--- a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm
+++ b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm
@@ -7,6 +7,7 @@ use warnings;
use mySociety::Random;
use constant COUNCIL_ID_BROMLEY => 2482;
+use constant COUNCIL_ID_ISLEOFWIGHT => 2636;
sub on_map_default_status { return 'open'; }
@@ -37,13 +38,116 @@ sub restriction {
return {};
}
-sub munge_category_list {
+sub munge_around_category_where {
+ my ($self, $where) = @_;
+
+ my $user = $self->{c}->user;
+ my @iow = grep { $_->name eq 'Isle of Wight Council' } @{ $self->{c}->stash->{bodies} };
+ return unless @iow;
+
+ # display all the categories on Isle of Wight at the moment as there's no way to
+ # do the expand bit later as we fetch it using ajax which uses a bounding box so
+ # can't determine the body
+ $where->{send_method} = [ { '!=' => 'Triage' }, undef ];
+ return $where;
+}
+
+sub munge_reports_categories_list {
+ my ($self, $categories) = @_;
+
+ my %bodies = map { $_->body->name => $_->body } @$categories;
+ if ( $bodies{'Isle of Wight Council'} ) {
+ my $user = $self->{c}->user;
+ my $b = $bodies{'Isle of Wight Council'};
+
+ if ( $user && ( $user->is_superuser || $user->belongs_to_body( $b->id ) ) ) {
+ @$categories = grep { !$_->send_method || $_->send_method ne 'Triage' } @$categories;
+ return @$categories;
+ }
+
+ @$categories = grep { $_->send_method && $_->send_method eq 'Triage' } @$categories;
+ return @$categories;
+ }
+}
+
+sub munge_report_new_category_list {
my ($self, $options, $contacts, $extras) = @_;
# No TfL Traffic Lights category in Hounslow
- my %bodies = map { $_->body->name => 1 } @$contacts;
- return unless $bodies{'Hounslow Borough Council'};
- @$options = grep { ($_->{category} || $_->category) !~ /^Traffic lights$/i } @$options;
+ my %bodies = map { $_->body->name => $_->body } @$contacts;
+ if ( $bodies{'Hounslow Borough Council'} ) {
+ @$options = grep { ($_->{category} || $_->category) !~ /^Traffic lights$/i } @$options;
+ }
+
+ if ( $bodies{'Isle of Wight Council'} ) {
+ my $user = $self->{c}->user;
+ if ( $user && ( $user->is_superuser || $user->belongs_to_body( $bodies{'Isle of Wight Council'}->id ) ) ) {
+ @$contacts = grep { !$_->send_method || $_->send_method ne 'Triage' } @$contacts;
+ my $seen = { map { $_->category => 1 } @$contacts };
+ @$options = grep { my $c = ($_->{category} || $_->category); $c =~ 'Pick a category' || $seen->{ $c } } @$options;
+ return;
+ }
+
+ @$contacts = grep { $_->send_method && $_->send_method eq 'Triage' } @$contacts;
+ my $seen = { map { $_->category => 1 } @$contacts };
+ @$options = grep { my $c = ($_->{category} || $_->category); $c =~ 'Pick a category' || $seen->{ $c } } @$options;
+ }
+}
+
+sub munge_load_and_group_problems {
+ my ($self, $where, $filter) = @_;
+
+ return unless $where->{category} && $self->{c}->stash->{body}->name eq 'Isle of Wight Council';
+
+ my $cat_names = $self->expand_triage_cat_list($where->{category});
+
+ $where->{category} = $cat_names;
+ my $problems = $self->problems->search($where, $filter);
+ return $problems;
+}
+
+sub expand_triage_cat_list {
+ my ($self, $categories) = @_;
+
+ my $b = $self->{c}->stash->{body};
+
+ my $all_cats = $self->{c}->model('DB::Contact')->not_deleted->search(
+ {
+ body_id => $b->id,
+ send_method => [{ '!=', 'Triage'}, undef]
+ }
+ );
+
+ my %group_to_category;
+ while ( my $cat = $all_cats->next ) {
+ next unless $cat->get_extra_metadata('group');
+ my $groups = $cat->get_extra_metadata('group');
+ $groups = ref $groups eq 'ARRAY' ? $groups : [ $groups ];
+ for my $group ( @$groups ) {
+ $group_to_category{$group} //= [];
+ push @{ $group_to_category{$group} }, $cat->category;
+ }
+ }
+
+ my $cats = $self->{c}->model('DB::Contact')->not_deleted->search(
+ {
+ body_id => $b->id,
+ category => $categories
+ }
+ );
+
+ my @cat_names;
+ while ( my $cat = $cats->next ) {
+ if ( $cat->send_method && $cat->send_method eq 'Triage' ) {
+ # include the category itself
+ push @cat_names, $cat->category;
+ push @cat_names, @{ $group_to_category{$cat->category} } if $group_to_category{$cat->category};
+ } else {
+ push @cat_names, $cat->category;
+ }
+ }
+
+ return \@cat_names;
}
sub title_list {
diff --git a/perllib/FixMyStreet/Cobrand/IsleOfWight.pm b/perllib/FixMyStreet/Cobrand/IsleOfWight.pm
new file mode 100644
index 000000000..49356e3ae
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand/IsleOfWight.pm
@@ -0,0 +1,236 @@
+package FixMyStreet::Cobrand::IsleOfWight;
+use parent 'FixMyStreet::Cobrand::Whitelabel';
+
+use strict;
+use warnings;
+
+sub council_area_id { 2636 }
+sub council_area { 'Isle of Wight' }
+sub council_name { 'Island Roads' }
+sub council_url { 'isleofwight' }
+sub all_reports_single_body { { name => "Isle of Wight Council" } }
+sub link_to_council_cobrand { "Island Roads" }
+
+sub enter_postcode_text {
+ my ($self) = @_;
+ return 'Enter an ' . $self->council_area . ' postcode, or street name and area';
+}
+
+sub admin_user_domain { ('islandroads.com') }
+
+sub on_map_default_status { 'open' }
+
+sub send_questionnaires { 0 }
+
+sub report_sent_confirmation_email { 'external_id' }
+
+sub map_type { 'IsleOfWight' }
+
+sub disambiguate_location {
+ my $self = shift;
+ my $string = shift;
+
+ return {
+ %{ $self->SUPER::disambiguate_location() },
+ centre => '50.675761,-1.296571',
+ bounds => [ 50.574653, -1.591732, 50.767567, -1.062957 ],
+ };
+}
+
+sub updates_disallowed {
+ my ($self, $problem) = @_;
+
+ my $c = $self->{c};
+ return 0 if $c->user_exists && $c->user->id eq $problem->user->id;
+ return 1;
+}
+
+sub get_geocoder { 'OSM' }
+
+sub open311_pre_send {
+ my ($self, $row, $open311) = @_;
+
+ return unless $row->extra;
+ my $extra = $row->get_extra_fields;
+ if (@$extra) {
+ @$extra = grep { $_->{name} ne 'urgent' } @$extra;
+ $row->set_extra_fields(@$extra);
+ }
+}
+
+sub open311_config {
+ my ($self, $row, $h, $params) = @_;
+
+ my $extra = $row->get_extra_fields;
+ push @$extra,
+ { name => 'report_url',
+ value => $h->{url} },
+ { name => 'title',
+ value => $row->title },
+ { name => 'description',
+ value => $row->detail };
+
+ $row->set_extra_fields(@$extra);
+}
+
+# Make sure fetched report description isn't shown.
+sub filter_report_description { "" }
+
+sub open311_munge_update_params {
+ my ($self, $params, $comment, $body) = @_;
+
+ if ($comment->mark_fixed) {
+ $params->{description} = "[The customer indicated that this issue had been fixed]\n\n" . $params->{description};
+ }
+
+ if ( $comment->get_extra_metadata('triage_report') ) {
+ $params->{description} = "Triaged by " . $comment->user->name . ' (' . $comment->user->email . "). " . $params->{description};
+ }
+
+ $params->{description} = "FMS-Update: " . $params->{description};
+}
+
+# this handles making sure the user sees the right categories on the new report page
+sub munge_reports_category_list {
+ my ($self, $categories) = @_;
+
+ my $user = $self->{c}->user;
+ my %bodies = map { $_->body->name => $_->body } @$categories;
+ my $b = $bodies{'Isle of Wight Council'};
+
+ if ( $user && ( $user->is_superuser || $user->belongs_to_body( $b->id ) ) ) {
+ @$categories = grep { !$_->send_method || $_->send_method ne 'Triage' } @$categories;
+ return @$categories;
+ }
+
+ @$categories = grep { $_->send_method && $_->send_method eq 'Triage' } @$categories;
+ return @$categories;
+}
+
+sub munge_report_new_category_list {
+ my ($self, $options, $contacts, $extras) = @_;
+
+ my $user = $self->{c}->user;
+ my %bodies = map { $_->body->name => $_->body } @$contacts;
+ my $b = $bodies{'Isle of Wight Council'};
+
+ if ( $user && ( $user->is_superuser || $user->belongs_to_body( $b->id ) ) ) {
+ @$contacts = grep { !$_->send_method || $_->send_method ne 'Triage' } @$contacts;
+ my $seen = { map { $_->category => 1 } @$contacts };
+ @$options = grep { my $c = ($_->{category} || $_->category); $c =~ 'Pick a category' || $seen->{ $c } } @$options;
+ return;
+ }
+
+ @$contacts = grep { $_->send_method && $_->send_method eq 'Triage' } @$contacts;
+ my $seen = { map { $_->category => 1 } @$contacts };
+ @$options = grep { my $c = ($_->{category} || $_->category); $c =~ 'Pick a category' || $seen->{ $c } } @$options;
+}
+
+sub munge_around_category_where {
+ my ($self, $where) = @_;
+
+ my $user = $self->{c}->user;
+ my $b = $self->{c}->model('DB::Body')->for_areas( $self->council_area_id )->first;
+ if ( $user && ( $user->is_superuser || $user->belongs_to_body( $b->id ) ) ) {
+ $where->{send_method} = [ { '!=' => 'Triage' }, undef ];
+ return $where;
+ }
+
+ $where->{'send_method'} = 'Triage';
+ return $where;
+}
+
+sub munge_load_and_group_problems {
+ my ($self, $where, $filter) = @_;
+
+ return unless $where->{category};
+
+ my $cat_names = $self->expand_triage_cat_list($where->{category});
+
+ $where->{category} = $cat_names;
+ my $problems = $self->problems->search($where, $filter);
+ return $problems;
+}
+
+sub munge_around_filter_category_list {
+ my $self = shift;
+
+ my $c = $self->{c};
+ return unless $c->stash->{filter_category};
+
+ my $cat_names = $self->expand_triage_cat_list([ keys %{$c->stash->{filter_category}} ]);
+ $c->stash->{filter_category} = { map { $_ => 1 } @$cat_names };
+}
+
+# this assumes that each Triage category has the same name as a group
+# and uses this to generate a list of categories that a triage category
+# could be triaged to
+sub expand_triage_cat_list {
+ my ($self, $categories) = @_;
+
+ my $b = $self->{c}->model('DB::Body')->for_areas( $self->council_area_id )->first;
+
+ my $all_cats = $self->{c}->model('DB::Contact')->not_deleted->search(
+ {
+ body_id => $b->id,
+ send_method => [{ '!=', 'Triage'}, undef]
+ }
+ );
+
+ my %group_to_category;
+ while ( my $cat = $all_cats->next ) {
+ next unless $cat->get_extra_metadata('group');
+ my $groups = $cat->get_extra_metadata('group');
+ $groups = ref $groups eq 'ARRAY' ? $groups : [ $groups ];
+ for my $group ( @$groups ) {
+ $group_to_category{$group} //= [];
+ push @{ $group_to_category{$group} }, $cat->category;
+ }
+ }
+
+ my $cats = $self->{c}->model('DB::Contact')->not_deleted->search(
+ {
+ body_id => $b->id,
+ category => $categories
+ }
+ );
+
+ my @cat_names;
+ while ( my $cat = $cats->next ) {
+ if ( $cat->send_method eq 'Triage' ) {
+ # include the category itself
+ push @cat_names, $cat->category;
+ push @cat_names, @{ $group_to_category{$cat->category} } if $group_to_category{$cat->category};
+ } else {
+ push @cat_names, $cat->category;
+ }
+ }
+
+ return \@cat_names;
+}
+
+sub open311_get_update_munging {
+ my ($self, $comment) = @_;
+
+ # If we've received an update via Open311 that's closed
+ # or fixed the report, also close it to updates.
+ $comment->problem->set_extra_metadata(closed_updates => 1)
+ if !$comment->problem->is_open;
+}
+
+sub admin_pages {
+ my $self = shift;
+ my $pages = $self->next::method();
+ $pages->{triage} = [ undef, undef ];
+ return $pages;
+}
+
+sub available_permissions {
+ my $self = shift;
+
+ my $perms = $self->next::method();
+ $perms->{Problems}->{triage} = "Triage reports";
+
+ return $perms;
+}
+1;
diff --git a/perllib/FixMyStreet/Cobrand/UKCouncils.pm b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
index 9f4610143..5f45609bb 100644
--- a/perllib/FixMyStreet/Cobrand/UKCouncils.pm
+++ b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
@@ -179,7 +179,11 @@ sub reports_body_check {
}
# We want to make sure we're only on our page.
- unless ( $self->council_name =~ /^\Q$code\E/ ) {
+ my $council_name = $self->council_name;
+ if (my $override = $self->all_reports_single_body) {
+ $council_name = $override->{name};
+ }
+ unless ( $council_name =~ /^\Q$code\E/ ) {
$c->res->redirect( 'https://www.fixmystreet.com' . $c->req->uri->path_query, 301 );
$c->detach();
}
diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm
index 39f446549..1ffcc7b40 100644
--- a/perllib/FixMyStreet/DB/Result/Comment.pm
+++ b/perllib/FixMyStreet/DB/Result/Comment.pm
@@ -231,6 +231,8 @@ sub meta_line {
$body = "$body <img src='/cobrands/greenwich/favicon.png' alt=''>";
} elsif ($body eq 'Hounslow Borough Council') {
$body = 'Hounslow Highways';
+ } elsif ($body eq 'Isle of Wight Council') {
+ $body = 'Island Roads';
}
}
my $cobrand_always_view_body_user = $c->cobrand->call_hook("always_view_body_contribute_details");
diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm
index 8159d7251..08b768719 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -751,7 +751,7 @@ sub defect_types {
# Note: this only makes sense when called on a problem that has been sent!
sub can_display_external_id {
my $self = shift;
- if ($self->external_id && $self->to_body_named('Oxfordshire|Lincolnshire')) {
+ if ($self->external_id && $self->to_body_named('Oxfordshire|Lincolnshire|Isle of Wight')) {
return 1;
}
return 0;
diff --git a/perllib/FixMyStreet/DB/Result/User.pm b/perllib/FixMyStreet/DB/Result/User.pm
index 51f959e0e..85fdc790b 100644
--- a/perllib/FixMyStreet/DB/Result/User.pm
+++ b/perllib/FixMyStreet/DB/Result/User.pm
@@ -317,7 +317,11 @@ sub body {
sub moderating_user_name {
my $self = shift;
- return $self->body || _('an administrator');
+ my $body = $self->body;
+ if ( $body && $body eq 'Isle of Wight Council' ) {
+ $body = 'Island Roads';
+ }
+ return $body || _('an administrator');
}
=head2 belongs_to_body
diff --git a/perllib/FixMyStreet/Map/IsleOfWight.pm b/perllib/FixMyStreet/Map/IsleOfWight.pm
new file mode 100644
index 000000000..2316e2939
--- /dev/null
+++ b/perllib/FixMyStreet/Map/IsleOfWight.pm
@@ -0,0 +1,63 @@
+# FixMyStreet:Map::IsleOfWight
+# IsleOfWight use their own tiles on their cobrand
+
+package FixMyStreet::Map::IsleOfWight;
+use base 'FixMyStreet::Map::UKCouncilWMTS';
+
+use strict;
+
+sub default_zoom { 7; }
+
+sub urls { [ 'https://gis.ringway.co.uk/server/rest/services/Hosted/IOW_OS/MapServer/WMTS/tile' ] }
+
+sub layer_names { [ 'Hosted_IOW_OS' ] }
+
+sub scales {
+ my $self = shift;
+ my @scales = (
+ # The first 5 levels don't load and are really zoomed-out, so
+ # they're not included here.
+ # '600000',
+ # '500000',
+ # '400000',
+ # '300000',
+ # '200000',
+ '100000',
+ '75000',
+ '50000',
+ '25000',
+ '10000',
+ '8000',
+ '6000',
+ '4000',
+ '2000',
+ '1000',
+ '400',
+ );
+ return @scales;
+}
+
+sub zoom_parameters {
+ my $self = shift;
+ my $params = {
+ zoom_levels => scalar $self->scales,
+ default_zoom => $self->default_zoom,
+ min_zoom_level => 0,
+ id_offset => 5, # see note above about zoom layers we've skipped
+ };
+ return $params;
+}
+
+sub copyright {
+ return 'Contains Ordnance Survey data &copy; Crown copyright and database rights 2019 OS 100019229. Use of this data is subject to <a href="/about/mapterms">terms and conditions</a>.';
+}
+
+
+sub map_javascript { [
+ '/vendor/OpenLayers/OpenLayers.wmts.js',
+ '/js/map-OpenLayers.js',
+ '/js/map-wmts-base.js',
+ '/js/map-wmts-isleofwight.js',
+] }
+
+1;
diff --git a/perllib/FixMyStreet/SendReport/Triage.pm b/perllib/FixMyStreet/SendReport/Triage.pm
new file mode 100644
index 000000000..38341f3ff
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport/Triage.pm
@@ -0,0 +1,20 @@
+package FixMyStreet::SendReport::Triage;
+
+use Moo;
+
+BEGIN { extends 'FixMyStreet::SendReport'; }
+
+sub send {
+ my $self = shift;
+ my ( $row, $h ) = @_;
+
+ $row->update({
+ state => 'for triage'
+ });
+
+ $self->success(1);
+
+ return 0;
+}
+
+1;
diff --git a/perllib/Open311/PostServiceRequestUpdates.pm b/perllib/Open311/PostServiceRequestUpdates.pm
index 1f080b168..14bebfcb7 100755
--- a/perllib/Open311/PostServiceRequestUpdates.pm
+++ b/perllib/Open311/PostServiceRequestUpdates.pm
@@ -14,6 +14,7 @@ use Open311;
use constant SEND_METHOD_OPEN311 => 'Open311';
has verbose => ( is => 'ro', default => 0 );
+has current_open311 => ( is => 'rw' );
sub send {
my $self = shift;
@@ -26,6 +27,7 @@ sub send {
while ( my $body = $bodies->next ) {
my $cobrand = $body->get_cobrand_handler;
next if $cobrand && $cobrand->call_hook('open311_post_update_skip');
+ $self->current_open311(Open311->new($self->open311_params($body)));
$self->process_body($body);
}
}
@@ -51,8 +53,6 @@ sub open311_params {
sub process_body {
my ($self, $body) = @_;
- my $o = Open311->new( $self->open311_params($body) );
-
my $comments = FixMyStreet::DB->resultset('Comment')->to_body($body)->search( {
'me.whensent' => undef,
'me.external_id' => undef,
@@ -82,12 +82,14 @@ sub process_body {
next if !$self->verbose && $comment->send_fail_count && retry_timeout($comment);
- $self->process_update($body, $o, $comment, $cobrand);
+ $self->process_update($body, $comment, $cobrand);
}
}
sub process_update {
- my ($self, $body, $o, $comment, $cobrand) = @_;
+ my ($self, $body, $comment, $cobrand) = @_;
+
+ my $o = $self->current_open311;
$cobrand->call_hook(open311_pre_send => $comment, $o);