From a1df51234bf6cd4ebaaa14754132080e883d8174 Mon Sep 17 00:00:00 2001 From: Paulo Castellano Date: Wed, 1 Apr 2026 12:02:15 -0300 Subject: [PATCH] =?UTF-8?q?fix:=20review=20#5=20=E2=80=94=20ContentSanitiz?= =?UTF-8?q?er=20in=20all=20publishers,=20refresh=20lock,=20CheckSocialConn?= =?UTF-8?q?ections=20includes=20TokenExpired?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Commands/CheckSocialConnections.php | 2 +- app/Models/SocialAccount.php | 1 - app/Services/Social/ConnectionVerifier.php | 40 +++++++++++++------ app/Services/Social/MastodonPublisher.php | 4 +- app/Services/Social/PinterestPublisher.php | 26 ++++++------ app/Services/Social/XPublisher.php | 8 ++-- 6 files changed, 50 insertions(+), 31 deletions(-) diff --git a/app/Console/Commands/CheckSocialConnections.php b/app/Console/Commands/CheckSocialConnections.php index f7df092e..b8d35acd 100644 --- a/app/Console/Commands/CheckSocialConnections.php +++ b/app/Console/Commands/CheckSocialConnections.php @@ -19,7 +19,7 @@ public function handle(): void { Workspace::query() ->whereHas('socialAccounts', function ($query) { - $query->where('status', Status::Connected); + $query->whereIn('status', [Status::Connected, Status::TokenExpired]); }) ->with('owner') ->chunk(100, function ($workspaces) { diff --git a/app/Models/SocialAccount.php b/app/Models/SocialAccount.php index a8f9bdc0..8e2a47f4 100644 --- a/app/Models/SocialAccount.php +++ b/app/Models/SocialAccount.php @@ -136,7 +136,6 @@ public function markAsTokenExpired(string $errorMessage): void $this->update([ 'status' => Status::TokenExpired, 'error_message' => $errorMessage, - 'disconnected_at' => now(), ]); } diff --git a/app/Services/Social/ConnectionVerifier.php b/app/Services/Social/ConnectionVerifier.php index f2ec7bc4..50cbca7b 100644 --- a/app/Services/Social/ConnectionVerifier.php +++ b/app/Services/Social/ConnectionVerifier.php @@ -7,6 +7,7 @@ use App\Enums\SocialAccount\Platform; use App\Exceptions\TokenExpiredException; use App\Models\SocialAccount; +use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; @@ -46,19 +47,32 @@ public function verify(SocialAccount $account): bool */ private function refreshTokenIfNeeded(SocialAccount $account): void { - match ($account->platform) { - Platform::LinkedIn, Platform::LinkedInPage => $this->refreshLinkedInToken($account), - Platform::X => $this->refreshXToken($account), - Platform::Bluesky => $this->refreshBlueskyToken($account), - Platform::YouTube => $this->refreshYouTubeToken($account), - Platform::TikTok => $this->refreshTikTokToken($account), - Platform::Pinterest => $this->refreshPinterestToken($account), - Platform::Threads => $this->refreshThreadsToken($account), - Platform::Instagram => $this->refreshInstagramToken($account), - // Facebook uses page tokens that don't expire - // Mastodon tokens don't expire - default => null, - }; + $lock = Cache::lock("token_refresh:{$account->id}", 30); + + if (! $lock->get()) { + // Another process is already refreshing this token + $account->refresh(); + + return; + } + + try { + match ($account->platform) { + Platform::LinkedIn, Platform::LinkedInPage => $this->refreshLinkedInToken($account), + Platform::X => $this->refreshXToken($account), + Platform::Bluesky => $this->refreshBlueskyToken($account), + Platform::YouTube => $this->refreshYouTubeToken($account), + Platform::TikTok => $this->refreshTikTokToken($account), + Platform::Pinterest => $this->refreshPinterestToken($account), + Platform::Threads => $this->refreshThreadsToken($account), + Platform::Instagram => $this->refreshInstagramToken($account), + // Facebook uses page tokens that don't expire + // Mastodon tokens don't expire + default => null, + }; + } finally { + $lock->release(); + } } private function refreshLinkedInToken(SocialAccount $account): void diff --git a/app/Services/Social/MastodonPublisher.php b/app/Services/Social/MastodonPublisher.php index 4e37940a..c6e076d6 100644 --- a/app/Services/Social/MastodonPublisher.php +++ b/app/Services/Social/MastodonPublisher.php @@ -22,6 +22,8 @@ public function publish(PostPlatform $postPlatform): array { $this->validateContentLength($postPlatform); + $content = $postPlatform->content ? app(ContentSanitizer::class)->sanitize($postPlatform->content, $postPlatform->platform) : null; + $account = $postPlatform->socialAccount; $instance = $account->meta['instance'] ?? 'https://mastodon.social'; @@ -38,7 +40,7 @@ public function publish(PostPlatform $postPlatform): array // Create status $payload = [ - 'status' => $postPlatform->content ?? '', + 'status' => $content ?? '', 'visibility' => 'public', ]; diff --git a/app/Services/Social/PinterestPublisher.php b/app/Services/Social/PinterestPublisher.php index 480e52af..cbce0587 100644 --- a/app/Services/Social/PinterestPublisher.php +++ b/app/Services/Social/PinterestPublisher.php @@ -32,15 +32,17 @@ public function publish(PostPlatform $postPlatform): array $account->refresh(); } + $content = $postPlatform->content ? app(ContentSanitizer::class)->sanitize($postPlatform->content, $postPlatform->platform) : null; + return match ($postPlatform->content_type) { - ContentType::PinterestPin => $this->publishImagePin($postPlatform), - ContentType::PinterestVideoPin => $this->publishVideoPin($postPlatform), - ContentType::PinterestCarousel => $this->publishCarousel($postPlatform), + ContentType::PinterestPin => $this->publishImagePin($postPlatform, $content), + ContentType::PinterestVideoPin => $this->publishVideoPin($postPlatform, $content), + ContentType::PinterestCarousel => $this->publishCarousel($postPlatform, $content), default => throw new \Exception("Unsupported content type: {$postPlatform->content_type->value}"), }; } - private function publishImagePin(PostPlatform $postPlatform): array + private function publishImagePin(PostPlatform $postPlatform, ?string $content): array { $account = $postPlatform->socialAccount; $media = $postPlatform->media->first(); @@ -87,8 +89,8 @@ private function publishImagePin(PostPlatform $postPlatform): array ], ]; - if ($postPlatform->content) { - $payload['description'] = $postPlatform->content; + if ($content) { + $payload['description'] = $content; } if (! empty(data_get($postPlatform->meta, 'title'))) { @@ -122,7 +124,7 @@ private function publishImagePin(PostPlatform $postPlatform): array ]; } - private function publishVideoPin(PostPlatform $postPlatform): array + private function publishVideoPin(PostPlatform $postPlatform, ?string $content): array { $account = $postPlatform->socialAccount; $media = $postPlatform->media->first(); @@ -221,8 +223,8 @@ private function publishVideoPin(PostPlatform $postPlatform): array ], ]; - if ($postPlatform->content) { - $payload['description'] = $postPlatform->content; + if ($content) { + $payload['description'] = $content; } if (! empty(data_get($postPlatform->meta, 'title'))) { @@ -256,7 +258,7 @@ private function publishVideoPin(PostPlatform $postPlatform): array ]; } - private function publishCarousel(PostPlatform $postPlatform): array + private function publishCarousel(PostPlatform $postPlatform, ?string $content): array { $account = $postPlatform->socialAccount; $medias = $postPlatform->media; @@ -283,8 +285,8 @@ private function publishCarousel(PostPlatform $postPlatform): array ], ]; - if ($postPlatform->content) { - $payload['description'] = $postPlatform->content; + if ($content) { + $payload['description'] = $content; } if (! empty(data_get($postPlatform->meta, 'title'))) { diff --git a/app/Services/Social/XPublisher.php b/app/Services/Social/XPublisher.php index d9b483b0..dbbdc876 100644 --- a/app/Services/Social/XPublisher.php +++ b/app/Services/Social/XPublisher.php @@ -28,6 +28,8 @@ public function publish(PostPlatform $postPlatform): array { $this->validateContentLength($postPlatform); + $content = $postPlatform->content ? app(ContentSanitizer::class)->sanitize($postPlatform->content, $postPlatform->platform) : null; + $account = $postPlatform->socialAccount; // Refresh token if expired or expiring soon @@ -40,8 +42,8 @@ public function publish(PostPlatform $postPlatform): array $data = []; - if (! empty($postPlatform->content)) { - $data['text'] = $postPlatform->content; + if (! empty($content)) { + $data['text'] = $content; } $mediaIds = []; @@ -65,7 +67,7 @@ public function publish(PostPlatform $postPlatform): array ]; } - if (empty($data['text'] ?? null) && empty($mediaIds)) { + if (empty($content) && empty($mediaIds)) { throw new \Exception('X posts require either text or media. Please add content to your post.'); }