Tabulator Score Entry checks published status
This commit is contained in:
parent
a0913861fc
commit
53529fe0e9
|
|
@ -5,6 +5,7 @@ namespace App\Http\Controllers;
|
|||
use App\Models\Audition;
|
||||
use App\Models\Entry;
|
||||
use App\Models\JudgeAdvancementVote;
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
|
@ -39,15 +40,23 @@ class JudgingController extends Controller
|
|||
|
||||
public function entryScoreSheet(Request $request, Entry $entry)
|
||||
{
|
||||
// Turn away users not assigned to judge this entry
|
||||
if ($request->user()->cannot('judge', $entry->audition)) {
|
||||
return redirect()->route('judging.index')->with('error', 'You are not assigned to judge this entry');
|
||||
}
|
||||
// Turn away users if the audition is published
|
||||
if ($entry->audition->hasFlag('seats_published') || $entry->audition->hasFlag('advancement_published')) {
|
||||
return redirect()->route('judging.auditionEntryList', $entry->audition)->with('error', 'Scores for entries in published auditions cannot be modified');
|
||||
return redirect()->route('judging.auditionEntryList', $entry->audition)->with('error',
|
||||
'Scores for entries in published auditions cannot be modified');
|
||||
}
|
||||
// Turn away users if the entry is flagged as a no-show
|
||||
if ($entry->hasFlag('no_show')) {
|
||||
return redirect()->route('judging.auditionEntryList', $entry->audition)->with('error',
|
||||
'The requested entry is marked as a no-show. Scores cannot be entered.');
|
||||
}
|
||||
$oldSheet = ScoreSheet::where('user_id', Auth::id())->where('entry_id', $entry->id)->value('subscores') ?? null;
|
||||
$oldVote = JudgeAdvancementVote::where('user_id', Auth::id())->where('entry_id', $entry->id)->first();
|
||||
$oldVote = $oldVote ? $oldVote->vote : 'novote';
|
||||
$oldVote = $oldVote ? $oldVote->vote : 'noVote';
|
||||
|
||||
return view('judging.entry_score_sheet', compact('entry', 'oldSheet', 'oldVote'));
|
||||
}
|
||||
|
|
@ -57,6 +66,7 @@ class JudgingController extends Controller
|
|||
if ($request->user()->cannot('judge', $entry->audition)) {
|
||||
abort(403, 'You are not assigned to judge this entry');
|
||||
}
|
||||
// TODO extract to a service class
|
||||
$scoringGuide = $entry->audition->scoringGuide()->with('subscores')->first();
|
||||
$scoreValidation = $scoringGuide->validateScores($request->input('score'));
|
||||
if ($scoreValidation != 'success') {
|
||||
|
|
@ -79,7 +89,8 @@ class JudgingController extends Controller
|
|||
|
||||
$this->advancementVote($request, $entry);
|
||||
|
||||
return redirect('/judging/audition/'.$entry->audition_id)->with('success', 'Entered scores for '.$entry->audition->name.' '.$entry->draw_number);
|
||||
return redirect('/judging/audition/'.$entry->audition_id)->with('success',
|
||||
'Entered scores for '.$entry->audition->name.' '.$entry->draw_number);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -114,7 +125,8 @@ class JudgingController extends Controller
|
|||
|
||||
$this->advancementVote($request, $entry);
|
||||
|
||||
return redirect('/judging/audition/'.$entry->audition_id)->with('success', 'Updated scores for '.$entry->audition->name.' '.$entry->draw_number);
|
||||
return redirect('/judging/audition/'.$entry->audition_id)->with('success',
|
||||
'Updated scores for '.$entry->audition->name.' '.$entry->draw_number);
|
||||
}
|
||||
|
||||
protected function advancementVote(Request $request, Entry $entry)
|
||||
|
|
@ -134,9 +146,10 @@ class JudgingController extends Controller
|
|||
'entry_id' => $entry->id,
|
||||
'vote' => $request->input('advancement-vote'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception) {
|
||||
return redirect(url()->previous())->with('error', 'Error saving advancement vote');
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use Tests\Feature\Models\ScoreSheet;
|
|||
|
||||
class ScoreController extends Controller
|
||||
{
|
||||
public function chooseEntry(Request $request)
|
||||
public function chooseEntry()
|
||||
{
|
||||
$method = 'GET';
|
||||
$formRoute = 'scores.entryScoreSheet';
|
||||
|
|
@ -29,6 +29,12 @@ class ScoreController extends Controller
|
|||
{
|
||||
$existing_sheets = [];
|
||||
$entry = Entry::with(['student', 'audition.room.judges'])->find($request->input('entry_id'));
|
||||
|
||||
$publishedCheck = $this->checkIfPublished($entry);
|
||||
if ($publishedCheck) {
|
||||
return $publishedCheck;
|
||||
}
|
||||
|
||||
$judges = $entry->audition->room->judges;
|
||||
foreach ($judges as $judge) {
|
||||
$scoreSheet = ScoreSheet::where('entry_id', $entry->id)->where('user_id', $judge->id)->first();
|
||||
|
|
@ -49,6 +55,11 @@ class ScoreController extends Controller
|
|||
|
||||
public function saveEntryScoreSheet(Request $request, Entry $entry)
|
||||
{
|
||||
$publishedCheck = $this->checkIfPublished($entry);
|
||||
if ($publishedCheck) {
|
||||
return $publishedCheck;
|
||||
}
|
||||
|
||||
$judges = $entry->audition->room->judges;
|
||||
|
||||
$subscores = $entry->audition->scoringGuide->subscores->sortBy('tiebreak_order');
|
||||
|
|
@ -84,4 +95,20 @@ class ScoreController extends Controller
|
|||
|
||||
return redirect()->route('scores.chooseEntry')->with('success', count($preparedScoreSheets).' Scores saved');
|
||||
}
|
||||
|
||||
protected function checkIfPublished($entry)
|
||||
{
|
||||
// We're not going to enter scores if seats are published
|
||||
if ($entry->audition->hasFlag('seats_published')) {
|
||||
return to_route('scores.chooseEntry')->with('error',
|
||||
'Cannot enter scores for entry '.$entry->id.'. '.$entry->audition->name.' seats are published');
|
||||
}
|
||||
// Nope, not if advancement is published either
|
||||
if ($entry->audition->hasFlag('advancement_published')) {
|
||||
return to_route('scores.chooseEntry')->with('error',
|
||||
'Cannot enter scores for entry '.$entry->id.'. '.$entry->audition->name.' advancement is published');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
</x-slot:right_side>
|
||||
</x-card.heading>
|
||||
|
||||
<x-form.form method="POST" action="{{ route('scores.saveEntryScoreSheet',[ 'entry' => $entry->id]) }}">
|
||||
<x-form.form method="POST" id='scoreForm' action="{{ route('scores.saveEntryScoreSheet',[ 'entry' => $entry->id]) }}">
|
||||
<x-table.table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
|
|
|||
|
|
@ -141,3 +141,12 @@ it('redirects if advancement is published', function () {
|
|||
->assertSessionHas('error', 'Scores for entries in published auditions cannot be modified');
|
||||
|
||||
});
|
||||
it('will not show a score sheet for an entry marked as no_show', function () {
|
||||
// Arrange
|
||||
$this->entries->first()->addFlag('no_show');
|
||||
$this->actingAs($this->user);
|
||||
// Act & Assert
|
||||
$response = $this->get(route('judging.entryScoreSheet', $this->entries->first()));
|
||||
$response->assertRedirect(route('judging.auditionEntryList', $this->entries[0]->audition))
|
||||
->assertSessionHas('error', 'The requested entry is marked as a no-show. Scores cannot be entered.');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Sinnbeck\DomAssertions\Asserts\AssertElement;
|
||||
use Sinnbeck\DomAssertions\Asserts\AssertForm;
|
||||
|
||||
use function Pest\Laravel\get;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
it('responds to only admin and tab users', function () {
|
||||
get(route('scores.chooseEntry'))
|
||||
->assertRedirect(route('home'));
|
||||
actAsAdmin();
|
||||
get(route('scores.chooseEntry'))
|
||||
->assertOk();
|
||||
actAsTab();
|
||||
get(route('scores.chooseEntry'))
|
||||
->assertOk();
|
||||
actAsNormal();
|
||||
get(route('scores.chooseEntry'))
|
||||
->assertRedirect(route('dashboard'))
|
||||
->assertSessionHas('error', 'You are not authorized to perform this action');
|
||||
});
|
||||
it('has an input for entry_id', function () {
|
||||
actAsAdmin();
|
||||
get(route('scores.chooseEntry'))
|
||||
->assertOk()
|
||||
->assertElementExists('#entry_id', function (AssertElement $element) {
|
||||
$element->is('input');
|
||||
});
|
||||
});
|
||||
it('submits to entry-flags.confirmNoShow', function () {
|
||||
actAsAdmin();
|
||||
get(route('scores.chooseEntry'))
|
||||
->assertOk()
|
||||
->assertFormExists('#entry-select-form', function (AssertForm $form) {
|
||||
$form->hasMethod('GET')
|
||||
->hasAction(route('scores.entryScoreSheet'));
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Audition;
|
||||
use App\Models\Entry;
|
||||
use App\Models\Event;
|
||||
use App\Models\Room;
|
||||
use App\Models\ScoringGuide;
|
||||
use App\Models\SubscoreDefinition;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Sinnbeck\DomAssertions\Asserts\AssertForm;
|
||||
|
||||
use function Pest\Laravel\get;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
function testData(): array
|
||||
{
|
||||
$data['judge'] = User::factory()->create();
|
||||
$data['room'] = Room::factory()->create();
|
||||
$data['room']->addJudge($data['judge']);
|
||||
$data['event'] = Event::factory()->create();
|
||||
$data['scoringGuide'] = ScoringGuide::factory()->create();
|
||||
$data['subscores'] = SubscoreDefinition::factory()->count(3)->create([
|
||||
'scoring_guide_id' => $data['scoringGuide']->id,
|
||||
]);
|
||||
$data['audition'] = Audition::factory()->create([
|
||||
'room_id' => $data['room']->id,
|
||||
'event_id' => $data['event']->id,
|
||||
'scoring_guide_id' => $data['scoringGuide']->id,
|
||||
]);
|
||||
$data['entry'] = Entry::factory()->create([
|
||||
'audition_id' => $data['audition']->id,
|
||||
]);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/** @noinspection PhpMissingReturnTypeInspection */
|
||||
function validRequest(array $data = [])
|
||||
{
|
||||
if (! $data) {
|
||||
$data = testData();
|
||||
}
|
||||
actAsTab();
|
||||
|
||||
return get(route('scores.entryScoreSheet', ['entry_id' => $data['entry']->id]));
|
||||
}
|
||||
|
||||
it('does not allow guests or normal users to access the admin score form', function () {
|
||||
get(route('scores.entryScoreSheet'))->assertRedirect(route('home'));
|
||||
actAsNormal();
|
||||
get(route('scores.entryScoreSheet'))->assertRedirect(route('dashboard'))->assertSessionHas('error',
|
||||
'You are not authorized to perform this action');
|
||||
});
|
||||
it('grants an admin or tab user access', function () {
|
||||
// Arrange
|
||||
$response = validRequest();
|
||||
// Act & Assert
|
||||
$response->assertOk();
|
||||
});
|
||||
it('has a form with field for each subscore for each judge', function () {
|
||||
// Arrange
|
||||
$data = testData();
|
||||
$response = validRequest($data);
|
||||
// Act & Assert
|
||||
$response->assertOk();
|
||||
$fieldsToCheck = [];
|
||||
foreach ($data['subscores'] as $subscore) {
|
||||
$fieldsToCheck[] = 'j'.$data['judge']->id.'ss'.$subscore->id;
|
||||
}
|
||||
/** @noinspection PhpExpressionResultUnusedInspection */
|
||||
$response->assertFormExists('#scoreForm', function (AssertForm $form) use ($fieldsToCheck) {
|
||||
$form->hasCSRF();
|
||||
$form->hasMethod('POST');
|
||||
$form->hasAction(route('scores.saveEntryScoreSheet', ['entry' => 1]));
|
||||
foreach ($fieldsToCheck as $field) {
|
||||
$form->contains('#'.$field);
|
||||
}
|
||||
});
|
||||
});
|
||||
it('will not accept scores for an entry in a an audition with published seats', function () {
|
||||
// Arrange
|
||||
$data = testData();
|
||||
$data['audition']->addFlag('seats_published');
|
||||
$response = validRequest($data);
|
||||
// Act & Assert
|
||||
$expectedError = 'Cannot enter scores for entry '.$data['entry']->id.'. '.$data['entry']->audition->name.' seats are published';
|
||||
$response
|
||||
->assertRedirect(route('scores.chooseEntry'))
|
||||
->assertSessionHas('error', $expectedError);
|
||||
});
|
||||
it('will not accept scores for an entry in an audition with published advancement', function () {
|
||||
// Arrange
|
||||
$data = testData();
|
||||
$data['audition']->addFlag('advancement_published');
|
||||
$response = validRequest($data);
|
||||
// Act & Assert
|
||||
$expectedError = 'Cannot enter scores for entry '.$data['entry']->id.'. '.$data['entry']->audition->name.' advancement is published';
|
||||
$response
|
||||
->assertRedirect(route('scores.chooseEntry'))
|
||||
->assertSessionHas('error', $expectedError);
|
||||
});
|
||||
Loading…
Reference in New Issue