Roberto Santini 1 viikko sitten
vanhempi
commit
980d119aaa

+ 33
- 0
app/Models/SentEmail.php Näytä tiedosto

@@ -0,0 +1,33 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Contracts\Filesystem\FileNotFoundException;
6
+use Illuminate\Support\Facades\Storage;
7
+use jdavidbakr\MailTracker\Model\SentEmail as BaseSentEmail;
8
+
9
+class SentEmail extends BaseSentEmail
10
+{
11
+    /**
12
+     * Preferisci il file HTML completo: la colonna content può restare
13
+     * un ritaglio vecchio e l'accessor del package la farebbe vincere sul file.
14
+     */
15
+    public function getContentAttribute(): ?string
16
+    {
17
+        if ($this->meta?->has('content_file_path')) {
18
+            $contentFilePath = $this->meta->get('content_file_path');
19
+            if (is_string($contentFilePath) && $contentFilePath !== '') {
20
+                try {
21
+                    $fromFile = Storage::disk(config('mail-tracker.tracker-filesystem'))->get($contentFilePath);
22
+                    if (is_string($fromFile) && $fromFile !== '') {
23
+                        return $fromFile;
24
+                    }
25
+                } catch (FileNotFoundException $e) {
26
+                    // fallback sulla colonna
27
+                }
28
+            }
29
+        }
30
+
31
+        return $this->attributes['content'] ?? null;
32
+    }
33
+}

+ 6
- 4
app/Notifications/AnnotazionePubblicaApertaDa.php Näytä tiedosto

@@ -4,6 +4,7 @@ namespace App\Notifications;
4 4
 
5 5
 use App\Models\Annotazione;
6 6
 use App\Models\Segnalazione;
7
+use App\Support\MailAnnotazioneHtml;
7 8
 use Illuminate\Bus\Queueable;
8 9
 use Illuminate\Contracts\Queue\ShouldQueue;
9 10
 use Illuminate\Notifications\Messages\MailMessage;
@@ -32,7 +33,8 @@ class AnnotazionePubblicaApertaDa extends Notification implements ShouldQueue
32 33
     public function toMail(object $notifiable): MailMessage
33 34
     {
34 35
         $this->segnalazione->loadMissing(['azienda']);
35
-        $this->annotazione->loadMissing(['user']);
36
+        $this->annotazione->loadMissing(['user', 'allegatiAnnotazione']);
37
+        $annotazioneHtml = MailAnnotazioneHtml::fromAnnotazione($this->annotazione);
36 38
 
37 39
         $stato = $this->segnalazione->getConfiguraStato();
38 40
         $priorita = $this->segnalazione->getConfiguraPriorita();
@@ -51,16 +53,16 @@ class AnnotazionePubblicaApertaDa extends Notification implements ShouldQueue
51 53
             ->markdown('mail.annotazione-pubblica-aperta-da', [
52 54
                 'segnalazione' => $this->segnalazione,
53 55
                 'annotazione' => $this->annotazione,
54
-                'annotazioneHtml' => (string) ($this->annotazione->text ?? ''),
56
+                'annotazioneHtml' => $annotazioneHtml->html,
55 57
                 'aziendaLabel' => $aziendaLabel,
56 58
                 'statoLabel' => $statoLabel,
57 59
                 'prioritaLabel' => $prioritaLabel,
58 60
                 'autoreLabel' => $autoreLabel,
59 61
             ]);
60 62
 
61
-        return $this->segnalazione->applyEmailDestinatari($mail, [
63
+        return $annotazioneHtml->bind($this->segnalazione->applyEmailDestinatari($mail, [
62 64
             strtolower((string) ($notifiable->email ?? '')),
63
-        ]);
65
+        ]));
64 66
     }
65 67
 
