Implemented account deletion. Not all cases covered with tests [skip ci]

This commit is contained in:
ErickSkrauch
2020-06-12 00:27:02 +03:00
parent c86817a93d
commit 0183e54442
56 changed files with 1041 additions and 188 deletions

View File

@@ -7,15 +7,12 @@ use common\models\Account;
use Yii;
use yii\queue\RetryableJobInterface;
class ClearAccountSessions implements RetryableJobInterface {
final class ClearAccountSessions implements RetryableJobInterface {
public $accountId;
private int $accountId;
public static function createFromAccount(Account $account): self {
$result = new static();
$result->accountId = $account->id;
return $result;
public function __construct(int $accountId) {
$this->accountId = $accountId;
}
/**
@@ -40,23 +37,23 @@ class ClearAccountSessions implements RetryableJobInterface {
* @throws \Exception
*/
public function execute($queue): void {
$account = Account::findOne($this->accountId);
$account = Account::findOne(['id' => $this->accountId]);
if ($account === null) {
return;
}
/** @var \common\models\AccountSession $authSession */
foreach ($account->getSessions()->each(100, Yii::$app->unbufferedDb) as $authSession) {
/** @var \common\models\AccountSession $authSession */
$authSession->delete();
}
/** @var \common\models\MinecraftAccessKey $key */
foreach ($account->getMinecraftAccessKeys()->each(100, Yii::$app->unbufferedDb) as $key) {
/** @var \common\models\MinecraftAccessKey $key */
$key->delete();
}
/** @var \common\models\OauthSession $oauthSession */
foreach ($account->getOauthSessions()->each(100, Yii::$app->unbufferedDb) as $oauthSession) {
/** @var \common\models\OauthSession $oauthSession */
$oauthSession->delete();
}
}

View File

@@ -7,26 +7,22 @@ use common\models\OauthClient;
use Yii;
use yii\queue\RetryableJobInterface;
class ClearOauthSessions implements RetryableJobInterface {
final class ClearOauthSessions implements RetryableJobInterface {
public string $clientId;
/**
* @var int
* @var int|null unix timestamp, that allows to limit this task to clear only some old sessions
*/
public $clientId;
public ?int $notSince;
/**
* @var int unix timestamp, that allows to limit this task to clear only some old sessions
*/
public $notSince;
public function __construct(string $clientId, int $notSince = null) {
$this->clientId = $clientId;
$this->notSince = $notSince;
}
public static function createFromOauthClient(OauthClient $client, int $notSince = null): self {
$result = new static();
$result->clientId = $client->id;
if ($notSince !== null) {
$result->notSince = $notSince;
}
return $result;
return new self($client->id, $notSince);
}
public function getTtr(): int {

View File

@@ -8,39 +8,46 @@ use common\models\WebHook;
use Yii;
use yii\queue\RetryableJobInterface;
class CreateWebHooksDeliveries implements RetryableJobInterface {
final class CreateWebHooksDeliveries implements RetryableJobInterface {
/**
* @var string
*/
public $type;
public string $type;
/**
* @var array
*/
public $payloads;
public array $payloads;
public function __construct(string $type, array $payloads) {
$this->type = $type;
$this->payloads = $payloads;
}
public static function createAccountEdit(Account $account, array $changedAttributes): self {
$result = new static();
$result->type = 'account.edit';
$result->payloads = [
return new static('account.edit', [
'id' => $account->id,
'uuid' => $account->uuid,
'username' => $account->username,
'email' => $account->email,
'lang' => $account->lang,
'isActive' => $account->status === Account::STATUS_ACTIVE,
'isDeleted' => $account->status === Account::STATUS_DELETED,
'registered' => date('c', (int)$account->created_at),
'changedAttributes' => $changedAttributes,
];
]);
}
return $result;
public static function createAccountDeletion(Account $account): self {
return new static('account.deletion', [
'id' => $account->id,
'uuid' => $account->uuid,
'username' => $account->username,
'email' => $account->email,
'registered' => date('c', (int)$account->created_at),
'deleted' => date('c', (int)$account->deleted_at),
]);
}
/**
* @return int time to reserve in seconds
*/
public function getTtr() {
public function getTtr(): int {
return 10;
}
@@ -50,14 +57,14 @@ class CreateWebHooksDeliveries implements RetryableJobInterface {
*
* @return bool
*/
public function canRetry($attempt, $error) {
public function canRetry($attempt, $error): bool {
return true;
}
/**
* @param \yii\queue\Queue $queue which pushed and is handling the job
*/
public function execute($queue) {
public function execute($queue): void {
/** @var WebHook[] $targets */
$targets = WebHook::find()
->joinWith('events e', false)

View File

@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace common\tasks;
use common\models\Account;
use Yii;
use yii\queue\RetryableJobInterface;
final class DeleteAccount implements RetryableJobInterface {
private int $accountId;
public function __construct(int $accountId) {
$this->accountId = $accountId;
}
public function getTtr(): int {
return PHP_INT_MAX; // Let it work as long as it needs to
}
public function canRetry($attempt, $error): bool {
return true;
}
/**
* @param \yii\queue\Queue $queue
* @throws \Throwable
*/
public function execute($queue): void {
$account = Account::findOne(['id' => $this->accountId]);
if ($account === null || $this->shouldAccountBeDeleted($account) === false) {
return;
}
$transaction = Yii::$app->db->beginTransaction();
(new ClearAccountSessions($account->id))->execute($queue);
foreach ($account->oauthClients as $oauthClient) {
(new ClearOauthSessions($oauthClient->id))->execute($queue);
}
/** @var \common\models\EmailActivation $emailActivation */
foreach ($account->getEmailActivations()->each(100, Yii::$app->unbufferedDb) as $emailActivation) {
$emailActivation->delete();
}
/** @var \common\models\UsernameHistory $usernameHistoryEntry */
foreach ($account->getUsernameHistory()->each(100, Yii::$app->unbufferedDb) as $usernameHistoryEntry) {
$usernameHistoryEntry->delete();
}
$account->delete();
$transaction->commit();
}
private function shouldAccountBeDeleted(Account $account): bool {
return $account->status === Account::STATUS_DELETED && $account->getDeleteAt()->subSecond()->isPast();
}
}