aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm3
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin/Triage.pm149
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm11
-rw-r--r--perllib/FixMyStreet/Cobrand/IsleOfWight.pm53
-rw-r--r--t/app/controller/admin/triage.t112
-rw-r--r--t/cobrand/isleofwight.t39
-rw-r--r--templates/email/isleofwight/other-reported.html42
-rw-r--r--templates/email/isleofwight/other-reported.txt43
-rw-r--r--templates/web/base/admin/report-category.html5
-rw-r--r--templates/web/base/admin/triage/_inspect.html77
-rw-r--r--templates/web/base/admin/triage/_list-filters.html53
-rw-r--r--templates/web/base/admin/triage/index.html42
-rw-r--r--templates/web/base/report/_inspect.html67
-rw-r--r--templates/web/base/report/inspect/information.html56
-rw-r--r--templates/web/base/report/inspect/public_update.html14
-rw-r--r--templates/web/base/report/updates.html3
-rw-r--r--templates/web/isleofwight/main_nav_items.html59
-rw-r--r--templates/web/isleofwight/report/inspect.html10
-rw-r--r--web/cobrands/fixmystreet/staff.js29
-rw-r--r--web/cobrands/isleofwight/assets.js15
20 files changed, 788 insertions, 94 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..42028a6f0
--- /dev/null
+++ b/perllib/FixMyStreet/App/Controller/Admin/Triage.pm
@@ -0,0 +1,149 @@
+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';
+ $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
+ } );
+ }
+}
+
+1;
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/Cobrand/IsleOfWight.pm b/perllib/FixMyStreet/Cobrand/IsleOfWight.pm
index 9e48b4d77..f2cd1a687 100644
--- a/perllib/FixMyStreet/Cobrand/IsleOfWight.pm
+++ b/perllib/FixMyStreet/Cobrand/IsleOfWight.pm
@@ -47,15 +47,6 @@ sub updates_disallowed {
sub get_geocoder { 'OSM' }
-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 open311_pre_send {
my ($self, $row, $open311) = @_;
@@ -89,7 +80,51 @@ sub open311_munge_update_params {
$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};
}
+sub munge_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 ) ) ) {
+ return;
+ }
+
+ @$contacts = grep { $_->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 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/t/app/controller/admin/triage.t b/t/app/controller/admin/triage.t
new file mode 100644
index 000000000..81eb28a5d
--- /dev/null
+++ b/t/app/controller/admin/triage.t
@@ -0,0 +1,112 @@
+use FixMyStreet::TestMech;
+
+my $mech = FixMyStreet::TestMech->new;
+
+my $user = $mech->create_user_ok('test@example.com', name => 'Test User');
+my $user2 = $mech->create_user_ok('test2@example.com', name => 'Test User 2');
+my $superuser = $mech->create_user_ok(
+ 'superuser@example.com',
+ name => 'Super User',
+ is_superuser => 1
+);
+
+my $iow = $mech->create_body_ok(2636, 'Isle of Wight Council', { can_be_devolved => 1 } );
+my $iow_contact = $mech->create_contact_ok(
+ body_id => $iow->id,
+ category => 'Potholes',
+ email => 'potholes@example.com',
+ send_method => 'Triage'
+);
+$mech->create_contact_ok(
+ body_id => $iow->id,
+ category => 'Traffic lights',
+ email => 'lights@example.com'
+);
+
+my $dt = DateTime->now();
+
+my ($report) = $mech->create_problems_for_body(
+ 1,
+ $iow->id,
+ 'TITLE',
+ {
+ areas => 2636,
+ category => 'Potholes',
+ whensent => $dt,
+ latitude => 50.71086,
+ longitude => -1.29573,
+ send_method_used => 'Triage',
+ }
+);
+
+warn $report->bodies_str;
+
+FixMyStreet::override_config {
+ STAGING_FLAGS => { send_reports => 1, skip_checks => 0 },
+ ALLOWED_COBRANDS => [ 'isleofwight' ],
+ MAPIT_URL => 'http://mapit.uk/',
+}, sub {
+ subtest "user can access triage page with triage permission" => sub {
+ $user->update({ from_body => $iow });
+ $mech->log_out_ok;
+ $mech->get_ok('/admin/triage');
+
+ $mech->log_in_ok($user->email);
+ $mech->get('/admin/triage');
+ is $mech->res->code, 403, 'permission denied';
+
+ $user->user_body_permissions->create( { body => $iow, permission_type => 'triage' } );
+ $mech->get_ok('/admin/triage');
+ };
+
+ subtest "reports marked for triage show triage interface" => sub {
+ $mech->log_out_ok;
+ $mech->log_in_ok( $user->email );
+
+ $mech->get_ok('/report/' . $report->id);
+ $mech->content_lacks('CONFIRM Subject');
+
+ $report->update( { state => 'for triage' } );
+
+ $mech->get_ok('/report/' . $report->id);
+ $mech->content_contains('CONFIRM Subject');
+ };
+
+ subtest "changing report category marks report as confirmed" => sub {
+ my $report_url = '/report/' . $report->id;
+ $mech->get_ok($report_url);
+
+ $mech->content_contains('Traffic lights');
+
+ $mech->submit_form_ok( {
+ with_fields => {
+ category => 'Traffic lights',
+ include_update => 0,
+ }
+ },
+ 'triage form submitted'
+ );
+
+ $mech->content_contains('Potholes');
+
+ $report->discard_changes;
+ is $report->state, 'confirmed', 'report marked as confirmed';
+ ok !$report->whensent, 'report marked to resend';
+
+ my @comments = $report->comments;
+ my $comment = $comments[0];
+ my $extra = $comment->get_extra_metadata();
+ is $extra->{triage_report}, 1, 'comment indicates it is for triage in extra';
+ is $extra->{holding_category}, 'Potholes', 'comment extra has previous category';
+ is $extra->{new_category}, 'Traffic lights', 'comment extra has new category';
+
+ $mech->get_ok($report_url);
+ $mech->content_contains('Report triaged from Potholes to Traffic lights');
+
+ $mech->log_out_ok;
+ $mech->get_ok($report_url);
+ $mech->content_lacks('Report triaged from Potholes to Traffic lights');
+ };
+};
+
+done_testing();
diff --git a/t/cobrand/isleofwight.t b/t/cobrand/isleofwight.t
index 6c6450028..414b683cd 100644
--- a/t/cobrand/isleofwight.t
+++ b/t/cobrand/isleofwight.t
@@ -212,7 +212,6 @@ subtest "fixing passes along the correct message" => sub {
};
};
-
subtest 'Check special Open311 request handling', sub {
my ($p) = $mech->create_problems_for_body(1, $isleofwight->id, 'Title', { category => 'Potholes', latitude => 50.7108, longitude => -1.29573 });
$p->set_extra_fields({ name => 'urgent', value => 'no'});
@@ -237,6 +236,44 @@ subtest 'Check special Open311 request handling', sub {
is $c->param('attribute[urgent]'), undef, 'no urgent param sent';
};
+subtest "triaging a report includes user in message" => sub {
+ FixMyStreet::override_config {
+ MAPIT_URL => 'http://mapit.uk/',
+ ALLOWED_COBRANDS => 'isleofwight',
+ }, sub {
+ my $test_res = HTTP::Response->new();
+ $test_res->code(200);
+ $test_res->message('OK');
+ $test_res->content('<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>');
+
+ my $o = Open311->new(
+ fixmystreet_body => $isleofwight,
+ test_mode => 1,
+ test_get_returns => { 'servicerequestupdates.xml' => $test_res },
+ );
+
+ my ($p) = $mech->create_problems_for_body(1, $isleofwight->id, 'Title', { external_id => 1 });
+
+ my $c = FixMyStreet::App->model('DB::Comment')->create({
+ problem => $p, user => $p->user, anonymous => 't', text => 'Update text',
+ problem_state => 'confirmed', state => 'confirmed', mark_fixed => 0,
+ confirmed => DateTime->now(),
+ });
+ $c->set_extra_metadata('triage_report', 1);
+ $c->update;
+
+ my $id = $o->post_service_request_update($c);
+ is $id, 248, 'correct update ID returned';
+ my $cgi = CGI::Simple->new($o->test_req_used->content);
+ my $name = $p->user->name . ' \(' . $p->user->email . '\)';
+ like $cgi->param('description'), qr/^FMS-Update:/, 'FMS update prefix included';
+ like $cgi->param('description'), qr/Triaged by $name/, 'Triage user details included';
+
+ $p->comments->delete;
+ $p->delete;
+ };
+};
+
my ($p) = $mech->create_problems_for_body(1, $isleofwight->id, '', { cobrand => 'isleofwight' });
my $alert = FixMyStreet::App->model('DB::Alert')->create( {
parameter => $p->id,
diff --git a/templates/email/isleofwight/other-reported.html b/templates/email/isleofwight/other-reported.html
new file mode 100644
index 000000000..8e85c5729
--- /dev/null
+++ b/templates/email/isleofwight/other-reported.html
@@ -0,0 +1,42 @@
+[%
+
+email_summary = "Thanks for logging your report";
+email_columns = 2;
+
+PROCESS '_email_settings.html';
+INCLUDE '_email_top.html';
+
+%]
+
+<th style="[% td_style %][% primary_column_style %]" id="primary_column">
+ [% start_padded_box %]
+ <h1 style="[% h1_style %]">Your report has been&nbsp;logged</h1>
+ [% IF report.state == 'for triage' %]
+ <p style="[% p_style %]">Thank you for submitting your report to FixMyStreet, it will be submitted to Island Roads for review.</p>
+ [% ELSE %]
+ <p style="[% p_style %]">Thank you, your enquiry has been received by Island Roads and appropriate action will be taken.</p>
+
+ <p style="[% p_style %]">We don't routinely contact customers regarding their enquiries, unless we have a specific query about
+ the issue. Any status updates for the issue can be tracked via FixMyStreet, if you contact us again about this issue,
+ please quote your 8-digit reference number.</p>
+
+ <p style="[% p_style %]">Thank you for submitting your enquiry to us via FixMyStreet.</p>
+ [% END %]
+
+[% IF cobrand.is_council && !cobrand.owns_problem( report ) %]
+<p style="[% p_style %]">Please note that [% cobrand.council_name %] is not responsible for this type
+of report, so it will instead be sent to [% report.body %].</p>
+[% ELSE %]
+[% TRY %][% INCLUDE '_council_reference.html' problem=report %][% CATCH file %][% END %]
+[% END %]
+ <p style="margin: 20px auto; text-align: center">
+ <a style="[% button_style %]" href="[% cobrand.base_url_for_report(report) %][% report.url %]">View my report</a>
+ </p>
+ [% end_padded_box %]
+</th>
+[% WRAPPER '_email_sidebar.html' object = report %]
+ <h2 style="[% h2_style %]">[% report.title | html %]</h2>
+ <p style="[% secondary_p_style %]">[% report.detail | html %]</p>
+[% END %]
+
+[% INCLUDE '_email_bottom.html' %]
diff --git a/templates/email/isleofwight/other-reported.txt b/templates/email/isleofwight/other-reported.txt
new file mode 100644
index 000000000..a368bd95e
--- /dev/null
+++ b/templates/email/isleofwight/other-reported.txt
@@ -0,0 +1,43 @@
+Subject: Your report has been logged: [% report.title %]
+
+Hello [% report.name %],
+
+[% IF report.state == 'for triage' %]
+Thank you for submitting your report to FixMyStreet, it will be
+submitted to Island Roads for review.
+[% ELSE %]
+Thank you, your enquiry has been received by Island Roads and
+appropriate action will be taken.
+
+We don't routinely contact customers regarding their enquiries,
+unless we have a specific query about the issue. Any status
+updates for the issue can be tracked via FixMyStreet, if you
+contact us again about this issue, please quote your 8-digit
+reference number.
+
+Thank you for submitting your enquiry to us via FixMyStreet.
+[% END %]
+
+[% IF cobrand.is_council && !cobrand.owns_problem( report ) %]
+Please note that [% cobrand.council_name %] is not responsible for this type
+of report, so it will instead be sent to [% report.body %].
+[% ELSE %]
+[% TRY %][% INCLUDE '_council_reference.txt' problem=report %][% CATCH file %][% END %]
+[% END %]
+
+It is available to view at:
+
+[% cobrand.base_url_for_report(report) %][% report.url %]
+
+Your report has the title:
+
+[% report.title %]
+
+And details:
+
+[% report.detail %]
+
+[% signature %]
+
+This email was sent automatically, from an unmonitored email account - so
+please do not reply to it.
diff --git a/templates/web/base/admin/report-category.html b/templates/web/base/admin/report-category.html
index 0416d71c0..64aa474b9 100644
--- a/templates/web/base/admin/report-category.html
+++ b/templates/web/base/admin/report-category.html
@@ -1,4 +1,7 @@
-<select class="form-control" name="category" id="category">
+[%~ IF NOT select_name %]
+ [%~ select_name = 'category' %]
+[%~ END %]
+<select class="form-control" name="[% select_name %]" id="[% select_name %]">
[% IF NOT problem.category OR NOT categories_hash.${problem.category} %]
<optgroup label="[% loc('Existing category') %]">
<option selected value="[% problem.category | html %]">[% (problem.category_display OR '-') | html %]</option>
diff --git a/templates/web/base/admin/triage/_inspect.html b/templates/web/base/admin/triage/_inspect.html
new file mode 100644
index 000000000..926197ceb
--- /dev/null
+++ b/templates/web/base/admin/triage/_inspect.html
@@ -0,0 +1,77 @@
+[% BLOCK category_list %]
+<select class="form-control" name="[% field_name %]" id="[% field_name %]">
+ [% IF category_options.size %]
+ [%~ IF category_groups.size ~%]
+ [%~ FOREACH group IN category_groups ~%]
+ [% IF group.name %]<optgroup label="[% group.name %]">[% END %]
+ [% group_select = 0 %]
+ [% selected = 0 %]
+ [%~ FOREACH cat_op IN group.categories ~%]
+ [% IF group_select == 0 AND problem.category == group.name %]
+ [% selected = 1; group_select = 1 %]
+ [% END %]
+ <option value="[% cat_op.category | html %]"[% ' selected' IF selected OR problem.category == cat_op.category %]>[% cat_op.category_display | html %] ([% cat_op.email | html %])</option>
+ [% selected = 0 %]
+ [%~ END ~%]
+ [% IF group.name %]</optgroup>[% END %]
+ [%~ END =%]
+ [% ELSE %]
+ [% FOREACH cat IN category_options %]
+ <option value="[% cat.category | html %]"[% ' selected' IF problem.category == cat.category %]>[% cat.category_display | html %]</option>
+ [% END %]
+ [% END %]
+ [% END %]
+</select>
+[% END %]
+
+[% permissions = c.user.permissions(problem) %]
+[% second_column = BLOCK -%]
+ <div id="side-inspect">
+
+ <h2 class="inspect-form-heading">[% loc('Inspect report') %]</h2>
+
+ [% INCLUDE 'errors.html' %]
+
+ <form name="report_inspect_form" id="report_inspect_form" method="post" action="[% c.uri_for( '/report', problem.id ) %]" class="validate">
+
+ [% INCLUDE 'report/inspect/information.html' no_relocate=1 %]
+
+ [% IF permissions.report_edit_category OR permissions.report_inspect OR permissions.triage %]
+ <div class="inspect-section">
+ <p>
+ <strong>Holding category:</strong> [% problem.category %]
+ </p>
+
+ <p>
+ <label for="category">CONFIRM Subject</label>
+ [% PROCESS category_list category_groups=end_groups field_name="category" categories_hash=end_categories category_options=end_options %]
+ </p>
+
+ </div>
+ [% END %]
+
+ <div class="inspect-section">
+ [%- extra_fields = problem.get_extra_fields -%]
+ [% FOR field IN extra_fields %]
+ [% NEXT IF field.name == 'urgent' %]
+ <p>
+ <label for="[% field.name %]">[% field.description %]</label>
+ <input class="form-control" name="[% field.name %]" type="text" value="[% field.value | html %]" disabled>
+ </p>
+ [% END %]
+
+ [% IF permissions.report_inspect OR permissions.triage %]
+ [% INCLUDE 'report/inspect/public_update.html' public_update_defaulted=0 %]
+ [% END %]
+
+ <p>
+ <input type="hidden" name="token" value="[% csrf_token %]" />
+ <input class="btn btn-primary" type="submit" value="[% loc('Save changes') %]" data-value-original="[% loc('Save changes') %]" data-value-duplicate="[% loc('Save + close as duplicate') %]" name="save" />
+ </p>
+ </div>
+
+ <input type="hidden" name="js" value="">
+ <input type="hidden" name="triage" value="1">
+ </form>
+ </div>
+[%- END %]
diff --git a/templates/web/base/admin/triage/_list-filters.html b/templates/web/base/admin/triage/_list-filters.html
new file mode 100644
index 000000000..f6bedcb80
--- /dev/null
+++ b/templates/web/base/admin/triage/_list-filters.html
@@ -0,0 +1,53 @@
+[% select_category = BLOCK %]
+ [% IF filter_categories.size %]
+ <select class="form-control js-multiple" name="filter_category" id="filter_categories" multiple data-all="[% loc('Everything') %]">
+ [% FOR cat IN filter_categories %]
+ <option value="[% cat.category | html %]"[% ' selected' IF filter_category.${cat.category} %]>
+ [% cat.category_display | html %]
+ [%~ IF cat.get_extra_metadata('help_text') %] ([% cat.get_extra_metadata('help_text') %])[% END ~%]
+ </option>
+ [% END %]
+ </select>
+ [% ELSE %]
+ [% loc('Everything') %]
+ [% END %]
+[% END %]
+
+<div class="report-list-filters-wrapper">
+
+[% IF use_form_wrapper %]
+ <form method="get" action="">
+[% END %]
+
+ <p class="report-list-filters">
+ [% tprintf(loc('<label for="statuses">Show</label> %s reports <label for="filter_categories">about</label> %s', "The first %s is a dropdown of all/fixed/etc, the second is a dropdown of categories"), 'untriaged', select_category) %]
+ <input type="submit" name="filter_update" value="[% loc('Go') %]">
+ </p>
+
+ <p class="report-list-filters">
+ <label for="sort">[% loc('Sort by') %]</label>
+ <select class="form-control" name="sort" id="sort">
+ [% IF shortlist %]
+ <option value="shortlist"[% ' selected' IF sort_key == 'shortlist' %]>[% loc('Manual order') %]</option>
+ [% END %]
+ <option value="created-desc"[% ' selected' IF sort_key == 'created-desc' %]>[% loc('Newest') %]</option>
+ <option value="created-asc"[% ' selected' IF sort_key == 'created-asc' %]>[% loc('Oldest') %]</option>
+ <option value="updated-desc"[% ' selected' IF sort_key == 'updated-desc' %]>[% loc('Recently updated') %]</option>
+ <option value="updated-asc"[% ' selected' IF sort_key == 'updated-asc' %]>[% loc('Least recently updated') %]</option>
+ <option value="comments-desc"[% ' selected' IF sort_key == 'comments-desc' %]>[% loc('Most commented') %]</option>
+ </select>
+ <input type="submit" name="filter_update" value="[% loc('Go') %]">
+ </p>
+ [% IF page == 'around' %]
+ <p id="show_old_reports_wrapper" class="report-list-filters[% ' hidden' UNLESS num_old_reports > 0 %]">
+ <label for="show_old_reports">[% loc('Show older reports') %]</label>
+ <input type="checkbox" name="show_old_reports" id="show_old_reports" value="1"[% ' checked' IF show_old_reports %]>
+ <input type="submit" name="filter_update" value="[% loc('Go') %]">
+ </p>
+ [% END %]
+
+[% IF use_form_wrapper %]
+ </form>
+[% END %]
+
+</div>
diff --git a/templates/web/base/admin/triage/index.html b/templates/web/base/admin/triage/index.html
new file mode 100644
index 000000000..f00bbc1fa
--- /dev/null
+++ b/templates/web/base/admin/triage/index.html
@@ -0,0 +1,42 @@
+[% SET body_name = body.name %]
+[% IF c.cobrand.moniker == 'hounslow' %]
+ [% SET body_name = 'Hounslow Highways' %]
+[% ELSIF c.cobrand.moniker == 'isleofwight' %]
+ [% SET body_name = 'Island Roads' %]
+[% END %]
+
+[%
+ PROCESS "report/photo-js.html";
+ PROCESS "maps/${map.type}.html";
+ SET bodyclass = 'mappage';
+ INCLUDE 'header.html',
+ title = 'Awaiting triage'
+ rss = [ tprintf(loc('Problems within %s, %s', "First %s is the body name, second %s the site name"), name, site_name), rss_url ]
+%]
+
+[% map_html %]
+
+</div>
+<div id="map_sidebar">
+ <div id="side">
+
+ <h1 id="reports_heading">
+ Awaiting triage
+ </h1>
+
+<section class="full-width">
+[% INCLUDE "admin/triage/_list-filters.html", use_form_wrapper = 1 %]
+<div class="js-pagination">
+[% INCLUDE 'pagination.html', param = 'p' %]
+</div>
+<div id="js-reports-list">
+ [% INCLUDE 'reports/_problem-list.html' %]
+</div>
+<div class="js-pagination">
+[% INCLUDE 'pagination.html', param = 'p' %]
+</div>
+</section>
+
+ </div>
+</div>
+[% INCLUDE 'footer.html' %]
diff --git a/templates/web/base/report/_inspect.html b/templates/web/base/report/_inspect.html
index fa79d9912..10f3b6b84 100644
--- a/templates/web/base/report/_inspect.html
+++ b/templates/web/base/report/_inspect.html
@@ -11,60 +11,7 @@
<form name="report_inspect_form" id="report_inspect_form" method="post" action="[% c.uri_for( '/report', problem.id ) %]" class="validate">
- <div class="inspect-section">
- <p style="float: right">
- <label for="non_public">[% loc('Private') %]</label>
- <input type="checkbox" id="non_public" name="non_public" value="1"[% ' checked' IF problem.non_public %]>
- </p>
- <p>
- <strong>[% loc('Report ID:') %]</strong>
- <span class="js-report-id">[% problem.id %]</span>
- [% IF c.user_exists AND c.cobrand.admin_allow_user(c.user) AND c.user.has_permission_to('report_edit', problem.bodies_str_ids) %]
- (<a href="[% c.uri_for_action( "admin/report_edit", problem.id ) %]">[% loc('admin') %]</a>)
- [% END %]
- </p>
- [% IF permissions.report_inspect AND problem.user.phone %]
- <p>
- <strong>[% loc('Phone Reporter:') %]</strong>
- <a href="tel:[% problem.user.phone | html %]">[% problem.user.phone_display | html %]</a>
- </p>
- [% END %]
- <p>
- [% SET local_coords = problem.local_coords; %]
- [% IF local_coords %]
- <strong>[% loc('Easting/Northing:') %]</strong>
- <span id="problem_easting">[% local_coords.0 %]</span>,
- <span id="problem_northing">[% local_coords.1 %]</span>
- [% ELSE %]
- <strong>[% loc('Latitude/Longitude:') %]</strong>
- <span id="problem_latitude">[% problem.latitude %]</span>,
- <span id="problem_longitude">[% problem.longitude %]</span>
- [% END %]
- <input type="hidden" name="longitude" value="[% problem.longitude %]">
- <input type="hidden" name="latitude" value="[% problem.latitude %]">
- </p>
- [% IF problem.nearest_address() %]
- <p>
- <strong>[% loc('Nearest calculated address:') %]</strong>
- [% problem.nearest_address() %]
- </p>
- [% END %]
- <p>
- <a target="_blank" href="https://www.google.com/maps/dir/?api=1&destination=[% problem.latitude %],[% problem.longitude %]" class="btn btn--block btn--navigate">[% loc('Navigate to this problem') %]</a>
- </p>
- <p>
- <a href="#" class="btn btn--block btn--geolocate">[% loc('Set to my current location') %]</a>
- </p>
- [% IF permissions.report_reject %]
- [% TRY %]
- [% INCLUDE 'report/_inspect_reject_button.html' %]
- [% CATCH file %]
- <p>
- <a href="[% c.uri_for( '/contact', { id => problem.id, reject => 1 } ) %]" class="btn btn--block">[% loc('Reject report') %]</a>
- </p>
- [% END %]
- [% END %]
- </div>
+ [% INCLUDE 'report/inspect/information.html' %]
[% IF permissions.report_edit_category OR permissions.report_inspect %]
<div class="inspect-section">
@@ -182,17 +129,7 @@
<div class="inspect-section">
[% IF permissions.report_inspect %]
- <p>
- <label class="label-containing-checkbox">
- <input type="checkbox" name="include_update" value="1" class="js-toggle-public-update" checked>
- [% loc('Save with a public update') %]
- </label>
- </p>
- <p>
- <label for="public_update">[% loc('Public update:') %]</label>
- [% INCLUDE 'admin/response_templates_select.html' for='public_update' %]
- <textarea rows="2" name="public_update" id="public_update" class="form-control">[% public_update | html %]</textarea>
- </p>
+ [% INCLUDE 'report/inspect/public_update.html' %]
[% END %]
[% IF problem.get_extra_metadata('inspected') %]
diff --git a/templates/web/base/report/inspect/information.html b/templates/web/base/report/inspect/information.html
new file mode 100644
index 000000000..cc8989522
--- /dev/null
+++ b/templates/web/base/report/inspect/information.html
@@ -0,0 +1,56 @@
+ <div class="inspect-section">
+ <p style="float: right">
+ <label for="non_public">[% loc('Private') %]</label>
+ <input type="checkbox" id="non_public" name="non_public" value="1"[% ' checked' IF problem.non_public %]>
+ </p>
+ <p>
+ <strong>[% loc('Report ID:') %]</strong>
+ <span class="js-report-id">[% problem.id %]</span>
+ [% IF c.user_exists AND c.cobrand.admin_allow_user(c.user) AND c.user.has_permission_to('report_edit', problem.bodies_str_ids) %]
+ (<a href="[% c.uri_for_action( "admin/report_edit", problem.id ) %]">[% loc('admin') %]</a>)
+ [% END %]
+ </p>
+ [% IF permissions.report_inspect AND problem.user.phone %]
+ <p>
+ <strong>[% loc('Phone Reporter:') %]</strong>
+ <a href="tel:[% problem.user.phone | html %]">[% problem.user.phone_display | html %]</a>
+ </p>
+ [% END %]
+ <p>
+ [% SET local_coords = problem.local_coords; %]
+ [% IF local_coords %]
+ <strong>[% loc('Easting/Northing:') %]</strong>
+ <span id="problem_easting">[% local_coords.0 %]</span>,
+ <span id="problem_northing">[% local_coords.1 %]</span>
+ [% ELSE %]
+ <strong>[% loc('Latitude/Longitude:') %]</strong>
+ <span id="problem_latitude">[% problem.latitude %]</span>,
+ <span id="problem_longitude">[% problem.longitude %]</span>
+ [% END %]
+ <input type="hidden" name="longitude" value="[% problem.longitude %]">
+ <input type="hidden" name="latitude" value="[% problem.latitude %]">
+ </p>
+ [% IF problem.nearest_address() %]
+ <p>
+ <strong>[% loc('Nearest calculated address:') %]</strong>
+ [% problem.nearest_address() %]
+ </p>
+ [% END %]
+ <p>
+ <a target="_blank" href="https://www.google.com/maps/dir/?api=1&destination=[% problem.latitude %],[% problem.longitude %]" class="btn btn--block btn--navigate">[% loc('Navigate to this problem') %]</a>
+ </p>
+ [% UNLESS no_relocate %]
+ <p>
+ <a href="#" class="btn btn--block btn--geolocate">[% loc('Set to my current location') %]</a>
+ </p>
+ [% END %]
+ [% IF permissions.report_reject %]
+ [% TRY %]
+ [% INCLUDE 'report/_inspect_reject_button.html' %]
+ [% CATCH file %]
+ <p>
+ <a href="[% c.uri_for( '/contact', { id => problem.id, reject => 1 } ) %]" class="btn btn--block">[% loc('Reject report') %]</a>
+ </p>
+ [% END %]
+ [% END %]
+ </div>
diff --git a/templates/web/base/report/inspect/public_update.html b/templates/web/base/report/inspect/public_update.html
new file mode 100644
index 000000000..be07d7b89
--- /dev/null
+++ b/templates/web/base/report/inspect/public_update.html
@@ -0,0 +1,14 @@
+[% IF NOT public_update_defaulted.defined %]
+ [% public_update_defaulted = 1 %]
+[% END %]
+ <p>
+ <label class="label-containing-checkbox">
+ <input type="checkbox" name="include_update" value="1" class="js-toggle-public-update"[% ' checked' IF public_update_defaulted %]>
+ [% loc('Save with a public update') %]
+ </label>
+ </p>
+ <p>
+ <label for="public_update">[% loc('Public update:') %]</label>
+ [% INCLUDE 'admin/response_templates_select.html' for='public_update' %]
+ <textarea rows="2" name="public_update" id="public_update" class="form-control">[% public_update | html %]</textarea>
+ </p>
diff --git a/templates/web/base/report/updates.html b/templates/web/base/report/updates.html
index 817cc7eb4..93bae4d64 100644
--- a/templates/web/base/report/updates.html
+++ b/templates/web/base/report/updates.html
@@ -6,6 +6,9 @@
[%- END %]
[%- NEXT %]
[%- END %]
+[%- IF update.get_extra_metadata('triage_report') == 1 AND ( NOT c.user OR ( NOT c.user.from_body AND NOT c.user.is_superuser ) ) %]
+ [%- NEXT %]
+[%- END %]
[% INCLUDE 'report/update.html' %]
[% END %]
diff --git a/templates/web/isleofwight/main_nav_items.html b/templates/web/isleofwight/main_nav_items.html
new file mode 100644
index 000000000..5b794a99d
--- /dev/null
+++ b/templates/web/isleofwight/main_nav_items.html
@@ -0,0 +1,59 @@
+[%~ IF problem ~%]
+ [%~ INCLUDE navitem uri='/report/new?longitude=' _ problem.longitude _ '&amp;latitude=' _ problem.latitude label=loc('Report another problem here') attrs='class="report-a-problem-btn"' ~%]
+[%~ ELSIF latitude AND longitude ~%]
+ [%~ INCLUDE navitem uri='/report/new?longitude=' _ longitude _ '&amp;latitude=' _ latitude label=loc('Report a problem here') attrs='class="report-a-problem-btn"' ~%]
+[%~ ELSIF homepage_template ~%]
+ [%~ INCLUDE navitem uri='/report' label=loc('Report a problem') attrs='class="report-a-problem-btn"' ~%]
+[%~ ELSE ~%]
+ [%~ INCLUDE navitem uri='/' label=loc('Report a problem') attrs='class="report-a-problem-btn"' ~%]
+[%~ END ~%]
+
+[%~ IF c.user_exists ~%]
+ [%~ INCLUDE navitem uri='/my' label=loc('Your account') ~%]
+[%~ ELSE ~%]
+ [%~ INCLUDE navitem uri='/auth' label=loc('Sign in') ~%]
+[%~ END ~%]
+
+[%~ IF c.user_exists AND c.user.has_body_permission_to('planned_reports') ~%]
+ [%~ INCLUDE navitem always_url=1 uri='/my/planned' label=loc('Shortlist') ~%]
+[%~ END ~%]
+
+[%~ IF c.user_exists AND c.user.has_body_permission_to('triage') ~%]
+ [%~ INCLUDE navitem always_url=1 uri='/admin/triage' label=loc('Awaiting triage') ~%]
+[%~ END ~%]
+
+[%~ UNLESS hide_all_reports_link ~%]
+ [%~
+ IF c.user_exists AND c.user.categories.size;
+ categories = c.user.categories_string | uri;
+ cat_suffix = "?filter_category=" _ categories;
+ END;
+
+ reports_uri = '/reports';
+ IF c.cobrand.council_area;
+ body_name = c.cobrand.council_area | uri;
+ reports_uri = "${reports_uri}/${body_name}";
+ END;
+
+ INCLUDE navitem uri=reports_uri label=loc('All reports') suffix=cat_suffix;
+ ~%]
+[%~ END ~%]
+
+[%~
+ IF pc;
+ pc_uri = pc | uri;
+ pc_suffix = "/list?pc=" _ pc_uri;
+ END;
+
+ INCLUDE navitem uri='/alert' label=loc('Local alerts') suffix=pc_suffix;
+~%]
+
+[%~ INCLUDE navitem uri='/faq' label=loc('Help') ~%]
+
+[%~ UNLESS hide_privacy_link ~%]
+ [%~ INCLUDE navitem uri=c.cobrand.privacy_policy_url label=loc('Privacy') liattrs='class="nav-menu__item--privacy"' ~%]
+[%~ END ~%]
+
+[%~ IF c.user_exists AND c.cobrand.admin_allow_user(c.user) ~%]
+ [%~ INCLUDE navitem uri='/admin' label=loc('Admin') ~%]
+[%~ END ~%]
diff --git a/templates/web/isleofwight/report/inspect.html b/templates/web/isleofwight/report/inspect.html
new file mode 100644
index 000000000..6cecff926
--- /dev/null
+++ b/templates/web/isleofwight/report/inspect.html
@@ -0,0 +1,10 @@
+[%
+ SET bodyclass = 'mappage with-actions';
+ SET two_column_sidebar = 1;
+ IF problem.state == 'for triage';
+ PROCESS 'admin/triage/_inspect.html';
+ ELSE;
+ PROCESS 'report/_inspect.html';
+ END;
+ INCLUDE 'report/display.html'
+%]
diff --git a/web/cobrands/fixmystreet/staff.js b/web/cobrands/fixmystreet/staff.js
index b074a49f3..17bd54b8b 100644
--- a/web/cobrands/fixmystreet/staff.js
+++ b/web/cobrands/fixmystreet/staff.js
@@ -261,19 +261,22 @@ fixmystreet.staff_set_up = {
if ('geolocation' in navigator) {
var el = document.querySelector('.btn--geolocate');
- fixmystreet.geolocate(el, function(pos) {
- var latlon = new OpenLayers.LonLat(pos.coords.longitude, pos.coords.latitude);
- var bng = latlon.clone().transform(
- new OpenLayers.Projection("EPSG:4326"),
- new OpenLayers.Projection("EPSG:27700") // TODO: Handle other projections
- );
- $("#problem_northing").text(bng.lat.toFixed(1));
- $("#problem_easting").text(bng.lon.toFixed(1));
- $("#problem_latitude").text(latlon.lat.toFixed(6));
- $("#problem_longitude").text(latlon.lon.toFixed(6));
- $inspect_form.find("input[name=latitude]").val(latlon.lat);
- $inspect_form.find("input[name=longitude]").val(latlon.lon);
- });
+ // triage pages may not show geolocation button
+ if (el) {
+ fixmystreet.geolocate(el, function(pos) {
+ var latlon = new OpenLayers.LonLat(pos.coords.longitude, pos.coords.latitude);
+ var bng = latlon.clone().transform(
+ new OpenLayers.Projection("EPSG:4326"),
+ new OpenLayers.Projection("EPSG:27700") // TODO: Handle other projections
+ );
+ $("#problem_northing").text(bng.lat.toFixed(1));
+ $("#problem_easting").text(bng.lon.toFixed(1));
+ $("#problem_latitude").text(latlon.lat.toFixed(6));
+ $("#problem_longitude").text(latlon.lon.toFixed(6));
+ $inspect_form.find("input[name=latitude]").val(latlon.lat);
+ $inspect_form.find("input[name=longitude]").val(latlon.lon);
+ });
+ }
}
// Make the "Provide an update" form toggleable, hidden by default.
diff --git a/web/cobrands/isleofwight/assets.js b/web/cobrands/isleofwight/assets.js
index 3df034f0c..a68b0418b 100644
--- a/web/cobrands/isleofwight/assets.js
+++ b/web/cobrands/isleofwight/assets.js
@@ -97,17 +97,26 @@ fixmystreet.assets.add($.extend(true, {}, defaults, {
})
}));
+function not_found_msg_update() {
+ $('.category_meta_message').html('Please select an item or a road/pavement/path on the map &raquo;');
+ $('.category_meta_message').removeClass('meta-highlight');
+ $("input[name=asset_details]").val('');
+}
+
function found_item(layer, asset) {
var id = asset.attributes.central_asset_id || '';
if (id !== '') {
var attrib = asset.attributes;
var asset_name = attrib.feature_type_name + '; ' + attrib.site_name + '; ' + attrib.feature_location;
$('.category_meta_message').html('You have selected ' + asset_name);
+ $('.category_meta_message').addClass('meta-highlight');
+ $("input[name=asset_details]").val(asset_name);
} else {
- $('.category_meta_message').html('Please select an item or a road/pavement/path on the map &raquo;');
+ not_found_msg_update();
}
}
+
var point_asset_defaults = $.extend(true, {}, defaults, {
snap_threshold: 5,
select_action: true,
@@ -118,7 +127,7 @@ var point_asset_defaults = $.extend(true, {}, defaults, {
found_item(this, asset);
},
asset_not_found: function() {
- $('.category_meta_message').html('Please select an item or a road/pavement/path on the map &raquo;');
+ not_found_msg_update();
}
}
@@ -145,7 +154,7 @@ var line_asset_defaults = $.extend(true, {}, defaults, {
if ( fixmystreet.assets.selectedFeature() ) {
return;
}
- $('.category_meta_message').html('Please select an item or a road/pavement/path on the map &raquo;');
+ not_found_msg_update();
}
}
});