fedi-feed-router/app/Actions/PublishRouteArticleAction.php

168 lines
5.3 KiB
PHP
Raw Permalink Normal View History

<?php
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;
use App\Services\Notification\NotificationService;
use App\Services\Publishing\ArticlePublishingService;
use App\Services\Publishing\PublishOutcome;
use Exception;
class PublishRouteArticleAction
{
public function __construct(
private FetchArticleDataAction $fetchArticleData,
private ArticlePublishingService $publishingService,
private NotificationService $notificationService,
) {}
/**
* @throws PublishException
*/
public function execute(RouteArticle $routeArticle): PublishOutcome
{
$article = $routeArticle->article;
$routeArticle->update(['publish_status' => PublishStatusEnum::PUBLISHING]);
try {
$extractedData = $this->resolvePublishData($article);
$outcome = $this->hasPublishableContent($extractedData)
? $this->publishingService->publishRouteArticle($routeArticle, $extractedData)
: PublishOutcome::failure('Could not recover the article content to publish');
} catch (Exception $e) {
$routeArticle->recordPublishFailed($e->getMessage());
ActionPerformed::dispatch('Failed to publish article', LogLevelEnum::ERROR, [
'article_id' => $article->id,
'error' => $e->getMessage(),
]);
ActivityLogged::dispatch(
ActivityTypeEnum::ERROR,
"Failed to publish \"{$article->title}\"",
['error' => $e->getMessage()],
$article,
);
$this->notificationService->send(
NotificationTypeEnum::PUBLISH_FAILED,
NotificationSeverityEnum::ERROR,
"Publish failed: {$article->title}",
$e->getMessage(),
$article,
);
throw $e;
}
match (true) {
$outcome->succeeded() => $this->recordPublished($routeArticle),
$outcome->wasSkipped() => $this->recordSkipped($routeArticle, $outcome),
default => $this->recordFailed($routeArticle, $outcome),
};
return $outcome;
}
/**
* @param array<string, mixed> $extractedData
*/
private function hasPublishableContent(array $extractedData): bool
{
return ! empty($extractedData['description']);
}
/**
* @return array<string, mixed>
*/
private function resolvePublishData(Article $article): array
{
if (empty($article->description) && empty($article->image_url)) {
return $this->fetchArticleData->execute($article);
}
return [
'title' => $article->title,
'description' => $article->description,
'thumbnail' => $article->image_url,
];
}
private function recordPublished(RouteArticle $routeArticle): void
{
$routeArticle->update([
'publish_status' => PublishStatusEnum::PUBLISHED,
'publish_error' => null,
]);
ActionPerformed::dispatch('Published article', LogLevelEnum::INFO, [
'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
{
$routeArticle->update(['publish_status' => PublishStatusEnum::SKIPPED]);
ActionPerformed::dispatch('Skipped publishing article', LogLevelEnum::INFO, [
'article_id' => $routeArticle->article->id,
'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
{
$article = $routeArticle->article;
$routeArticle->recordPublishFailed($outcome->reason ?? 'Publishing failed');
ActionPerformed::dispatch('No publication created for article', LogLevelEnum::WARNING, [
'article_id' => $article->id,
'title' => $article->title,
'reason' => $outcome->reason,
]);
ActivityLogged::dispatch(
ActivityTypeEnum::ERROR,
"Failed to publish \"{$article->title}\"",
['reason' => $outcome->reason],
$article,
);
$this->notificationService->send(
NotificationTypeEnum::PUBLISH_FAILED,
NotificationSeverityEnum::WARNING,
"Publish failed: {$article->title}",
$outcome->reason ?? 'No publication was created for this article.',
$article,
);
}
}