diff options
Diffstat (limited to 'lib/Travelynx/Command/maintenance.pm')
-rw-r--r-- | lib/Travelynx/Command/maintenance.pm | 169 |
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; |