participantApplication($request); $app->assertMayEditSignup('file'); return $app; } public function store(Request $request): JsonResponse { $maxKb = (int) config('contest.file_max_kb', 20480); $data = $request->validate([ 'kind' => ['required', 'string', Rule::in(['plan', 'supporting'])], 'file' => ['required', 'file', 'max:'.$maxKb], ]); $app = $this->application($request); $app->loadMissing('competition'); $uploaded = $data['file']; $ext = strtolower($uploaded->getClientOriginalExtension()); $schemaRow = SignupFormFileRules::fileFieldRow($app->competition, $data['kind']); $allowedExt = SignupFormFileRules::effectiveAllowedExtensions($schemaRow); if (! in_array($ext, $allowedExt, true)) { throw ValidationException::withMessages([ 'file' => ['仅支持:'.implode('、', $allowedExt)], ]); } $maxFiles = SignupFormFileRules::maxCount($schemaRow); if ($maxFiles !== null) { $current = $app->files()->where('kind', $data['kind'])->count(); if ($current >= $maxFiles) { throw ValidationException::withMessages([ 'file' => ['最多可上传 '.$maxFiles.' 个文件'], ]); } } $path = $uploaded->store("applications/{$app->id}", 'public'); $file = ApplicationFile::create([ 'application_id' => $app->id, 'kind' => $data['kind'], 'disk' => 'public', 'path' => $path, 'original_name' => $uploaded->getClientOriginalName(), 'size' => $uploaded->getSize(), 'mime' => $uploaded->getClientMimeType(), ]); return response()->json([ 'id' => $file->id, 'kind' => $file->kind, 'original_name' => $file->original_name, 'size' => $file->size, 'url' => $file->participantPreviewSignedUrl(), ], 201); } /** * 选手附件预览(签名 URL,GET 无需 Bearer;由 API 在 json 中下发短期有效链接)。 */ public function downloadSigned(Request $request, ApplicationFile $file): StreamedResponse { if (! Storage::disk($file->disk)->exists($file->path)) { abort(404); } return Storage::disk($file->disk)->response( $file->path, $file->clientDownloadName(), [ 'Cache-Control' => 'private, no-store', ], $file->preferredStreamDisposition(), ); } public function destroy(Request $request, ApplicationFile $file): JsonResponse { if ($file->application->user_id !== $request->user()->id) { abort(404); } $file->application->assertMayEditSignup('file'); Storage::disk($file->disk)->delete($file->path); $file->delete(); return response()->json(['message' => 'deleted']); } }