diff --git a/app/Http/Controllers/Judging/PrelimJudgingController.php b/app/Http/Controllers/Judging/PrelimJudgingController.php
index 4046279..a6518eb 100644
--- a/app/Http/Controllers/Judging/PrelimJudgingController.php
+++ b/app/Http/Controllers/Judging/PrelimJudgingController.php
@@ -2,8 +2,14 @@
namespace App\Http\Controllers\Judging;
+use App\Actions\Tabulation\EnterPrelimScore;
+use App\Exceptions\AuditionAdminException;
use App\Http\Controllers\Controller;
+use App\Models\Entry;
use App\Models\PrelimDefinition;
+use App\Models\PrelimScoreSheet;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
class PrelimJudgingController extends Controller
{
@@ -18,4 +24,48 @@ class PrelimJudgingController extends Controller
return view('judging.prelim_entry_list', compact('prelimDefinition', 'entries', 'subscores', 'published'));
}
+
+ public function prelimScoreEntryForm(Entry $entry)
+ {
+ if (auth()->user()->cannot('judge', $entry->audition->prelimDefinition)) {
+ return redirect()->route('dashboard')->with('error', 'You are not assigned to judge that prelim audition.');
+ }
+ if ($entry->audition->hasFlag('seats_published')) {
+ return redirect()->route('dashboard')->with('error',
+ 'Scores for entries in published auditions cannot be modified.');
+ }
+ if ($entry->hasFlag('no_show')) {
+ return redirect()->route('judging.prelimEntryList', $entry->audition->prelimDefinition)->with('error',
+ 'The requested entry is marked as a no-show. Scores cannot be entered.');
+ }
+
+ $oldSheet = PrelimScoreSheet::where('user_id', Auth::id())->where('entry_id',
+ $entry->id)->value('subscores') ?? null;
+
+ return view('judging.prelim_entry_form', compact('entry', 'oldSheet'));
+ }
+
+ /**
+ * @throws AuditionAdminException
+ */
+ public function savePrelimScoreSheet(Entry $entry, Request $request, EnterPrelimScore $scribe)
+ {
+ if (auth()->user()->cannot('judge', $entry->audition->prelimDefinition)) {
+ return redirect()->route('dashboard')->with('error', 'You are not assigned to judge that prelim audition.');
+ }
+
+ // Validate form data
+ $subscores = $entry->audition->prelimDefinition->scoringGuide->subscores;
+ $validationChecks = [];
+ foreach ($subscores as $subscore) {
+ $validationChecks['score'.'.'.$subscore->id] = 'required|integer|max:'.$subscore->max_score;
+ }
+ $validatedData = $request->validate($validationChecks);
+
+ // Enter the score
+ $scribe(auth()->user(), $entry, $validatedData['score']);
+
+ return redirect()->route('judging.prelimEntryList', $entry->audition->prelimDefinition)->with('success',
+ 'Entered prelim scores for '.$entry->audition->name.' '.$entry->draw_number);
+ }
}
diff --git a/resources/views/judging/prelim_entry_form.blade.php b/resources/views/judging/prelim_entry_form.blade.php
new file mode 100644
index 0000000..58ca75b
--- /dev/null
+++ b/resources/views/judging/prelim_entry_form.blade.php
@@ -0,0 +1,58 @@
+
+ @php
+ $oldScores = session()->get('oldScores') ?? null;
+ @endphp
+
+ Prelim Score Entry
+
+
+ {{ $entry->audition->name }} {{ $entry->draw_number }}
+
+
+ - All Scores must be complete
+ - You may enter zero
+ - Whole numbers only
+
+
+
+
+ @if($oldSheet)
+ {{-- if there are existing scores, make this a patch request --}}
+ @method('PATCH')
+ @endif
+
+ @foreach($entry->audition->prelimDefinition->scoringGuide->subscores()->orderBy('display_order')->get() as $subscore)
+ @php
+ if($oldScores) {
+ $value = $oldScores['score'][$subscore->id];
+ } elseif ($oldSheet) {
+ $value = $oldSheet[$subscore->id]['score'];
+ } else {
+ $value = '';
+ }
+ @endphp
+
+
+
+
+ {{ $subscore->name }} max: {{$subscore->max_score}}
+
+
+
+
+
+ @endforeach
+
+
+ Save Scores
+
+
+
+
diff --git a/resources/views/judging/prelim_entry_list.blade.php b/resources/views/judging/prelim_entry_list.blade.php
index 3c70d8a..c1feaa8 100644
--- a/resources/views/judging/prelim_entry_list.blade.php
+++ b/resources/views/judging/prelim_entry_list.blade.php
@@ -24,7 +24,7 @@
@if(! $published && ! $entry->hasFlag('no_show'))
-
+
@endif
{{ $prelimDefinition->audition->name }} {{ $entry->draw_number }}
@if($entry->hasFlag('no_show'))
diff --git a/routes/judging.php b/routes/judging.php
index 0919583..6776fb7 100644
--- a/routes/judging.php
+++ b/routes/judging.php
@@ -20,6 +20,8 @@ Route::middleware(['auth', 'verified', CheckIfCanJudge::class])->prefix('judging
// Prelim Audition Related Routes
Route::middleware(['auth', 'verified', CheckIfCanJudge::class])->prefix('judging/prelims')->controller(PrelimJudgingController::class)->group(function () {
Route::get('/{prelimDefinition}', 'prelimEntryList')->name('judging.prelimEntryList');
+ route::get('/enterScore/{entry}', 'prelimScoreEntryForm')->name('judging.prelimScoreEntryForm');
+ route::post('/enterScore/{entry}', 'savePrelimScoreSheet')->name('judging.savePrelimScoreSheet');
});
// Bonus score judging routes
diff --git a/tests/Feature/app/Http/Controllers/Judging/PrelimJudgingControllerTest.php b/tests/Feature/app/Http/Controllers/Judging/PrelimJudgingControllerTest.php
index 45b7416..7388f9b 100644
--- a/tests/Feature/app/Http/Controllers/Judging/PrelimJudgingControllerTest.php
+++ b/tests/Feature/app/Http/Controllers/Judging/PrelimJudgingControllerTest.php
@@ -4,7 +4,10 @@ use App\Actions\Draw\RunDraw;
use App\Models\Audition;
use App\Models\Entry;
use App\Models\PrelimDefinition;
+use App\Models\PrelimScoreSheet;
use App\Models\Room;
+use App\Models\ScoringGuide;
+use App\Models\SubscoreDefinition;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
@@ -76,3 +79,118 @@ describe('PrelimJudgingController:prelimEntryList', function () {
});
});
+
+describe('PrelimJudgingController:prelimScoreEntryForm', function () {
+ beforeEach(function () {
+ $this->room = Room::factory()->create();
+ $this->finalsRoom = Room::factory()->create();
+ $this->scoringGuide = ScoringGuide::factory()->create();
+ $this->audition = Audition::factory()->create(['room_id' => $this->finalsRoom->id]);
+ $this->prelimDefinition = PrelimDefinition::create([
+ 'audition_id' => $this->audition->id,
+ 'room_id' => $this->room->id,
+ 'scoring_guide_id' => $this->scoringGuide->id,
+ 'passing_score' => 75,
+ ]);
+ $this->prelimJudge = User::factory()->create(['judging_preference' => 'Prelims']);
+ $this->finalsJudge = User::factory()->create(['judging_preference' => 'Finals']);
+ $this->room->addJudge($this->prelimJudge);
+ $this->finalsRoom->addJudge($this->finalsJudge);
+ $this->entry = Entry::factory()->create(['audition_id' => $this->audition->id]);
+
+ });
+ it('denies access to non-judges', function () {
+ actAsNormal();
+ $entry = Entry::factory()->create();
+ $response = $this->get(route('judging.prelimScoreEntryForm', $this->entry));
+ $response->assertRedirect(route('dashboard'));
+ $response->assertSessionHas('error', 'You are not assigned to judge.');
+ });
+
+ it('denies access if the judge is not assigned to the room', function () {
+ $this->actingAs($this->finalsJudge);
+ $response = $this->get(route('judging.prelimScoreEntryForm', $this->entry));
+ $response->assertRedirect(route('dashboard'));
+ $response->assertSessionHas('error', 'You are not assigned to judge that prelim audition.');
+ });
+
+ it('denies access if the audition is published', function () {
+ $this->actingAs($this->prelimJudge);
+ $this->entry->audition->addFlag('seats_published');
+ $response = $this->get(route('judging.prelimScoreEntryForm', $this->entry));
+ $response->assertRedirect(route('dashboard'));
+ $response->assertSessionHas('error', 'Scores for entries in published auditions cannot be modified.');
+ });
+
+ it('denies access if the entry is flagged as a no-show', function () {
+ $this->entry->addFlag('no_show');
+ $this->actingAs($this->prelimJudge);
+ $response = $this->get(route('judging.prelimScoreEntryForm', $this->entry));
+ $response->assertRedirect(route('judging.prelimEntryList', $this->prelimDefinition));
+ $response->assertSessionHas('error', 'The requested entry is marked as a no-show. Scores cannot be entered.');
+ });
+
+ it('gives us a form to enter a score for an entry', function () {
+ $this->actingAs($this->prelimJudge);
+ $response = $this->get(route('judging.prelimScoreEntryForm', $this->entry));
+ $response->assertOk();
+ $response->assertDontSee($this->entry->student->last_name)
+ ->assertDontSee($this->entry->student->first_name);
+ foreach (SubscoreDefinition::all() as $subscore) {
+ $response->assertSee($subscore->name);
+ $response->assertSee('score['.$subscore->id.']');
+ }
+ });
+});
+
+describe('PrelimJudgingController:savePrelimEntryForm', function () {
+ beforeEach(function () {
+ $this->room = Room::factory()->create();
+ $this->finalsRoom = Room::factory()->create();
+ $this->scoringGuide = ScoringGuide::factory()->create();
+ $this->audition = Audition::factory()->create(['room_id' => $this->finalsRoom->id]);
+ $this->prelimDefinition = PrelimDefinition::create([
+ 'audition_id' => $this->audition->id,
+ 'room_id' => $this->room->id,
+ 'scoring_guide_id' => $this->scoringGuide->id,
+ 'passing_score' => 75,
+ ]);
+ $this->prelimJudge = User::factory()->create(['judging_preference' => 'Prelims']);
+ $this->finalsJudge = User::factory()->create(['judging_preference' => 'Finals']);
+ $this->room->addJudge($this->prelimJudge);
+ $this->finalsRoom->addJudge($this->finalsJudge);
+ $this->entry = Entry::factory()->create(['audition_id' => $this->audition->id]);
+
+ });
+ it('denies access to non-judges', function () {
+ actAsNormal();
+ $response = $this->post(route('judging.savePrelimScoreSheet', $this->entry));
+ $response->assertRedirect(route('dashboard'));
+ $response->assertSessionHas('error', 'You are not assigned to judge.');
+ });
+
+ it('denies access if the judge is not assigned to the room', function () {
+ $this->actingAs($this->finalsJudge);
+ $response = $this->post(route('judging.savePrelimScoreSheet', $this->entry));
+ $response->assertRedirect(route('dashboard'));
+ $response->assertSessionHas('error', 'You are not assigned to judge that prelim audition.');
+ });
+
+ it('saves a score sheet', function () {
+ $subscoreIds = SubscoreDefinition::all()->pluck('id')->toArray();
+ $submitData = [
+ 'score' => [
+ $subscoreIds[0] => 10,
+ $subscoreIds[1] => 20,
+ $subscoreIds[2] => 30,
+ $subscoreIds[3] => 40,
+ $subscoreIds[4] => 50,
+ ],
+ ];
+ $this->actingAs($this->prelimJudge);
+ $response = $this->post(route('judging.savePrelimScoreSheet', $this->entry), $submitData);
+ $response->assertRedirect(route('judging.prelimEntryList', $this->prelimDefinition));
+ $response->assertSessionHas('success');
+ expect(PrelimScoreSheet::where('entry_id', $this->entry->id)->count())->toBe(1);
+ });
+});