diff options
author | Matthew Somerville <matthew-github@dracos.co.uk> | 2018-05-14 15:25:20 +0100 |
---|---|---|
committer | Matthew Somerville <matthew-github@dracos.co.uk> | 2018-05-23 18:55:10 +0100 |
commit | df731c5a0ffccc434550ca4dd2ecace5287848fa (patch) | |
tree | 2d5c2bd50830c68b7f925520802ea06bcb7f6235 | |
parent | e663d5e373dfafedd4be7e6e79ac79eae511b54d (diff) |
Script to email/anonymize inactive users.
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rwxr-xr-x | bin/process-inactive-accounts | 43 | ||||
-rw-r--r-- | perllib/FixMyStreet/Script/Inactive.pm | 93 | ||||
-rw-r--r-- | t/script/inactive.t | 28 | ||||
-rw-r--r-- | templates/email/default/inactive-account.html | 26 | ||||
-rw-r--r-- | templates/email/default/inactive-account.txt | 18 |
6 files changed, 209 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 104ad1c3c..13d45bd5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ - 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. - Development improvements: - Add HTML email previewer. - Add CORS header to Open311 output. #2022 diff --git a/bin/process-inactive-accounts b/bin/process-inactive-accounts new file mode 100755 index 000000000..3df200d3d --- /dev/null +++ b/bin/process-inactive-accounts @@ -0,0 +1,43 @@ +#!/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', 'email=i', 'verbose|v', 'help|h', 'dry-run|n'); +pod2usage(0) if $h{help}; +pod2usage(1) if !$h{anonymize}; +pod2usage("Anonymize time must be greater than email time") + if $h{email} && $h{email} >= $h{anonymize}; + +FixMyStreet::Script::Inactive->new(%h)->users; + +__END__ + +=head1 NAME + +process-inactive-accounts - deal with anonymizing old inactive accounts + +=head1 SYNOPSIS + +process-inactive-accounts --anonymize N [--email N] + + Options: + --anonymize Anonymize accounts inactive longer than this time (months) + --email Email accounts inactive longer than this time (months) + --dry-run Don't actually anonymize anything or send any emails + --verbose Output as to which users are being affected + --help This help message + +=cut diff --git a/perllib/FixMyStreet/Script/Inactive.pm b/perllib/FixMyStreet/Script/Inactive.pm new file mode 100644 index 000000000..766135e12 --- /dev/null +++ b/perllib/FixMyStreet/Script/Inactive.pm @@ -0,0 +1,93 @@ +package FixMyStreet::Script::Inactive; + +use v5.14; +use warnings; + +use Moo; +use CronFns; +use FixMyStreet; +use FixMyStreet::Cobrand; +use FixMyStreet::DB; +use FixMyStreet::Email; + +has anonymize => ( is => 'ro' ); +has email => ( is => 'ro' ); +has verbose => ( is => 'ro' ); +has dry_run => ( is => 'ro' ); + +sub BUILDARGS { + my ($cls, %args) = @_; + $args{dry_run} = delete $args{'dry-run'}; + return \%args; +} + +has cobrand => ( + is => 'lazy', + default => sub { + my $base_url = FixMyStreet->config('BASE_URL'); + my $site = CronFns::site($base_url); + my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker($site)->new; + $cobrand->set_lang_and_domain(undef, 1); + $cobrand; + }, +); + +sub users { + my $self = shift; + + say "DRY RUN" if $self->dry_run; + $self->anonymize_users; + $self->email_inactive_users if $self->email; +} + +sub anonymize_users { + my $self = shift; + + my $users = FixMyStreet::DB->resultset("User")->search({ + last_active => { '<', interval($self->anonymize) }, + }); + + while (my $user = $users->next) { + say "Anonymizing user #" . $user->id if $self->verbose; + next if $self->dry_run; + $user->anonymize_account; + } +} + +sub email_inactive_users { + my $self = shift; + + my $users = FixMyStreet::DB->resultset("User")->search({ + last_active => [ -and => { '<', interval($self->email) }, + { '>=', interval($self->anonymize) } ], + }); + while (my $user = $users->next) { + next if $user->get_extra_metadata('inactive_email_sent'); + + say "Emailing user #" . $user->id if $self->verbose; + next if $self->dry_run; + FixMyStreet::Email::send_cron( + $user->result_source->schema, + 'inactive-account.txt', + { + email_from => $self->email, + anonymize_from => $self->anonymize, + user => $user, + url => $self->cobrand->base_url_with_lang . '/my', + }, + { To => [ $user->email, $user->name ] }, + undef, 0, $self->cobrand, + ); + + $user->set_extra_metadata('inactive_email_sent', 1); + $user->update; + } +} + +sub interval { + my $interval = shift; + my $s = "current_timestamp - '$interval months'::interval"; + return \$s; +} + +1; diff --git a/t/script/inactive.t b/t/script/inactive.t new file mode 100644 index 000000000..0eaeea2ad --- /dev/null +++ b/t/script/inactive.t @@ -0,0 +1,28 @@ +use FixMyStreet::TestMech; + +use_ok 'FixMyStreet::Script::Inactive'; + +my $in = FixMyStreet::Script::Inactive->new( anonymize => 6, email => 3 ); +my $mech = FixMyStreet::TestMech->new; + +my $user = FixMyStreet::DB->resultset("User")->find_or_create({ email => 'test@example.com' }); +my $t = DateTime->new(year => 2016, month => 1, day => 1, hour => 12); +$user->last_active($t); +$user->update; + +my $user_inactive = FixMyStreet::DB->resultset("User")->find_or_create({ email => 'inactive@example.com' }); +$t = DateTime->now->subtract(months => 4); +$user_inactive->last_active($t); +$user_inactive->update; + +subtest 'Anonymization of inactive users' => sub { + $in->users; + + my $email = $mech->get_email; + like $email->as_string, qr/inactive\@example.com/, 'Inactive email sent'; + + $user->discard_changes; + is $user->email, 'removed-' . $user->id . '@example.org', 'User has been anonymized'; +}; + +done_testing; diff --git a/templates/email/default/inactive-account.html b/templates/email/default/inactive-account.html new file mode 100644 index 000000000..78b277877 --- /dev/null +++ b/templates/email/default/inactive-account.html @@ -0,0 +1,26 @@ +[% + +email_summary = "Your inactive account on " _ site_name; +email_columns = 1; + +PROCESS '_email_settings.html'; + +INCLUDE '_email_top.html'; + +%] + +<th style="[% td_style %][% only_column_style %]"> + <h1 style="[% h1_style %]">Your inactive account</h1> + <p style="[% p_style %]"> +Your account on [% site_name %] has been inactive for [% email_from %] +[% nget('month', 'months', email_from) %], and we automatically remove +accounts that have been inactive after [% anonymize_from %] +[% nget('month', 'months', anonymize_from) %]. If you wish to keep your +account, please log in to the site and that will keep it active: +</p> + <p style="margin: 20px auto; text-align: center"> + <a style="[% button_style %]" href="[% url %]">Visit [% site_name %]</a> + </p> + <p style="[% p_style %]">Thanks for using the site.</p> + +[% INCLUDE '_email_bottom.html' %] diff --git a/templates/email/default/inactive-account.txt b/templates/email/default/inactive-account.txt new file mode 100644 index 000000000..1b6b8b5bd --- /dev/null +++ b/templates/email/default/inactive-account.txt @@ -0,0 +1,18 @@ +Subject: Your inactive account on [% site_name %] + +Hello [% user.name %], + +Your account on [% site_name %] has been inactive for [% email_from %] +[% nget('month', 'months', email_from) %], and we automatically remove +accounts that have been inactive after [% anonymize_from %] +[% nget('month', 'months', anonymize_from) %]. If you wish to keep your +account, please log in to the site and that will keep it active: + +[% url %] + +Thanks for using the site. + +[% INCLUDE 'signature.txt' %] + +This email was sent automatically, from an unmonitored email account - so +please do not reply to it. |