Skip to content

Commit

Permalink
Delete inactive users
Browse files Browse the repository at this point in the history
  • Loading branch information
marienfressinaud committed Nov 28, 2024
1 parent ebf6a49 commit 17c1bcf
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 35 deletions.
6 changes: 4 additions & 2 deletions src/jobs/scheduled/Cleaner.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use App\models;
use App\services;
use App\utils;

/**
* Job to clean the system.
Expand Down Expand Up @@ -45,7 +44,10 @@ public function perform(): void
models\FetchLog::deleteOlderThan(\Minz\Time::ago(3, 'days'));
models\Token::deleteExpired();
models\Session::deleteExpired();
models\User::deleteNotValidatedOlderThan(\Minz\Time::ago(6, 'months'));
models\User::deleteInactiveAndNotified(
inactive_since: \Minz\Time::ago(6, 'months'),
notified_since: \Minz\Time::ago(1, 'month'),
);
models\Collection::deleteUnfollowedOlderThan($support_user->id, \Minz\Time::ago(7, 'days'));
models\Link::deleteNotStoredOlderThan($support_user->id, \Minz\Time::ago(7, 'days'));
/** @var int */
Expand Down
20 changes: 14 additions & 6 deletions src/models/dao/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,28 @@ public static function countActivePerMonth(int $year): array
}

/**
* Delete not validated users older than the given date.
* Delete the inactive users that have been notified about it.
*/
public static function deleteNotValidatedOlderThan(\DateTimeImmutable $date): bool
{
public static function deleteInactiveAndNotified(
\DateTimeImmutable $inactive_since,
\DateTimeImmutable $notified_since
): bool {
$sql = <<<SQL
DELETE FROM users
WHERE validated_at IS NULL
AND created_at < ?
WHERE last_activity_at <= :inactive_since
AND deletion_notified_at <= :notified_since
AND email != :support_email
SQL;

/** @var string */
$support_email = \Minz\Configuration::$application['support_email'];

$database = Database::get();
$statement = $database->prepare($sql);
return $statement->execute([
$date->format(Database\Column::DATETIME_FORMAT),
':inactive_since' => $inactive_since->format(Database\Column::DATETIME_FORMAT),
':notified_since' => $notified_since->format(Database\Column::DATETIME_FORMAT),
':support_email' => \Minz\Email::sanitize($support_email),
]);
}

Expand Down
94 changes: 67 additions & 27 deletions tests/jobs/scheduled/CleanerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,56 +137,96 @@ public function testPerformKeepsCurrentSession(): void
$this->assertTrue(models\Token::exists($token->token));
}

public function testPerformDeletesOldInvalidatedUsers(): void
public function testPerformDeletesInactiveAndNotifiedUsers(): void
{
/** @var \DateTimeImmutable */
$now = $this->fake('dateTime');
$this->freeze($now);
$this->freeze();
$cleaner_job = new Cleaner();
/** @var int */
$months = $this->fake('numberBetween', 7, 24);
$created_at = \Minz\Time::ago($months, 'months');
$inactivity_months = 6;
$notified_months = 1;
$user = UserFactory::create([
'created_at' => $created_at,
'validated_at' => null,
'last_activity_at' => \Minz\Time::ago($inactivity_months, 'months'),
'deletion_notified_at' => \Minz\Time::ago($notified_months, 'months'),
]);

$cleaner_job->perform();

$this->assertFalse(models\User::exists($user->id));
}

public function testPerformKeepsOldValidatedUsers(): void
public function testPerformKeepsInactiveButNotNotifiedUsers(): void
{
/** @var \DateTimeImmutable */
$now = $this->fake('dateTime');
$this->freeze($now);
$this->freeze();
$cleaner_job = new Cleaner();
/** @var int */
$months = $this->fake('numberBetween', 7, 24);
$created_at = \Minz\Time::ago($months, 'months');
$inactivity_months = 6;
$user = UserFactory::create([
'created_at' => $created_at,
'validated_at' => \Minz\Time::now(),
'last_activity_at' => \Minz\Time::ago($inactivity_months, 'months'),
'deletion_notified_at' => null,
]);

$cleaner_job->perform();

$this->assertTrue(models\User::exists($user->id));
}

public function testPerformKeepsRecentInvalidatedUsers(): void
public function testPerformKeepsRecentNotifiedUser(): void
{
/** @var \DateTimeImmutable */
$now = $this->fake('dateTime');
$this->freeze($now);
$this->freeze();
$cleaner_job = new Cleaner();
/** @var int */
$months = $this->fake('numberBetween', 0, 6);
$created_at = \Minz\Time::ago($months, 'months');
$inactivity_months = 6;
$notified_months = 0;
$user = UserFactory::create([
'created_at' => $created_at,
'validated_at' => null,
'last_activity_at' => \Minz\Time::ago($inactivity_months, 'months'),
'deletion_notified_at' => \Minz\Time::ago($notified_months, 'months'),
]);

$cleaner_job->perform();

$this->assertTrue(models\User::exists($user->id));
}

public function testPerformKeepsRecentInactiveButNotifiedUsers(): void
{
$this->freeze();
$cleaner_job = new Cleaner();
$inactivity_months = 5;
$notified_months = 1;
$user = UserFactory::create([
'last_activity_at' => \Minz\Time::ago($inactivity_months, 'months'),
'deletion_notified_at' => \Minz\Time::ago($notified_months, 'months'),
]);

$cleaner_job->perform();

$this->assertTrue(models\User::exists($user->id));
}

public function testPerformKeepsActiveUsers(): void
{
$this->freeze();
$cleaner_job = new Cleaner();
$inactivity_months = 0;
$user = UserFactory::create([
'last_activity_at' => \Minz\Time::ago($inactivity_months, 'months'),
'deletion_notified_at' => null,
]);

$cleaner_job->perform();

$this->assertTrue(models\User::exists($user->id));
}

public function testPerformKeepsSupportUser(): void
{
$this->freeze();
$cleaner_job = new Cleaner();
/** @var string */
$support_email = \Minz\Configuration::$application['support_email'];
$inactivity_months = 6;
$notified_months = 1;
$user = UserFactory::create([
'last_activity_at' => \Minz\Time::ago($inactivity_months, 'months'),
'deletion_notified_at' => \Minz\Time::ago($notified_months, 'months'),
'email' => $support_email,
]);

$cleaner_job->perform();
Expand Down

0 comments on commit 17c1bcf

Please sign in to comment.