66 68
     /**

+ 6
- 6
app/Notifications/NuovaSegnalazioneAdmin.php Näytä tiedosto

@@ -8,7 +8,7 @@ use Illuminate\Notifications\Notification;
8 8
 use Illuminate\Contracts\Queue\ShouldQueue;
9 9
 use Illuminate\Queue\InteractsWithQueue;
10 10
 use App\Models\Segnalazione;
11
-use App\Support\IsolaHtml;
11
+use App\Support\MailAnnotazioneHtml;
12 12
 
13 13
 class NuovaSegnalazioneAdmin extends Notification implements ShouldQueue
14 14
 {
@@ -42,18 +42,18 @@ class NuovaSegnalazioneAdmin extends Notification implements ShouldQueue
42 42
         $aziendaLabel = $this->segnalazione->azienda ? $this->segnalazione->azienda->full_name : 'N/D';
43 43
         $prioritaLabel = $priorita ? $priorita->label : ($this->segnalazione->priorita ?? 'N/D');
44 44
         $subject = $this->segnalazione->mailSubject();
45
-        $this->segnalazione->loadMissing(['annotazioni']);
45
+        $this->segnalazione->loadMissing(['annotazioni.allegatiAnnotazione']);
46 46
         $primaAnnotazione = $this->segnalazione->annotazioni->sortBy('id')->first();
47
-        $annotazioneHtml = IsolaHtml::fragment((string) ($primaAnnotazione->text ?? ''));
47
+        $annotazioneHtml = MailAnnotazioneHtml::fromAnnotazione($primaAnnotazione);
48 48
 
49
-        return (new MailMessage)
49
+        return $annotazioneHtml->bind((new MailMessage)
50 50
             ->subject($subject)
51 51
             ->markdown('mail.nuova-segnalazione-admin', [
52 52
                 'segnalazione' => $this->segnalazione,
53 53
                 'aziendaLabel' => $aziendaLabel,
54 54
                 'prioritaLabel' => $prioritaLabel,
55
-                'annotazioneHtml' => $annotazioneHtml,
56
-            ]);
55
+                'annotazioneHtml' => $annotazioneHtml->html,
56
+            ]));
57 57
     }
58 58
 
59 59
     /**

+ 6
- 4
app/Notifications/NuovaSegnalazioneUser.php Näytä tiedosto

@@ -9,7 +9,7 @@ use Illuminate\Notifications\Notification;
9 9
 use Illuminate\Queue\InteractsWithQueue;
10 10
 use App\Models\Segnalazione;
11 11
 use App\Services\SegnalazioneTicketPdfService;
12
-use App\Support\IsolaHtml;
12
+use App\Support\MailAnnotazioneHtml;
13 13
 
14 14
 class NuovaSegnalazioneUser extends Notification implements ShouldQueue
15 15
 {
@@ -51,9 +51,9 @@ class NuovaSegnalazioneUser extends Notification implements ShouldQueue
51 51
         // Subject stabile [#ID] titolo (+ Re: su riassegnazione)
52 52
         $subject = $this->segnalazione->mailSubject($this->isReassignment);
53 53
 
54
-        $this->segnalazione->loadMissing(['annotazioni']);
54
+        $this->segnalazione->loadMissing(['annotazioni.allegatiAnnotazione']);
55 55
         $primaAnnotazione = $this->segnalazione->annotazioni->sortBy('id')->first();
56
-        $annotazioneHtml = IsolaHtml::fragment((string) ($primaAnnotazione->text ?? ''));
56
+        $annotazioneHtml = MailAnnotazioneHtml::fromAnnotazione($primaAnnotazione);
57 57
 
58 58
         $mail = (new MailMessage)
59 59
             ->subject($subject)
@@ -63,9 +63,11 @@ class NuovaSegnalazioneUser extends Notification implements ShouldQueue
63 63
                 'prioritaLabel' => $prioritaLabel,
64 64
                 'isReassignment' => $this->isReassignment,
65 65
                 'isApertaDa' => $this->isApertaDa,
66
-                'annotazioneHtml' => $annotazioneHtml,
66
+                'annotazioneHtml' => $annotazioneHtml->html,
67 67
             ]);
68 68
 
69
+        $mail = $annotazioneHtml->bind($mail);
70
+
69 71
         try {
70 72
             $pdfService = app(SegnalazioneTicketPdfService::class);
71 73
             $mail->attachData(

+ 18
- 13
app/Notifications/RispostaEmailAssegnatario.php Näytä tiedosto

@@ -4,15 +4,17 @@ namespace App\Notifications;
4 4
 
5 5
 use App\Models\Annotazione;
6 6
 use App\Models\Segnalazione;
7
+use App\Support\MailAnnotazioneHtml;
7 8
 use Illuminate\Bus\Queueable;
8 9
 use Illuminate\Contracts\Queue\ShouldQueue;
9 10
 use Illuminate\Notifications\Messages\MailMessage;
10 11
 use Illuminate\Notifications\Notification;
11 12
 use Illuminate\Queue\InteractsWithQueue;
13
+use Illuminate\Queue\SerializesModels;
12 14
 
13 15
 class RispostaEmailAssegnatario extends Notification implements ShouldQueue
14 16
 {
15
-    use Queueable, InteractsWithQueue;
17
+    use Queueable, InteractsWithQueue, SerializesModels;
16 18
 
17 19
     public function __construct(
18 20
         protected Segnalazione $segnalazione,
@@ -31,7 +33,8 @@ class RispostaEmailAssegnatario extends Notification implements ShouldQueue
31 33
     public function toMail(object $notifiable): MailMessage
32 34
     {
33 35
         $this->segnalazione->loadMissing(['azienda']);
34
-        $this->annotazione->loadMissing(['user']);
36
+        $this->annotazione->loadMissing(['user', 'allegatiAnnotazione']);
37
+        $annotazioneHtml = MailAnnotazioneHtml::fromAnnotazione($this->annotazione);
35 38
 
36 39
         $stato = $this->segnalazione->getConfiguraStato();
37 40
         $priorita = $this->segnalazione->getConfiguraPriorita();
@@ -45,17 +48,19 @@ class RispostaEmailAssegnatario extends Notification implements ShouldQueue
45 48
             ? $this->annotazione->user->full_name
46 49
             : trim((string) ($this->annotazione->riferimento ?: $this->annotazione->email ?: 'Mittente email'));
47 50
 
48
-        return (new MailMessage)
49
-            ->subject($this->segnalazione->mailSubject(true))
50
-            ->markdown('mail.risposta-email-assegnatario', [
51
-                'segnalazione' => $this->segnalazione,
52
-                'annotazione' => $this->annotazione,
53
-                'annotazioneHtml' => (string) ($this->annotazione->text ?? ''),
54
-                'aziendaLabel' => $aziendaLabel,
55
-                'statoLabel' => $statoLabel,
56
-                'prioritaLabel' => $prioritaLabel,
57
-                'autoreLabel' => $autoreLabel,
58
-            ]);
51
+        return $annotazioneHtml->bind(
52
+            (new MailMessage)
53
+                ->subject($this->segnalazione->mailSubject(true))
54
+                ->markdown('mail.risposta-email-assegnatario', [
55
+                    'segnalazione' => $this->segnalazione,
56
+                    'annotazione' => $this->annotazione,
57
+                    'annotazioneHtml' => $annotazioneHtml->html,
58
+                    'aziendaLabel' => $aziendaLabel,
59
+                    'statoLabel' => $statoLabel,
60
+                    'prioritaLabel' => $prioritaLabel,
61
+                    'autoreLabel' => $autoreLabel,
62
+                ])
63
+        );
59 64
     }
60 65
 
61 66
     /**

+ 2
- 0
app/Providers/AppServiceProvider.php Näytä tiedosto

@@ -4,6 +4,7 @@ namespace App\Providers;
4 4
 
5 5
 use Illuminate\Support\ServiceProvider;
6 6
 use Illuminate\Support\Facades\Vite;
7
+use jdavidbakr\MailTracker\MailTracker;
7 8
 
8 9
 class AppServiceProvider extends ServiceProvider
9 10
 {
@@ -32,6 +33,7 @@ class AppServiceProvider extends ServiceProvider
32 33
 
33 34
     \App\Models\Reparto::observe(\App\Observers\RepartoObserver::class);
34 35
     \App\Models\Segnalazione::observe(\App\Observers\SegnalazioneObserver::class);
36
+    MailTracker::useSentEmailModel(\App\Models\SentEmail::class);
35 37
 
36 38
     // InviaNotificaSegnalazione è registrato da Laravel tramite event discovery (app/Listeners).
37 39
     // Non usare qui Event::listen(...): verrebbe eseguito due handle() per ogni NuovaSegnalazione.

+ 373
- 0
app/Support/MailAnnotazioneHtml.php Näytä tiedosto

@@ -0,0 +1,373 @@
1
+<?php
2
+
3
+namespace App\Support;
4
+
5
+use App\Models\Annotazione;
6
+use Illuminate\Notifications\Messages\MailMessage;
7
+use Illuminate\Support\Facades\Storage;
8
+use Symfony\Component\Mime\Email;
9
+use Symfony\Component\Mime\Part\DataPart;
10
+
11
+/**
12
+ * Prepara l'HTML delle annotazioni per le email:
13
+ * toglie html/body nidificati (che troncherebbero l'anteprima nel browser)
14
+ * e converte le immagini (data URI, cid, file locali) in allegati inline CID
15
+ * perché Gmail ignora le data:image nel corpo HTML.
16
+ */
17
+final class MailAnnotazioneHtml
18
+{
19
+    private const CID_DOMAIN = 'inline.myazienda';
20
+
21
+    private const MAX_IMAGE_BYTES = 10485760;
22
+
23
+    /**
24
+     * @param  list<array{cid: string, name: string, mime: string, data: string}>  $parts
25
+     */
26
+    public function __construct(
27
+        public readonly string $html,
28
+        public readonly array $parts = [],
29
+    ) {
30
+    }
31
+
32
+    public static function fromAnnotazione(?Annotazione $annotazione): self
33
+    {
34
+        $annotazione?->loadMissing('allegatiAnnotazione');
35
+
36
+        return self::fromHtml((string) ($annotazione?->text ?? ''), $annotazione);
37
+    }
38
+
39
+    public static function fromHtml(string $html, ?Annotazione $annotazione = null): self
40
+    {
41
+        $html = self::unwrap($html);
42
+        $parts = [];
43
+        $cache = [];
44
+
45
+        if ($html === '' || ! preg_match('/<img\b/i', $html)) {
46
+            return new self($html, $parts);
47
+        }
48
+
49
+        $rewritten = preg_replace_callback(
50
+            '/<img\b[^>]*>/i',
51
+            function (array $imgMatch) use ($annotazione, &$parts, &$cache) {
52
+                $tag = $imgMatch[0];
53
+                $src = self::extractSrc($tag);
54
+                if ($src === null || $src === '') {
55
+                    return $tag;
56
+                }
57
+
58
+                if (isset($cache[$src])) {
59
+                    return self::replaceSrc($tag, 'cid:'.$cache[$src]);
60
+                }
61
+
62
+                $resolved = self::resolveImage($src, $annotazione);
63
+                if ($resolved === null) {
64
+                    return $tag;
65
+                }
66
+
67
+                $cid = $resolved['sha1'].'@'.self::CID_DOMAIN;
68
+                $cache[$src] = $cid;
69
+                $parts[] = [
70
+                    'cid' => $cid,
71
+                    'name' => $resolved['name'],
72
+                    'mime' => $resolved['mime'],
73
+                    'data' => $resolved['data'],
74
+                ];
75
+                self::storePreviewSidecar($resolved['sha1'], $resolved['data'], $resolved['mime']);
76
+
77
+                return self::replaceSrc($tag, 'cid:'.$cid);
78
+            },
79
+            $html
80
+        );
81
+
82
+        return new self(is_string($rewritten) ? $rewritten : $html, $parts);
83
+    }
84
+
85
+    public function bind(MailMessage $mail): MailMessage
86
+    {
87
+        if ($this->parts === []) {
88
+            return $mail;
89
+        }
90
+
91
+        return $mail->withSymfonyMessage(function (Email $email) {
92
+            $this->attachTo($email);
93
+        });
94
+    }
95
+
96
+    public function attachTo(Email $email): void
97
+    {
98
+        foreach ($this->parts as $part) {
99
+            $dataPart = (new DataPart($part['data'], $part['name'], $part['mime']))->asInline();
100
+            $dataPart->setContentId($part['cid']);
101
+            $email->addPart($dataPart);
102
+        }
103
+    }
104
+
105
+    public static function hasVisibleContent(string $html): bool
106
+    {
107
+        if (trim(strip_tags($html)) !== '') {
108
+            return true;
109
+        }
110
+
111
+        return (bool) preg_match('/<img\b/i', $html);
112
+    }
113
+
114
+    /**
115
+     * Sostituisce cid: con data URI per l'anteprima Mail Tracker (il browser non ha le parti MIME).
116
+     */
117
+    public static function forPreview(?string $html): string
118
+    {
119
+        $html = (string) $html;
120
+        if ($html === '' || ! str_contains($html, 'cid:')) {
121
+            return $html;
122
+        }
123
+
124
+        return preg_replace_callback(
125
+            '/(<img\b[^>]*?\bsrc\s*=\s*)(["\'])cid:([^"\']+)\2/i',
126
+            function (array $m) {
127
+                $cid = html_entity_decode($m[3], ENT_QUOTES | ENT_HTML5, 'UTF-8');
128
+                $dataUri = self::previewDataUri($cid);
129
+                if ($dataUri === null) {
130
+                    return $m[0];
131
+                }
132
+
133
+                return $m[1].$m[2].$dataUri.$m[2];
134
+            },
135
+            $html
136
+        ) ?? $html;
137
+    }
138
+
139
+    public static function unwrap(string $html): string
140
+    {
141
+        $html = trim($html);
142
+        if ($html === '') {
143
+            return '';
144
+        }
145
+
146
+        if (preg_match('/<body\b[^>]*>(.*)<\/body>/is', $html, $m)) {
147
+            $html = $m[1];
148
+        } else {
149
+            $html = preg_replace('/<!DOCTYPE[^>]*>/i', '', $html) ?? $html;
150
+            $html = preg_replace('/<head\b[^>]*>.*?<\/head>/is', '', $html) ?? $html;
151
+            $html = preg_replace('/<\/?html\b[^>]*>/i', '', $html) ?? $html;
152
+        }
153
+
154
+        $html = preg_replace('/<\/(?:body|html)\s*>/i', '', $html) ?? $html;
155
+
156
+        return trim($html);
157
+    }
158
+
159
+    private static function extractSrc(string $tag): ?string
160
+    {
161
+        if (preg_match('/\bsrc\s*=\s*"([^"]*)"/i', $tag, $m) || preg_match("/\bsrc\s*=\s*'([^']*)'/i", $tag, $m)) {
162
+            return trim(html_entity_decode($m[1], ENT_QUOTES | ENT_HTML5, 'UTF-8'));
163
+        }
164
+
165
+        return null;
166
+    }
167
+
168
+    private static function replaceSrc(string $tag, string $src): string
169
+    {
170
+        $quoted = htmlspecialchars($src, ENT_QUOTES | ENT_HTML5, 'UTF-8');
171
+        $replaced = preg_replace('/\bsrc\s*=\s*"[^"]*"/i', 'src="'.$quoted.'"', $tag, 1);
172
+        if (is_string($replaced) && $replaced !== $tag) {
173
+            return $replaced;
174
+        }
175
+
176
+        $replaced = preg_replace("/\bsrc\s*=\s*'[^']*'/i", 'src="'.$quoted.'"', $tag, 1);
177
+
178
+        return is_string($replaced) ? $replaced : $tag;
179
+    }
180
+
181
+    /**
182
+     * @return array{data: string, mime: string, name: string, sha1: string}|null
183
+     */
184
+    private static function resolveImage(string $src, ?Annotazione $annotazione): ?array
185
+    {
186
+        if (str_starts_with(strtolower($src), 'data:image/')) {
187
+            return self::fromDataUri($src);
188
+        }
189
+
190
+        if (str_starts_with(strtolower($src), 'cid:')) {
191
+            return self::fromCid(substr($src, 4), $annotazione);
192
+        }
193
+
194
+        $path = self::localPathFromUrl($src);
195
+        if ($path !== null) {
196
+            return self::fromFile($path, basename($path));
197
+        }
198
+
199
+        return null;
200
+    }
201
+
202
+    /**
203
+     * @return array{data: string, mime: string, name: string, sha1: string}|null
204
+     */
205
+    private static function fromDataUri(string $src): ?array
206
+    {
207
+        if (! preg_match('#^data:image/(png|jpe?g|gif|webp|bmp|x-icon)(;charset=[^;]+)?;base64,(.+)$#is', $src, $m)) {
208
+            return null;
209
+        }
210
+
211
+        $binary = base64_decode(preg_replace('/\s+/', '', $m[3]) ?? '', true);
212
+        if (! is_string($binary) || $binary === '') {
213
+            return null;
214
+        }
215
+
216
+        $ext = strtolower($m[1]) === 'jpeg' ? 'jpg' : strtolower($m[1]);
217
+        if ($ext === 'x-icon') {
218
+            $ext = 'ico';
219
+        }
220
+
221
+        return self::pack($binary, 'image/'.($ext === 'jpg' ? 'jpeg' : $ext), 'inline.'.$ext);
222
+    }
223
+
224
+    /**
225
+     * @return array{data: string, mime: string, name: string, sha1: string}|null
226
+     */
227
+    private static function fromCid(string $cid, ?Annotazione $annotazione): ?array
228
+    {
229
+        $cid = trim($cid, " \t\n\r\0\x0B<>\"'");
230
+        if ($cid === '' || ! $annotazione) {
231
+            return null;
232
+        }
233
+
234
+        $allegati = $annotazione->allegatiAnnotazione ?? collect();
235
+        $filename = strstr($cid, '@', true) ?: $cid;
236
+        $filename = strtolower($filename);
237
+
238
+        foreach ($allegati as $allegato) {
239
+            $nome = strtolower((string) $allegato->nome);
240
+            $base = strtolower(basename((string) $allegato->path_file));
241
+            if ($nome === '' && $base === '') {
242
+                continue;
243
+            }
244
+            if ($nome !== $filename && $base !== $filename && ! str_starts_with($nome, $filename)) {
245
+                continue;
246
+            }
247
+            if (! $allegato->path_file || ! Storage::disk('allegatiAnnotazioni')->exists($allegato->path_file)) {
248
+                continue;
249
+            }
250
+
251
+            return self::fromFile(
252
+                Storage::disk('allegatiAnnotazioni')->path($allegato->path_file),
253
+                $allegato->nome ?: basename((string) $allegato->path_file)
254
+            );
255
+        }
256
+
257
+        return null;
258
+    }
259
+
260
+    /**
261
+     * @return array{data: string, mime: string, name: string, sha1: string}|null
262
+     */
263
+    private static function fromFile(string $path, string $name): ?array
264
+    {
265
+        if (! is_file($path) || ! is_readable($path)) {
266
+            return null;
267
+        }
268
+
269
+        $mime = (string) (mime_content_type($path) ?: '');
270
+        if (! str_starts_with($mime, 'image/')) {
271
+            return null;
272
+        }
273
+
274
+        $binary = file_get_contents($path);
275
+        if (! is_string($binary) || $binary === '') {
276
+            return null;
277
+        }
278
+
279
+        $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION) ?: 'png');
280
+
281
+        return self::pack($binary, $mime, 'inline.'.$ext);
282
+    }
283
+
284
+    /**
285
+     * @return array{data: string, mime: string, name: string, sha1: string}|null
286
+     */
287
+    private static function pack(string $binary, string $mime, string $name): ?array
288
+    {
289
+        if (strlen($binary) > self::MAX_IMAGE_BYTES) {
290
+            return null;
291
+        }
292
+
293
+        return [
294
+            'data' => $binary,
295
+            'mime' => $mime,
296
+            'name' => $name,
297
+            'sha1' => sha1($binary),
298
+        ];
299
+    }
300
+
301
+    private static function localPathFromUrl(string $src): ?string
302
+    {
303
+        $src = trim($src);
304
+        if ($src === '') {
305
+            return null;
306
+        }
307
+
308
+        $path = $src;
309
+        if (preg_match('#^https?://#i', $src)) {
310
+            $path = (string) (parse_url($src, PHP_URL_PATH) ?: '');
311
+        }
312
+
313
+        $path = urldecode($path);
314
+
315
+        if (preg_match('#/storage/allegatiAnnotazioni/(.+)$#', $path, $m)) {
316
+            $relative = $m[1];
317
+            if (Storage::disk('allegatiAnnotazioni')->exists($relative)) {
318
+                return Storage::disk('allegatiAnnotazioni')->path($relative);
319
+            }
320
+        }
321
+
322
+        if (preg_match('#/storage/(.+)$#', $path, $m)) {
323
+            $relative = $m[1];
324
+            if (Storage::disk('public')->exists($relative)) {
325
+                return Storage::disk('public')->path($relative);
326
+            }
327
+        }
328
+
329
+        return null;
330
+    }
331
+
332
+    private static function storePreviewSidecar(string $sha1, string $data, string $mime): void
333
+    {
334
+        try {
335
+            $disk = Storage::disk('local');
336
+            $binPath = 'mail-inline/'.$sha1.'.bin';
337
+            if (! $disk->exists($binPath)) {
338
+                $disk->put($binPath, $data);
339
+                $disk->put('mail-inline/'.$sha1.'.mime', $mime);
340
+            }
341
+        } catch (\Throwable $e) {
342
+            report($e);
343
+        }
344
+    }
345
+
346
+    private static function previewDataUri(string $cid): ?string
347
+    {
348
+        $cid = trim($cid, " \t\n\r\0\x0B<>");
349
+        $sha1 = strstr($cid, '@', true) ?: $cid;
350
+        if (! preg_match('/^[a-f0-9]{40}$/', $sha1)) {
351
+            return null;
352
+        }
353
+
354
+        try {
355
+            $disk = Storage::disk('local');
356
+            $binPath = 'mail-inline/'.$sha1.'.bin';
357
+            if (! $disk->exists($binPath)) {
358
+                return null;
359
+            }
360
+            $mime = $disk->exists('mail-inline/'.$sha1.'.mime')
361
+                ? trim((string) $disk->get('mail-inline/'.$sha1.'.mime'))
362
+                : 'image/png';
363
+            $binary = $disk->get($binPath);
364
+            if (! is_string($binary) || $binary === '') {
365
+                return null;
366
+            }
367
+
368
+            return 'data:'.$mime.';base64,'.base64_encode($binary);
369
+        } catch (\Throwable $e) {
370
+            return null;
371
+        }
372
+    }
373
+}

