• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

LeTraceurSnorkLibrary / MessSaga / 23892487014

02 Apr 2026 08:54AM UTC coverage: 29.947% (-1.7%) from 31.674%
23892487014

Pull #15

github

web-flow
Merge c1433e08b into a7d6f3637
Pull Request #15: feat: add s3 as storage

30 of 155 new or added lines in 14 files covered. (19.35%)

4 existing lines in 4 files now uncovered.

448 of 1496 relevant lines covered (29.95%)

0.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/app/Jobs/ProcessConversationMediaUpload.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace App\Jobs;
6

7
use App\Models\Conversation;
8
use App\Models\MediaAttachment;
9
use App\Models\MediaTypes\SupportedMediaTypesEnum;
10
use App\Services\Import\Archives\Exceptions\ArchiveExtractionFailedException;
11
use App\Services\Import\Factories\ImportArchiveExtractorFactory;
12
use App\Services\Media\ImportedMediaResolverService;
13
use App\Services\Media\Storage\MediaStorageInterface;
14
use App\Services\Parsers\ParserRegistry;
15
use Illuminate\Bus\Queueable;
16
use Illuminate\Contracts\Queue\ShouldQueue;
17
use Illuminate\Foundation\Bus\Dispatchable;
18
use Illuminate\Queue\InteractsWithQueue;
19
use Illuminate\Queue\SerializesModels;
20
use Illuminate\Support\Facades\Log;
21
use Illuminate\Support\Facades\Storage;
22

23
class ProcessConversationMediaUpload implements ShouldQueue
24
{
25
    use Dispatchable;
26
    use InteractsWithQueue;
27
    use Queueable;
28
    use SerializesModels;
29

30
    /**
31
     * @param int    $userId
32
     * @param int    $conversationId
33
     * @param string $path
34
     */
35
    public function __construct(
36
        public int    $userId,
37
        public int    $conversationId,
38
        public string $path
39
    ) {
40
    }
×
41

42
    /**
43
     * @param ParserRegistry                $parserRegistry
44
     * @param ImportedMediaResolverService  $importedMediaResolverService
45
     * @param MediaStorageInterface         $mediaStorage
46
     * @param ImportArchiveExtractorFactory $archiveExtractorsFactory
47
     *
48
     * @return void
49
     */
50
    public function handle(
51
        ParserRegistry                $parserRegistry,
52
        ImportedMediaResolverService  $importedMediaResolverService,
53
        MediaStorageInterface         $mediaStorage,
54
        ImportArchiveExtractorFactory $archiveExtractorsFactory
55
    ): void {
NEW
56
        $importsTmpDiskName = (string)config('filesystems.imports_tmp_disk', 'imports_tmp');
×
NEW
57
        $importsTmpDisk     = Storage::disk($importsTmpDiskName);
×
UNCOV
58
        $extractedDir = null;
×
59

60
        $conversation = Conversation::with('messengerAccount')->find($this->conversationId);
×
61
        if (!$conversation || $conversation->messengerAccount->user_id !== $this->userId) {
×
62
            return;
×
63
        }
64

65
        try {
66
            $archiveExtractor = $archiveExtractorsFactory->makeForPath($this->path);
×
67
            if ($archiveExtractor === null) {
×
68
                return;
×
69
            }
70

71
            $source       = $archiveExtractor->extract($this->path, $conversation->messengerAccount->type);
×
72
            $extractedDir = $source->getExtractedDir();
×
73
            if ($extractedDir === null) {
×
74
                return;
×
75
            }
76

77
            // Для догрузки медиа нужен весь распакованный архив, а не messenger-specific media root.
NEW
78
            $absoluteExtracted = $importsTmpDisk->path($extractedDir);
×
79

80
            $parser   = $parserRegistry->get($conversation->messengerAccount->type);
×
81
            $relation = $parser->getMessagesRelation($conversation);
×
82
            $model    = $relation->getRelated();
×
83

84
            $pending = MediaAttachment::query()
×
85
                ->where('conversation_id', $conversation->id)
×
86
                ->whereNotNull('export_path')
×
87
                ->where(function ($q): void {
×
88
                    $q->whereNull('stored_path')->orWhere('stored_path', '');
×
89
                })
×
90
                ->orderBy('id')
×
91
                ->get();
×
92

93
            $messageIdByAttachmentId = $model->newQuery()
×
94
                ->whereIn('media_attachment_id', $pending->pluck('id')->all())
×
95
                ->pluck('id', 'media_attachment_id');
×
96

97
            foreach ($pending as $media) {
×
98
                $messageId = $messageIdByAttachmentId->get($media->id);
×
99
                if ($messageId === null) {
×
100
                    continue;
×
101
                }
102

NEW
103
                $storedPath = $importedMediaResolverService->copyForMessage(
×
104
                    $absoluteExtracted,
×
105
                    (string)$media->export_path,
×
106
                    $conversation->id,
×
107
                    (int)$messageId
×
108
                );
×
109
                if ($storedPath === null) {
×
110
                    continue;
×
111
                }
112

NEW
113
                $mime = $mediaStorage->mimeType($storedPath);
×
114
                $media->update([
×
115
                    'stored_path'       => $storedPath,
×
116
                    'media_type'        => SupportedMediaTypesEnum::detect($mime
×
117
                        ?: null, $media->export_path)?->value,
×
118
                    'mime_type'         => $mime
×
119
                        ?: null,
×
120
                    'original_filename' => basename($storedPath),
×
121
                ]);
×
122
            }
123
        } catch (ArchiveExtractionFailedException $e) {
×
124
            Log::warning('Archive extraction failed', [
×
125
                'user_id'         => $this->userId,
×
126
                'conversation_id' => $this->conversationId,
×
127
                'path'            => $this->path,
×
128
                'reason'          => $e->getMessage(),
×
129
            ]);
×
130
        } finally {
NEW
131
            if (isset($extractedDir) && $importsTmpDisk->exists($extractedDir)) {
×
NEW
132
                $importsTmpDisk->deleteDirectory($extractedDir);
×
133
            }
NEW
134
            if ($importsTmpDisk->exists($this->path)) {
×
NEW
135
                $importsTmpDisk->delete($this->path);
×
136
            }
137
        }
138
    }
139
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc