create(['mobile' => '13800138001']); $competition = Competition::query()->create([ 'slug' => 'xxf-close', 'name' => '测试赛', 'published' => true, 'signup_close_at' => now()->subHour(), 'settings' => [ 'post_close_file_edit' => [ 'enabled' => true, 'user_mobiles' => ['13800138001'], ], ], ]); Application::query()->create([ 'user_id' => $user->id, 'competition_id' => $competition->id, 'status' => 'submitted', 'project_name' => '原项目', 'submitted_at' => now()->subDay(), ]); Sanctum::actingAs($user); $this->getJson('/api/applications/current?competition_slug=xxf-close') ->assertOk() ->assertJsonPath('participant_may_edit', false) ->assertJsonPath('participant_may_edit_files', true); $this->postJson('/api/applications/current/save?competition_slug=xxf-close', [ 'project_name' => '试图改项目名', ])->assertStatus(422); $this->withHeader('Accept', 'application/json') ->post('/api/applications/current/files?competition_slug=xxf-close', [ 'kind' => 'plan', 'file' => UploadedFile::fake()->create('补传计划书.pdf', 100, 'application/pdf'), ]) ->assertCreated(); $this->assertSame(1, ApplicationFile::query()->count()); } public function test_non_allowlisted_user_cannot_upload_after_close(): void { Storage::fake('public'); $user = User::query()->create(['mobile' => '13800138002']); $competition = Competition::query()->create([ 'slug' => 'xxf-close-2', 'name' => '测试赛', 'published' => true, 'signup_close_at' => now()->subHour(), 'settings' => [ 'post_close_file_edit' => [ 'enabled' => true, 'user_mobiles' => ['13800138001'], ], ], ]); Application::query()->create([ 'user_id' => $user->id, 'competition_id' => $competition->id, 'status' => 'submitted', ]); Sanctum::actingAs($user); $this->getJson('/api/applications/current?competition_slug=xxf-close-2') ->assertOk() ->assertJsonPath('participant_may_edit', false) ->assertJsonPath('participant_may_edit_files', false); $this->withHeader('Accept', 'application/json') ->post('/api/applications/current/files?competition_slug=xxf-close-2', [ 'kind' => 'plan', 'file' => UploadedFile::fake()->create('计划书.pdf', 100, 'application/pdf'), ]) ->assertStatus(422) ->assertJsonValidationErrors(['file']); } public function test_review_lock_blocks_allowlisted_file_edit(): void { Storage::fake('public'); $user = User::query()->create(['mobile' => '13800138003']); $competition = Competition::query()->create([ 'slug' => 'xxf-close-3', 'name' => '测试赛', 'published' => true, 'signup_close_at' => now()->subHour(), 'settings' => [ 'post_close_file_edit' => [ 'enabled' => true, 'user_mobiles' => ['13800138003'], ], ], ]); $application = Application::query()->create([ 'user_id' => $user->id, 'competition_id' => $competition->id, 'status' => 'submitted', ]); $reviewer = Reviewer::query()->create([ 'mobile' => '13900139003', 'username' => 'rev_pcfe', 'name' => '评委', 'status' => 'active', 'password_hash' => 'unused', ]); ApplicationReviewScore::query()->create([ 'application_id' => $application->id, 'reviewer_id' => $reviewer->id, 'payload_json' => [], 'line_total' => 80, ]); Sanctum::actingAs($user); $this->getJson('/api/applications/current?competition_slug=xxf-close-3') ->assertOk() ->assertJsonPath('participant_may_edit', false) ->assertJsonPath('participant_may_edit_files', false); $this->withHeader('Accept', 'application/json') ->post('/api/applications/current/files?competition_slug=xxf-close-3', [ 'kind' => 'plan', 'file' => UploadedFile::fake()->create('计划书.pdf', 100, 'application/pdf'), ]) ->assertStatus(422) ->assertJsonValidationErrors(['file']); } }