Draw functionality complete
This commit is contained in:
parent
a28380e2fe
commit
817eb574bd
|
|
@ -3,12 +3,14 @@
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\ClearDrawRequest;
|
||||||
use App\Http\Requests\RunDrawRequest;
|
use App\Http\Requests\RunDrawRequest;
|
||||||
use App\Models\Audition;
|
use App\Models\Audition;
|
||||||
use App\Models\Event;
|
use App\Models\Event;
|
||||||
use App\Services\DrawService;
|
use App\Services\DrawService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use function array_keys;
|
use function array_keys;
|
||||||
use function to_route;
|
use function to_route;
|
||||||
|
|
||||||
|
|
@ -51,6 +53,16 @@ class DrawController extends Controller
|
||||||
$drawnAuditions = Audition::whereHas('flags', function ($query) {
|
$drawnAuditions = Audition::whereHas('flags', function ($query) {
|
||||||
$query->where('flag_name', 'drawn');
|
$query->where('flag_name', 'drawn');
|
||||||
})->get();
|
})->get();
|
||||||
|
|
||||||
return view('admin.draw.edit', compact('drawnAuditions'));
|
return view('admin.draw.edit', compact('drawnAuditions'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function destroy(ClearDrawRequest $request)
|
||||||
|
{
|
||||||
|
$auditions = Audition::with('flags')->findMany(array_keys($request->input('audition', [])));
|
||||||
|
$this->drawService->clearDrawsOnCollection($auditions);
|
||||||
|
|
||||||
|
return to_route('admin.draw.index')->with('status', 'Draw completed successfully');
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use App\Models\Audition;
|
||||||
|
use Illuminate\Contracts\Validation\Validator;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
use function to_route;
|
||||||
|
|
||||||
|
class ClearDrawRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function authorize(): true
|
||||||
|
{
|
||||||
|
// Return true if the user is authorized to make this request.
|
||||||
|
// You might want to check if the user is an admin, for example.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'audition' => ['required', 'array'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function messages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'audition.required' => 'No auditions were selected',
|
||||||
|
'audition.array' => 'Invalid request format',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withValidator($validator): void
|
||||||
|
{
|
||||||
|
$validator->after(function ($validator) {
|
||||||
|
foreach ($this->input('audition', []) as $auditionId => $value) {
|
||||||
|
if (! is_numeric($auditionId) || ! Audition::where('id', $auditionId)->exists()) {
|
||||||
|
$validator->errors()->add('audition', 'One or more invalid auditions were selected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function failedValidation(Validator $validator)
|
||||||
|
{
|
||||||
|
$msg = $validator->errors()->get('audition')[0];
|
||||||
|
|
||||||
|
return to_route('admin.draw.index')->with('error', $msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -40,4 +40,15 @@ class DrawService
|
||||||
|
|
||||||
return $auditions->contains(fn ($audition) => $audition->hasFlag('drawn'));
|
return $auditions->contains(fn ($audition) => $audition->hasFlag('drawn'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function clearDrawForAudition(Audition $audition): void
|
||||||
|
{
|
||||||
|
$audition->removeFlag('drawn');
|
||||||
|
DB::table('entries')->where('audition_id', $audition->id)->update(['draw_number' => null]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clearDrawsOnCollection($auditions): void
|
||||||
|
{
|
||||||
|
$auditions->each(fn ($audition) => $this->clearDrawForAudition($audition));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Audition;
|
||||||
|
use App\Models\Entry;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
uses(RefreshDatabase::class);
|
||||||
|
|
||||||
|
it('only allows admin users to manage the draw', function () {
|
||||||
|
$this->get(route('admin.draw.edit'))
|
||||||
|
->assertRedirect(route('home'));
|
||||||
|
actAsNormal();
|
||||||
|
$this->get(route('admin.draw.edit'))
|
||||||
|
->assertSessionHas('error', 'You are not authorized to perform this action')
|
||||||
|
->assertRedirect(route('dashboard'));
|
||||||
|
actAsAdmin();
|
||||||
|
$this->get(route('admin.draw.edit'))
|
||||||
|
->assertOk()
|
||||||
|
->assertViewIs('admin.draw.edit');
|
||||||
|
|
||||||
|
});
|
||||||
|
it('lists auditions that have been drawn', function () {
|
||||||
|
$audition = Audition::factory()->create();
|
||||||
|
$drawnAudition = Audition::factory()->create();
|
||||||
|
$drawnAudition->addFlag('drawn');
|
||||||
|
actAsAdmin();
|
||||||
|
$response = $this->get(route('admin.draw.edit'));
|
||||||
|
$response->assertOk()
|
||||||
|
->assertSee($drawnAudition->name)
|
||||||
|
->assertDontSee($audition->name);
|
||||||
|
});
|
||||||
|
it('has a warning message', function () {
|
||||||
|
actAsAdmin();
|
||||||
|
$response = $this->get(route('admin.draw.edit'));
|
||||||
|
$response->assertOk()
|
||||||
|
->assertSee('Caution');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('submits to the admin.draw.destroy route', function () {
|
||||||
|
actAsAdmin();
|
||||||
|
$this->get(route('admin.draw.edit'))
|
||||||
|
->assertOk()
|
||||||
|
->assertSee(route('admin.draw.destroy'));
|
||||||
|
});
|
||||||
|
it('does not allow a non-admin user to clear a draw', function () {
|
||||||
|
$this->delete(route('admin.draw.destroy'))
|
||||||
|
->assertRedirect(route('home'));
|
||||||
|
actAsNormal();
|
||||||
|
$this->delete(route('admin.draw.destroy'))
|
||||||
|
->assertSessionHas('error', 'You are not authorized to perform this action')
|
||||||
|
->assertRedirect(route('dashboard'));
|
||||||
|
});
|
||||||
|
it('allows an administrator to clear a draw', function () {
|
||||||
|
$audition = Audition::factory()->create();
|
||||||
|
$audition->addFlag('drawn');
|
||||||
|
$entries = Entry::factory()->count(3)->create(['audition_id' => $audition->id]);
|
||||||
|
$n = 1;
|
||||||
|
$entries->each(function ($entry) use (&$n) {
|
||||||
|
$entry->draw_number = $n;
|
||||||
|
$entry->save();
|
||||||
|
$n++;
|
||||||
|
});
|
||||||
|
actAsAdmin();
|
||||||
|
/** @noinspection PhpUnhandledExceptionInspection */
|
||||||
|
$this->delete(route('admin.draw.destroy'), ['audition' => [$audition->id => 'on']])
|
||||||
|
->assertSessionHasNoErrors()
|
||||||
|
->assertRedirect(route('admin.draw.index'));
|
||||||
|
|
||||||
|
$entries->each(function ($entry) {
|
||||||
|
$entry->refresh();
|
||||||
|
expect($entry->draw_number)->toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
$checkAudition = Audition::find($audition->id);
|
||||||
|
expect($checkAudition->hasFlag('drawn'))->toBeFalse();
|
||||||
|
});
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use App\Models\Audition;
|
use App\Models\Audition;
|
||||||
use App\Models\Entry;
|
use App\Models\Entry;
|
||||||
|
use App\Services\DrawService;
|
||||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
|
||||||
uses(RefreshDatabase::class);
|
uses(RefreshDatabase::class);
|
||||||
|
|
@ -48,7 +49,7 @@ it('sets a drawn flag on the audition once a draw is run', function () {
|
||||||
$audition = Audition::factory()->create();
|
$audition = Audition::factory()->create();
|
||||||
actAsAdmin();
|
actAsAdmin();
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
$response = $this->post(route('admin.draw.store', ['audition['.$audition->id.']' => 'on']));
|
$this->post(route('admin.draw.store', ['audition['.$audition->id.']' => 'on']));
|
||||||
expect($audition->hasFlag('drawn'))->toBeTrue();
|
expect($audition->hasFlag('drawn'))->toBeTrue();
|
||||||
});
|
});
|
||||||
it('refuses to draw an audition that has an existing draw', function () {
|
it('refuses to draw an audition that has an existing draw', function () {
|
||||||
|
|
@ -72,4 +73,21 @@ it('randomizes the order of the entries in the audition', function () {
|
||||||
expect($audition->entries->sortBy('draw_number')->pluck('id'))
|
expect($audition->entries->sortBy('draw_number')->pluck('id'))
|
||||||
->not()->toBe($entries->pluck('id'));
|
->not()->toBe($entries->pluck('id'));
|
||||||
});
|
});
|
||||||
// sets the draw_number column on each entry in the audition based on the randomized entry order
|
it('sets the draw_number column on each entry in the audition based on the randomized entry order', function () {
|
||||||
|
// Arrange
|
||||||
|
$audition = Audition::factory()->hasEntries(10)->create();
|
||||||
|
Entry::all()->each(fn ($entry) => expect($entry->draw_number)->toBeNull());
|
||||||
|
$drawService = new DrawService();
|
||||||
|
$drawService->runOneDraw($audition);
|
||||||
|
// Act & Assert
|
||||||
|
Entry::all()->each(fn ($entry) => expect($entry->draw_number)->not()->toBeNull());
|
||||||
|
});
|
||||||
|
it('only sets draw numbers in the specified audition', function () {
|
||||||
|
// Arrange
|
||||||
|
$audition = Audition::factory()->hasEntries(10)->create();
|
||||||
|
$bonusEntry = Entry::factory()->create();
|
||||||
|
$drawService = new DrawService();
|
||||||
|
$drawService->runOneDraw($audition);
|
||||||
|
// Act & Assert
|
||||||
|
expect($bonusEntry->draw_number)->toBeNull();
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue