Judge prelim entry scores functioning.
This commit is contained in:
parent
ca80260bda
commit
0e4b8acce6
|
|
@ -2,8 +2,14 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\Judging;
|
namespace App\Http\Controllers\Judging;
|
||||||
|
|
||||||
|
use App\Actions\Tabulation\EnterPrelimScore;
|
||||||
|
use App\Exceptions\AuditionAdminException;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Entry;
|
||||||
use App\Models\PrelimDefinition;
|
use App\Models\PrelimDefinition;
|
||||||
|
use App\Models\PrelimScoreSheet;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class PrelimJudgingController extends Controller
|
class PrelimJudgingController extends Controller
|
||||||
{
|
{
|
||||||
|
|
@ -18,4 +24,48 @@ class PrelimJudgingController extends Controller
|
||||||
|
|
||||||
return view('judging.prelim_entry_list', compact('prelimDefinition', 'entries', 'subscores', 'published'));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
<x-layout.app>
|
||||||
|
@php
|
||||||
|
$oldScores = session()->get('oldScores') ?? null;
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<x-slot:page_title>Prelim Score Entry</x-slot:page_title>
|
||||||
|
<x-card.card class="mx-auto max-w-md">
|
||||||
|
<x-card.heading>
|
||||||
|
{{ $entry->audition->name }} {{ $entry->draw_number }}
|
||||||
|
<x-slot:subheading>
|
||||||
|
<ul class="mt-.5 max-w-2xl text-sm leading-6 text-gray-500">
|
||||||
|
<li>All Scores must be complete</li>
|
||||||
|
<li>You may enter zero</li>
|
||||||
|
<li>Whole numbers only</li>
|
||||||
|
</ul>
|
||||||
|
</x-slot:subheading>
|
||||||
|
</x-card.heading>
|
||||||
|
<x-form.form method="POST" action="{{ route('judging.savePrelimScoreSheet', $entry) }}">
|
||||||
|
@if($oldSheet)
|
||||||
|
{{-- if there are existing scores, make this a patch request --}}
|
||||||
|
@method('PATCH')
|
||||||
|
@endif
|
||||||
|
<x-card.list.body class="mt-1">
|
||||||
|
@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
|
||||||
|
|
||||||
|
<li class="py-2">
|
||||||
|
|
||||||
|
<x-form.field
|
||||||
|
name="score[{{$subscore->id}}]"
|
||||||
|
type="number"
|
||||||
|
placeholder="{{$subscore->name}}"
|
||||||
|
:value="$value"
|
||||||
|
max="{{ $subscore->max_score }}"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<x-slot:label>{{ $subscore->name }} <span class="text-xs text-base text-gray-400 pl-3">max: {{$subscore->max_score}}</span></x-slot:label>
|
||||||
|
|
||||||
|
</x-form.field>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
|
||||||
|
@endforeach
|
||||||
|
</x-card.list.body>
|
||||||
|
<x-form.footer>
|
||||||
|
<x-form.button class="mb-5">Save Scores</x-form.button>
|
||||||
|
</x-form.footer>
|
||||||
|
</x-form.form>
|
||||||
|
</x-card.card>
|
||||||
|
</x-layout.app>
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<x-table.td>
|
<x-table.td>
|
||||||
@if(! $published && ! $entry->hasFlag('no_show'))
|
@if(! $published && ! $entry->hasFlag('no_show'))
|
||||||
<a href="#">
|
<a href="{{ route('judging.prelimScoreEntryForm', $entry) }}">
|
||||||
@endif
|
@endif
|
||||||
{{ $prelimDefinition->audition->name }} {{ $entry->draw_number }}
|
{{ $prelimDefinition->audition->name }} {{ $entry->draw_number }}
|
||||||
@if($entry->hasFlag('no_show'))
|
@if($entry->hasFlag('no_show'))
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ Route::middleware(['auth', 'verified', CheckIfCanJudge::class])->prefix('judging
|
||||||
// Prelim Audition Related Routes
|
// Prelim Audition Related Routes
|
||||||
Route::middleware(['auth', 'verified', CheckIfCanJudge::class])->prefix('judging/prelims')->controller(PrelimJudgingController::class)->group(function () {
|
Route::middleware(['auth', 'verified', CheckIfCanJudge::class])->prefix('judging/prelims')->controller(PrelimJudgingController::class)->group(function () {
|
||||||
Route::get('/{prelimDefinition}', 'prelimEntryList')->name('judging.prelimEntryList');
|
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
|
// Bonus score judging routes
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,10 @@ use App\Actions\Draw\RunDraw;
|
||||||
use App\Models\Audition;
|
use App\Models\Audition;
|
||||||
use App\Models\Entry;
|
use App\Models\Entry;
|
||||||
use App\Models\PrelimDefinition;
|
use App\Models\PrelimDefinition;
|
||||||
|
use App\Models\PrelimScoreSheet;
|
||||||
use App\Models\Room;
|
use App\Models\Room;
|
||||||
|
use App\Models\ScoringGuide;
|
||||||
|
use App\Models\SubscoreDefinition;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue