Sprint 2: Live data, CRUD modals, commitments, document upload
Frontend: - Connect MetroMap to live Inertia props (replace hardcoded demo data) - Drill-down navigation via router.visit for project-level maps - Reactive breadcrumb based on map level - Empty state when no projects exist - Reusable Modal component with retro styling - ProjectForm and CommitmentForm with Inertia useForm - FormInput reusable component (text, date, textarea, select) - FloatingActions FAB button for creating projects/themes Backend: - CommitmentService + CommitmentController (CRUD, mark complete, overdue) - DocumentService + DocumentController (upload, download, delete) - MapController now passes users and speerpunten to frontend - 7 new routes (4 commitment, 3 document) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
77
app/Services/DocumentService.php
Normal file
77
app/Services/DocumentService.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\AuditLog;
|
||||
use App\Models\Document;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class DocumentService
|
||||
{
|
||||
/**
|
||||
* Get all documents for a project with auteur.
|
||||
*/
|
||||
public function getForProject(int $projectId): Collection
|
||||
{
|
||||
return Document::with('auteur')
|
||||
->where('project_id', $projectId)
|
||||
->latest()
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a file and create the Document record.
|
||||
*/
|
||||
public function upload(array $data, UploadedFile $file): Document
|
||||
{
|
||||
return DB::transaction(function () use ($data, $file) {
|
||||
$projectId = $data['project_id'];
|
||||
$path = $file->store("documents/{$projectId}", 'local');
|
||||
|
||||
$document = Document::create([
|
||||
'project_id' => $projectId,
|
||||
'fase_id' => $data['fase_id'] ?? null,
|
||||
'titel' => $data['titel'],
|
||||
'type' => $data['type'] ?? $file->getClientOriginalExtension(),
|
||||
'bestandspad' => $path,
|
||||
'versie' => 1,
|
||||
'auteur_id' => Auth::id(),
|
||||
]);
|
||||
|
||||
$this->audit('uploaded', $document);
|
||||
|
||||
return $document;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the file from storage and soft-delete the Document record.
|
||||
*/
|
||||
public function delete(Document $document): void
|
||||
{
|
||||
DB::transaction(function () use ($document) {
|
||||
if ($document->bestandspad && Storage::disk('local')->exists($document->bestandspad)) {
|
||||
Storage::disk('local')->delete($document->bestandspad);
|
||||
}
|
||||
|
||||
$this->audit('deleted', $document);
|
||||
|
||||
$document->delete();
|
||||
});
|
||||
}
|
||||
|
||||
private function audit(string $action, Document $document, ?array $extra = null): void
|
||||
{
|
||||
AuditLog::create([
|
||||
'user_id' => Auth::id(),
|
||||
'action' => "document.{$action}",
|
||||
'entity_type' => 'document',
|
||||
'entity_id' => $document->id,
|
||||
'payload' => $extra,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user