From 551491ea87935e3c100b47193af2bd2521803c63 Mon Sep 17 00:00:00 2001 From: Matt Young Date: Mon, 15 Jul 2024 15:19:29 -0500 Subject: [PATCH] Bonus Score Judge Management #20 Implement bonus scores Bonus score judge management complete. --- .../Admin/BonusScoreDefinitionController.php | 32 ++++- app/Models/BonusScoreDefinition.php | 5 + ...ate_bonus_score_judge_assignment_table.php | 34 ++++++ .../bonus-scores/judge-assignments.blade.php | 111 ++++++++++++++++++ routes/admin.php | 2 + .../Pages/Setup/BonusScoreJudgesTest.php | 70 +++++++++++ 6 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 database/migrations/2024_07_15_194558_create_bonus_score_judge_assignment_table.php create mode 100644 resources/views/admin/bonus-scores/judge-assignments.blade.php create mode 100644 tests/Feature/Pages/Setup/BonusScoreJudgesTest.php diff --git a/app/Http/Controllers/Admin/BonusScoreDefinitionController.php b/app/Http/Controllers/Admin/BonusScoreDefinitionController.php index f47c60d..b7f600c 100644 --- a/app/Http/Controllers/Admin/BonusScoreDefinitionController.php +++ b/app/Http/Controllers/Admin/BonusScoreDefinitionController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use App\Models\Audition; use App\Models\BonusScoreDefinition; +use App\Models\User; use App\Rules\ValidateAuditionKey; use Exception; use Illuminate\Http\Request; @@ -82,6 +83,35 @@ class BonusScoreDefinitionController extends Controller public function judges() { - echo 'boo'; + $bonusScores = BonusScoreDefinition::all(); + $users = User::all(); + + return view('admin.bonus-scores.judge-assignments', compact('bonusScores', 'users')); + } + + public function assignJudge(BonusScoreDefinition $bonusScore) + { + if (! $bonusScore->exists()) { + return redirect()->route('admin.bonus-scores.judges')->with('error', 'Bonus Score not found'); + } + $validData = request()->validate([ + 'judge' => 'required|exists:users,id', + ]); + $bonusScore->judges()->attach($validData['judge']); + + return redirect()->route('admin.bonus-scores.judges')->with('success', 'Judge assigned to bonus score'); + } + + public function removeJudge(BonusScoreDefinition $bonusScore) + { + if (! $bonusScore->exists()) { + return redirect()->route('admin.bonus-scores.judges')->with('error', 'Bonus Score not found'); + } + $validData = request()->validate([ + 'judge' => 'required|exists:users,id', + ]); + $bonusScore->judges()->detach($validData['judge']); + + return redirect()->route('admin.bonus-scores.judges')->with('success', 'Judge removed from bonus score'); } } diff --git a/app/Models/BonusScoreDefinition.php b/app/Models/BonusScoreDefinition.php index 590df30..8cc82a9 100644 --- a/app/Models/BonusScoreDefinition.php +++ b/app/Models/BonusScoreDefinition.php @@ -16,4 +16,9 @@ class BonusScoreDefinition extends Model { return $this->belongsToMany(Audition::class, 'bonus_score_audition_assignment')->orderBy('score_order'); } + + public function judges(): BelongsToMany + { + return $this->belongsToMany(User::class, 'bonus_score_judge_assignment'); + } } diff --git a/database/migrations/2024_07_15_194558_create_bonus_score_judge_assignment_table.php b/database/migrations/2024_07_15_194558_create_bonus_score_judge_assignment_table.php new file mode 100644 index 0000000..8e19376 --- /dev/null +++ b/database/migrations/2024_07_15_194558_create_bonus_score_judge_assignment_table.php @@ -0,0 +1,34 @@ +id(); + $table->foreignIdFor(BonusScoreDefinition::class) + ->constrained('bonus_score_definitions', 'id', 'bs_judge_assignment_bonus_score_definition_id') + ->onDelete('cascade')->onUpdate('cascade'); + $table->foreignIdFor(User::class) + ->constrained()->onDelete('cascade')->onUpdate('cascade'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('bonus_score_judge_assignment'); + } +}; diff --git a/resources/views/admin/bonus-scores/judge-assignments.blade.php b/resources/views/admin/bonus-scores/judge-assignments.blade.php new file mode 100644 index 0000000..116d14d --- /dev/null +++ b/resources/views/admin/bonus-scores/judge-assignments.blade.php @@ -0,0 +1,111 @@ + +
+ +
+ + +
diff --git a/routes/admin.php b/routes/admin.php index b89835d..f126e75 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -39,6 +39,8 @@ Route::middleware(['auth', 'verified', CheckIfAdmin::class])->prefix('admin/')-> Route::delete('/{audition}/unassign_audition', 'unassignAudition')->name('admin.bonus-scores.unassignAudition'); Route::delete('/{bonusScore}', 'destroy')->name('admin.bonus-scores.destroy'); Route::get('/judges', 'judges')->name('admin.bonus-scores.judges'); + Route::delete('{bonusScore}/judges/', 'removeJudge')->name('admin.bonus-scores.judges.remove'); + Route::post('{bonusScore}/judges/', 'assignJudge')->name('admin.bonus-scores.judges.assign'); }); diff --git a/tests/Feature/Pages/Setup/BonusScoreJudgesTest.php b/tests/Feature/Pages/Setup/BonusScoreJudgesTest.php new file mode 100644 index 0000000..4108e96 --- /dev/null +++ b/tests/Feature/Pages/Setup/BonusScoreJudgesTest.php @@ -0,0 +1,70 @@ +get(route('admin.bonus-scores.judges')) + ->assertRedirect(route('home')); + + actAsNormal(); + $this->get(route('admin.bonus-scores.judges')) + ->assertRedirect(route('dashboard')) + ->assertSessionHas('error', 'You are not authorized to perform this action'); + + actAsTab(); + $this->get(route('admin.bonus-scores.judges')) + ->assertRedirect(route('dashboard')) + ->assertSessionHas('error', 'You are not authorized to perform this action'); +}); +it('grants access to an administrator', function () { + // Arrange + actAsAdmin(); + // Act & Assert + $this->get(route('admin.bonus-scores.judges')) + ->assertOk() + ->assertViewIs('admin.bonus-scores.judge-assignments'); +}); +it('shows a link to the room judge assignment screen', function () { + // Arrange + actAsAdmin(); + // Act & Assert + $this->get(route('admin.bonus-scores.judges')) + ->assertOk() + ->assertSee(route('admin.rooms.judgingAssignment')); +}); +it('shows a card for each bonus score', function () { + // Arrange + $bonusScores = BonusScoreDefinition::factory()->count(3)->create(); + actAsAdmin(); + // Act & Assert + $response = $this->get(route('admin.bonus-scores.judges')); + $response->assertOk(); + $bonusScores->each(fn ($bonus) => $response->assertElementExists('#bonus-'.$bonus->id.'-card')); +}); +it('can assign a judge to a bonus score', function () { + // Arrange + $bonusScore = BonusScoreDefinition::factory()->create(); + $judge = User::factory()->create(); + actAsAdmin(); + // Act & Assert + $this->post(route('admin.bonus-scores.judges.assign', $bonusScore), ['judge' => $judge->id]) + ->assertRedirect(route('admin.bonus-scores.judges')) + ->assertSessionHas('success', 'Judge assigned to bonus score'); + expect($bonusScore->judges()->count())->toBe(1); +}); +it('can assign a judge to a room', function () { + // Arrange + $bonusScore = BonusScoreDefinition::factory()->create(); + $judge = User::factory()->create(); + $bonusScore->judges()->attach($judge->id); + actAsAdmin(); + // Act & Assert + $this->delete(route('admin.bonus-scores.judges.remove', $bonusScore), ['judge' => $judge->id]) + ->assertRedirect(route('admin.bonus-scores.judges')) + ->assertSessionHas('success', 'Judge removed from bonus score'); + expect($bonusScore->judges()->count())->toBe(0); +});