+ 1
- 1
resources/views/mail/annotazione-pubblica-aperta-da.blade.php Näytä tiedosto

@@ -16,7 +16,7 @@
16 16
 **Autore:** {{ $autoreLabel }}
17 17
 </x-mail::panel>
18 18
 
19
-@if(filled(trim(strip_tags($annotazioneHtml))))
19
+@if(\App\Support\MailAnnotazioneHtml::hasVisibleContent($annotazioneHtml))
20 20
 <div class="annotazione-mail">{!! $annotazioneHtml !!}</div>
21 21
 @endif
22 22
 

+ 1
- 1
resources/views/mail/nuova-segnalazione-admin.blade.php Näytä tiedosto

@@ -8,7 +8,7 @@
8 8
 **Priorità:** {{ $prioritaLabel }}
9 9
 @endcomponent
10 10
 
11
-@if(!empty($annotazioneHtml) && filled(trim(strip_tags($annotazioneHtml))))
11
+@if(\App\Support\MailAnnotazioneHtml::hasVisibleContent($annotazioneHtml ?? ''))
12 12
 {!! $annotazioneHtml !!}
13 13
 @endif
14 14
 

+ 1
- 1
resources/views/mail/nuova-segnalazione-user.blade.php Näytä tiedosto

@@ -18,7 +18,7 @@ Ti è stata assegnata una nuova richiesta: **{{ $segnalazione->titolo }}**.
18 18
 **Priorità:** {{ $prioritaLabel }}
19 19
 @endcomponent
20 20
 
21
-@if(!empty($annotazioneHtml) && filled(trim(strip_tags($annotazioneHtml))))
21
+@if(\App\Support\MailAnnotazioneHtml::hasVisibleContent($annotazioneHtml ?? ''))
22 22
 {!! $annotazioneHtml !!}
23 23
 @endif
24 24
 

+ 1
- 2
resources/views/mail/risposta-email-assegnatario.blade.php Näytä tiedosto

@@ -10,8 +10,7 @@
10 10
 **Da:** {{ $autoreLabel }}
11 11
 @endcomponent
12 12
 
13
-@if(filled(trim(strip_tags($annotazioneHtml))))
14
-
13
+@if(\App\Support\MailAnnotazioneHtml::hasVisibleContent($annotazioneHtml ?? ''))
15 14
 {!! $annotazioneHtml !!}
16 15
 @endif
17 16
 

+ 1
- 1
resources/views/vendor/emailTrakingViews/show.blade.php Näytä tiedosto

@@ -1 +1 @@
1
-{!!$email->content!!}
1
+{!! \App\Support\MailAnnotazioneHtml::forPreview($email->content) !!}

Loading…
Peruuta
Tallenna