feat: complete Epic 0 — foundation migration & infrastructure setup
Stories 0.2-0.5: rename folders→declarations (backend+frontend), configure Redis for cache/queue/sessions, add foundation database migrations (permissions, archived_at), replace DeclarationStatus enum with architecture lifecycle values, create DeclarationObserver for status transition validation and auto-archive, fix controller status transitions to respect observer rules. 93 tests pass (240 assertions). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
81
app/Http/Controllers/DeclarationMediaController.php
Normal file
81
app/Http/Controllers/DeclarationMediaController.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Enums\ActorType;
|
||||
use App\Models\Declaration;
|
||||
use App\Models\MediaDownload;
|
||||
use App\Models\Workspace;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class DeclarationMediaController extends Controller
|
||||
{
|
||||
protected function currentWorkspace(Request $request): Workspace
|
||||
{
|
||||
$workspaceId = $request->session()->get('current_workspace_id');
|
||||
|
||||
return Workspace::query()->findOrFail($workspaceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly uploaded file.
|
||||
*/
|
||||
public function store(Request $request, Declaration $declaration): RedirectResponse
|
||||
{
|
||||
$workspace = $this->currentWorkspace($request);
|
||||
|
||||
if ($declaration->workspace_id !== $workspace->id) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'files' => ['required', 'array', 'min:1'],
|
||||
'files.*' => ['file', 'max:10240'],
|
||||
]);
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
foreach ($request->file('files') as $file) {
|
||||
$declaration->addMedia($file)
|
||||
->withCustomProperties([
|
||||
'uploaded_by_type' => ActorType::User,
|
||||
'uploaded_by_id' => $user->id,
|
||||
])
|
||||
->toMediaCollection('documents');
|
||||
}
|
||||
|
||||
return back()->with('flash', ['type' => 'success', 'message' => 'Fichier(s) téléchargé(s).']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a media file.
|
||||
*/
|
||||
public function download(Request $request, Declaration $declaration, int $mediaId): Response
|
||||
{
|
||||
$workspace = $this->currentWorkspace($request);
|
||||
|
||||
if ($declaration->workspace_id !== $workspace->id) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$media = Media::query()
|
||||
->where('model_type', Declaration::class)
|
||||
->where('model_id', $declaration->id)
|
||||
->where('id', $mediaId)
|
||||
->firstOrFail();
|
||||
|
||||
try {
|
||||
MediaDownload::query()->updateOrCreate(
|
||||
['media_id' => $media->id, 'user_id' => $request->user()->id],
|
||||
['downloaded_at' => now()],
|
||||
);
|
||||
} catch (\Throwable) {
|
||||
// Tracking failure must never block the download
|
||||
}
|
||||
|
||||
return $media->toResponse($request);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user