fix(social): unify status lock + i18n notification strings

Two follow-up fixes from the code review:

1. **Unified lock key for markAsDisconnected / markAsTokenExpired.**
   Both methods now use `social_account_status:{id}` instead of
   different keys. Prevents the race where `markAsDisconnected` and
   `markAsTokenExpired` could run concurrently on the same account
   (publish-time vs verify-batch-time), causing overlapping updates and
   duplicate notifications.

2. **i18n for notification title/body in markAsTokenExpired and
   markAsDisconnected.** Strings were previously hardcoded in English.
   Added `notifications.account_disconnected.{title,body}` and
   `notifications.account_token_expired.{title,body}` in en, pt-BR, es.
   Follows the project convention (e.g. `Mail/PostPublished`) of
   concatenating the `@` prefix in PHP before passing the username to
   the translation placeholder, instead of putting `@:account` in the
   lang file.
This commit is contained in:
Paulo Castellano 2026-05-12 19:11:23 -03:00
parent d349e499b5
commit a37eb6ae9e
7 changed files with 41 additions and 13 deletions

View file

@ -130,7 +130,7 @@ protected function profileUrl(): Attribute
public function markAsDisconnected(string $errorMessage): void
{
$lock = Cache::lock("social_account_disconnect:{$this->id}", 10);
$lock = Cache::lock("social_account_status:{$this->id}", 10);
if ($lock->get()) {
try {
@ -144,16 +144,18 @@ public function markAsDisconnected(string $errorMessage): void
]);
if ($wasConnected && $this->workspace->owner) {
$platformName = $this->platform->label();
$accountName = $this->username ?? $this->display_name;
$placeholders = [
'platform' => $this->platform->label(),
'account' => '@'.($this->username ?? $this->display_name),
];
SendNotification::dispatch(
user: $this->workspace->owner,
workspaceId: $this->workspace_id,
type: Type::AccountDisconnected,
channel: Channel::Both,
title: "{$platformName} account disconnected",
body: "@{$accountName} needs to be reconnected",
title: __('notifications.account_disconnected.title', $placeholders),
body: __('notifications.account_disconnected.body', $placeholders),
data: ['social_account_id' => $this->id],
mailable: new AccountDisconnected($this),
);
@ -166,7 +168,7 @@ public function markAsDisconnected(string $errorMessage): void
public function markAsTokenExpired(string $errorMessage, bool $notify = true): void
{
$lock = Cache::lock("social_account_token_expired:{$this->id}", 10);
$lock = Cache::lock("social_account_status:{$this->id}", 10);
if (! $lock->get()) {
return;
@ -183,16 +185,18 @@ public function markAsTokenExpired(string $errorMessage, bool $notify = true): v
]);
if ($notify && $wasUsable && $this->workspace->owner) {
$platformName = $this->platform->label();
$accountName = $this->username ?? $this->display_name;
$placeholders = [
'platform' => $this->platform->label(),
'account' => '@'.($this->username ?? $this->display_name),
];
SendNotification::dispatch(
user: $this->workspace->owner,
workspaceId: $this->workspace_id,
type: Type::AccountDisconnected,
channel: Channel::Both,
title: "{$platformName} account needs to be reconnected",
body: "@{$accountName} session expired — please reconnect to keep posting",
title: __('notifications.account_token_expired.title', $placeholders),
body: __('notifications.account_token_expired.body', $placeholders),
data: ['social_account_id' => $this->id],
mailable: new AccountDisconnected($this),
);

View file

@ -7,4 +7,12 @@
'title' => 'Your post is ready',
'body' => 'The AI just finished. Tap to review and publish.',
],
'account_disconnected' => [
'title' => ':platform account disconnected',
'body' => ':account needs to be reconnected',
],
'account_token_expired' => [
'title' => ':platform account needs to be reconnected',
'body' => ':account session expired — please reconnect to keep posting',
],
];

View file

@ -7,4 +7,12 @@
'title' => 'Tu publicación está lista',
'body' => 'La IA terminó. Toca para revisar y publicar.',
],
'account_disconnected' => [
'title' => 'Cuenta de :platform desconectada',
'body' => ':account necesita reconectarse',
],
'account_token_expired' => [
'title' => 'Cuenta de :platform necesita reconectarse',
'body' => 'La sesión de :account expiró — reconéctala para seguir publicando',
],
];

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -7,4 +7,12 @@
'title' => 'Seu post está pronto',
'body' => 'A AI terminou. Toque pra revisar e publicar.',
],
'account_disconnected' => [
'title' => 'Conta do :platform desconectada',
'body' => ':account precisa ser reconectada',
],
'account_token_expired' => [
'title' => 'Conta do :platform precisa ser reconectada',
'body' => 'Sessão de :account expirou — reconecte pra continuar postando',
],
];