Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
SyncChannelPostsJob
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 5
182
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 dispatchForAllActiveChannels
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 handle
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 syncLemmyChannelPosts
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
 getAuthToken
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3namespace App\Jobs;
4
5use App\Enums\PlatformEnum;
6use App\Exceptions\PlatformAuthException;
7use App\Models\PlatformAccount;
8use App\Models\PlatformChannel;
9use App\Modules\Lemmy\Services\LemmyApiService;
10use App\Services\Log\LogSaver;
11use Exception;
12use Illuminate\Contracts\Queue\ShouldBeUnique;
13use Illuminate\Contracts\Queue\ShouldQueue;
14use Illuminate\Database\Eloquent\Collection;
15use Illuminate\Foundation\Queue\Queueable;
16use Illuminate\Support\Facades\Cache;
17
18class SyncChannelPostsJob implements ShouldQueue, ShouldBeUnique
19{
20    use Queueable;
21
22    public function __construct(
23        private readonly PlatformChannel $channel
24    ) {
25        $this->onQueue('sync');
26    }
27
28    public static function dispatchForAllActiveChannels(): void
29    {
30        PlatformChannel::with(['platformInstance', 'platformAccounts'])
31            ->whereHas('platformInstance', fn ($query) => $query->where('platform', PlatformEnum::LEMMY))
32            ->whereHas('platformAccounts', fn ($query) => $query->where('is_active', true))
33            ->where('is_active', true)
34            ->get()
35            ->each(function (PlatformChannel $channel) {
36                self::dispatch($channel);
37                LogSaver::info('Dispatched sync job for channel', $channel);
38            });
39    }
40
41    public function handle(): void
42    {
43        LogSaver::info('Starting channel posts sync job', $this->channel);
44
45        match ($this->channel->platformInstance->platform) {
46            PlatformEnum::LEMMY => $this->syncLemmyChannelPosts(),
47        };
48
49        LogSaver::info('Channel posts sync job completed', $this->channel);
50    }
51
52    /**
53     * @throws PlatformAuthException
54     */
55    private function syncLemmyChannelPosts(): void
56    {
57        try {
58            /** @var Collection<int, PlatformAccount> $accounts */
59            $accounts = $this->channel->activePlatformAccounts()->get();
60            $account = $accounts->first();
61
62            if (! $account) {
63                throw new PlatformAuthException(PlatformEnum::LEMMY, 'No active account found for channel');
64            }
65
66            $api = new LemmyApiService($this->channel->platformInstance->url);
67            $token = $this->getAuthToken($api, $account);
68
69            $platformChannelId = $this->channel->channel_id
70                ? $this->channel->channel_id
71                : $api->getCommunityId($this->channel->name, $token);
72
73            $api->syncChannelPosts($token, $platformChannelId, $this->channel->name);
74
75            LogSaver::info('Channel posts synced successfully', $this->channel);
76
77        } catch (Exception $e) {
78            LogSaver::error('Failed to sync channel posts', $this->channel, [
79                'error' => $e->getMessage()
80            ]);
81
82            throw $e;
83        }
84    }
85
86    /**
87     * @throws PlatformAuthException
88     */
89    private function getAuthToken(LemmyApiService $api, PlatformAccount $account): string
90    {
91        $cacheKey = "lemmy_jwt_token_{$account->id}";
92        $cachedToken = Cache::get($cacheKey);
93
94        if ($cachedToken) {
95            return $cachedToken;
96        }
97
98        if (!$account->username || !$account->password) {
99            throw new PlatformAuthException(PlatformEnum::LEMMY, 'Missing credentials for account');
100        }
101
102        $token = $api->login($account->username, $account->password);
103
104        if (!$token) {
105            throw new PlatformAuthException(PlatformEnum::LEMMY, 'Login failed for account');
106        }
107
108        Cache::put($cacheKey, $token, 3600);
109
110        return $token;
111    }
112}