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

LeTraceurSnorkLibrary / MessSaga / 23844646769

01 Apr 2026 10:42AM UTC coverage: 31.674% (+31.1%) from 0.549%
23844646769

push

github

web-flow
feat: media files import

431 of 801 new or added lines in 30 files covered. (53.81%)

4 existing lines in 4 files now uncovered.

439 of 1386 relevant lines covered (31.67%)

0.74 hits per line

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

94.29
/app/Services/Import/MessagePreparationService.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace App\Services\Import;
6

7
use App\Models\MediaTypes\SupportedMediaTypesEnum;
8
use App\Models\Message;
9
use App\Services\Import\DTO\PreparedMessageRowResult;
10
use App\Services\Media\MediaFileStorageService;
11
use Carbon\Carbon;
12
use Exception;
13
use Illuminate\Database\Eloquent\Model;
14
use Illuminate\Support\Facades\Crypt;
15
use Illuminate\Support\Facades\Storage;
16

17
class MessagePreparationService
18
{
19
    /**
20
     * @param MediaFileStorageService $mediaFileStorageService
21
     */
22
    public function __construct(
23
        private readonly MediaFileStorageService $mediaFileStorageService
24
    ) {
25
    }
8✔
26

27
    /**
28
     * @param mixed $externalId
29
     *
30
     * @return string|null
31
     */
32
    public function normalizeExternalId(mixed $externalId): ?string
33
    {
34
        if (!is_scalar($externalId)) {
2✔
35
            return null;
1✔
36
        }
37

38
        $normalized = trim((string)$externalId);
2✔
39

40
        return $normalized !== ''
2✔
41
            ? $normalized
1✔
42
            : null;
2✔
43
    }
44

45
    /**
46
     * @param array<string, mixed> $message
47
     *
48
     * @return string
49
     */
50
    public function buildDeduplicationHash(array $message): string
51
    {
52
        $sentAt = $message['sent_at'] ?? '';
2✔
53
        if ($sentAt instanceof Carbon) {
2✔
54
            $sentAtFormatted = $sentAt->format('Y-m-d H:i:s');
1✔
55
        } elseif (is_string($sentAt)) {
1✔
56
            try {
57
                $sentAtFormatted = Carbon::parse($sentAt)->format('Y-m-d H:i:s');
1✔
58
            } catch (Exception) {
1✔
59
                $sentAtFormatted = $sentAt;
1✔
60
            }
61
        } else {
NEW
62
            $sentAtFormatted = (string)$sentAt;
×
63
        }
64

65
        return hash(
2✔
66
            'sha256',
2✔
67
            $sentAtFormatted
2✔
68
            . ($message['text'] ?? '')
2✔
69
            . ($message['sender_name'] ?? '')
2✔
70
            . ($message['sender_external_id'] ?? '')
2✔
71
        );
2✔
72
    }
73

74
    /**
75
     * @param string|null          $mediaRootPath
76
     * @param array<string, mixed> $message
77
     * @param int                  $conversationId
78
     *
79
     * @return string|null
80
     */
81
    public function copyAttachmentForMessage(
82
        ?string $mediaRootPath,
83
        array   $message,
84
        int     $conversationId
85
    ): ?string {
86
        if ($mediaRootPath === null || empty($message['attachment_export_path'])) {
2✔
87
            return null;
1✔
88
        }
89

90
        return $this->mediaFileStorageService->copyForConversation(
1✔
91
            $mediaRootPath,
1✔
92
            (string)$message['attachment_export_path'],
1✔
93
            $conversationId
1✔
94
        );
1✔
95
    }
96

97
    /**
98
     * @param array<string, mixed>  $message
99
     * @param int                   $conversationId
100
     * @param class-string<Message> $messageModelClass
101
     * @param string|null           $attachmentStoredPath
102
     *
103
     * @return PreparedMessageRowResult
104
     */
105
    public function prepareMessageRowForInsert(
106
        array   $message,
107
        int     $conversationId,
108
        string  $messageModelClass,
109
        ?string $attachmentStoredPath = null
110
    ): PreparedMessageRowResult {
111
        $exportRaw        = $message['attachment_export_path'] ?? null;
2✔
112
        $exportNormalized = $this->normalizeExportPath($exportRaw);
2✔
113

114
        unset($message['attachment_export_path'], $message['attachment_stored_path']);
2✔
115

116
        $text = $message['text'] ?? null;
2✔
117

118
        $sentAt = $message['sent_at'] ?? null;
2✔
119
        if ($sentAt instanceof Carbon) {
2✔
120
            $sentAt = $sentAt->format('Y-m-d H:i:s');
1✔
121
        }
122

123
        $row = array_merge($message, [
2✔
124
            'conversation_id' => $conversationId,
2✔
125
            'sent_at'         => $sentAt,
2✔
126
            'text'            => $text
2✔
127
                ? Crypt::encryptString($text)
2✔
128
                : null,
129
        ]);
2✔
130

131
        /**
132
         * @var Model $model
133
         */
134
        $model   = $messageModelClass::make();
2✔
135
        $allowed = $model->getFillable();
2✔
136
        $row     = array_merge(
2✔
137
            array_fill_keys($allowed, null),
2✔
138
            array_intersect_key($row, array_flip($allowed))
2✔
139
        );
2✔
140

141
        $mediaPayload = null;
2✔
142
        if ($exportNormalized !== null || $attachmentStoredPath !== null) {
2✔
143
            $mime = null;
1✔
144
            if ($attachmentStoredPath !== null && Storage::exists($attachmentStoredPath)) {
1✔
145
                $mime = Storage::mimeType($attachmentStoredPath);
1✔
146
            }
147
            $mediaPayload = [
1✔
148
                'stored_path'       => $attachmentStoredPath,
1✔
149
                'export_path'       => $exportNormalized,
1✔
150
                'media_type'        => SupportedMediaTypesEnum::detect($mime, $exportNormalized)?->value,
1✔
151
                'mime_type'         => $mime,
1✔
152
                'original_filename' => $exportNormalized
1✔
153
                    ? basename(str_replace('\\', '/', $exportNormalized))
1✔
NEW
154
                    : ($attachmentStoredPath
×
NEW
155
                        ? basename($attachmentStoredPath)
×
156
                        : null),
157
            ];
1✔
158
        }
159

160
        return new PreparedMessageRowResult($row, $mediaPayload);
2✔
161
    }
162

163
    /**
164
     * @param mixed $exportRaw
165
     *
166
     * @return string|null
167
     */
168
    private function normalizeExportPath(mixed $exportRaw): ?string
169
    {
170
        if (!is_string($exportRaw)) {
2✔
171
            return null;
1✔
172
        }
173

174
        $normalized = trim(str_replace('\\', '/', $exportRaw));
1✔
175
        if ($normalized === '') {
1✔
NEW
176
            return null;
×
177
        }
178

179
        return $normalized;
1✔
180
    }
181
}
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