Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
ArticlePublishingService
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 2
30
0.00% covered (danger)
0.00%
0 / 1
 publishToRoutedChannels
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
 publishToChannel
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace App\Services\Publishing;
4
5use App\Enums\PlatformEnum;
6use App\Exceptions\PublishException;
7use App\Models\Article;
8use App\Models\ArticlePublication;
9use App\Models\PlatformChannel;
10use App\Modules\Lemmy\Services\LemmyPublisher;
11use App\Services\Log\LogSaver;
12use Exception;
13use Illuminate\Database\Eloquent\Collection as EloquentCollection;
14use Illuminate\Support\Collection;
15use RuntimeException;
16
17class ArticlePublishingService
18{
19    /**
20     * @param array<string, mixed> $extractedData
21     * @return EloquentCollection<int, ArticlePublication>
22     * @throws PublishException
23     */
24    public function publishToRoutedChannels(Article $article, array $extractedData): EloquentCollection
25    {
26        if (! $article->is_valid) {
27            throw new PublishException($article, PlatformEnum::LEMMY, new RuntimeException('CANNOT_PUBLISH_INVALID_ARTICLE'));
28        }
29
30        $feed = $article->feed;
31        
32        /** @var EloquentCollection<int, PlatformChannel> $activeChannels */
33        $activeChannels = $feed->activeChannels()->with(['platformInstance', 'activePlatformAccounts'])->get();
34
35        return $activeChannels->map(function (PlatformChannel $channel) use ($article, $extractedData) {
36            $account = $channel->activePlatformAccounts()->first();
37
38            if (! $account) {
39                LogSaver::warning('No active account for channel', $channel, [
40                    'article_id' => $article->id
41                ]);
42
43                return null;
44            }
45
46            return $this->publishToChannel($article, $extractedData, $channel, $account);
47        })
48        ->filter();
49    }
50
51    /**
52     * @param array<string, mixed> $extractedData
53     */
54    private function publishToChannel(Article $article, array $extractedData, PlatformChannel $channel, mixed $account): ?ArticlePublication
55    {
56        try {
57            $publisher = new LemmyPublisher($account);
58            $postData = $publisher->publishToChannel($article, $extractedData, $channel);
59
60            $publication = ArticlePublication::create([
61                'article_id' => $article->id,
62                'post_id' => $postData['post_view']['post']['id'],
63                'platform_channel_id' => $channel->id,
64                'published_by' => $account->username,
65                'published_at' => now(),
66                'platform' => $channel->platformInstance->platform->value,
67                'publication_data' => $postData,
68            ]);
69
70            LogSaver::info('Published to channel via routing', $channel, [
71                'article_id' => $article->id,
72                'priority' => $channel->pivot->priority ?? null
73            ]);
74
75            return $publication;
76        } catch (Exception $e) {
77            LogSaver::warning('Failed to publish to channel', $channel, [
78                'article_id' => $article->id,
79                'error' => $e->getMessage()
80            ]);
81
82            return null;
83        }
84    }
85}