Auditionadmin 20 - Bonus scores are fully functional #25
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Judging;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Audition;
|
||||||
|
use App\Models\BonusScore;
|
||||||
|
use App\Models\BonusScoreDefinition;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class BonusScoreEntryListController extends Controller
|
||||||
|
{
|
||||||
|
public function __invoke(Audition $audition)
|
||||||
|
{
|
||||||
|
/** @var BonusScoreDefinition $bonusScore */
|
||||||
|
$bonusScore = $audition->bonusScore()->first();
|
||||||
|
if (! $bonusScore->judges->contains(auth()->id())) {
|
||||||
|
return redirect()->route('dashboard')->with('error', 'You are not assigned to judge this bonus score');
|
||||||
|
}
|
||||||
|
$entries = $audition->entries()->orderBy('draw_number')->get();
|
||||||
|
$entries = $entries->reject(fn ($entry) => $entry->hasFlag('no_show'));
|
||||||
|
$entries->each(fn ($entry) => $entry->audition = $audition);
|
||||||
|
|
||||||
|
$scores = BonusScore::where('user_id', Auth::user()->id)
|
||||||
|
->with('entry.audition')
|
||||||
|
->with('originallyScoredEntry.audition')
|
||||||
|
->get()
|
||||||
|
->keyBy('entry_id');
|
||||||
|
|
||||||
|
return view('judging.bonus_score_entry_list', compact('audition', 'entries', 'scores'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers\Judging;
|
||||||
|
|
||||||
use App\Actions\Tabulation\EnterScore;
|
use App\Actions\Tabulation\EnterScore;
|
||||||
use App\Exceptions\AuditionServiceException;
|
use App\Exceptions\AuditionServiceException;
|
||||||
use App\Exceptions\ScoreEntryException;
|
use App\Exceptions\ScoreEntryException;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Audition;
|
use App\Models\Audition;
|
||||||
use App\Models\Entry;
|
use App\Models\Entry;
|
||||||
use App\Models\JudgeAdvancementVote;
|
use App\Models\JudgeAdvancementVote;
|
||||||
|
|
@ -3,8 +3,24 @@
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
class BonusScore extends Model
|
class BonusScore extends Model
|
||||||
{
|
{
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
|
public function entry(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Entry::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function judge(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function originallyScoredEntry(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Entry::class, 'originally_scored_entry');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
@php use Carbon\Carbon; @endphp
|
||||||
|
<x-layout.app>
|
||||||
|
<x-slot:page_title>Judging Dashboard - Bonus Scores</x-slot:page_title>
|
||||||
|
<x-table.table>
|
||||||
|
<x-slot:title>{{ $audition->name }} - Bonus Score</x-slot:title>
|
||||||
|
<x-table.body>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<x-table.th>Entry</x-table.th>
|
||||||
|
<x-table.th>Score</x-table.th>
|
||||||
|
<x-table.th>Scored On</x-table.th>
|
||||||
|
<x-table.th>Score Timestamp</x-table.th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<x-table.body>
|
||||||
|
@foreach($entries as $entry)
|
||||||
|
<tr>
|
||||||
|
<x-table.td>{{ $audition->name }} {{ $entry->draw_number }}</x-table.td>
|
||||||
|
@if($scores->has($entry->id))
|
||||||
|
<x-table.td>{{ $scores[$entry->id]->score }}</x-table.td>
|
||||||
|
<x-table.td>{{ $scores[$entry->id]->originallyScoredEntry->audition->name }}</x-table.td>
|
||||||
|
<x-table.td>{{ Carbon::create($scores[$entry->id]->created_at)->setTimezone('America/Chicago')->format('m/d/y H:i') }}</x-table.td>
|
||||||
|
|
||||||
|
@endif
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</x-table.body>
|
||||||
|
</x-table.body>
|
||||||
|
</x-table.table>
|
||||||
|
</x-layout.app>
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
<x-card.heading>{{ $bonusScore->name }}</x-card.heading>
|
<x-card.heading>{{ $bonusScore->name }}</x-card.heading>
|
||||||
<x-card.list.body>
|
<x-card.list.body>
|
||||||
@foreach($bonusScore->auditions as $audition)
|
@foreach($bonusScore->auditions as $audition)
|
||||||
<a href="#">
|
<a href="{{ route('judging.bonusScore.EntryList', $audition) }}">
|
||||||
<x-card.list.row class="!py-3 ml-3">
|
<x-card.list.row class="!py-3 ml-3">
|
||||||
{{ $audition->name }}
|
{{ $audition->name }}
|
||||||
</x-card.list.row>
|
</x-card.list.row>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Judging Routes
|
// Judging Routes
|
||||||
use App\Http\Controllers\JudgingController;
|
use App\Http\Controllers\Judging\BonusScoreEntryListController;
|
||||||
|
use App\Http\Controllers\Judging\JudgingController;
|
||||||
use App\Http\Middleware\CheckIfCanJudge;
|
use App\Http\Middleware\CheckIfCanJudge;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
|
|
@ -11,3 +13,8 @@ Route::middleware(['auth', 'verified', CheckIfCanJudge::class])->prefix('judging
|
||||||
Route::post('/entry/{entry}', 'saveScoreSheet')->name('judging.saveScoreSheet');
|
Route::post('/entry/{entry}', 'saveScoreSheet')->name('judging.saveScoreSheet');
|
||||||
Route::patch('/entry/{entry}', 'updateScoreSheet')->name('judging.updateScoreSheet');
|
Route::patch('/entry/{entry}', 'updateScoreSheet')->name('judging.updateScoreSheet');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Bonus score judging routes
|
||||||
|
Route::middleware(['auth', 'verified', CheckIfCanJudge::class])->prefix('judging/bonus_scores')->group(function () {
|
||||||
|
Route::get('/{audition}', BonusScoreEntryListController::class)->name('judging.bonusScore.EntryList');
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Http\Controllers\DashboardController;
|
|
||||||
use App\Http\Controllers\EntryController;
|
|
||||||
use App\Http\Controllers\FilterController;
|
use App\Http\Controllers\FilterController;
|
||||||
use App\Http\Controllers\JudgingController;
|
|
||||||
use App\Http\Controllers\PdfInvoiceController;
|
|
||||||
use App\Http\Controllers\SchoolController;
|
|
||||||
use App\Http\Controllers\StudentController;
|
|
||||||
use App\Http\Controllers\Tabulation\DoublerDecisionController;
|
|
||||||
use App\Http\Controllers\TestController;
|
use App\Http\Controllers\TestController;
|
||||||
use App\Http\Controllers\UserController;
|
|
||||||
use App\Http\Middleware\CheckIfAdmin;
|
|
||||||
use App\Http\Middleware\CheckIfCanJudge;
|
|
||||||
use App\Http\Middleware\CheckIfCanTab;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
require __DIR__.'/admin.php';
|
require __DIR__.'/admin.php';
|
||||||
|
|
@ -23,7 +11,6 @@ require __DIR__.'/user.php';
|
||||||
|
|
||||||
Route::get('/test', [TestController::class, 'flashTest'])->middleware('auth', 'verified');
|
Route::get('/test', [TestController::class, 'flashTest'])->middleware('auth', 'verified');
|
||||||
|
|
||||||
|
|
||||||
Route::view('/', 'welcome')->middleware('guest')->name('home');
|
Route::view('/', 'welcome')->middleware('guest')->name('home');
|
||||||
Route::get('/results', [App\Http\Controllers\ResultsPage::class, '__invoke'])->name('results');
|
Route::get('/results', [App\Http\Controllers\ResultsPage::class, '__invoke'])->name('results');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Audition;
|
||||||
|
use App\Models\BonusScore;
|
||||||
|
use App\Models\BonusScoreDefinition;
|
||||||
|
use App\Models\Entry;
|
||||||
|
use App\Models\Room;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
|
||||||
|
use function Pest\Laravel\actingAs;
|
||||||
|
|
||||||
|
uses(RefreshDatabase::class);
|
||||||
|
|
||||||
|
it('denies access go a guest', function () {
|
||||||
|
$response = $this->get(route('judging.bonusScore.EntryList', 1));
|
||||||
|
$response->assertRedirect(route('home'));
|
||||||
|
});
|
||||||
|
it('denies access to a user not assigned to judge this bonus score', function () {
|
||||||
|
$bonusScore = BonusScoreDefinition::factory()->create();
|
||||||
|
$audition = Audition::factory()->create();
|
||||||
|
$audition->bonusScore()->attach($bonusScore->id);
|
||||||
|
$room = Room::factory()->create();
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$room->addJudge($user->id);
|
||||||
|
actingAs($user);
|
||||||
|
$this->get(route('judging.bonusScore.EntryList', $audition->id))
|
||||||
|
->assertRedirect(route('dashboard'))
|
||||||
|
->assertSessionHas('error', 'You are not assigned to judge this bonus score');
|
||||||
|
});
|
||||||
|
it('shows all entries to an authorized judge', function () {
|
||||||
|
// Arrange
|
||||||
|
$bonusScore = BonusScoreDefinition::factory()->create();
|
||||||
|
$audition = Audition::factory()->create();
|
||||||
|
$audition->bonusScore()->attach($bonusScore->id);
|
||||||
|
$entries[1] = Entry::factory()->create(['audition_id' => $audition->id, 'draw_number' => 1]);
|
||||||
|
$entries[2] = Entry::factory()->create(['audition_id' => $audition->id, 'draw_number' => 2]);
|
||||||
|
$entries[3] = Entry::factory()->create(['audition_id' => $audition->id, 'draw_number' => 3]);
|
||||||
|
$entries[4] = Entry::factory()->create(['audition_id' => $audition->id, 'draw_number' => 4]);
|
||||||
|
$entries = collect($entries);
|
||||||
|
$judge = User::factory()->create();
|
||||||
|
$bonusScore->judges()->attach($judge->id);
|
||||||
|
actingAs($judge);
|
||||||
|
// Act & Assert
|
||||||
|
$response = $this->get(route('judging.bonusScore.EntryList', $audition->id));
|
||||||
|
$response->assertOk();
|
||||||
|
$entries->each(fn ($entry) => $response->assertSee($entry->audition->name.' '.$entry->draw_number));
|
||||||
|
});
|
||||||
|
it('shows existing scores for an entry', function () {
|
||||||
|
$bonusScore = BonusScoreDefinition::factory()->create(['max_score' => 100]);
|
||||||
|
$audition = Audition::factory()->create();
|
||||||
|
$audition->bonusScore()->attach($bonusScore->id);
|
||||||
|
$entry = Entry::factory()->create(['audition_id' => $audition->id, 'draw_number' => 1]);
|
||||||
|
$judge = User::factory()->create();
|
||||||
|
$bonusScore->judges()->attach($judge->id);
|
||||||
|
BonusScore::create([
|
||||||
|
'entry_id' => $entry->id,
|
||||||
|
'user_id' => $judge->id,
|
||||||
|
'originally_scored_entry' => $entry->id,
|
||||||
|
'score' => 42,
|
||||||
|
]);
|
||||||
|
actingAs($judge);
|
||||||
|
// Act
|
||||||
|
$response = $this->get(route('judging.bonusScore.EntryList', $audition));
|
||||||
|
$response->assertOk()
|
||||||
|
->assertSeeInOrder(['<tr>', e($audition->name), $entry->draw_number, 42, '</tr>'], false);
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue