From f8084d144ce3088cfe4100f54cc4a5d8ced88441 Mon Sep 17 00:00:00 2001 From: myrmidex Date: Mon, 10 Aug 2026 20:44:57 +0200 Subject: [PATCH] 91 - Record activity from fetch, validate and publish paths --- app/Actions/PublishRouteArticleAction.php | 30 +++++++++++++++++++++++ app/Jobs/ArticleDiscoveryForFeedJob.php | 18 ++++++++++++++ app/Listeners/ValidateArticleListener.php | 16 ++++++++++++ app/Models/RouteArticle.php | 20 +++++++++++++++ 4 files changed, 84 insertions(+) diff --git a/app/Actions/PublishRouteArticleAction.php b/app/Actions/PublishRouteArticleAction.php index cb2b3180..2185d3c8 100644 --- a/app/Actions/PublishRouteArticleAction.php +++ b/app/Actions/PublishRouteArticleAction.php @@ -2,11 +2,13 @@ namespace App\Actions; +use App\Enums\ActivityTypeEnum; use App\Enums\LogLevelEnum; use App\Enums\NotificationSeverityEnum; use App\Enums\NotificationTypeEnum; use App\Enums\PublishStatusEnum; use App\Events\ActionPerformed; +use App\Events\ActivityLogged; use App\Exceptions\PublishException; use App\Models\Article; use App\Models\RouteArticle; @@ -48,6 +50,13 @@ public function execute(RouteArticle $routeArticle): PublishOutcome 'error' => $e->getMessage(), ]); + ActivityLogged::dispatch( + ActivityTypeEnum::ERROR, + "Failed to publish \"{$article->title}\"", + ['error' => $e->getMessage()], + $article, + ); + $this->notificationService->send( NotificationTypeEnum::PUBLISH_FAILED, NotificationSeverityEnum::ERROR, @@ -101,6 +110,13 @@ private function recordPublished(RouteArticle $routeArticle): void 'article_id' => $routeArticle->article->id, 'title' => $routeArticle->article->title, ]); + + ActivityLogged::dispatch( + ActivityTypeEnum::PUBLISH, + "Published \"{$routeArticle->article->title}\"", + ['route_article_id' => $routeArticle->id], + $routeArticle->article, + ); } private function recordSkipped(RouteArticle $routeArticle, PublishOutcome $outcome): void @@ -112,6 +128,13 @@ private function recordSkipped(RouteArticle $routeArticle, PublishOutcome $outco 'title' => $routeArticle->article->title, 'reason' => $outcome->reason, ]); + + ActivityLogged::dispatch( + ActivityTypeEnum::PUBLISH, + "Skipped \"{$routeArticle->article->title}\"", + ['skipped' => true, 'reason' => $outcome->reason], + $routeArticle->article, + ); } private function recordFailed(RouteArticle $routeArticle, PublishOutcome $outcome): void @@ -128,6 +151,13 @@ private function recordFailed(RouteArticle $routeArticle, PublishOutcome $outcom 'attempt' => $routeArticle->publish_attempts, ]); + ActivityLogged::dispatch( + ActivityTypeEnum::ERROR, + "Failed to publish \"{$article->title}\"", + ['reason' => $outcome->reason, 'attempt' => $routeArticle->publish_attempts], + $article, + ); + $this->notificationService->send( NotificationTypeEnum::PUBLISH_FAILED, NotificationSeverityEnum::WARNING, diff --git a/app/Jobs/ArticleDiscoveryForFeedJob.php b/app/Jobs/ArticleDiscoveryForFeedJob.php index e8bce63e..7ecc3e26 100644 --- a/app/Jobs/ArticleDiscoveryForFeedJob.php +++ b/app/Jobs/ArticleDiscoveryForFeedJob.php @@ -2,8 +2,10 @@ namespace App\Jobs; +use App\Enums\ActivityTypeEnum; use App\Enums\NotificationSeverityEnum; use App\Enums\NotificationTypeEnum; +use App\Events\ActivityLogged; use App\Models\Feed; use App\Models\Notification; use App\Services\Article\ArticleFetcher; @@ -43,8 +45,24 @@ public function handle(LogSaver $logSaver, ArticleFetcher $articleFetcher, Notif $this->feed->update(['last_fetched_at' => now()]); if ($articles->isEmpty()) { + ActivityLogged::dispatch( + ActivityTypeEnum::ERROR, + "{$this->feed->name} returned no articles", + ['articles_count' => 0], + $this->feed, + ); + $this->warnFeedReturnedNothing($notificationService); + + return; } + + ActivityLogged::dispatch( + ActivityTypeEnum::FETCH, + "Fetched {$articles->count()} articles from {$this->feed->name}", + ['articles_count' => $articles->count()], + $this->feed, + ); } private function warnFeedReturnedNothing(NotificationService $notificationService): void diff --git a/app/Listeners/ValidateArticleListener.php b/app/Listeners/ValidateArticleListener.php index 27d44314..124551a7 100644 --- a/app/Listeners/ValidateArticleListener.php +++ b/app/Listeners/ValidateArticleListener.php @@ -2,8 +2,10 @@ namespace App\Listeners; +use App\Enums\ActivityTypeEnum; use App\Enums\LogLevelEnum; use App\Events\ActionPerformed; +use App\Events\ActivityLogged; use App\Events\NewArticleFetched; use App\Services\Article\ValidationService; use Exception; @@ -32,11 +34,25 @@ public function handle(NewArticleFetched $event): void try { $this->validationService->validate($article); + + ActivityLogged::dispatch( + ActivityTypeEnum::VALIDATE, + "Validated \"{$article->title}\"", + [], + $article, + ); } catch (Exception $e) { ActionPerformed::dispatch('Article validation failed', LogLevelEnum::ERROR, [ 'article_id' => $article->id, 'error' => $e->getMessage(), ]); + + ActivityLogged::dispatch( + ActivityTypeEnum::ERROR, + "Validation failed for \"{$article->title}\"", + ['error' => $e->getMessage()], + $article, + ); } } } diff --git a/app/Models/RouteArticle.php b/app/Models/RouteArticle.php index 2e7bb263..be1e5da8 100644 --- a/app/Models/RouteArticle.php +++ b/app/Models/RouteArticle.php @@ -2,8 +2,10 @@ namespace App\Models; +use App\Enums\ActivityTypeEnum; use App\Enums\ApprovalStatusEnum; use App\Enums\PublishStatusEnum; +use App\Events\ActivityLogged; use App\Events\RouteArticleApproved; use Database\Factories\RouteArticleFactory; use Illuminate\Database\Eloquent\Builder; @@ -105,12 +107,30 @@ public function approve(): void $this->update(['approval_status' => ApprovalStatusEnum::APPROVED]); + ActivityLogged::dispatch( + ActivityTypeEnum::APPROVE, + "Approved \"{$this->article->title}\"", + ['route_article_id' => $this->id], + $this->article, + ); + event(new RouteArticleApproved($this)); } public function reject(): void { + if ($this->isRejected()) { + return; + } + $this->update(['approval_status' => ApprovalStatusEnum::REJECTED]); + + ActivityLogged::dispatch( + ActivityTypeEnum::REJECT, + "Rejected \"{$this->article->title}\"", + ['route_article_id' => $this->id], + $this->article, + ); } private const RETRY_BACKOFF_MINUTES = [5, 30, 120, 360];