summaryrefslogtreecommitdiff
path: root/lib/Travelynx/Command/maintenance.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Travelynx/Command/maintenance.pm')
-rw-r--r--lib/Travelynx/Command/maintenance.pm169
1 files changed, 53 insertions, 116 deletions
diff --git a/lib/Travelynx/Command/maintenance.pm b/lib/Travelynx/Command/maintenance.pm
index 5f609cb..c9c7ed6 100644
--- a/lib/Travelynx/Command/maintenance.pm
+++ b/lib/Travelynx/Command/maintenance.pm
@@ -1,6 +1,6 @@
package Travelynx::Command::maintenance;
-# Copyright (C) 2020 Daniel Friesel
+# Copyright (C) 2020-2023 Birte Kristina Friesel
#
# SPDX-License-Identifier: AGPL-3.0-or-later
use Mojo::Base 'Mojolicious::Command';
@@ -14,10 +14,11 @@ has usage => sub { shift->extract_usage };
sub run {
my ( $self, $filename ) = @_;
- my $now = DateTime->now( time_zone => 'Europe/Berlin' );
- my $verification_deadline = $now->clone->subtract( hours => 48 );
- my $deletion_deadline = $now->clone->subtract( hours => 72 );
- my $old_deadline = $now->clone->subtract( years => 1 );
+ my $now = DateTime->now( time_zone => 'Europe/Berlin' );
+ my $verification_deadline = $now->clone->subtract( hours => 48 );
+ my $deletion_deadline = $now->clone->subtract( hours => 72 );
+ my $old_deadline = $now->clone->subtract( years => 1 );
+ my $old_notification_deadline = $now->clone->subtract( weeks => 4 );
my $db = $self->app->pg->db;
my $tx = $db->begin;
@@ -82,12 +83,40 @@ sub run {
printf( "Pruned %d pending mail change(s)\n", $rows );
}
+ my $to_notify = $db->select(
+ 'users',
+ [ 'id', 'name', 'email', 'last_seen' ],
+ {
+ last_seen => { '<', $old_deadline },
+ deletion_notified => undef
+ }
+ );
+
+ for my $user ( $to_notify->hashes->each ) {
+ say "Sending account deletion notification to uid $user->{id}...";
+ $self->app->sendmail->age_deletion_notification(
+ name => $user->{name},
+ email => $user->{email},
+ last_seen => $user->{last_seen},
+ login_url => $self->app->base_url_for('login')->to_abs,
+ account_url => $self->app->base_url_for('account')->to_abs,
+ imprint_url => $self->app->base_url_for('impressum')->to_abs,
+ );
+ $self->app->users->mark_deletion_notified( uid => $user->{id} );
+ }
+
my $to_delete = $db->select( 'users', ['id'],
{ deletion_requested => { '<', $deletion_deadline } } );
my @uids_to_delete = $to_delete->arrays->map( sub { shift->[0] } )->each;
- $to_delete
- = $db->select( 'users', ['id'], { last_seen => { '<', $old_deadline } } );
+ $to_delete = $db->select(
+ 'users',
+ ['id'],
+ {
+ last_seen => { '<', $old_deadline },
+ deletion_notified => { '<', $old_notification_deadline }
+ }
+ );
push( @uids_to_delete,
$to_delete->arrays->map( sub { shift->[0] } )->each );
@@ -97,34 +126,30 @@ sub run {
"About to delete %d accounts, which is quite a lot.\n",
scalar @uids_to_delete
);
+ for my $uid (@uids_to_delete) {
+ my $journeys_res = $db->select(
+ 'journeys',
+ 'count(*) as count',
+ { user_id => $uid }
+ )->hash;
+ printf STDERR (
+ " - UID %5d (%4d journeys)\n",
+ $uid, $journeys_res->{count}
+ );
+ }
say STDERR 'Aborting maintenance. Please investigate.';
exit(1);
}
for my $uid (@uids_to_delete) {
say "Deleting uid ${uid}...";
- my $tokens_res = $db->delete( 'tokens', { user_id => $uid } );
- my $stats_res = $db->delete( 'journey_stats', { user_id => $uid } );
- my $journeys_res = $db->delete( 'journeys', { user_id => $uid } );
- my $transit_res = $db->delete( 'in_transit', { user_id => $uid } );
- my $hooks_res = $db->delete( 'webhooks', { user_id => $uid } );
- my $trwl_res = $db->delete( 'traewelling', { user_id => $uid } );
-
- # TODO + traewelling, webhooks
- my $password_res
- = $db->delete( 'pending_passwords', { user_id => $uid } );
- my $user_res = $db->delete( 'users', { id => $uid } );
-
+ my $count = $self->app->users->delete(
+ uid => $uid,
+ db => $db,
+ in_transaction => 1
+ );
printf( " %d tokens, %d monthly stats, %d journeys\n",
- $tokens_res->rows, $stats_res->rows, $journeys_res->rows );
-
- if ( $user_res->rows != 1 ) {
- printf STDERR (
- "Deleted %d rows from users, expected 1. Rollback and abort.\n",
- $user_res->rows
- );
- exit(1);
- }
+ $count->{tokens}, $count->{stats}, $count->{journeys} );
}
$tx->commit;
@@ -144,94 +169,6 @@ sub run {
);
$tx->commit;
}
-
- # Add estimated polylines to journeys logged before 2020-01-28
-
- $tx = $db->begin;
-
- say 'Adding polylines to journeys logged before 2020-01-28';
- my $no_polyline
- = $db->select( 'journeys', 'count(*) as count', { polyline_id => undef } )
- ->hash;
- say "Checking $no_polyline->{count} journeys ...";
-
- for my $journey (
- $db->select( 'journeys', [ 'id', 'route' ], { polyline_id => undef } )
- ->hashes->each )
- {
-
- # prior to v1.9.4, routes were stored as [["stop1"], ["stop2"], ...].
- # Nowadays, the common format is [["stop1", {}, null], ...].
- # entry[1] is non-empty only while checked in, entry[2] is non-null only
- # if the stop is unscheduled or has been cancelled.
- #
- # Here, we pretend to use the new format, as we're looking for
- # matching routes in more recent journeys.
- #
- # Note that journey->{route} is serialized JSON (i.e., a string).
- # It is not deserialized for performance reasons.
- $journey->{route}
- =~ s/ (?<! additional ) (?<! cancelled ) "] /", {}, null]/gx;
-
- my $ref = $db->select(
- 'journeys',
- [ 'id', 'polyline_id' ],
- {
- route => $journey->{route},
- polyline_id => { '!=', undef },
- edited => 0,
- },
- { limit => 1 }
- )->hash;
- if ($ref) {
- my $rows = $db->update(
- 'journeys',
- { polyline_id => $ref->{polyline_id} },
- { id => $journey->{id} }
- )->rows;
- if ( $rows != 1 ) {
- say STDERR
-"Database update returned $rows rows, expected 1. Rollback and abort.";
- exit(1);
- }
- }
- else {
- while ( my ( $old_name, $new_name )
- = each %{ $self->app->renamed_station } )
- {
- $journey->{route} =~ s{"\Q$old_name\E"}{"$new_name"};
- }
- my $ref = $db->select(
- 'journeys',
- [ 'id', 'polyline_id' ],
- {
- route => $journey->{route},
- polyline_id => { '!=', undef },
- edited => 0,
- },
- { limit => 1 }
- )->hash;
- if ($ref) {
- my $rows = $db->update(
- 'journeys',
- { polyline_id => $ref->{polyline_id} },
- { id => $journey->{id} }
- )->rows;
- if ( $rows != 1 ) {
- say STDERR
-"Database update returned $rows rows, expected 1. Rollback and abort.";
- exit(1);
- }
- }
- }
- }
-
- my $remaining
- = $db->select( 'journeys', 'count(*) as count', { polyline_id => undef } )
- ->hash;
- say "Done! Remaining journeys without polyline: " . $remaining->{count};
-
- $tx->commit;
}
1;