<?php
 namespace App\Services\Ticket; use App\Models\Setting; use App\Models\Ticket; use App\Models\TicketOriginalEmail; use App\Models\TicketReply; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; class TicketEmlRetentionService { public function store(Ticket $ticket, string $rawEml, ?TicketReply $reply = null, ?string $fromEmail = null, ?string $subject = null): ?TicketOriginalEmail { if (! Setting::get('ticket_store_original_eml', false)) { return null; } if (trim($rawEml) === '') { return null; } $dateFolder = now()->format('Y-m-d'); $uuid = (string) Str::uuid(); $path = "tickets/{$dateFolder}/eml/{$ticket->id}/{$uuid}.eml"; Storage::disk('private')->put($path, $rawEml); $record = TicketOriginalEmail::create([ 'ticket_id' => $ticket->id, 'reply_id' => $reply?->id, 'file_path' => $path, 'uuid' => $uuid, 'from_email' => $fromEmail ? Str::limit($fromEmail, 255, '') : null, 'subject' => $subject ? Str::limit($subject, 500, '') : null, 'file_size' => strlen($rawEml), 'scan_status' => null, 'date_folder' => $dateFolder, 'pruned' => false, ]); \App\Jobs\ScanTicketEmlJob::dispatch($record->id); Log::info('Email pipe: Original .eml stored', [ 'ticket_id' => $ticket->id, 'eml_id' => $record->id, 'size' => $record->file_size, ]); return $record; } public function prune(): int { $days = (int) Setting::get('ticket_eml_retention_days', 0); if ($days <= 0) { return 0; } $cutoff = now()->subDays($days)->format('Y-m-d'); $disk = Storage::disk('private'); $pruned = 0; TicketOriginalEmail::where('pruned', false) ->where('date_folder', '<', $cutoff) ->chunkById(200, function ($records) use ($disk, &$pruned) { foreach ($records as $record) { if ($disk->exists($record->file_path)) { $disk->delete($record->file_path); } $record->update([ 'pruned' => true, 'pruned_at' => now(), ]); Log::info('Email pipe: .eml pruned (retention expired)', [ 'ticket_id' => $record->ticket_id, 'eml_id' => $record->id, 'date_folder' => $record->date_folder, ]); $this->leaveTombstone($record); $pruned++; } }); return $pruned; } private function leaveTombstone(TicketOriginalEmail $record): void { $ticket = $record->ticket; if (! $ticket) { return; } $note = __('admin/tickets.eml_tombstone_note', [ 'date' => $record->created_at?->format('Y-m-d') ?? $record->date_folder, ]); TicketReply::create([ 'ticket_id' => $ticket->id, 'mail' => 'system', 'message' => $note, 'content_format' => 'plain', 'is_internal' => true, ]); } } 