diff options
-rwxr-xr-x | bin/process-inactive-reports | 8 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/TfL.pm | 30 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/Result/Problem.pm | 11 | ||||
-rw-r--r-- | perllib/FixMyStreet/Script/Inactive.pm | 57 | ||||
-rw-r--r-- | t/cobrand/tfl.t | 10 | ||||
-rw-r--r-- | t/script/inactive.t | 77 |
6 files changed, 175 insertions, 18 deletions
diff --git a/bin/process-inactive-reports b/bin/process-inactive-reports index d2c030c2c..f1e9af2eb 100755 --- a/bin/process-inactive-reports +++ b/bin/process-inactive-reports @@ -15,9 +15,9 @@ use FixMyStreet::Script::Inactive; use Pod::Usage; my %h; -GetOptions(\%h, 'anonymize=i', 'close=i', 'verbose|v', 'help|h', 'dry-run|n'); +GetOptions(\%h, 'anonymize=i', 'close=i', 'delete=i', 'cobrand=s', 'verbose|v', 'help|h', 'dry-run|n'); pod2usage(0) if $h{help}; -pod2usage(1) unless $h{anonymize} || $h{close}; +pod2usage(1) unless $h{anonymize} || $h{close} || $h{delete}; FixMyStreet::Script::Inactive->new(%h)->reports; @@ -29,11 +29,13 @@ process-inactive-reports - deal with anonymizing inactive non-open reports =head1 SYNOPSIS -process-inactive-reports [--anonymize N] [--close N] +process-inactive-reports [--anonymize N] [--close N] [--delete N] [--cobrand COBRAND] Options: --anonymize Anonymize non-open reports (and related) inactive longer than this time (months) --close Close comments on non-open reports inactive longer than this time (months) + --delete Delete non-open reports inactive longer than this time (months) + --cobrand Only act upon reports made on this cobrand --dry-run Don't actually anonymize anything or send any emails --verbose Output as to which reports are being affected --help This help message diff --git a/perllib/FixMyStreet/Cobrand/TfL.pm b/perllib/FixMyStreet/Cobrand/TfL.pm index 751831b10..797b872a4 100644 --- a/perllib/FixMyStreet/Cobrand/TfL.pm +++ b/perllib/FixMyStreet/Cobrand/TfL.pm @@ -119,6 +119,36 @@ sub report_age { '6 weeks' } # We don't want any reports made before the go-live date visible sub cut_off_date { '2019-12-09 12:00' } +sub problems_restriction { + my ($self, $rs) = @_; + return $rs if FixMyStreet->staging_flag('skip_checks'); + $rs = $self->next::method($rs); + my $table = ref $rs eq 'FixMyStreet::DB::ResultSet::Nearby' ? 'problem' : 'me'; + $rs = $rs->search({ + "$table.lastupdate" => { '>=', \"now() - '3 years'::interval" } + }); + return $rs; +} + +sub problems_sql_restriction { + my ($self, $item_table) = @_; + my $q = $self->next::method($item_table); + if ($item_table ne 'comment') { + $q .= " AND lastupdate >= now() - '3 years'::interval"; + } + return $q; +} + +sub inactive_reports_filter { + my ($self, $time, $rs) = @_; + if ($time < 7*12) { + $rs = $rs->search({ extra => { like => '%safety_critical,T5:value,T2:no%' } }); + } else { + $rs = $rs->search({ extra => { like => '%safety_critical,T5:value,T3:yes%' } }); + } + return $rs; +} + sub password_expiry { return if FixMyStreet->test_mode; # uncoverable statement diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm index a188d9c2b..d9bb8e125 100644 --- a/perllib/FixMyStreet/DB/Result/Problem.pm +++ b/perllib/FixMyStreet/DB/Result/Problem.pm @@ -1187,4 +1187,15 @@ has inspection_log_entry => ( }, ); +has alerts => ( + is => 'ro', + lazy => 1, + default => sub { + my $self = shift; + return $self->result_source->schema->resultset('Alert')->search({ + alert_type => 'new_updates', parameter => $self->id + }); + }, +); + 1; diff --git a/perllib/FixMyStreet/Script/Inactive.pm b/perllib/FixMyStreet/Script/Inactive.pm index 0468d2a52..e09417648 100644 --- a/perllib/FixMyStreet/Script/Inactive.pm +++ b/perllib/FixMyStreet/Script/Inactive.pm @@ -12,17 +12,23 @@ use FixMyStreet::Email; has anonymize => ( is => 'ro' ); has close => ( is => 'ro' ); +has delete => ( is => 'ro' ); has email => ( is => 'ro' ); has verbose => ( is => 'ro' ); has dry_run => ( is => 'ro' ); +has cobrand => ( + is => 'ro', + coerce => sub { FixMyStreet::Cobrand->get_class_for_moniker($_[0])->new }, +); + sub BUILDARGS { my ($cls, %args) = @_; $args{dry_run} = delete $args{'dry-run'}; return \%args; } -has cobrand => ( +has base_cobrand => ( is => 'lazy', default => sub { my $base_url = FixMyStreet->config('BASE_URL'); @@ -55,6 +61,7 @@ sub reports { say "DRY RUN" if $self->dry_run; $self->anonymize_reports if $self->anonymize; + $self->delete_reports if $self->delete; $self->close_updates if $self->close; } @@ -66,6 +73,7 @@ sub close_updates { state => [ FixMyStreet::DB::Result::Problem->closed_states(), FixMyStreet::DB::Result::Problem->fixed_states() ], extra => [ undef, { -not_like => '%closed_updates%' } ], }); + $problems = $problems->search({ cobrand => $self->cobrand->moniker }) if $self->cobrand; while (my $problem = $problems->next) { say "Closing updates on problem #" . $problem->id if $self->verbose; @@ -75,18 +83,28 @@ sub close_updates { } } -sub anonymize_reports { - my $self = shift; - - # Need to look though them all each time, in case any new updates/alerts +sub _relevant_reports { + my ($self, $time) = @_; my $problems = FixMyStreet::DB->resultset("Problem")->search({ - lastupdate => { '<', interval($self->anonymize) }, + lastupdate => { '<', interval($time) }, state => [ FixMyStreet::DB::Result::Problem->closed_states(), FixMyStreet::DB::Result::Problem->fixed_states(), FixMyStreet::DB::Result::Problem->hidden_states(), ], }); + if ($self->cobrand) { + $problems = $problems->search({ cobrand => $self->cobrand->moniker }); + $problems = $self->cobrand->call_hook(inactive_reports_filter => $time, $problems) || $problems; + } + return $problems; +} + +sub anonymize_reports { + my $self = shift; + + # Need to look though them all each time, in case any new updates/alerts + my $problems = $self->_relevant_reports($self->anonymize); while (my $problem = $problems->next) { say "Anonymizing problem #" . $problem->id if $self->verbose; @@ -110,10 +128,8 @@ sub anonymize_reports { }); # Remove alerts - could just delete, but of interest how many there were, perhaps? - FixMyStreet::DB->resultset('Alert')->search({ + $problem->alerts->search({ user_id => { '!=' => $self->anonymous_user->id }, - alert_type => 'new_updates', - parameter => $problem->id, })->update({ user_id => $self->anonymous_user->id, whendisabled => \'current_timestamp', @@ -121,11 +137,30 @@ sub anonymize_reports { } } +sub delete_reports { + my $self = shift; + + my $problems = $self->_relevant_reports($self->delete); + + while (my $problem = $problems->next) { + say "Deleting associated data of problem #" . $problem->id if $self->verbose; + next if $self->dry_run; + + $problem->comments->delete; + $problem->questionnaires->delete; + $problem->alerts->delete; + } + say "Deleting all matching problems" if $self->verbose; + return if $self->dry_run; + $problems->delete; +} + sub anonymize_users { my $self = shift; my $users = FixMyStreet::DB->resultset("User")->search({ last_active => { '<', interval($self->anonymize) }, + email => { -not_like => 'removed-%@' . FixMyStreet->config('EMAIL_DOMAIN') }, }); while (my $user = $users->next) { @@ -154,10 +189,10 @@ sub email_inactive_users { email_from => $self->email, anonymize_from => $self->anonymize, user => $user, - url => $self->cobrand->base_url_with_lang . '/my', + url => $self->base_cobrand->base_url_with_lang . '/my', }, { To => [ $user->email, $user->name ] }, - undef, 0, $self->cobrand, + undef, 0, $self->base_cobrand, ); $user->set_extra_metadata('inactive_email_sent', 1); diff --git a/t/cobrand/tfl.t b/t/cobrand/tfl.t index 33506e8c4..e1990c946 100644 --- a/t/cobrand/tfl.t +++ b/t/cobrand/tfl.t @@ -556,6 +556,16 @@ subtest 'check report age on /around' => sub { }); }; +subtest 'check report age in general' => sub { + my $report = FixMyStreet::DB->resultset("Problem")->find({ title => 'Test Report 1'}); + $report->update({ state => 'confirmed' }); + $mech->get_ok('/report/' . $report->id); + $report->update({ lastupdate => \"current_timestamp-'4 years'::interval" }); + $mech->get('/report/' . $report->id); + is $mech->res->code, 404; + $report->update({ lastupdate => \"current_timestamp" }); +}; + subtest 'TfL admin allows inspectors to be assigned to borough areas' => sub { $mech->log_in_ok($superuser->email); diff --git a/t/script/inactive.t b/t/script/inactive.t index 489ff55ca..5ef4073dd 100644 --- a/t/script/inactive.t +++ b/t/script/inactive.t @@ -1,4 +1,5 @@ use FixMyStreet::TestMech; +use Test::Output; use_ok 'FixMyStreet::Script::Inactive'; @@ -22,6 +23,7 @@ for (my $m = 1; $m <= 12; $m++) { dt => $t, lastupdate => "$t", state => $m % 2 ? 'fixed - user' : 'confirmed', + cobrand => $m % 3 ? 'default' : 'bromley', }); } @@ -50,23 +52,90 @@ subtest 'Anonymization of inactive fixed/closed reports' => sub { is $comment->user->email, 'removed-automatically@example.org', 'Comment user anonymized'; }; +subtest 'Test operating on one cobrand only' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'bromley' + }, sub { + my $in = FixMyStreet::Script::Inactive->new( cobrand => 'bromley', close => 1 ); + $in->reports; + # Reports not a multiple of 2 are fixed, reports a multiple of 3 are bromley + $problems[2]->discard_changes; + is $problems[2]->get_extra_metadata('closed_updates'), 1, 'Closed to updates'; + $problems[4]->discard_changes; + is $problems[4]->get_extra_metadata('closed_updates'), undef, 'Not closed to updates'; + $problems[6]->discard_changes; + is $problems[6]->get_extra_metadata('closed_updates'), undef, 'Not closed to updates'; + $problems[8]->discard_changes; + is $problems[8]->get_extra_metadata('closed_updates'), 1, 'Closed to updates'; + }; +}; + subtest 'Closing updates on inactive fixed/closed reports' => sub { my $in = FixMyStreet::Script::Inactive->new( close => 1 ); $in->reports; - $problems[2]->discard_changes; - is $problems[2]->get_extra_metadata('closed_updates'), 1, 'Closed to updates'; - $mech->get_ok("/report/" . $problems[2]->id); + $problems[4]->discard_changes; + is $problems[4]->get_extra_metadata('closed_updates'), 1, 'Closed to updates'; + $mech->get_ok("/report/" . $problems[4]->id); $mech->content_contains('now closed to updates'); }; +subtest 'Deleting reports' => sub { + my $in = FixMyStreet::Script::Inactive->new( delete => 6 ); + $in->reports; + + my $count = FixMyStreet::DB->resultset("Problem")->count; + is $count, 6, 'Six left'; + + $mech->get("/report/" . $problems[2]->id); + is $mech->res->code, 404; +}; + subtest 'Anonymization of inactive users' => sub { - $in->users; + my $in = FixMyStreet::Script::Inactive->new( anonymize => 6, email => 3, verbose => 1 ); + stdout_is { $in->users } "Anonymizing user #" . $user->id . "\nEmailing user #" . $user_inactive->id . "\n", 'users dealt with first time'; my $email = $mech->get_email; like $email->as_string, qr/inactive\@example.com/, 'Inactive email sent'; + $mech->clear_emails_ok; $user->discard_changes; is $user->email, 'removed-' . $user->id . '@example.org', 'User has been anonymized'; + + stdout_is { $in->users } '', 'No output second time'; + + $mech->email_count_is(0); # No further email sent + + $user->discard_changes; + is $user->email, 'removed-' . $user->id . '@example.org', 'User has been anonymized'; +}; + +subtest 'Test TfL deletion of safety critical reports' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'tfl' + }, sub { + for (my $y = 2; $y <= 10; $y+=2) { + # 2 years, not safety; 4 years safety, 6 years not safety, 8 years safety, 10 years not safety + my $t = DateTime->now->subtract(years => $y); + my ($problem) = $mech->create_problems_for_body(1, 2237, 'Title', { + dt => $t, + lastupdate => "$t", + state => 'fixed - user', + cobrand => 'tfl', + }); + $problem->update_extra_field({ name => 'safety_critical', value => $y % 4 ? 'no' : 'yes' }); + $problem->update; + } + + my $in = FixMyStreet::Script::Inactive->new( cobrand => 'tfl', delete => 36 ); + $in->reports; + my $count = FixMyStreet::DB->resultset("Problem")->search({ cobrand => 'tfl' })->count; + is $count, 3, 'Three reports left, one too recent, two safety critical'; + + $in = FixMyStreet::Script::Inactive->new( cobrand => 'tfl', delete => 84 ); + $in->reports; + $count = FixMyStreet::DB->resultset("Problem")->search({ cobrand => 'tfl' })->count; + is $count, 2, 'Two reports left, two too recent'; + } }; done_testing; |