diff options
-rw-r--r-- | CHANGELOG.md | 3 | ||||
-rwxr-xr-x | bin/process-inactive-reports | 40 | ||||
-rw-r--r-- | perllib/FixMyStreet/Script/Inactive.pm | 57 | ||||
-rw-r--r-- | t/script/inactive.t | 35 |
4 files changed, 134 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 13d45bd5b..c5baa0408 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,7 +54,8 @@ - Deleted body categories now hidden by default #1962 - Display contents of report's extra field #1809 - Store user creation and last active times. - - Add script to anonymize/email inactive users. + - Add scripts to anonymize inactive users and reports, + or email inactive users. - Development improvements: - Add HTML email previewer. - Add CORS header to Open311 output. #2022 diff --git a/bin/process-inactive-reports b/bin/process-inactive-reports new file mode 100755 index 000000000..3f133d11a --- /dev/null +++ b/bin/process-inactive-reports @@ -0,0 +1,40 @@ +#!/usr/bin/env perl + +use v5.14; +use warnings; + +BEGIN { + use File::Basename qw(dirname); + use File::Spec; + my $d = dirname(File::Spec->rel2abs($0)); + require "$d/../setenv.pl"; +} + +use Getopt::Long; +use FixMyStreet::Script::Inactive; +use Pod::Usage; + +my %h; +GetOptions(\%h, 'anonymize=i', 'verbose|v', 'help|h', 'dry-run|n'); +pod2usage(0) if $h{help}; +pod2usage(1) unless $h{anonymize}; + +FixMyStreet::Script::Inactive->new(%h)->reports; + +__END__ + +=head1 NAME + +process-inactive-reports - deal with anonymizing inactive non-open reports + +=head1 SYNOPSIS + +process-inactive-reports --anonymize N + + Options: + --anonymize Anonymize non-open reports (and related) inactive longer than this time (months) + --dry-run Don't actually anonymize anything or send any emails + --verbose Output as to which reports are being affected + --help This help message + +=cut diff --git a/perllib/FixMyStreet/Script/Inactive.pm b/perllib/FixMyStreet/Script/Inactive.pm index 766135e12..3c6be9901 100644 --- a/perllib/FixMyStreet/Script/Inactive.pm +++ b/perllib/FixMyStreet/Script/Inactive.pm @@ -32,6 +32,15 @@ has cobrand => ( }, ); +has anonymous_user => ( + is => 'lazy', + default => sub { + FixMyStreet::DB->resultset("User")->find_or_create({ + email => 'removed-automatically@' . FixMyStreet->config('EMAIL_DOMAIN'), + }); + } +); + sub users { my $self = shift; @@ -40,6 +49,54 @@ sub users { $self->email_inactive_users if $self->email; } +sub reports { + my $self = shift; + + say "DRY RUN" if $self->dry_run; + + # Need to look though them all each time, in case any new updates/alerts + my $problems = FixMyStreet::DB->resultset("Problem")->search({ + lastupdate => { '<', interval($self->anonymize) }, + state => [ + FixMyStreet::DB::Result::Problem->closed_states(), + FixMyStreet::DB::Result::Problem->fixed_states(), + FixMyStreet::DB::Result::Problem->hidden_states(), + ], + }); + + while (my $problem = $problems->next) { + say "Anonymizing problem #" . $problem->id if $self->verbose; + next if $self->dry_run; + + # Remove personal data from the report + $problem->update({ + user => $self->anonymous_user, + name => '', + anonymous => 1, + send_questionnaire => 0, + }) if $problem->user != $self->anonymous_user; + + # Remove personal data from the report's updates + $problem->comments->search({ + user_id => { '!=' => $self->anonymous_user->id }, + })->update({ + user_id => $self->anonymous_user->id, + name => '', + anonymous => 1, + }); + + # Remove alerts - could just delete, but of interest how many there were, perhaps? + FixMyStreet::DB->resultset('Alert')->search({ + user_id => { '!=' => $self->anonymous_user->id }, + alert_type => 'new_updates', + parameter => $problem->id, + })->update({ + user_id => $self->anonymous_user->id, + whendisabled => \'current_timestamp', + }); + } +} + sub anonymize_users { my $self = shift; diff --git a/t/script/inactive.t b/t/script/inactive.t index 0eaeea2ad..9d1e3f4bd 100644 --- a/t/script/inactive.t +++ b/t/script/inactive.t @@ -15,6 +15,41 @@ $t = DateTime->now->subtract(months => 4); $user_inactive->last_active($t); $user_inactive->update; +my @problems; +for (my $m = 1; $m <= 12; $m++) { + my $t = DateTime->new(year => 2017, month => $m, day => 1, hour => 12); + push @problems, $mech->create_problems_for_body(1, 2237, 'Title', { + dt => $t, + lastupdate => "$t", + state => $m % 2 ? 'fixed - user' : 'confirmed', + }); +} + +$mech->create_comment_for_problem($problems[0], $user, 'Name', 'Update', 0, 'confirmed', $problems[0]->state); +FixMyStreet::DB->resultset("Alert")->create({ alert_type => 'new_updates', parameter => $problems[2]->id, user => $user }); + +subtest 'Anonymization of inactive fixed/closed reports' => sub { + $in->reports; + + my $count = FixMyStreet::DB->resultset("Problem")->search({ user_id => $user->id })->count; + is $count, 6, 'Six non-anonymised'; + + my $comment = FixMyStreet::DB->resultset("Comment")->first; + my $alert = FixMyStreet::DB->resultset("Alert")->first; + is $comment->anonymous, 1, 'Comment anonymized'; + is $comment->user->email, 'removed-automatically@example.org', 'Comment user anonymized'; + is $alert->user->email, 'removed-automatically@example.org', 'Alert anonymized'; + isnt $alert->whendisabled, undef, 'Alert disabled'; + + $mech->create_comment_for_problem($problems[0], $user, 'Name 2', 'Update', 0, 'confirmed', $problems[0]->state); + $comment = FixMyStreet::DB->resultset("Comment")->search({ name => 'Name 2' })->first; + + $in->reports; + $comment->discard_changes; + is $comment->anonymous, 1, 'Comment anonymized'; + is $comment->user->email, 'removed-automatically@example.org', 'Comment user anonymized'; +}; + subtest 'Anonymization of inactive users' => sub { $in->users; |