feat: harden admin auth and ticket workflows

- add rotating admin refresh tokens and password gates\n- expand ticket galleries, exports, and client resources\n- improve IP allocation auditing and dashboard data\n- enforce encrypted client access tokens on public routes
This commit is contained in:
baodev0
2026-10-16 17:00:55 +07:00
parent 0cdf224309
commit 0b08689ea4
52 changed files with 1421 additions and 118 deletions
+21 -1
View File
@@ -45,6 +45,7 @@ class IpAllocationService
return DB::transaction(function () use ($ids, $customer, $data, $admin, $files) {
$pools = $this->allocatable($this->pools($ids, lock: true));
$copies = $this->emailCopies(IpAllocationMail::ALLOCATED, $data['cc'] ?? null);
foreach ($pools as $pool) {
$from = $pool->status;
@@ -67,6 +68,7 @@ class IpAllocationService
'customer_name' => $customer->fullname,
'service_name' => $pool->service_name,
'email_to' => $data['to'],
...$copies,
'note' => $data['note'] ?? null,
]);
}
@@ -116,6 +118,7 @@ class IpAllocationService
$groups = $this->revocationGroups($this->revocable($this->pools($ids, lock: true)));
return $groups->map(function (Collection $pools, string $key) use ($data, $recipients, $admin) {
$copies = $this->emailCopies(IpAllocationMail::REVOKED, $recipients[$key]['cc'] ?? null);
$mail = $this->revocationMail($pools, $data, $recipients[$key]['subject'] ?? null);
$customerId = $pools->first()->customer_id;
foreach ($pools as $pool) {
@@ -136,6 +139,7 @@ class IpAllocationService
...$before,
'effective_date' => $data['date'],
'email_to' => $recipients[$key]['to'],
...$copies,
'note' => $data['note'] ?? null,
]);
}
@@ -255,19 +259,35 @@ class IpAllocationService
}
}
/**
* @return array{email_cc: string|null, email_bcc: string|null}
*/
private function emailCopies(string $scenario, ?string $cc): array
{
$config = $this->templates->loadTemplate($scenario)->mailConfig();
$join = fn (array $emails) => $emails ? implode(', ', array_values(array_unique($emails))) : null;
return [
'email_cc' => $join([...EmailRecipients::parse($cc), ...($config['cc'] ?? [])]),
'email_bcc' => $join($config['bcc'] ?? []),
];
}
private function send(IpAllocationMail $mail, string $to, ?string $cc, ?int $customerId, User $admin): void
{
AutoEmailGate::markManual();
$template = $this->templates->loadTemplate($mail->type);
$toList = EmailRecipients::parse($to);
$ccList = EmailRecipients::parse($cc);
$copies = $this->emailCopies($mail->type, $cc);
MailLog::create([
'template_id' => $template->id,
'subject' => $mail->envelope()->subject,
'from_address' => $template->mailConfig()['from_email'] ?? config('mail.from.address'),
'to' => implode(', ', $toList),
'cc' => $ccList ? implode(', ', $ccList) : null,
'cc' => $copies['email_cc'],
'bcc' => $copies['email_bcc'],
'customer_id' => $customerId,
'sent_by' => $admin->id,
'message' => (clone $mail)->render(),