diff options
-rwxr-xr-x | bin/oxfordshire/archive-old-enquiries | 29 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Auth.pm | 10 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/Result/Problem.pm | 40 | ||||
-rw-r--r-- | perllib/FixMyStreet/Script/ArchiveOldEnquiries.pm | 141 | ||||
-rw-r--r-- | perllib/Utils.pm | 33 | ||||
-rw-r--r-- | t/app/model/problem.t | 75 | ||||
-rw-r--r-- | t/app/script/archive_old_enquiries.t | 163 | ||||
-rw-r--r-- | t/utils.t | 8 | ||||
-rw-r--r-- | templates/email/oxfordshire/archive.html | 58 | ||||
-rw-r--r-- | templates/email/oxfordshire/archive.txt | 28 | ||||
-rw-r--r-- | templates/web/base/report/update/form_update.html | 10 |
11 files changed, 584 insertions, 11 deletions
diff --git a/bin/oxfordshire/archive-old-enquiries b/bin/oxfordshire/archive-old-enquiries new file mode 100755 index 000000000..7fe66703a --- /dev/null +++ b/bin/oxfordshire/archive-old-enquiries @@ -0,0 +1,29 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +require 5.8.0; + +BEGIN { + use File::Basename qw(dirname); + use File::Spec; + my $d = dirname(File::Spec->rel2abs($0)); + require "$d/../../setenv.pl"; +} + +use FixMyStreet::Script::ArchiveOldEnquiries; +use Getopt::Long::Descriptive; + +my ($opts, $usage) = describe_options( + '%c %o', + ['commit|c', "actually close reports and send emails. Omitting this flag will do a dry-run"], + ['body|b=s', "which body ID to close reports for"], + ['cobrand=s', "which cobrand template to use for sent emails"], + ['closure-cutoff=s', "Anything before this will be closed with no email"], + ['email-cutoff=s', "Anything before this will be closed with an email sent to the reporter"], + ['limit|l=s', "limit to a certain number of reports/users to be closed"], + ['help|h', "print usage message and exit" ], +); +print($usage->text), exit if $opts->help; + +FixMyStreet::Script::ArchiveOldEnquiries::archive($opts); diff --git a/perllib/FixMyStreet/App/Controller/Auth.pm b/perllib/FixMyStreet/App/Controller/Auth.pm index b41e88209..70821f79d 100644 --- a/perllib/FixMyStreet/App/Controller/Auth.pm +++ b/perllib/FixMyStreet/App/Controller/Auth.pm @@ -223,7 +223,7 @@ sub token : Path('/M') : Args(1) { $c->authenticate( { email => $user->email }, 'no_password' ); # send the user to their page - $c->detach( 'redirect_on_signin', [ $data->{r} ] ); + $c->detach( 'redirect_on_signin', [ $data->{r}, $data->{p} ] ); } =head2 facebook_sign_in @@ -411,7 +411,7 @@ Used after signing in to take the person back to where they were. sub redirect_on_signin : Private { - my ( $self, $c, $redirect ) = @_; + my ( $self, $c, $redirect, $params ) = @_; unless ( $redirect ) { $c->detach('redirect_to_categories') if $c->user->from_body && scalar @{ $c->user->categories }; $redirect = 'my'; @@ -420,7 +420,11 @@ sub redirect_on_signin : Private { if ( $c->cobrand->moniker eq 'zurich' ) { $redirect = 'admin' if $c->user->from_body; } - $c->res->redirect( $c->uri_for( "/$redirect" ) ); + if (defined $params) { + $c->res->redirect( $c->uri_for( "/$redirect", $params ) ); + } else { + $c->res->redirect( $c->uri_for( "/$redirect" ) ); + } } =head2 redirect_to_categories diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm index 0092dd8b5..97cb28fe8 100644 --- a/perllib/FixMyStreet/DB/Result/Problem.pm +++ b/perllib/FixMyStreet/DB/Result/Problem.pm @@ -182,6 +182,8 @@ use Utils; use FixMyStreet::Map::FMS; use LWP::Simple qw($ua); use RABX; +use URI; +use URI::QueryParam; my $IM = eval { require Image::Magick; @@ -511,6 +513,30 @@ sub admin_url { return $cobrand->admin_base_url . '/report_edit/' . $self->id; } +=head2 tokenised_url + +Return a url for this problem report that logs a user in + +=cut + +sub tokenised_url { + my ($self, $user, $params) = @_; + + my $token = FixMyStreet::App->model('DB::Token')->create( + { + scope => 'email_sign_in', + data => { + id => $self->id, + email => $user->email, + r => $self->url, + p => $params, + } + } + ); + + return "/M/". $token->token; +} + =head2 is_open Returns 1 if the problem is in a open state otherwise 0. @@ -659,6 +685,20 @@ sub body { return $body; } + +=head2 time_ago + Returns how long ago a problem was reported in an appropriately + prettified duration, depending on the duration. +=cut + +sub time_ago { + my ( $self, $date ) = @_; + $date ||= 'confirmed'; + my $duration = time() - $self->$date->epoch; + + return Utils::prettify_duration( $duration ); +} + =head2 response_templates Returns all ResponseTemplates attached to this problem's bodies, in alphabetical diff --git a/perllib/FixMyStreet/Script/ArchiveOldEnquiries.pm b/perllib/FixMyStreet/Script/ArchiveOldEnquiries.pm new file mode 100644 index 000000000..5d1d45379 --- /dev/null +++ b/perllib/FixMyStreet/Script/ArchiveOldEnquiries.pm @@ -0,0 +1,141 @@ +package FixMyStreet::Script::ArchiveOldEnquiries; + +use strict; +use warnings; +require 5.8.0; + +use FixMyStreet; +use FixMyStreet::App; +use FixMyStreet::DB; +use FixMyStreet::Cobrand; +use FixMyStreet::Map; +use FixMyStreet::Email; + + +my $opts = { + commit => 0, + body => '2237', + cobrand => 'oxfordshire', + closure_cutoff => "2015-01-01 00:00:00", + email_cutoff => "2016-01-01 00:00:00", +}; + +sub query { + return { + bodies_str => { 'LIKE', "%".$opts->{body}."%"}, + -and => [ + lastupdate => { '<', $opts->{email_cutoff} }, + lastupdate => { '>', $opts->{closure_cutoff} }, + ], + state => [ FixMyStreet::DB::Result::Problem->open_states() ], + }; +} + +sub archive { + my $params = shift; + if ( $params ) { + $opts = { + %$opts, + %$params, + }; + } + + unless ( $opts->{commit} ) { + printf "Doing a dry run; emails won't be sent and reports won't be closed.\n"; + printf "Re-run with --commit to actually archive reports.\n\n"; + } + + my @user_ids = FixMyStreet::DB->resultset('Problem')->search(query(), + { + distinct => 1, + columns => ['user_id'], + rows => $opts->{limit}, + })->all; + + @user_ids = map { $_->user_id } @user_ids; + + my $users = FixMyStreet::DB->resultset('User')->search({ + id => \@user_ids + }); + + my $user_count = $users->count; + my $problem_count = FixMyStreet::DB->resultset('Problem')->search(query(), + { + columns => ['id'], + rows => $opts->{limit}, + })->count; + + printf("%d users will receive closure emails about %d reports which will be closed.\n", $user_count, $problem_count); + + if ( $opts->{commit} ) { + my $i = 0; + while ( my $user = $users->next ) { + printf("%d/%d: User ID %d\n", ++$i, $user_count, $user->id); + send_email_and_close($user); + } + } + + my $problems_to_close = FixMyStreet::DB->resultset('Problem')->search({ + bodies_str => { 'LIKE', "%".$opts->{body}."%"}, + lastupdate => { '<', $opts->{closure_cutoff} }, + state => [ FixMyStreet::DB::Result::Problem->open_states() ], + }, { + rows => $opts->{limit}, + }); + + printf("Closing %d old reports, without sending emails: ", $problems_to_close->count); + + if ( $opts->{commit} ) { + $problems_to_close->update({ state => 'closed', send_questionnaire => 0 }); + } + + printf("done.\n") +} + +sub send_email_and_close { + my ($user) = @_; + + my $problems = $user->problems->search(query(), { + order_by => { -desc => 'confirmed' }, + }); + + my @problems = $problems->all; + + return if scalar(@problems) == 0; + + my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker($opts->{cobrand})->new(); + $cobrand->set_lang_and_domain($problems[0]->lang, 1); + FixMyStreet::Map::set_map_class($cobrand->map_type); + + my %h = ( + reports => [@problems], + report_count => scalar(@problems), + site_name => $cobrand->moniker, + user => $user, + cobrand => $cobrand, + ); + + # Send email + printf(" Sending email about %d reports: ", scalar(@problems)); + my $email_error = FixMyStreet::Email::send_cron( + $problems->result_source->schema, + 'archive.txt', + \%h, + { + To => [ [ $user->email, $user->name ] ], + }, + undef, + undef, + $cobrand, + $problems[0]->lang, + ); + + unless ( $email_error ) { + printf("done.\n Closing reports: "); + + $problems->update({ state => 'closed', send_questionnaire => 0 }); + printf("done.\n"); + } else { + printf("error! Not closing reports for this user.\n") + } +} diff --git a/perllib/Utils.pm b/perllib/Utils.pm index 7dd2a3f39..6ba20e9d3 100644 --- a/perllib/Utils.pm +++ b/perllib/Utils.pm @@ -99,7 +99,7 @@ sub truncate_coordinate { Strip leading and trailing white space from a string. Also reduces all white space to a single space. -Trim +Trim =cut @@ -195,7 +195,28 @@ sub prettify_dt { # argument is duration in seconds, rounds to the nearest minute sub prettify_duration { my ($s, $nearest) = @_; - if ($nearest eq 'week') { + + unless ( defined $nearest ) { + if ($s < 3600) { + $nearest = 'minute'; + } elsif ($s < 3600*24) { + $nearest = 'hour'; + } elsif ($s < 3600*24*7) { + $nearest = 'day'; + } elsif ($s < 3600*24*7*4) { + $nearest = 'week'; + } elsif ($s < 3600*24*7*4*12) { + $nearest = 'month'; + } else { + $nearest = 'year'; + } + } + + if ($nearest eq 'year') { + $s = int(($s+60*60*24*3.5)/60/60/24/7/4/12)*60*60*24*7*4*12; + } elsif ($nearest eq 'month') { + $s = int(($s+60*60*24*3.5)/60/60/24/7/4)*60*60*24*7*4; + } elsif ($nearest eq 'week') { $s = int(($s+60*60*24*3.5)/60/60/24/7)*60*60*24*7; } elsif ($nearest eq 'day') { $s = int(($s+60*60*12)/60/60/24)*60*60*24; @@ -206,6 +227,8 @@ sub prettify_duration { return _('less than a minute') if $s == 0; } my @out = (); + _part(\$s, 60*60*24*7*4*12, \@out); + _part(\$s, 60*60*24*7*4, \@out); _part(\$s, 60*60*24*7, \@out); _part(\$s, 60*60*24, \@out); _part(\$s, 60*60, \@out); @@ -217,7 +240,11 @@ sub _part { if ($$s >= $m) { my $i = int($$s / $m); my $str; - if ($m == 60*60*24*7) { + if ($m == 60*60*24*7*4*12) { + $str = mySociety::Locale::nget("%d year", "%d years", $i); + } elsif ($m == 60*60*24*7*4) { + $str = mySociety::Locale::nget("%d month", "%d months", $i); + } elsif ($m == 60*60*24*7) { $str = mySociety::Locale::nget("%d week", "%d weeks", $i); } elsif ($m == 60*60*24) { $str = mySociety::Locale::nget("%d day", "%d days", $i); diff --git a/t/app/model/problem.t b/t/app/model/problem.t index 1130078c0..52213ed51 100644 --- a/t/app/model/problem.t +++ b/t/app/model/problem.t @@ -5,6 +5,7 @@ use Test::More; use FixMyStreet::TestMech; use FixMyStreet; +use FixMyStreet::App; use FixMyStreet::DB; use mySociety::Locale; use Sub::Override; @@ -53,7 +54,7 @@ is $problem->whensent, undef, 'inflating null confirmed ok'; is $problem->lastupdate, undef, 'inflating null confirmed ok'; is $problem->created, undef, 'inflating null confirmed ok'; -for my $test ( +for my $test ( { desc => 'more or less empty problem', changed => {}, @@ -242,7 +243,7 @@ for my $test ( }; } -for my $test ( +for my $test ( { state => 'partial', is_visible => 0, @@ -774,6 +775,76 @@ subtest 'check duplicate reports' => sub { is $problem2->duplicates->[0]->title, $problem1->title, 'problem2 includes problem1 in duplicates'; }; +subtest 'generates a tokenised url for a user' => sub { + my ($problem) = $mech->create_problems_for_body(1, $body_ids{2651}, 'TITLE'); + my $url = $problem->tokenised_url($user); + (my $token = $url) =~ s/\/M\///g; + + like $url, qr/\/M\//, 'problem generates tokenised url'; + + my $token_obj = FixMyStreet::App->model('DB::Token')->find( { + scope => 'email_sign_in', token => $token + } ); + is $token, $token_obj->token, 'token is generated in database with correct scope'; + is $token_obj->data->{r}, $problem->url, 'token has correct redirect data'; +}; + +subtest 'stores params in a token' => sub { + my ($problem) = $mech->create_problems_for_body(1, $body_ids{2651}, 'TITLE'); + my $url = $problem->tokenised_url($user, { foo => 'bar', baz => 'boo'}); + (my $token = $url) =~ s/\/M\///g; + + my $token_obj = FixMyStreet::App->model('DB::Token')->find( { + scope => 'email_sign_in', token => $token + } ); + + is_deeply $token_obj->data->{p}, { foo => 'bar', baz => 'boo'}, 'token has correct params'; +}; + +subtest 'get report time ago in appropriate format' => sub { + my ($problem) = $mech->create_problems_for_body(1, $body_ids{2651}, 'TITLE'); + + $problem->update( { + confirmed => DateTime->now->subtract( minutes => 2) + } ); + is $problem->time_ago, '2 minutes', 'problem returns time ago in minutes'; + + $problem->update( { + confirmed => DateTime->now->subtract( hours => 18) + } ); + is $problem->time_ago, '18 hours', 'problem returns time ago in hours'; + + $problem->update( { + confirmed => DateTime->now->subtract( days => 4) + } ); + is $problem->time_ago, '4 days', 'problem returns time ago in days'; + + $problem->update( { + confirmed => DateTime->now->subtract( weeks => 3 ) + } ); + is $problem->time_ago, '3 weeks', 'problem returns time ago in weeks'; + + $problem->update( { + confirmed => DateTime->now->subtract( months => 4 ) + } ); + is $problem->time_ago, '4 months', 'problem returns time ago in months'; + + $problem->update( { + confirmed => DateTime->now->subtract( years => 2 ) + } ); + is $problem->time_ago, '2 years', 'problem returns time ago in years'; + +}; + +subtest 'time ago works with other dates' => sub { + my ($problem) = $mech->create_problems_for_body(1, $body_ids{2651}, 'TITLE'); + + $problem->update( { + lastupdate => DateTime->now->subtract( days => 4) + } ); + is $problem->time_ago('lastupdate'), '4 days', 'problem returns last updated time ago in days'; +}; + END { $problem->comments->delete if $problem; $problem->delete if $problem; diff --git a/t/app/script/archive_old_enquiries.t b/t/app/script/archive_old_enquiries.t new file mode 100644 index 000000000..e87d6a0f8 --- /dev/null +++ b/t/app/script/archive_old_enquiries.t @@ -0,0 +1,163 @@ +use strict; +use warnings; +use Test::More; +use FixMyStreet::TestMech; +use FixMyStreet::Script::ArchiveOldEnquiries; + +mySociety::Locale::gettext_domain( 'FixMyStreet' ); + +my $mech = FixMyStreet::TestMech->new(); + +$mech->clear_emails_ok; + +my $opts = { + commit => 1, +}; + +my $user = $mech->create_user_ok('test@example.com', name => 'Test User'); +my $oxfordshire = $mech->create_body_ok(2237, 'Oxfordshire County Council', id => 2237); +my $west_oxon = $mech->create_body_ok(2420, 'West Oxfordshire District Council', id => 2420); + +subtest 'sets reports to the correct status' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'oxfordshire' ], + }, sub { + my ($report) = $mech->create_problems_for_body(1, $oxfordshire->id, 'Test', { + areas => ',2237,', + user_id => $user->id, + }); + + my ($report1) = $mech->create_problems_for_body(1, $oxfordshire->id . "," .$west_oxon->id, 'Test', { + areas => ',2237,', + lastupdate => '2015-12-01 07:00:00', + user => $user, + }); + + my ($report2) = $mech->create_problems_for_body(1, $oxfordshire->id, 'Test 2', { + areas => ',2237,', + lastupdate => '2015-12-01 08:00:00', + user => $user, + state => 'investigating', + }); + + my ($report3, $report4) = $mech->create_problems_for_body(2, $oxfordshire->id, 'Test', { + areas => ',2237,', + lastupdate => '2014-12-01 07:00:00', + user => $user, + }); + + my ($report5) = $mech->create_problems_for_body(1, $oxfordshire->id . "," .$west_oxon->id, 'Test', { + areas => ',2237,', + lastupdate => '2014-12-01 07:00:00', + user => $user, + state => 'in progress' + }); + + FixMyStreet::Script::ArchiveOldEnquiries::archive($opts); + + $report->discard_changes; + $report1->discard_changes; + $report2->discard_changes; + $report3->discard_changes; + $report4->discard_changes; + $report5->discard_changes; + + is $report1->state, 'closed', 'Report 1 has been set to closed'; + is $report2->state, 'closed', 'Report 2 has been set to closed'; + is $report3->state, 'closed', 'Report 3 has been set to closed'; + is $report4->state, 'closed', 'Report 4 has been set to closed'; + is $report5->state, 'closed', 'Report 5 has been set to closed'; + + is $report->state, 'confirmed', 'Recent report has been left alone'; + }; +}; + +subtest 'sends emails to a user' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'oxfordshire' ], + }, sub { + $mech->clear_emails_ok; + $mech->email_count_is(0); + + $mech->create_problems_for_body(1, $oxfordshire->id, 'Shiny new report', { + areas => ',2237,', + user => $user, + }); + + $mech->create_problems_for_body(1, $oxfordshire->id, 'Problem the first', { + areas => ',2237,', + lastupdate => '2015-12-01 07:00:00', + user => $user, + }); + + $mech->create_problems_for_body(1, $oxfordshire->id, 'Problem the second', { + areas => ',2237,', + lastupdate => '2015-12-01 07:00:00', + user => $user, + }); + + $mech->create_problems_for_body(1, $oxfordshire->id, 'Problem the third', { + areas => ',2237,', + lastupdate => '2015-12-01 07:00:00', + user => $user, + }); + + $mech->create_problems_for_body(1, $oxfordshire->id, 'Really old report', { + areas => ',2237,', + lastupdate => '2014-12-01 07:00:00', + user => $user, + }); + + FixMyStreet::Script::ArchiveOldEnquiries::archive($opts); + + my @emails = $mech->get_email; + $mech->email_count_is(1); + + my $email = $emails[0]; + my $body = $mech->get_text_body_from_email($email); + + like $body, qr/Problem the first/, 'Email body matches report name'; + like $body, qr/Problem the second/, 'Email body matches report name'; + like $body, qr/Problem the third/, 'Email body matches report name'; + + unlike $body, qr/Shiny new report/, 'Email body does not have new report'; + unlike $body, qr/Really old report/, 'Email body does not have old report'; + }; +}; + +subtest 'user with old reports does not get email' => sub { + $mech->clear_emails_ok; + $mech->email_count_is(0); + + $mech->create_problems_for_body(4, $oxfordshire->id, 'Really old report', { + areas => ',2237,', + lastupdate => '2014-12-01 07:00:00', + user => $user, + }); + + FixMyStreet::Script::ArchiveOldEnquiries::archive($opts); + + my @emails = $mech->get_email; + $mech->email_count_is(0); +}; + +subtest 'user with new reports does not get email' => sub { + $mech->clear_emails_ok; + $mech->email_count_is(0); + + $mech->create_problems_for_body(4, $oxfordshire->id, 'Shiny new report', { + areas => ',2237,', + user => $user, + }); + + FixMyStreet::Script::ArchiveOldEnquiries::archive($opts); + + $mech->email_count_is(0); +}; + +done_testing(); + +END { + $mech->delete_user($user); + $mech->delete_body($oxfordshire); +} @@ -91,10 +91,18 @@ is Utils::prettify_dt($dt, 1), $dt->strftime("%H:%M, %e %b %Y"); $dt = DateTime->now->subtract(days => 400); is Utils::prettify_dt($dt), $dt->strftime("%H:%M, %a %e %B %Y"); +is Utils::prettify_duration(12*5*7*86400+3600+60+1, 'year'), '1 year'; +is Utils::prettify_duration(25*5*7*86400+3600+60+1, 'year'), '2 years'; +is Utils::prettify_duration(5*7*86400+3600+60+1, 'month'), '1 month'; is Utils::prettify_duration(7*86400+3600+60+1, 'week'), '1 week'; is Utils::prettify_duration(86400+3600+60+1, 'day'), '1 day'; is Utils::prettify_duration(86400+3600+60+1, 'hour'), '1 day, 1 hour'; is Utils::prettify_duration(86400+3600+60+1, 'minute'), '1 day, 1 hour, 1 minute'; is Utils::prettify_duration(20, 'minute'), 'less than a minute'; +# prettify_duration should choose a $nearest sensibly if it's not given +is Utils::prettify_duration(12*5*7*86400+3600+60+1), '1 year'; +is Utils::prettify_duration(7*86400+3600+60+1), '1 week'; +is Utils::prettify_duration(14*86400+3600+60+1), '2 weeks'; +is Utils::prettify_duration(1800), '30 minutes'; done_testing(); diff --git a/templates/email/oxfordshire/archive.html b/templates/email/oxfordshire/archive.html new file mode 100644 index 000000000..ed48456a2 --- /dev/null +++ b/templates/email/oxfordshire/archive.html @@ -0,0 +1,58 @@ +[% + +email_summary = "Your reports on " _ site_name; + +PROCESS '_email_settings.html'; + +INCLUDE '_email_top.html'; + +%] + +<th style="[% td_style %][% only_column_style %]"> + <h1 style="[% h1_style %]">Your [% site_name %] reports on FixMyStreet</h1> + <p style="[% p_style %]"> + Hello [% user.name %], + </p> + <p style="[% p_style %]"> + FixMyStreet is being updated in Oxfordshire to + improve how problems get fixed. + </p> + <p style="[% p_style %]"> + As part of these updates, we are closing old reports that appear to be + resolved but remain open in the system. + </p> + <p style="[% p_style %]"> + We noticed that you have [% report_count %] old [% nget('report', 'reports', report_count) %] on the system, + which we've listed below. + </p> + <p style="[% p_style %]"> + If your report is no longer an issue, you don't need to do anything. + </p> + <p style="[% p_style %]"> + If you believe that your report is still a problem, you can reopen it by + clicking the 'reopen' button by a report. + </p> + + [% FOR report IN reports %] + <div style="[% list_item_style %]"> + [% IF report.photo %] + <a href="[% cobrand.base_url_for_report( report ) %]/report/[% report.id %]"> + <img style="[% list_item_photo_style %]" src="[% inline_image(report.get_first_image_fp) %]" alt=""> + </a> + [% END %] + <h2 style="[% list_item_h2_style %]"> + [%~ report.title | html ~%] + </h2> + <p style="[% list_item_p_style %]">[% report.detail | html %]</p> + <p style="[% list_item_date_style %]"> + Reported [% report.time_ago %] ago. + </p> + <p> + <a style="[% button_style %]" href="[% cobrand.base_url_for_report( report ) %][% report.tokenised_url( user, { reopen => 'true' } ) %]#update_form">Reopen report</a> + </p> + </div> + [% END %] + +</th> + +[% INCLUDE '_email_bottom.html' %] diff --git a/templates/email/oxfordshire/archive.txt b/templates/email/oxfordshire/archive.txt new file mode 100644 index 000000000..6ecf5b02f --- /dev/null +++ b/templates/email/oxfordshire/archive.txt @@ -0,0 +1,28 @@ +Subject: Your reports on [% site_name %] + +Hello [% user.name %], + +FixMyStreet is being updated in Oxfordshire to improve how problems get fixed. + +As part of these updates, we are closing old reports that appear to be resolved but remain open in the system. + +We noticed that you have [% report_count %] old [% nget('report', 'reports', report_count) %] on the system, which we've listed below. + +If your report is no longer an issue, you don't need to do anything. + +If you believe that your report is still a problem, you can reopen it by clicking or copying and pasting +the link marked 'Reopen?' by a report. + +[% FOR report IN reports %] + +[% report.title %] + +Reported [% report.time_ago %] ago. + +Reopen? [% cobrand.base_url_for_report( report ) %][% report.tokenised_url( user, { reopen => 'true' } ) %]#update_form + +---- + +[% END %] + +The mySociety team and Oxfordshire County Council diff --git a/templates/web/base/report/update/form_update.html b/templates/web/base/report/update/form_update.html index e0464eec3..f15a1f74b 100644 --- a/templates/web/base/report/update/form_update.html +++ b/templates/web/base/report/update/form_update.html @@ -47,10 +47,14 @@ [% END %] </select> [% ELSE %] - [% IF problem.is_fixed AND ((c.user_exists AND c.user.id == problem.user_id) OR alert_to_reporter) %] + [% IF (problem.is_fixed OR problem.state == 'closed') AND ((c.user_exists AND c.user.id == problem.user_id) OR alert_to_reporter) %] - <input type="checkbox" name="reopen" id="form_reopen" value="1"[% ' checked' IF update.mark_open %]> - <label class="inline" for="form_reopen">[% loc('This problem has not been fixed') %]</label> + <input type="checkbox" name="reopen" id="form_reopen" value="1"[% ' checked' IF (update.mark_open || c.req.params.reopen) %]> + [% IF problem.is_closed %] + <label class="inline" for="form_reopen">[% loc('This problem is still ongoing') %]</label> + [% ELSE %] + <label class="inline" for="form_reopen">[% loc('This problem has not been fixed') %]</label> + [% END %] [% ELSIF !problem.is_fixed %] |