where('code', $code)->where('locale', 'pt-MZ')->where('status', 'published') ->where(fn ($query) => $query->whereNull('valid_from')->orWhereDate('valid_from', '<=', today())) ->where(fn ($query) => $query->whereNull('valid_to')->orWhereDate('valid_to', '>', today())) ->orderByDesc('version_no')->firstOrFail(); $etag = '"questionnaire-'.$version->id.'-v'.$version->version_no.'"'; return response()->json(['data' => $version])->header('ETag', $etag)->header('Cache-Control', 'private, max-age=60'); } public function store(StoreSimulationRequest $request, SimulationExecution $execution): JsonResponse { $key = $request->header('Idempotency-Key'); abort_unless(is_string($key) && strlen($key) >= 16 && strlen($key) <= 128, 428, 'Idempotency-Key é obrigatório.'); $actorId = $request->user()?->id; $token = $actorId === null ? $request->header('X-Simulation-Token') : null; abort_if($actorId === null && (! is_string($token) || strlen($token) < 32 || strlen($token) > 256), 422, 'X-Simulation-Token opaco gerado pelo cliente é obrigatório para execução anónima.'); $validated = $request->validated(); $data = ['base' => (string) $validated['base'], 'rate' => (string) $validated['rate'], 'reduction' => (string) ($validated['reduction'] ?? '0'), 'organization_id' => $validated['organization_id'] ?? null]; $organizationId = $data['organization_id'] ?? null; $execution->authorizeOrganization($actorId, $organizationId); $result = $execution->create($data, $actorId, $organizationId, $token, $key); $simulation = $result['simulation']; $body = ['data' => $simulation, 'replayed' => $result['replayed']]; if ($actorId === null) { $body['access_token'] = $token; } return response()->json($body, $result['replayed'] ? 200 : 202) ->header('ETag', $execution->etag($simulation)) ->header('Location', url('/api/v1/simulations/'.$simulation->id)); } public function show(Request $request, string $id, SimulationExecution $execution): JsonResponse { abort_unless(Str::isUuid($id), 404); $simulation = $execution->find($id, $request); if ($request->user()) { abort_unless(app(SimulationPolicy::class)->view($request->user(), $simulation), 404); } else { abort_unless($simulation->anonymous_token_hash !== null && hash_equals($simulation->anonymous_token_hash, (string) $execution->tokenHash($request)), 404); } return response()->json(['data' => $simulation])->header('ETag', $execution->etag($simulation)); } public function updateScenario(UpdateSimulationScenarioRequest $request, string $id, string $scenarioId, SimulationExecution $execution): JsonResponse { abort_unless(Str::isUuid($id) && Str::isUuid($scenarioId), 404); $simulation = $execution->find($id, $request); if ($request->user()) { abort_unless(app(SimulationPolicy::class)->update($request->user(), $simulation), 403); } else { abort_unless($simulation->anonymous_token_hash !== null && hash_equals($simulation->anonymous_token_hash, (string) $execution->tokenHash($request)), 404); } $validated = $request->validated(); $data = ['label' => (string) $validated['label'], 'base' => (string) $validated['base'], 'rate' => (string) $validated['rate'], 'reduction' => (string) ($validated['reduction'] ?? '0')]; $updated = $execution->updateScenario($id, $scenarioId, $data, $request); return response()->json(['data' => $updated], 202)->header('ETag', $execution->etag($updated)); } public function report(Request $request, string $id, string $reportId, SimulationExecution $execution): JsonResponse { abort_unless(Str::isUuid($id) && Str::isUuid($reportId), 404); $simulation = $execution->find($id, $request); if ($request->user()) { abort_unless(app(SimulationPolicy::class)->view($request->user(), $simulation), 404); } else { abort_unless($simulation->anonymous_token_hash !== null && hash_equals($simulation->anonymous_token_hash, (string) $execution->tokenHash($request)), 404); } $report = $simulation->reports->firstWhere('id', $reportId); abort_if($report === null, 404); return response()->json(['data' => $report]); } public function jobs(Request $request, string $id, SimulationExecution $execution): JsonResponse { abort_unless(Str::isUuid($id), 404); $simulation = $execution->find($id, $request); if ($request->user()) { abort_unless(app(SimulationPolicy::class)->view($request->user(), $simulation), 404); } else { abort_unless($simulation->anonymous_token_hash !== null && hash_equals($simulation->anonymous_token_hash, (string) $execution->tokenHash($request)), 404); } $jobs = DB::transaction(function () use ($request, $id, $execution) { $execution->setContext($request->user()?->id, $execution->tokenHash($request)); return SimulationJob::query()->where('simulation_id', $id) ->orderBy('created_at')->orderBy('id')->get(); }); return response()->json(['data' => $jobs]); } }