feat: implement soft deletes, mailbox reclaims, cooldowns, and auto-cleanup

This commit is contained in:
idevakk
2026-03-06 02:39:47 +05:30
parent e79c3f79a2
commit e6fd4e6f4c
8 changed files with 176 additions and 11 deletions

View File

@@ -209,9 +209,77 @@ class Mailbox extends Component
return;
}
$address = $this->createType === 'random'
? fake()->userName().'_'.rand(10, 99).'@'.$this->customDomain
: $this->customUsername.'@'.$this->customDomain;
if ($this->createType === 'random') {
do {
$address = fake()->userName().rand(10, 99).'@'.$this->customDomain;
} while (MailboxModel::withTrashed()->where('address', $address)->exists());
} else {
$address = $this->customUsername.'@'.$this->customDomain;
// Check if address already exists
$existing = MailboxModel::withTrashed()->where('address', $address)->first();
if ($existing) {
// Scenario A: Same User Reclaiming
$isOwner = (auth()->check() && $existing->user_id === auth()->id())
|| ($existing->session_id === Session::getId());
if ($isOwner) {
if ($existing->trashed()) {
$existing->restore();
}
if (now() > $existing->expires_at) {
$existing->update([
'expires_at' => now()->addDays($this->getValidityDays()),
'last_accessed_at' => now(),
]);
}
$this->currentMailboxId = $existing->id;
$this->showCreateModal = false;
$this->customUsername = '';
Session::put('last_mailbox_id', $existing->id);
return;
}
// Scenario B: Different User Claiming
if (! $existing->trashed()) {
$this->dispatch('notify', message: 'Address already in use.', type: 'danger');
return;
}
// Address is soft-deleted. Check Tier-based Cooldown
$user = auth()->user();
$hoursRequired = match (true) {
! $user => 24, // Guest
$user->isEnterprise() || $user->isAdmin() => 0,
$user->isPro() => 6,
$user->isFree() => 12,
default => 12,
};
$cooldownEndsAt = $existing->deleted_at->copy()->addHours($hoursRequired);
if (now()->lessThan($cooldownEndsAt)) {
$diff = now()->diff($cooldownEndsAt);
$parts = [];
if ($diff->d > 0) $parts[] = $diff->d . 'd';
if ($diff->h > 0) $parts[] = $diff->h . 'h';
if ($diff->i > 0) $parts[] = $diff->i . 'm';
if ($diff->s > 0 || empty($parts)) $parts[] = $diff->s . 's';
$remaining = implode(' ', $parts);
$this->dispatch('notify', message: "Address is in cooldown. Try again in {$remaining}.", type: 'warning');
return;
}
// Cooldown passed. Permanently delete the old record to sever email history.
$existing->forceDelete();
}
}
$mailbox = MailboxModel::create([
'mailbox_hash' => bin2hex(random_bytes(32)),
@@ -250,7 +318,9 @@ class Mailbox extends Component
return;
}
$address = fake()->userName().'_'.rand(10, 99).'@'.$domain->name;
do {
$address = fake()->userName().rand(10, 99).'@'.$domain->name;
} while (MailboxModel::withTrashed()->where('address', $address)->exists());
$mailbox = MailboxModel::create([
'mailbox_hash' => bin2hex(random_bytes(32)),
@@ -297,7 +367,7 @@ class Mailbox extends Component
$this->autoCreateRandomMailbox();
}
$this->isCreatingFirstMailbox = false;
// Ensure the component re-renders fully with the new data
$this->dispatch('$refresh');
}