113 lines
3.4 KiB
PHP
113 lines
3.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Article;
|
|
|
|
use App\Enums\ApprovalStatusEnum;
|
|
use App\Models\Article;
|
|
use App\Models\Keyword;
|
|
use App\Models\Route;
|
|
use App\Models\RouteArticle;
|
|
use App\Models\Setting;
|
|
use Illuminate\Support\Collection;
|
|
|
|
class ValidationService
|
|
{
|
|
public function __construct(
|
|
private ArticleFetcher $articleFetcher
|
|
) {}
|
|
|
|
public function validate(Article $article): Article
|
|
{
|
|
logger('Validating article for routes: '.$article->id);
|
|
|
|
$articleData = $this->articleFetcher->fetchArticleData($article);
|
|
|
|
$updateData = [];
|
|
|
|
if (! empty($articleData)) {
|
|
$updateData['title'] = $articleData['title'] ?? $article->title;
|
|
$updateData['description'] = $articleData['description'] ?? $article->description;
|
|
$updateData['content'] = $articleData['full_article'] ?? null;
|
|
}
|
|
|
|
if (! isset($articleData['full_article']) || empty($articleData['full_article'])) {
|
|
logger()->warning('Article data missing full_article content', [
|
|
'article_id' => $article->id,
|
|
'url' => $article->url,
|
|
]);
|
|
|
|
$updateData['validated_at'] = now();
|
|
$article->update($updateData);
|
|
|
|
return $article->refresh();
|
|
}
|
|
|
|
$updateData['validated_at'] = now();
|
|
$article->update($updateData);
|
|
|
|
$this->createRouteArticles($article, $articleData['full_article']);
|
|
|
|
return $article->refresh();
|
|
}
|
|
|
|
private function createRouteArticles(Article $article, string $content): void
|
|
{
|
|
$activeRoutes = Route::where('feed_id', $article->feed_id)
|
|
->where('is_active', true)
|
|
->get();
|
|
|
|
// Batch-load all active keywords for this feed, grouped by channel
|
|
$keywordsByChannel = Keyword::where('feed_id', $article->feed_id)
|
|
->where('is_active', true)
|
|
->get()
|
|
->groupBy('platform_channel_id');
|
|
|
|
foreach ($activeRoutes as $route) {
|
|
$routeKeywords = $keywordsByChannel->get($route->platform_channel_id, collect());
|
|
$status = $this->evaluateKeywords($routeKeywords, $content);
|
|
|
|
if ($status === ApprovalStatusEnum::PENDING && $this->shouldAutoApprove($route)) {
|
|
$status = ApprovalStatusEnum::APPROVED;
|
|
}
|
|
|
|
RouteArticle::firstOrCreate(
|
|
[
|
|
'feed_id' => $route->feed_id,
|
|
'platform_channel_id' => $route->platform_channel_id,
|
|
'article_id' => $article->id,
|
|
],
|
|
[
|
|
'approval_status' => $status,
|
|
'validated_at' => now(),
|
|
]
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param Collection<int, Keyword> $keywords
|
|
*/
|
|
private function evaluateKeywords(Collection $keywords, string $content): ApprovalStatusEnum
|
|
{
|
|
if ($keywords->isEmpty()) {
|
|
return ApprovalStatusEnum::PENDING;
|
|
}
|
|
|
|
foreach ($keywords as $keyword) {
|
|
if (stripos($content, $keyword->keyword) !== false) {
|
|
return ApprovalStatusEnum::PENDING;
|
|
}
|
|
}
|
|
|
|
return ApprovalStatusEnum::REJECTED;
|
|
}
|
|
|
|
private function shouldAutoApprove(Route $route): bool
|
|
{
|
|
if ($route->auto_approve !== null) {
|
|
return $route->auto_approve;
|
|
}
|
|
|
|
return ! Setting::isPublishingApprovalsEnabled();
|
|
}
|
|
}
|