$user->getKey(), 'reason' => $reason, 'status' => AccountDeletionRequest::STATUS_PENDING, 'metadata' => $metadata, ]); $this->auditLog->record( category: 'account_deletion', event: 'requested', context: ['deletion_request_id' => $request->getKey()], subject: $user ); $extension = ExtensionHelper::getExtension('other', 'ComplianceTools'); if ($extension && $extension->config('auto_approve_deletions')) { $this->approve($request, null, '[auto-approved]'); } return $request->fresh(); } public function approve(AccountDeletionRequest $request, ?User $processor = null, ?string $notes = null): AccountDeletionRequest { if ($request->status === AccountDeletionRequest::STATUS_COMPLETED) { return $request; } DB::transaction(function () use ($request, $processor, $notes) { $request->forceFill([ 'status' => AccountDeletionRequest::STATUS_APPROVED, 'admin_notes' => $notes, 'processed_by' => $processor?->getKey(), 'processed_at' => now(), 'snapshot' => $this->snapshotUser($request->user), ])->save(); $this->anonymizeUser($request->user); $request->forceFill(['status' => AccountDeletionRequest::STATUS_COMPLETED])->save(); }); $this->auditLog->record( category: 'account_deletion', event: 'approved', context: ['deletion_request_id' => $request->getKey()], subject: $request->user, actor: $processor ); return $request; } public function deny(AccountDeletionRequest $request, User $processor, ?string $notes = null): AccountDeletionRequest { if ($request->status !== AccountDeletionRequest::STATUS_PENDING) { return $request; } $request->forceFill([ 'status' => AccountDeletionRequest::STATUS_DENIED, 'admin_notes' => $notes, 'processed_by' => $processor->getKey(), 'processed_at' => now(), ])->save(); $this->auditLog->record( category: 'account_deletion', event: 'denied', context: ['deletion_request_id' => $request->getKey()], subject: $request->user, actor: $processor ); return $request; } protected function snapshotUser(User $user): array { return [ 'user' => $user->only([ 'id', 'first_name', 'last_name', 'email', 'created_at', ]), ]; } protected function anonymizeUser(User $user): void { $anonymizedEmail = sprintf('deleted-user-%s-%s@anonymous.invalid', $user->getKey(), Str::random(10)); $updates = [ 'first_name' => null, 'last_name' => null, 'email' => $anonymizedEmail, 'password' => Hash::make(Str::random(32)), 'tfa_secret' => null, ]; if (method_exists($user, 'properties') && $user->properties()->exists()) { $user->properties()->delete(); } $user->forceFill($updates)->save(); if (method_exists($user, 'tokens')) { $user->tokens()->delete(); } if (method_exists($user, 'sessions')) { $user->sessions()->delete(); } $this->auditLog->record( category: 'account_deletion', event: 'anonymized', context: ['user_id' => $user->getKey(), 'email' => $anonymizedEmail], subject: $user ); } }