From 1cc43c1bced32459b99abafb34da4f391585fe03 Mon Sep 17 00:00:00 2001 From: Matt Young Date: Mon, 14 Jul 2025 13:28:36 -0500 Subject: [PATCH] Removed unused EntryScoreController --- app/Actions/Tabulation/EnterScore.php | 1 + .../Tabulation/EntryFlagController.php | 30 +- .../Tabulation/ScoreController.php | 27 +- .../views/components/form/option.blade.php | 2 +- .../tabulation/no_show_confirm.blade.php | 27 +- .../Tabulation/EntryFlagControllerTest.php | 200 +++++++++++++ .../Tabulation/ScoreControllerTest.php | 283 ++++++++++++++++++ 7 files changed, 551 insertions(+), 19 deletions(-) create mode 100644 tests/Feature/app/Http/Controllers/Tabulation/EntryFlagControllerTest.php create mode 100644 tests/Feature/app/Http/Controllers/Tabulation/ScoreControllerTest.php diff --git a/app/Actions/Tabulation/EnterScore.php b/app/Actions/Tabulation/EnterScore.php index 54023c4..bb5646e 100644 --- a/app/Actions/Tabulation/EnterScore.php +++ b/app/Actions/Tabulation/EnterScore.php @@ -85,6 +85,7 @@ class EnterScore if (! $scores->keys()->contains($subscore->id)) { throw new AuditionAdminException('Invalid Score Submission'); } + if ($scores[$subscore->id] > $subscore->max_score) { throw new AuditionAdminException('Supplied subscore exceeds maximum allowed'); } diff --git a/app/Http/Controllers/Tabulation/EntryFlagController.php b/app/Http/Controllers/Tabulation/EntryFlagController.php index 5a1a8c0..9ceca76 100644 --- a/app/Http/Controllers/Tabulation/EntryFlagController.php +++ b/app/Http/Controllers/Tabulation/EntryFlagController.php @@ -9,6 +9,9 @@ use Illuminate\Http\Request; use function to_route; +/** + * Used for tabulation enter noshow menu option + */ class EntryFlagController extends Controller { public function noShowSelect() @@ -30,11 +33,11 @@ class EntryFlagController extends Controller // If any results are published, get gone if ($entry->audition->hasFlag('seats_published')) { return to_route('entry-flags.noShowSelect')->with('error', - 'Cannot enter a no-show for an entry in an audition where seats are published'); + 'Cannot enter a no-show or failed-prelim for an entry in an audition where seats are published'); } if ($entry->audition->hasFlag('advancement_published')) { return to_route('entry-flags.noShowSelect')->with('error', - 'Cannot enter a no-show for an entry in an audition where advancement is published'); + 'Cannot enter a no-show or failed-prelim for an entry in an audition where advancement is published'); } if ($entry->hasFlag('no_show')) { @@ -43,6 +46,12 @@ class EntryFlagController extends Controller $submitRouteName = 'entry-flags.undoNoShow'; $cardHeading = 'Undo No-Show'; $method = 'DELETE'; + } elseif ($entry->hasFlag('failed_prelim')) { + $formId = 'no-show-cancellation-form'; + $buttonName = 'Remove Failed Prelim'; + $submitRouteName = 'entry-flags.undoNoShow'; + $cardHeading = 'Undo Failed-Prelim'; + $method = 'DELETE'; } else { $formId = 'no-show-confirmation-form'; $buttonName = 'Confirm No Show'; @@ -85,21 +94,32 @@ class EntryFlagController extends Controller { if ($entry->audition->hasFlag('seats_published')) { return to_route('entry-flags.noShowSelect')->with('error', - 'Cannot undo a no-show for an entry in an audition where seats are published'); + 'Cannot undo a no-show or failed-prelim for an entry in an audition where seats are published'); } if ($entry->audition->hasFlag('advancement_published')) { return to_route('entry-flags.noShowSelect')->with('error', - 'Cannot undo a no-show for an entry in an audition where advancement is published'); + 'Cannot undo a no-show or failed-prelim for an entry in an audition where advancement is published'); } $entry->removeFlag('no_show'); + $entry->removeFlag('failed_prelim'); return to_route('entry-flags.noShowSelect')->with('success', - 'No Show status has been removed for '.$entry->audition->name.' #'.$entry->draw_number.' (ID: '.$entry->id.').'); + $entry->audition->name.' #'.$entry->draw_number.' (ID: '.$entry->id.') may now be scored.'); } public function undoDecline(Entry $entry) { + if ($entry->audition->hasFlag('seats_published')) { + return redirect()->back() + ->with('error', 'Cannot undo a decline for an entry in an audition where seats are published'); + } + + if ($entry->audition->hasFlag('advancement_published')) { + return redirect()->back() + ->with('error', 'Cannot undo a no-show or failed-prelim for an entry in an audition where advancement is published'); + } + $entry->removeFlag('declined'); return redirect()->back()->with('success', 'Decline cleared'); diff --git a/app/Http/Controllers/Tabulation/ScoreController.php b/app/Http/Controllers/Tabulation/ScoreController.php index b4863a8..d506b47 100644 --- a/app/Http/Controllers/Tabulation/ScoreController.php +++ b/app/Http/Controllers/Tabulation/ScoreController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\Tabulation; use App\Actions\Tabulation\EnterScore; -use App\Exceptions\ScoreEntryException; +use App\Exceptions\AuditionAdminException; use App\Http\Controllers\Controller; use App\Models\Entry; use App\Models\EntryTotalScore; @@ -12,6 +12,9 @@ use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Session; +/** + * Provides functionality for entering judge scores from the admin side. + */ class ScoreController extends Controller { public function chooseEntry() @@ -25,7 +28,6 @@ class ScoreController extends Controller public function destroyScore(ScoreSheet $score) { - EntryTotalScore::where('entry_id', $score->entry_id)->delete(); if ($score->entry->audition->hasFlag('seats_published')) { return redirect()->back()->with('error', 'Cannot delete scores for an entry where seats are published'); } @@ -33,6 +35,7 @@ class ScoreController extends Controller return redirect()->back()->with('error', 'Cannot delete scores for an entry where advancement is published'); } + EntryTotalScore::where('entry_id', $score->entry_id)->delete(); $score->delete(); return redirect()->back()->with('success', 'Score Deleted'); @@ -41,7 +44,7 @@ class ScoreController extends Controller public function entryScoreSheet(Request $request) { $existing_sheets = []; - $entry = Entry::with(['student', 'audition.room.judges'])->find($request->input('entry_id')); + $entry = Entry::with(['student', 'audition.room.judges'])->findOrFail($request->input('entry_id')); $publishedCheck = $this->checkIfPublished($entry); if ($publishedCheck) { @@ -58,9 +61,7 @@ class ScoreController extends Controller } $scoring_guide = $entry->audition->scoringGuide; $subscores = $entry->audition->scoringGuide->subscores->sortBy('display_order'); - if (! $entry) { - return redirect()->route('tabulation.chooseEntry')->with('error', 'Entry not found'); - } + if ($entry->hasFlag('no_show')) { session()->flash('error', 'This entry is marked as a no-show. Entering a score will remove the no-show flag'); @@ -76,20 +77,32 @@ class ScoreController extends Controller if ($publishedCheck) { return $publishedCheck; } + + /** + * Here we process the submission from the scoring form. + * We're expecting submitted data to include an array for each judge. + * Each array should be called judge+ the judges ID number + * The array should have a key for each subscore and the value of the score submitted + */ foreach ($request->all() as $key => $value) { + // We're not interested in submission values that don't ahve judge in the name if (! str_contains($key, 'judge')) { continue; } + // Extract the judge ID from the field name and load the user $judge_id = str_replace('judge', '', $key); $judge = User::find($judge_id); + + // Check for existing scores, if so, tell EnterScores action that we're updating it, otherwise a new score $existingScore = ScoreSheet::where('entry_id', $entry->id) ->where('user_id', $judge->id)->first(); if ($existingScore === null) { $existingScore = false; } + try { $scoreRecorder($judge, $entry, $value, $existingScore); - } catch (ScoreEntryException $e) { + } catch (AuditionAdminException $e) { return redirect()->route('scores.entryScoreSheet', ['entry_id' => $entry->id]) ->with('error', $e->getMessage()); } diff --git a/resources/views/components/form/option.blade.php b/resources/views/components/form/option.blade.php index f7745c0..46711ed 100644 --- a/resources/views/components/form/option.blade.php +++ b/resources/views/components/form/option.blade.php @@ -8,7 +8,7 @@
- +
diff --git a/resources/views/tabulation/no_show_confirm.blade.php b/resources/views/tabulation/no_show_confirm.blade.php index 72084cb..36432bb 100644 --- a/resources/views/tabulation/no_show_confirm.blade.php +++ b/resources/views/tabulation/no_show_confirm.blade.php @@ -26,8 +26,16 @@
@endif - - {{ $cardHeading }} + + + @if($method !== "DELETE") + + @else + {{ $buttonName }} + @endif + + + {{ $entry->student->full_name() }} @@ -37,14 +45,21 @@ {{ $entry->audition->name }} #{{ $entry->draw_number ?? ' no draw number' }} - + @if($buttonName == "Confirm No Show") - - + + @endif - {{ $buttonName }} + + @if($method !== "DELETE") + + @else + {{ $buttonName }} + @endif + + diff --git a/tests/Feature/app/Http/Controllers/Tabulation/EntryFlagControllerTest.php b/tests/Feature/app/Http/Controllers/Tabulation/EntryFlagControllerTest.php new file mode 100644 index 0000000..e76a9e0 --- /dev/null +++ b/tests/Feature/app/Http/Controllers/Tabulation/EntryFlagControllerTest.php @@ -0,0 +1,200 @@ +entry = Entry::factory()->create(); +}); + +describe('EntryFlagController::noShowSelect', function () { + it('presents a from to choose an entry by ID', function () { + actAsTab(); + $this->get(route('entry-flags.noShowSelect'))->assertOk() + ->assertViewis('tabulation.choose_entry') + ->assertSee(route('entry-flags.confirmNoShow')); + }); + it('does not allow access to guests or normal users', function () { + $this->get(route('entry-flags.noShowSelect'))->assertRedirect(route('home')); + actAsNormal(); + $this->get(route('entry-flags.noShowSelect'))->assertRedirect(route('dashboard')); + }); +}); + +describe('EntryFlagController::noShowConfirm', function () { + it('does not allow access to guests or normal users', function () { + $this->get(route('entry-flags.noShowSelect'))->assertRedirect(route('home')); + actAsNormal(); + $this->get(route('entry-flags.noShowSelect'))->assertRedirect(route('dashboard')); + }); + it('shows a form to enter a no-show or failed-prelim if the entry has no flags', function () { + actAsAdmin(); + $response = $this->get(route('entry-flags.confirmNoShow', ['entry_id' => $this->entry->id])); + $response->assertOk() + ->assertViewIs('tabulation.no_show_confirm') + ->assertSee('No-Show') + ->assertSee('Fail Prelim'); + }); + it('does not entertain an invalid entry id', function () { + actAsAdmin(); + $response = $this->get(route('entry-flags.confirmNoShow', ['entry_id' => 999999999])); + $response->assertRedirect(); + }); + it('does not allow us to set a flag if the relevant audition seats are published', function () { + actAsAdmin(); + $this->entry->audition->addFlag('seats_published'); + $response = $this->get(route('entry-flags.confirmNoShow', ['entry_id' => $this->entry->id])); + $response->assertRedirect(route('entry-flags.noShowSelect')) + ->assertSessionHas('error', + 'Cannot enter a no-show or failed-prelim for an entry in an audition where seats are published'); + }); + it('does not allow us to set a flag if the relevant audition advancement is published', function () { + actAsAdmin(); + $this->entry->audition->addFlag('advancement_published'); + $response = $this->get(route('entry-flags.confirmNoShow', ['entry_id' => $this->entry->id])); + $response->assertRedirect(route('entry-flags.noShowSelect')) + ->assertSessionHas('error', + 'Cannot enter a no-show or failed-prelim for an entry in an audition where advancement is published'); + }); + it('returns the appropriate form if the entry is already a no-show', function () { + actAsAdmin(); + $this->entry->addFlag('no_show'); + $response = $this->get(route('entry-flags.confirmNoShow', ['entry_id' => $this->entry->id])); + $response->assertOk() + ->assertSee('Remove No Show'); + }); + it('returns the appropriate form if the entry is already a failed-prelim', function () { + actAsAdmin(); + $this->entry->addFlag('failed_prelim'); + $response = $this->get(route('entry-flags.confirmNoShow', ['entry_id' => $this->entry->id])); + $response->assertOk() + ->assertSee('Remove Failed Prelim'); + }); + it('shows scores if they exist', function () { + $judge = User::factory()->create(); + DB::table('score_sheets')->insert([ + 'entry_id' => $this->entry->id, + 'user_id' => $judge->id, + 'subscores' => json_encode([ + 3 => [ + 'score' => 12, + 'subscore_id' => 3, + 'subscore_name' => 'Subscore 3', + ], + ]), + 'seating_total' => 35, + 'advancement_total' => 35, + ]); + actAsAdmin(); + $response = $this->get(route('entry-flags.confirmNoShow', ['entry_id' => $this->entry->id])); + $response->assertOk() + ->assertViewIs('tabulation.no_show_confirm') + ->assertSee('Subscore 3'); + }); +}); + +describe('EntryFlagController::enterNoShow', function () { + it('does not allow access to guests or normal users', function () { + $this->post(route('entry-flags.enterNoShow', $this->entry))->assertRedirect(route('home')); + actAsNormal(); + $this->post(route('entry-flags.enterNoShow', $this->entry))->assertRedirect(route('dashboard')); + }); + it('passes exception from AuditionAdminException', function () { + $this->entry->audition->addFlag('seats_published'); + actAsAdmin(); + $resposne = $this->post(route('entry-flags.enterNoShow', $this->entry), [ + 'noshow-type' => 'noshow', + ]); + $resposne->assertRedirect(route('entry-flags.noShowSelect')) + ->assertSessionHas('error', + 'Cannot enter a no-show for an entry in an audition where seats are published'); + }); + it('can set a flag', function () { + actAsAdmin(); + $response = $this->post(route('entry-flags.enterNoShow', $this->entry), [ + 'noshow-type' => 'noshow', + ]); + $response->assertRedirect(route('entry-flags.noShowSelect'))->assertSessionHas('success'); + expect($this->entry->fresh()->hasFlag('no_show'))->toBeTrue(); + }); +}); + +describe('EntryFlagController::removeNoShow', function () { + it('does not allow access to guests or normal users', function () { + $this->delete(route('entry-flags.undoNoShow', $this->entry))->assertRedirect(route('home')); + actAsNormal(); + $this->delete(route('entry-flags.undoNoShow', $this->entry))->assertRedirect(route('dashboard')); + }); + it('removes a no-show flag', function () { + $this->entry->addFlag('no_show'); + actAsAdmin(); + $response = $this->delete(route('entry-flags.undoNoShow', $this->entry)); + $response->assertRedirect(route('entry-flags.noShowSelect'))->assertSessionHas('success'); + expect($this->entry->fresh()->hasFlag('no_show'))->toBeFalse(); + }); + it('removes a failed-prelim flag', function () { + $this->entry->addFlag('failed_prelim'); + actAsAdmin(); + $response = $this->delete(route('entry-flags.undoNoShow', $this->entry)); + $response->assertRedirect(route('entry-flags.noShowSelect'))->assertSessionHas('success'); + expect($this->entry->fresh()->hasFlag('failed_prelim'))->toBeFalse(); + }); + it('will not remove flags if the audition seats are published', function () { + $this->entry->addFlag('failed_prelim'); + $this->entry->audition->addFlag('seats_published'); + actAsAdmin(); + $response = $this->delete(route('entry-flags.undoNoShow', $this->entry)); + $response->assertRedirect(route('entry-flags.noShowSelect')) + ->assertSessionHas('error', + 'Cannot undo a no-show or failed-prelim for an entry in an audition where seats are published'); + expect($this->entry->fresh()->hasFlag('failed_prelim'))->toBeTrue(); + }); + it('will not remove flags if the audition advancement is published', function () { + $this->entry->addFlag('failed_prelim'); + $this->entry->audition->addFlag('advancement_published'); + actAsAdmin(); + $response = $this->delete(route('entry-flags.undoNoShow', $this->entry)); + $response->assertRedirect(route('entry-flags.noShowSelect')) + ->assertSessionHas('error', + 'Cannot undo a no-show or failed-prelim for an entry in an audition where advancement is published'); + expect($this->entry->fresh()->hasFlag('failed_prelim'))->toBeTrue(); + }); +}); + +describe('EntryFlagController::undoDecline', function () { + it('does not allow access to guests or normal users', function () { + $this->delete(route('entry-flags.undoDecline', $this->entry))->assertRedirect(route('home')); + actAsNormal(); + $this->delete(route('entry-flags.undoDecline', $this->entry))->assertRedirect(route('dashboard')); + }); + it('removes a declined flag', function () { + $this->entry->addFlag('declined'); + actAsAdmin(); + $response = $this->delete(route('entry-flags.undoDecline', $this->entry)); + $response->assertRedirect()->assertSessionHas('success'); + expect($this->entry->fresh()->hasFlag('declined'))->toBeFalse(); + }); + it('will not remove flags if the audition seats are published', function () { + $this->entry->addFlag('declined'); + $this->entry->audition->addFlag('seats_published'); + actAsAdmin(); + $response = $this->delete(route('entry-flags.undoDecline', $this->entry)); + $response->assertRedirect() + ->assertSessionHas('error', + 'Cannot undo a decline for an entry in an audition where seats are published'); + expect($this->entry->fresh()->hasFlag('declined'))->toBeTrue(); + }); + it('will not remove flags if the audition advancement is published', function () { + $this->entry->addFlag('declined'); + $this->entry->audition->addFlag('advancement_published'); + actAsAdmin(); + $response = $this->delete(route('entry-flags.undoDecline', $this->entry)); + $response->assertRedirect() + ->assertSessionHas('error', + 'Cannot undo a no-show or failed-prelim for an entry in an audition where advancement is published'); + expect($this->entry->fresh()->hasFlag('declined'))->toBeTrue(); + }); +}); diff --git a/tests/Feature/app/Http/Controllers/Tabulation/ScoreControllerTest.php b/tests/Feature/app/Http/Controllers/Tabulation/ScoreControllerTest.php new file mode 100644 index 0000000..3b33086 --- /dev/null +++ b/tests/Feature/app/Http/Controllers/Tabulation/ScoreControllerTest.php @@ -0,0 +1,283 @@ +scoringGuide = ScoringGuide::factory()->create(); + $this->user = User::factory()->create(); + $this->entry = Entry::factory()->create(); + $this->entry->audition->update(['scoring_guide_id' => $this->scoringGuide->id]); + $this->room = Room::factory()->create(); + $this->entry->audition->update(['room_id' => $this->room->id]); + $this->judge1 = User::factory()->create(); + $this->judge2 = User::factory()->create(); + $this->room->addJudge($this->judge1); + $this->room->addJudge($this->judge2); + DB::table('score_sheets')->insert([ + 'user_id' => $this->user->id, + 'entry_id' => $this->entry->id, + 'subscores' => json_encode([12, 3, 5]), + 'seating_total' => 1, + 'advancement_total' => 1, + ]); + $this->scoreSheet = ScoreSheet::first(); +}); + +describe('ScoreController::chooseEntry', function () { + it('does not allow access to guests or normal users', function () { + $this->get(route('scores.chooseEntry'))->assertRedirect(route('home')); + actAsNormal(); + $this->get(route('scores.chooseEntry'))->assertRedirect(route('dashboard')); + }); + it('provides a form to enter an entry id to select an entry to score', function () { + actAsTab(); + $this->get(route('scores.chooseEntry'))->assertOk(); + actAsAdmin(); + $this->get(route('scores.chooseEntry'))->assertOk()->assertViewIs('tabulation.choose_entry'); + }); +}); + +describe('ScoreController::destroyScore', function () { + it('does not allow access to guests or normal users', function () { + + $this->delete(route('scores.destroy', $this->scoreSheet))->assertRedirect(route('home')); + actAsNormal(); + $this->delete(route('scores.destroy', $this->scoreSheet))->assertRedirect(route('dashboard')); + }); + + it('deletes a score sheet', function () { + actAsTab(); + $response = $this->from(route('scores.chooseEntry'))->delete(route('scores.destroy', $this->scoreSheet)); + $response->assertRedirect(route('scores.chooseEntry')); + expect(ScoreSheet::count())->toBe(0); + }); + + it('will not delete a score if seats are published in the relative audition', function () { + $this->entry->audition->addFlag('seats_published'); + actAsTab(); + + $response = $this->from(route('scores.chooseEntry'))->delete(route('scores.destroy', $this->scoreSheet)); + $response->assertRedirect(route('scores.chooseEntry'))->assertSessionHas('error', + 'Cannot delete scores for an entry where seats are published'); + expect(ScoreSheet::count())->toBe(1); + }); + + it('will not delete a score if advancement is published in the relative audition', function () { + $this->entry->audition->addFlag('advancement_published'); + actAsTab(); + + $response = $this->from(route('scores.chooseEntry'))->delete(route('scores.destroy', $this->scoreSheet)); + $response->assertRedirect(route('scores.chooseEntry'))->assertSessionHas('error', + 'Cannot delete scores for an entry where advancement is published'); + expect(ScoreSheet::count())->toBe(1); + }); +}); + +describe('ScoreController::entryScoreSheet', function () { + it('does not allow access to guests or normal users', function () { + $this->get(route('scores.entryScoreSheet', $this->entry))->assertRedirect(route('home')); + actAsNormal(); + $this->get(route('scores.entryScoreSheet', $this->entry))->assertRedirect(route('dashboard')); + }); + it('provides a form to enter a score for an entry', function () { + actAsTab(); + + $response = $this->get(route('scores.entryScoreSheet', [ + 'entry_id' => $this->entry->id, + ])); + $response->assertOk()->assertSee(route('scores.saveEntryScoreSheet', $this->entry)) + ->assertSee($this->judge1->full_name()) + ->assertSee($this->judge2->full_name()); + foreach ($this->scoringGuide->subscores as $subscore) { + $response->assertSee($subscore->name) + ->assertSee('judge'.$this->judge1->id.'['.$subscore->id.']') + ->assertSee('judge'.$this->judge2->id.'['.$subscore->id.']'); + } + }); + it('alerts us if the entry is a no-show', function () { + actAsTab(); + $this->entry->addFlag('no_show'); + $response = $this->get(route('scores.entryScoreSheet', [ + 'entry_id' => $this->entry->id, + ])); + $response->assertOk()->assertSee(route('scores.saveEntryScoreSheet', $this->entry)) + ->assertSee('This entry is marked as a no-show'); + }); + it('alerts us if the entry already has scores and shows the old scores', function () { + actAsTab(); + DB::table('score_sheets')->insert([ + 'user_id' => $this->judge1->id, + 'entry_id' => $this->entry->id, + 'seating_total' => 98, + 'advancement_total' => 98, + 'subscores' => json_encode([ + $this->scoringGuide->subscores[0]->id => [ + 'score' => 13, + 'subscore_id' => $this->scoringGuide->subscores[0]->id, + 'subscore_name' => $this->scoringGuide->subscores[0]->name, + ], + $this->scoringGuide->subscores[1]->id => [ + 'score' => 23, + 'subscore_id' => $this->scoringGuide->subscores[1]->id, + 'subscore_name' => $this->scoringGuide->subscores[1]->name, + ], + $this->scoringGuide->subscores[2]->id => [ + 'score' => 33, + 'subscore_id' => $this->scoringGuide->subscores[2]->id, + 'subscore_name' => $this->scoringGuide->subscores[2]->name, + ], + $this->scoringGuide->subscores[3]->id => [ + 'score' => 43, + 'subscore_id' => $this->scoringGuide->subscores[3]->id, + 'subscore_name' => $this->scoringGuide->subscores[3]->name, + ], + $this->scoringGuide->subscores[4]->id => [ + 'score' => 53, + 'subscore_id' => $this->scoringGuide->subscores[4]->id, + 'subscore_name' => $this->scoringGuide->subscores[4]->name, + ], + ]), + ]); + $response = $this->get(route('scores.entryScoreSheet', [ + 'entry_id' => $this->entry->id, + ])); + $response->assertOk()->assertSee(route('scores.saveEntryScoreSheet', $this->entry)) + ->assertSee('Scores exist') + ->assertSee('13') + ->assertSee('23') + ->assertSee('33') + ->assertSee('43') + ->assertSee('53'); + }); + it('will not give us a form if seats are published in the relative audition', function () { + actAsTab(); + $this->entry->audition->addFlag('seats_published'); + $response = $this->get(route('scores.entryScoreSheet', [ + 'entry_id' => $this->entry->id, + ])); + $response->assertRedirect(route('scores.chooseEntry'))->assertSessionHas('error', + 'Cannot enter scores for entry '.$this->entry->id.'. '.$this->entry->audition->name.' seats are published'); + }); + it('will not give us a form if advancement is published in the relative audition', function () { + actAsTab(); + $this->entry->audition->addFlag('advancement_published'); + $response = $this->get(route('scores.entryScoreSheet', [ + 'entry_id' => $this->entry->id, + ])); + $response->assertRedirect(route('scores.chooseEntry'))->assertSessionHas('error', + 'Cannot enter scores for entry '.$this->entry->id.'. '.$this->entry->audition->name.' advancement is published'); + }); + it('deals with an invalid entry', function () { + actAsTab(); + $this->entry->audition->addFlag('seats_published'); + $response = $this->get(route('scores.entryScoreSheet', [ + 'entry_id' => 308, + ])); + $response->assertNotFound(); + }); +}); + +describe('ScoreController::saveEntryScoreSheet', function () { + it('does not allow access to guests or normal users', function () { + $this->post(route('scores.saveEntryScoreSheet', $this->entry))->assertRedirect(route('home')); + actAsNormal(); + $this->post(route('scores.saveEntryScoreSheet', $this->entry))->assertRedirect(route('dashboard')); + }); + it('will not post scores to an entry in an audition with published seats', function () { + actAsAdmin(); + $this->entry->audition->addFlag('seats_published'); + $this->post(route('scores.saveEntryScoreSheet', $this->entry)) + ->assertRedirect(route('scores.chooseEntry'))->assertSessionHas('error', + 'Cannot enter scores for entry '.$this->entry->id.'. '.$this->entry->audition->name.' seats are published'); + }); + it('will not post scores to an entry in an audition with published advancement', function () { + actAsAdmin(); + $this->entry->audition->addFlag('advancement_published'); + $this->post(route('scores.saveEntryScoreSheet', $this->entry)) + ->assertRedirect(route('scores.chooseEntry'))->assertSessionHas('error', + 'Cannot enter scores for entry '.$this->entry->id.'. '.$this->entry->audition->name.' advancement is published'); + }); + it('records scores', function () { + actAsTab(); + ScoreSheet::truncate(); + $response = $this->post(route('scores.saveEntryScoreSheet', $this->entry), [ + 'judge'.$this->judge1->id => [ + $this->scoringGuide->subscores[0]->id => 15, + $this->scoringGuide->subscores[1]->id => 25, + $this->scoringGuide->subscores[2]->id => 45, + $this->scoringGuide->subscores[3]->id => 55, + $this->scoringGuide->subscores[4]->id => 65, + ], + 'judge'.$this->judge2->id => [ + $this->scoringGuide->subscores[0]->id => 10, + $this->scoringGuide->subscores[1]->id => 20, + $this->scoringGuide->subscores[2]->id => 40, + $this->scoringGuide->subscores[3]->id => 50, + $this->scoringGuide->subscores[4]->id => 60, + ], + ]); + $response->assertRedirect(route('scores.chooseEntry'))->assertSessionHas('success'); + expect(ScoreSheet::count())->toBe(2); + }); + + it('if student was marked as a no-show, undo that', function () { + actAsTab(); + ScoreSheet::truncate(); + $this->entry->addFlag('no_show'); + $response = $this->post(route('scores.saveEntryScoreSheet', $this->entry), [ + 'judge'.$this->judge1->id => [ + $this->scoringGuide->subscores[0]->id => 15, + $this->scoringGuide->subscores[1]->id => 25, + $this->scoringGuide->subscores[2]->id => 45, + $this->scoringGuide->subscores[3]->id => 55, + $this->scoringGuide->subscores[4]->id => 65, + ], + 'judge'.$this->judge2->id => [ + $this->scoringGuide->subscores[0]->id => 10, + $this->scoringGuide->subscores[1]->id => 20, + $this->scoringGuide->subscores[2]->id => 40, + $this->scoringGuide->subscores[3]->id => 50, + $this->scoringGuide->subscores[4]->id => 60, + ], + 'distractor' => 'nonsense', + ]); + $response->assertRedirect(route('scores.chooseEntry'))->assertSessionHas('success'); + expect(ScoreSheet::count())->toBe(2); + $this->entry->refresh(); + expect($this->entry->hasFlag('no_show'))->toBeFalse(); + }); + + it('passes exceptions from the EnterScore action', function () { + actAsTab(); + ScoreSheet::truncate(); + $this->entry->addFlag('no_show'); + $response = $this->post(route('scores.saveEntryScoreSheet', $this->entry), [ + 'judge'.$this->judge1->id => [ + $this->scoringGuide->subscores[0]->id => 15, + $this->scoringGuide->subscores[1]->id => 25, + $this->scoringGuide->subscores[2]->id => 45, + $this->scoringGuide->subscores[3]->id => 55, + $this->scoringGuide->subscores[4]->id => 65, + 9278 => 33, + ], + 'judge'.$this->judge2->id => [ + $this->scoringGuide->subscores[0]->id => 10, + $this->scoringGuide->subscores[1]->id => 20, + $this->scoringGuide->subscores[2]->id => 40, + $this->scoringGuide->subscores[3]->id => 50, + $this->scoringGuide->subscores[4]->id => 60, + ], + 'distractor' => 'nonsense', + ]); + $response->assertRedirect(route('scores.entryScoreSheet', ['entry_id' => $this->entry->id]))->assertSessionHas('error', 'Invalid number of scores'); + + }); + +});