Files
AggloSign/backend/app/Http/Controllers/Admin/ImageController.php
T

77 lines
3.3 KiB
PHP

<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Admin\Concerns\ScopedToTenant;
use App\Http\Controllers\Controller;
use App\Models\AuditLog;
use App\Models\Campaign;
use App\Models\Template;
use App\Signature\ImageLibrary;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
/** Écran « Images » : dépôt et suppression des logos et bannières (voir ImageLibrary pour les formats). */
class ImageController extends Controller
{
use ScopedToTenant;
public function __construct(private readonly ImageLibrary $library) {}
public function index(): View
{
$images = $this->library->all()->map(fn (array $img) => $img + ['used_in' => $this->usages($img['name'])]);
return view('admin.images.index', ['images' => $images, 'maxKb' => config('signature.image_max_kb')]);
}
public function store(Request $request): RedirectResponse
{
$request->validate([
'image' => ['required', ...ImageLibrary::uploadRules()],
'name' => ['nullable', 'string', 'max:80'],
], ImageLibrary::uploadMessages('image'));
$name = $this->library->store($request->file('image'), $request->input('name'));
AuditLog::record('admin', $this->actor(), 'image.upload', null, ['file' => $name], $this->tenantId());
return back()->with('status', "Image « {$name} » en ligne. Dans un template : {{site_url}}/img/{$name}");
}
public function destroy(string $name): RedirectResponse
{
$name = basename($name);
abort_unless($this->library->exists($name), 404);
if ($used = $this->usages($name)) {
return back()->withErrors(['image' => "« {$name} » est utilisée par : ".implode(', ', $used).'. Retirez-la d\'abord.']);
}
$this->library->delete($name);
AuditLog::record('admin', $this->actor(), 'image.delete', null, ['file' => $name], $this->tenantId());
return back()->with('status', "Image « {$name} » supprimée.");
}
/** Templates (publiés ou brouillons) et campagnes qui référencent l'image. */
private function usages(string $name): array
{
$like = '%/img/'.$name.'%';
$templates = Template::where('tenant_id', $this->tenantId())
->where(fn ($q) => $q->where('html_full', 'like', $like)->orWhere('html_short', 'like', $like)
->orWhere('draft_html_full', 'like', $like)->orWhere('draft_html_short', 'like', $like))
->pluck('name')->map(fn ($n) => "template {$n}");
$campaigns = Campaign::where('tenant_id', $this->tenantId())->where('image_path', $name)
->pluck('name')->map(fn ($n) => "campagne {$n}");
// La bibliothèque est commune à toutes les collectivités : une image utilisée ailleurs reste protégée.
$elsewhere = Template::where('tenant_id', '!=', $this->tenantId())
->where(fn ($q) => $q->where('html_full', 'like', $like)->orWhere('html_short', 'like', $like)
->orWhere('draft_html_full', 'like', $like)->orWhere('draft_html_short', 'like', $like))->exists()
|| Campaign::where('tenant_id', '!=', $this->tenantId())->where('image_path', $name)->exists();
return $templates->merge($campaigns)->when($elsewhere, fn ($c) => $c->push('une autre collectivité'))->all();
}
}