eraseScheduledAccount static method
Runs job: erases the account and removes it, when its deletion is
still scheduled and its window has closed.
The deletion is claimed by compare-and-set first. A person who signed in to cancel moved it to cancelled, and the claim finds nothing to take -- however long the job waited in the queue. An erasure that cannot reach an adapter (DV-PRIVACY-009) puts the deletion back and throws, so the account stays until one completes.
Implementation
static Future<void> eraseScheduledAccount(DVAccountErasureJob job) async {
final DVPrivacy? privacy = _configuredPrivacy();
if (privacy == null) {
throw StateError('An account erasure is due and DV.Privacy is not '
'configured in this process. Set DARTVEL_PRIVACY_KEY.');
}
final DVAccountDeletionStore store = _deletionStore(privacy);
final DVAccountDeletion? deletion = await store.find(job.userId);
if (deletion == null) return;
final DateTime now = clock().toUtc();
final DateTime? claimed = deletion.claimedAt;
final bool claimable = switch (deletion.state) {
DVAccountDeletionState.scheduled => !now.isBefore(deletion.dueAt),
DVAccountDeletionState.erasing =>
claimed != null && now.difference(claimed) >= staleErasureClaim,
_ => false,
};
if (!claimable) return;
if (!await store.move(job.userId,
from: deletion.state,
to: DVAccountDeletionState.erasing,
claimedAt: claimed,
newClaimedAt: now)) {
return;
}
try {
final Object? provider = _credentials?.provider;
if (provider is! DVAccountProvider) {
throw StateError('An account erasure is due and no DVAccountProvider '
'is installed with DVAuthEndpoints.install in this process.');
}
final DVErasureResult erasure = await privacy.erase(
subject: job.userId,
reason: 'The account holder deleted their account.',
requestedAt: deletion.requestedAt,
requestedBy: job.userId,
runBy: 'DVAuthEndpoints.eraseScheduledAccount',
);
if (!erasure.complete) {
throw StateError('The account erasure could not reach '
'${erasure.unreached.join(', ')} (DV-PRIVACY-009).');
}
await _removeAccount(provider, job.userId);
await store.move(job.userId,
from: DVAccountDeletionState.erasing,
to: DVAccountDeletionState.erased,
claimedAt: now);
} on Object {
await store.move(job.userId,
from: DVAccountDeletionState.erasing,
to: DVAccountDeletionState.scheduled,
claimedAt: now);
rethrow;
}
}