updates to entry action
This commit is contained in:
parent
66fe859f06
commit
b09f1b13ca
|
|
@ -17,37 +17,51 @@ class CreateEntry
|
|||
/**
|
||||
* @throws ManageEntryException
|
||||
*/
|
||||
public function __invoke(Student|int $student, Audition|int $audition, string|array|null $entry_for = null)
|
||||
{
|
||||
return $this->createEntry($student, $audition, $entry_for);
|
||||
public function __invoke(
|
||||
Student|int $student,
|
||||
Audition|int $audition,
|
||||
$for_seating = false,
|
||||
$for_advancement = false,
|
||||
$late_fee_waived = false
|
||||
) {
|
||||
return $this->createEntry($student, $audition, $for_seating, $for_advancement, $late_fee_waived);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ManageEntryException
|
||||
*/
|
||||
public function createEntry(Student|int $student, Audition|int $audition, string|array|null $entry_for = null): Entry
|
||||
{
|
||||
public function createEntry(
|
||||
Student|int $student,
|
||||
Audition|int $audition,
|
||||
$for_seating = false,
|
||||
$for_advancement = false,
|
||||
$late_fee_waived = false
|
||||
): Entry {
|
||||
if (is_int($student)) {
|
||||
$student = Student::find($student);
|
||||
}
|
||||
if (is_int($audition)) {
|
||||
$audition = Audition::find($audition);
|
||||
}
|
||||
|
||||
if (! $entry_for) {
|
||||
$entry_for = ['seating', 'advancement'];
|
||||
}
|
||||
$entry_for = collect($entry_for);
|
||||
$this->verifySubmission($student, $audition);
|
||||
if (! $for_advancement && ! $for_seating) {
|
||||
$for_seating = true;
|
||||
$for_advancement = true;
|
||||
}
|
||||
$entry = Entry::make([
|
||||
'student_id' => $student->id,
|
||||
'audition_id' => $audition->id,
|
||||
'draw_number' => $this->checkDraw($audition),
|
||||
'for_seating' => $entry_for->contains('seating'),
|
||||
'for_advancement' => $entry_for->contains('advancement'),
|
||||
'for_seating' => $for_seating,
|
||||
'for_advancement' => $for_advancement,
|
||||
]);
|
||||
$entry->save();
|
||||
|
||||
if ($late_fee_waived) {
|
||||
$entry->addFlag('late_fee_waived');
|
||||
$entry->refresh();
|
||||
}
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use App\Actions\Entries\UpdateEntry;
|
|||
use App\Exceptions\AuditionAdminException;
|
||||
use App\Exceptions\ManageEntryException;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\EntryStoreRequest;
|
||||
use App\Models\Audition;
|
||||
use App\Models\AuditLogEntry;
|
||||
use App\Models\Entry;
|
||||
|
|
@ -15,7 +16,6 @@ use App\Models\Seat;
|
|||
use App\Models\Student;
|
||||
use App\Services\ScoreService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
use function auditionSetting;
|
||||
use function compact;
|
||||
|
|
@ -25,9 +25,6 @@ class EntryController extends Controller
|
|||
{
|
||||
public function index()
|
||||
{
|
||||
if (! Auth::user()->is_admin) {
|
||||
abort(403);
|
||||
}
|
||||
$perPage = 25;
|
||||
$filters = session('adminEntryFilters') ?? null;
|
||||
$minGrade = Audition::min('minimum_grade');
|
||||
|
|
@ -38,31 +35,31 @@ class EntryController extends Controller
|
|||
$entries = Entry::with(['student.school', 'audition']);
|
||||
$entries->orderBy('id', 'DESC');
|
||||
if ($filters) {
|
||||
if ($filters['id']) {
|
||||
if ($filters['id'] ?? false) {
|
||||
$entries->where('id', $filters['id']);
|
||||
}
|
||||
|
||||
if ($filters['audition']) {
|
||||
if ($filters['audition'] ?? false) {
|
||||
$entries->where('audition_id', $filters['audition']);
|
||||
}
|
||||
if ($filters['school']) {
|
||||
if ($filters['school'] ?? false) {
|
||||
$entries->whereHas('student', function ($query) use ($filters) {
|
||||
$query->where('school_id', '=', $filters['school']);
|
||||
});
|
||||
}
|
||||
if ($filters['grade']) {
|
||||
if ($filters['grade'] ?? false) {
|
||||
$entries->whereHas('student', function ($query) use ($filters) {
|
||||
$query->where('grade', $filters['grade']);
|
||||
});
|
||||
}
|
||||
|
||||
if ($filters['first_name']) {
|
||||
if ($filters['first_name'] ?? false) {
|
||||
$entries->whereHas('student', function ($query) use ($filters) {
|
||||
$query->where('first_name', 'like', '%'.$filters['first_name'].'%');
|
||||
});
|
||||
}
|
||||
|
||||
if ($filters['last_name']) {
|
||||
if ($filters['last_name'] ?? false) {
|
||||
$entries->whereHas('student', function ($query) use ($filters) {
|
||||
$query->where('last_name', 'like', '%'.$filters['last_name'].'%');
|
||||
});
|
||||
|
|
@ -110,27 +107,9 @@ class EntryController extends Controller
|
|||
return view('admin.entries.create', ['students' => $students, 'auditions' => $auditions]);
|
||||
}
|
||||
|
||||
public function store(Request $request, CreateEntry $creator)
|
||||
public function store(EntryStoreRequest $request, CreateEntry $creator)
|
||||
{
|
||||
if (! Auth::user()->is_admin) {
|
||||
abort(403);
|
||||
}
|
||||
$validData = request()->validate([
|
||||
'student_id' => ['required', 'exists:students,id'],
|
||||
'audition_id' => ['required', 'exists:auditions,id'],
|
||||
]);
|
||||
|
||||
$validData['for_seating'] = $request->get('for_seating') ? 1 : 0;
|
||||
$validData['for_advancement'] = $request->get('for_advancement') ? 1 : 0;
|
||||
$validData['late_fee_waived'] = $request->get('late_fee_waived') ? 1 : 0;
|
||||
$enter_for = [];
|
||||
if ($validData['for_seating']) {
|
||||
$enter_for[] = 'seating';
|
||||
}
|
||||
if ($validData['for_advancement']) {
|
||||
$enter_for[] = 'advancement';
|
||||
}
|
||||
|
||||
$validData = $request->validatedWithEnterFor();
|
||||
try {
|
||||
$entry = $creator($validData['student_id'], $validData['audition_id'], $enter_for);
|
||||
} catch (ManageEntryException $ex) {
|
||||
|
|
|
|||
|
|
@ -38,8 +38,12 @@ class EntryController extends Controller
|
|||
public function store(EntryStoreRequest $request, CreateEntry $creator)
|
||||
{
|
||||
$validData = $request->validatedWithEnterFor();
|
||||
|
||||
$creator($validData['student_id'], $validData['audition_id'], $validData['enter_for'] ?? []);
|
||||
$creator(
|
||||
$validData['student_id'],
|
||||
$validData['audition_id'],
|
||||
for_seating: $validData['for_seating'],
|
||||
for_advancement: $validData['for_advancement'],
|
||||
);
|
||||
|
||||
return redirect()->route('entries.index')->with('success', 'The entry has been added.');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,13 @@
|
|||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Audition;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class EntryStoreRequest extends FormRequest
|
||||
{
|
||||
public function authorize()
|
||||
public function authorize(): bool
|
||||
{
|
||||
if (auth()->user()->is_admin) {
|
||||
return true;
|
||||
|
|
@ -20,17 +21,25 @@ class EntryStoreRequest extends FormRequest
|
|||
return false;
|
||||
}
|
||||
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
$rules = [
|
||||
'student_id' => ['required', 'exists:students,id'],
|
||||
'audition_id' => ['required', 'exists:auditions,id'],
|
||||
'for_seating' => ['sometimes', 'boolean'],
|
||||
'for_advancement' => ['sometimes', 'boolean'],
|
||||
];
|
||||
|
||||
// Add late_fee_waived validation only for admin users
|
||||
if (auth()->user()->is_admin) {
|
||||
$rules['late_fee_waived'] = ['sometimes', 'boolean'];
|
||||
}
|
||||
|
||||
return $rules;
|
||||
|
||||
}
|
||||
|
||||
public function withValidator($validator)
|
||||
public function withValidator($validator): void
|
||||
{
|
||||
$validator->after(function ($validator) {
|
||||
$auditionId = $this->input('audition_id');
|
||||
|
|
@ -42,10 +51,12 @@ class EntryStoreRequest extends FormRequest
|
|||
return;
|
||||
}
|
||||
|
||||
$currentDate = Carbon::now('America/Chicago')->format('Y-m-d');
|
||||
if (! Auth::user()->is_admin) { //Admins don't care about deadlines
|
||||
$currentDate = Carbon::now('America/Chicago')->format('Y-m-d');
|
||||
|
||||
if ($audition->entry_deadline < $currentDate) {
|
||||
$validator->errors()->add('entry_deadline', 'The entry deadline for that audition has passed.');
|
||||
if ($audition->entry_deadline < $currentDate) {
|
||||
$validator->errors()->add('entry_deadline', 'The entry deadline for that audition has passed.');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -53,13 +64,21 @@ class EntryStoreRequest extends FormRequest
|
|||
/**
|
||||
* Prepare the data for validation.
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
// Normalize the boolean inputs to 1 or 0
|
||||
$this->merge([
|
||||
$data = [
|
||||
'for_seating' => $this->boolean('for_seating'),
|
||||
'for_advancement' => $this->boolean('for_advancement'),
|
||||
]);
|
||||
];
|
||||
|
||||
// Only include late_fee_waived in the data if the user is admin
|
||||
if (auth()->user()->is_admin) {
|
||||
$data['late_fee_waived'] = $this->boolean('late_fee_waived');
|
||||
}
|
||||
|
||||
$this->merge($data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ it('allows setting only seating', function () {
|
|||
test('allows setting only advancement', function () {
|
||||
$student = Student::factory()->create(['grade' => 9]);
|
||||
$audition = Audition::factory()->create(['minimum_grade' => 9, 'maximum_grade' => 12]);
|
||||
$this->scribe->createEntry($student, $audition, 'advancement');
|
||||
$this->scribe->createEntry($student, $audition, for_advancement: true);
|
||||
$thisEntry = Entry::where('student_id', $student->id)->first();
|
||||
|
||||
expect($thisEntry->for_seating)->toBeFalsy()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,260 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Audition;
|
||||
use App\Models\Entry;
|
||||
use App\Models\Event;
|
||||
use App\Models\Student;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$this->event = Event::factory()->create();
|
||||
$this->auditions = Audition::factory()->count(2)->create(['event_id' => $this->event->id]);
|
||||
$this->students = Student::factory()->count(2)->create();
|
||||
$this->entry1 = Entry::factory()->create([
|
||||
'audition_id' => $this->auditions[0]->id, 'student_id' => $this->students[0]->id, 'for_seating' => 1,
|
||||
'for_advancement' => 0,
|
||||
]);
|
||||
$this->entry2 = Entry::factory()->create([
|
||||
'audition_id' => $this->auditions[1]->id, 'student_id' => $this->students[1]->id, 'for_seating' => 1,
|
||||
'for_advancement' => 1,
|
||||
]);
|
||||
$this->entry3 = Entry::factory()->create([
|
||||
'audition_id' => $this->auditions[0]->id, 'student_id' => $this->students[1]->id, 'for_seating' => 0,
|
||||
'for_advancement' => 1,
|
||||
]);
|
||||
$this->entry4 = Entry::factory()->create([
|
||||
'audition_id' => $this->auditions[1]->id, 'student_id' => $this->students[0]->id, 'for_seating' => 1,
|
||||
'for_advancement' => 1,
|
||||
]);
|
||||
$this->entry1->student->update(['grade' => 9]);
|
||||
$this->entry2->student->update(['grade' => 10]);
|
||||
});
|
||||
|
||||
describe('EntryController::index', function () {
|
||||
it('denies access to non-admins', function () {
|
||||
$this->get(route('admin.entries.index'))->assertRedirect(route('home'));
|
||||
actAsNormal();
|
||||
$this->get(route('admin.entries.index'))->assertRedirect(route('dashboard'));
|
||||
actAsTab();
|
||||
$this->get(route('admin.entries.index'))->assertRedirect(route('dashboard'));
|
||||
});
|
||||
it('provides a list of entries', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->get(route('admin.entries.index'))->assertOk()
|
||||
->assertViewIs('admin.entries.index');
|
||||
foreach (Entry::all() as $entry) {
|
||||
$response->assertSee($entry->student->full_name());
|
||||
$response->assertSee($entry->audition->name);
|
||||
}
|
||||
});
|
||||
describe('test filters', function () {
|
||||
it('can filter by ID', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->withSession([
|
||||
'adminEntryFilters' => [
|
||||
'id' => $this->entry4->id,
|
||||
],
|
||||
])->get(route('admin.entries.index'))->assertOk();
|
||||
saveContentLocally($response->getContent());
|
||||
$response->assertSee($this->entry4->student->full_name())
|
||||
->assertDontSee($this->entry2->student->full_name());
|
||||
});
|
||||
it('can filter by first_name', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->withSession([
|
||||
'adminEntryFilters' => [
|
||||
'first_name' => $this->entry4->student->first_name,
|
||||
],
|
||||
])->get(route('admin.entries.index'))->assertOk();
|
||||
saveContentLocally($response->getContent());
|
||||
$response->assertSee($this->entry4->student->full_name())
|
||||
->assertDontSee($this->entry2->student->full_name());
|
||||
});
|
||||
it('can filter by last_name', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->withSession([
|
||||
'adminEntryFilters' => [
|
||||
'last_name' => $this->entry4->student->last_name,
|
||||
],
|
||||
])->get(route('admin.entries.index'))->assertOk();
|
||||
saveContentLocally($response->getContent());
|
||||
$response->assertSee($this->entry4->student->full_name())
|
||||
->assertDontSee($this->entry2->student->full_name());
|
||||
});
|
||||
it('can filter by audition', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->withSession([
|
||||
'adminEntryFilters' => [
|
||||
'audition' => $this->entry1->audition_id,
|
||||
],
|
||||
])->get(route('admin.entries.index'))->assertOk();
|
||||
saveContentLocally($response->getContent());
|
||||
$returnedEntries = $response->viewData('entries');
|
||||
expect($returnedEntries->contains('id', $this->entry1->id))->toBeTrue()
|
||||
->and($returnedEntries->contains('id', $this->entry2->id))->toBeFalse()
|
||||
->and($returnedEntries->contains('id', $this->entry3->id))->toBeTrue()
|
||||
->and($returnedEntries->contains('id', $this->entry4->id))->toBeFalse();
|
||||
});
|
||||
it('can filter by school', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->withSession([
|
||||
'adminEntryFilters' => [
|
||||
'school' => $this->entry1->student->school_id,
|
||||
],
|
||||
])->get(route('admin.entries.index'))->assertOk();
|
||||
saveContentLocally($response->getContent());
|
||||
$returnedEntries = $response->viewData('entries');
|
||||
expect($returnedEntries->contains('id', $this->entry1->id))->toBeTrue()
|
||||
->and($returnedEntries->contains('id', $this->entry2->id))->toBeFalse()
|
||||
->and($returnedEntries->contains('id', $this->entry3->id))->toBeFalse()
|
||||
->and($returnedEntries->contains('id', $this->entry4->id))->toBeTrue();
|
||||
});
|
||||
it('can filter by grade', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->withSession([
|
||||
'adminEntryFilters' => [
|
||||
'grade' => 9,
|
||||
],
|
||||
])->get(route('admin.entries.index'))->assertOk();
|
||||
saveContentLocally($response->getContent());
|
||||
$returnedEntries = $response->viewData('entries');
|
||||
expect($returnedEntries->contains('id', $this->entry1->id))->toBeTrue()
|
||||
->and($returnedEntries->contains('id', $this->entry2->id))->toBeFalse()
|
||||
->and($returnedEntries->contains('id', $this->entry3->id))->toBeFalse()
|
||||
->and($returnedEntries->contains('id', $this->entry4->id))->toBeTrue();
|
||||
});
|
||||
it('can show auditions entered in seating', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->withSession([
|
||||
'adminEntryFilters' => [
|
||||
'entry_type' => 'seats',
|
||||
],
|
||||
])->get(route('admin.entries.index'))->assertOk();
|
||||
saveContentLocally($response->getContent());
|
||||
$returnedEntries = $response->viewData('entries');
|
||||
expect($returnedEntries->contains('id', $this->entry1->id))->toBeTrue()
|
||||
->and($returnedEntries->contains('id', $this->entry2->id))->toBeTrue()
|
||||
->and($returnedEntries->contains('id', $this->entry3->id))->toBeFalse()
|
||||
->and($returnedEntries->contains('id', $this->entry4->id))->toBeTrue();
|
||||
});
|
||||
it('can show auditions entered in advancement', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->withSession([
|
||||
'adminEntryFilters' => [
|
||||
'entry_type' => 'advancement',
|
||||
],
|
||||
])->get(route('admin.entries.index'))->assertOk();
|
||||
saveContentLocally($response->getContent());
|
||||
$returnedEntries = $response->viewData('entries');
|
||||
expect($returnedEntries->contains('id', $this->entry1->id))->toBeFalse()
|
||||
->and($returnedEntries->contains('id', $this->entry2->id))->toBeTrue()
|
||||
->and($returnedEntries->contains('id', $this->entry3->id))->toBeTrue()
|
||||
->and($returnedEntries->contains('id', $this->entry4->id))->toBeTrue();
|
||||
});
|
||||
it('can show auditions entered only in seating', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->withSession([
|
||||
'adminEntryFilters' => [
|
||||
'entry_type' => 'seatsOnly',
|
||||
],
|
||||
])->get(route('admin.entries.index'))->assertOk();
|
||||
saveContentLocally($response->getContent());
|
||||
$returnedEntries = $response->viewData('entries');
|
||||
expect($returnedEntries->contains('id', $this->entry1->id))->toBeTrue()
|
||||
->and($returnedEntries->contains('id', $this->entry2->id))->toBeFalse()
|
||||
->and($returnedEntries->contains('id', $this->entry3->id))->toBeFalse()
|
||||
->and($returnedEntries->contains('id', $this->entry4->id))->toBeFalse();
|
||||
});
|
||||
it('can show auditions entered only in advancement', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->withSession([
|
||||
'adminEntryFilters' => [
|
||||
'entry_type' => 'advancementOnly',
|
||||
],
|
||||
])->get(route('admin.entries.index'))->assertOk();
|
||||
saveContentLocally($response->getContent());
|
||||
$returnedEntries = $response->viewData('entries');
|
||||
expect($returnedEntries->contains('id', $this->entry1->id))->toBeFalse()
|
||||
->and($returnedEntries->contains('id', $this->entry2->id))->toBeFalse()
|
||||
->and($returnedEntries->contains('id', $this->entry3->id))->toBeTrue()
|
||||
->and($returnedEntries->contains('id', $this->entry4->id))->toBeFalse();
|
||||
});
|
||||
it('can limit the number of results per page', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->withSession([
|
||||
'adminEntryFilters' => [
|
||||
'entries_per_page' => 1,
|
||||
],
|
||||
])->get(route('admin.entries.index'))->assertOk();
|
||||
$returnedEntries = $response->viewData('entries');
|
||||
expect($returnedEntries->count())->toEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('EntryController::create', function () {
|
||||
it('denies access to non-admins', function () {
|
||||
$this->get(route('admin.entries.create'))->assertRedirect(route('home'));
|
||||
actAsNormal();
|
||||
$this->get(route('admin.entries.create'))->assertRedirect(route('dashboard'));
|
||||
actAsTab();
|
||||
$this->get(route('admin.entries.create'))->assertRedirect(route('dashboard'));
|
||||
});
|
||||
it('provides a form to make an entry', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->get(route('admin.entries.create'));
|
||||
$response->assertOk();
|
||||
});
|
||||
it('provides auditions to the form', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->get(route('admin.entries.create'));
|
||||
$response->assertOk();
|
||||
$response->assertViewHas('auditions');
|
||||
$returnedAuditions = $response->viewData('auditions');
|
||||
foreach (Audition::all() as $audition) {
|
||||
expect($returnedAuditions->contains('id', $audition->id))->toBeTrue();
|
||||
}
|
||||
});
|
||||
it('does not provide published auditions to the form', function () {
|
||||
actAsAdmin();
|
||||
$unavailableAudition[0] = Audition::factory()->create();
|
||||
$unavailableAudition[0]->addFlag('seats_published');
|
||||
$unavailableAudition[1] = Audition::factory()->create();
|
||||
$unavailableAudition[1]->addFlag('advancement_published');
|
||||
|
||||
$response = $this->get(route('admin.entries.create'));
|
||||
$response->assertOk();
|
||||
$response->assertViewHas('auditions');
|
||||
$returnedAuditions = $response->viewData('auditions');
|
||||
foreach ($unavailableAudition as $audition) {
|
||||
expect($returnedAuditions->contains('id', $audition->id))->toBeFalse();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('EntryController::store', function () {
|
||||
beforeEach(function () {
|
||||
$this->testAudition = Audition::factory()->create();
|
||||
$this->testStudent = Student::factory()->create();
|
||||
$this->testSubmitData = [
|
||||
'student_id' => $this->testStudent->id,
|
||||
'audition_id' => $this->testAudition->id,
|
||||
'for_seating' => 'on',
|
||||
'for_advancement' => 'on',
|
||||
'late_fee_waived' => 'on',
|
||||
];
|
||||
});
|
||||
it('denies access to non-admins', function () {
|
||||
$this->post(route('admin.entries.store'), $this->testSubmitData)->assertRedirect(route('home'));
|
||||
actAsNormal();
|
||||
$this->post(route('admin.entries.store'), $this->testSubmitData)->assertRedirect(route('dashboard'));
|
||||
actAsTab();
|
||||
$this->post(route('admin.entries.store'), $this->testSubmitData)->assertRedirect(route('dashboard'));
|
||||
});
|
||||
it('creates an entry', function () {
|
||||
actAsAdmin();
|
||||
$this->post(route('admin.entries.store'), $this->testSubmitData);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue