Merge pull request #10 from okorpheus/add-scopes-to-models
Add scopes to models
This commit is contained in:
commit
e79f484bfe
|
|
@ -19,7 +19,7 @@ class EntryController extends Controller
|
|||
$entries = $entries->sortBy(function ($entry) {
|
||||
return $entry->student->last_name.$entry->student->first_name.$entry->audition->score_order;
|
||||
});
|
||||
$auditions = Audition::deadlineNotPast();
|
||||
$auditions = Audition::open()->get();
|
||||
$students = Auth::user()->students;
|
||||
|
||||
return view('entries.index', ['entries' => $entries, 'students' => $students, 'auditions' => $auditions]);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
|
@ -25,11 +27,6 @@ class Audition extends Model
|
|||
protected $scored_entries_count; //Set by TabulationService
|
||||
|
||||
|
||||
public static function deadlineNotPast()
|
||||
{
|
||||
return Audition::where('entry_deadline', '>=', now())->get();
|
||||
}
|
||||
|
||||
public function event(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Event::class);
|
||||
|
|
@ -50,7 +47,7 @@ class Audition extends Model
|
|||
return $this->belongsTo(ScoringGuide::class);
|
||||
}
|
||||
|
||||
public function dislpay_fee(): string
|
||||
public function display_fee(): string
|
||||
{
|
||||
return '$'.number_format($this->entry_fee / 100, 2);
|
||||
}
|
||||
|
|
@ -134,7 +131,7 @@ class Audition extends Model
|
|||
}
|
||||
|
||||
/**
|
||||
* @return BelongsToMany|\App\Models\User[]
|
||||
* @return BelongsToMany|User[]
|
||||
*/
|
||||
public function judges(): array|BelongsToMany
|
||||
{
|
||||
|
|
@ -185,4 +182,35 @@ class Audition extends Model
|
|||
// remove related auditionFlag where flag_name = $flag
|
||||
$this->flags()->where('flag_name', $flag)->delete();
|
||||
}
|
||||
|
||||
public function scopeOpen(Builder $query): void
|
||||
{
|
||||
$query->where('entry_deadline', '>=', Carbon::now());
|
||||
}
|
||||
|
||||
public function scopeForSeating(Builder $query): void
|
||||
{
|
||||
$query->where('for_seating', 1);
|
||||
}
|
||||
|
||||
public function scopeForAdvancement(Builder $query): void
|
||||
{
|
||||
$query->where('for_advancement', 1);
|
||||
}
|
||||
|
||||
public function scopeSeatsPublished(Builder $query): Builder
|
||||
{
|
||||
return $query->whereHas('flags', function (Builder $query) {
|
||||
$query->where('flag_name', 'seats_published');
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public function scopeAdvancementPublished(Builder $query): Builder
|
||||
{
|
||||
return $query->whereHas('flags', function (Builder $query) {
|
||||
$query->where('flag_name', 'advancement_published');
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
|
@ -69,7 +70,7 @@ class Entry extends Model
|
|||
|
||||
}
|
||||
|
||||
public function addFlag($flag)
|
||||
public function addFlag($flag): void
|
||||
{
|
||||
if ($this->hasFlag($flag)) {
|
||||
return;
|
||||
|
|
@ -78,7 +79,7 @@ class Entry extends Model
|
|||
$this->flags()->create(['flag_name' => $flag]);
|
||||
}
|
||||
|
||||
public function removeFlag($flag)
|
||||
public function removeFlag($flag): void
|
||||
{
|
||||
// remove related auditionFlag where flag_name = $flag
|
||||
$this->flags()->where('flag_name', $flag)->delete();
|
||||
|
|
@ -100,4 +101,23 @@ class Entry extends Model
|
|||
{
|
||||
return $this->hasOne(Seat::class);
|
||||
}
|
||||
|
||||
public function scopeForSeating(Builder $query): void
|
||||
{
|
||||
$query->where('for_seating', 1);
|
||||
}
|
||||
|
||||
public function scopeForAdvancement(Builder $query): void
|
||||
{
|
||||
$query->where('for_advancement', 1);
|
||||
}
|
||||
|
||||
public function scopeAvailable(Builder $query): void
|
||||
{
|
||||
$query->whereDoesntHave('flags', function (Builder $query) {
|
||||
$query->where('flag_name', 'declined')
|
||||
->orWhere('flag_name', 'no-show')
|
||||
->orWhere('flag_name', 'failed-prelim');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ class InvoiceDataServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
if (auditionSetting('fee_structure')) {
|
||||
$this->app->singleton(InvoiceDataService::class, function ($app) {
|
||||
return match (auditionSetting('fee_structure')) {
|
||||
'oneFeePerEntry' => new InvoiceOneFeePerEntry($app->make(EntryService::class)),
|
||||
|
|
@ -36,3 +37,4 @@ class InvoiceDataServiceProvider extends ServiceProvider
|
|||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Event;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
|
|
@ -16,8 +18,44 @@ class AuditionFactory extends Factory
|
|||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
$instruments = [
|
||||
'Flute',
|
||||
'Oboe',
|
||||
'Clarinet',
|
||||
'Bass Clarinet',
|
||||
'Contra Clarinet',
|
||||
'Bassoon',
|
||||
'Alto Sax',
|
||||
'Tenor Sax',
|
||||
'Bari Sax',
|
||||
'Trumpet',
|
||||
'Horn',
|
||||
'Trombone',
|
||||
'Euphonium',
|
||||
'Tuba',
|
||||
'String Bass',
|
||||
'Percussion',
|
||||
];
|
||||
|
||||
$event = Event::factory()->create();
|
||||
|
||||
return [
|
||||
//
|
||||
'event_id' => $event->id,
|
||||
'name' => $this->faker->randomElement($instruments).$this->faker->randomNumber(1),
|
||||
'score_order' => 1,
|
||||
'entry_deadline' => Carbon::tomorrow(),
|
||||
'entry_fee' => 1000,
|
||||
'minimum_grade' => 7,
|
||||
'maximum_grade' => 12,
|
||||
'for_seating' => 1,
|
||||
'for_advancement' => 1,
|
||||
];
|
||||
}
|
||||
|
||||
public function closed(?Carbon $entryDeadline = null): self
|
||||
{
|
||||
return $this->state(
|
||||
fn (array $attributes) => ['entry_deadline' => $entryDeadline ?? Carbon::yesterday()]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Audition;
|
||||
use App\Models\Student;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
|
|
@ -16,9 +18,28 @@ class EntryFactory extends Factory
|
|||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
$student = Student::factory()->create();
|
||||
$audition = Audition::factory()->create();
|
||||
return [
|
||||
'student_id' => 3,
|
||||
'audition_id' =>3
|
||||
'student_id' => $student->id,
|
||||
'audition_id' => $audition->id,
|
||||
'draw_number' => null,
|
||||
'for_seating' => 1,
|
||||
'for_advancement' => 1,
|
||||
];
|
||||
}
|
||||
|
||||
public function seatingOnly(): self
|
||||
{
|
||||
return $this->state(
|
||||
fn (array $attributes) => ['for_advancement' => 0]
|
||||
);
|
||||
}
|
||||
|
||||
public function advanceOnly(): self
|
||||
{
|
||||
return $this->state(
|
||||
fn (array $attributes) => ['for_seating' => 0]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class EventFactory extends Factory
|
|||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'Concert Band Auditions'
|
||||
'name' => $this->faker->name(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\School;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
|
|
@ -16,7 +17,9 @@ class StudentFactory extends Factory
|
|||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
$school = School::factory()->create();
|
||||
return [
|
||||
'school_id' => $school->id,
|
||||
'first_name' => fake()->firstName(),
|
||||
'last_name' => fake()->lastName(),
|
||||
'grade' => rand(7,12),
|
||||
|
|
|
|||
|
|
@ -23,7 +23,11 @@ class UserFactory extends Factory
|
|||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
$judingPrefPossibilities = ['woodwinds','flute','clarinet','saxophones', 'low clarinets','oboe','bassoon','double reeds','brass','low brass','trumpet','trombone','horn','tuba','euphonium','percussion'];
|
||||
$judingPrefPossibilities = [
|
||||
'woodwinds', 'flute', 'clarinet', 'saxophones', 'low clarinets', 'oboe', 'bassoon', 'double reeds', 'brass',
|
||||
'low brass', 'trumpet', 'trombone', 'horn', 'tuba', 'euphonium', 'percussion',
|
||||
];
|
||||
|
||||
return [
|
||||
'first_name' => fake()->firstName(),
|
||||
'last_name' => fake()->lastName(),
|
||||
|
|
@ -46,4 +50,18 @@ class UserFactory extends Factory
|
|||
'email_verified_at' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function admin(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'is_admin' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
public function tab(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'is_tab' => 1,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,11 +27,12 @@
|
|||
<div x-data="sortableList()" x-init="init">
|
||||
<x-table.body id="sortable-list">
|
||||
@foreach($auditions as $audition)
|
||||
<tr data-id="{{ $audition->id }}" @dblclick="window.location.href='/admin/auditions/{{ $audition->id }}/edit'">
|
||||
<tr data-id="{{ $audition->id }}"
|
||||
@dblclick="window.location.href='/admin/auditions/{{ $audition->id }}/edit'">
|
||||
<x-table.td>{{ $audition->event->name }}</x-table.td>
|
||||
<x-table.td>{{ $audition->name }}</x-table.td>
|
||||
<x-table.td>{{ $audition->entry_deadline }}</x-table.td>
|
||||
<x-table.td>{{ $audition->dislpay_fee() }}</x-table.td>
|
||||
<x-table.td>{{ $audition->display_fee() }}</x-table.td>
|
||||
<x-table.td>{{ $audition->minimum_grade }} - {{ $audition->maximum_grade }}</x-table.td>
|
||||
@if(auditionSetting('advanceTo'))
|
||||
<x-table.td>
|
||||
|
|
@ -80,8 +81,7 @@
|
|||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
console.log('Order updated successfully');
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
console.log(data.status);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,9 +16,7 @@
|
|||
<x-layout.app>
|
||||
<x-slot:page_title>Test Page</x-slot:page_title>
|
||||
@php
|
||||
dump($totalFees);
|
||||
dump($lines);
|
||||
|
||||
dump(Audition::open()->get());
|
||||
@endphp
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Audition;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('only returns open auditions for open scope', function () {
|
||||
// Arrange
|
||||
$openAudition = Audition::factory()->create();
|
||||
Audition::factory()->closed()->create();
|
||||
|
||||
// Act & Assert
|
||||
expect(Audition::open()->get())
|
||||
->toHaveCount(1)
|
||||
->first()->id->toEqual($openAudition->id);
|
||||
});
|
||||
|
||||
it('only returns auditions for seating with forSeating scope', function () {
|
||||
// Arrange
|
||||
Audition::factory(['for_seating' => 0])->create();
|
||||
$seatingAudition = Audition::factory()->create();
|
||||
|
||||
// Act & Assert
|
||||
expect(Audition::forSeating()->get())
|
||||
->toHaveCount(1)
|
||||
->first()->id->toEqual($seatingAudition->id);
|
||||
});
|
||||
|
||||
it('only returns auditions for advancement with for forAdvancement scope', function () {
|
||||
// Arrange
|
||||
Audition::factory(['for_advancement' => 0])->create();
|
||||
$advancementAudition = Audition::factory()->create();
|
||||
|
||||
// Act & Assert
|
||||
expect(Audition::forAdvancement()->get())
|
||||
->toHaveCount(1)
|
||||
->first()->id->toEqual($advancementAudition->id);
|
||||
});
|
||||
|
||||
it('only returns published auditions for seatsPublished scope', function () {
|
||||
// Arrange
|
||||
Audition::factory()->create();
|
||||
$published = Audition::factory()->create();
|
||||
$published->addFlag('seats_published');
|
||||
|
||||
// Act & Assert
|
||||
expect(Audition::seatsPublished()->get())
|
||||
->toHaveCount(1)
|
||||
->first()->id->toEqual($published->id);
|
||||
|
||||
});
|
||||
|
||||
it('only returns published advancement auditions for advancementPublished scope', function () {
|
||||
// Arrange
|
||||
Audition::factory()->create();
|
||||
$published = Audition::factory()->create();
|
||||
$published->addFlag('advancement_published');
|
||||
|
||||
// Act & Assert
|
||||
expect(Audition::advancementPublished()->get())
|
||||
->toHaveCount(1)
|
||||
->first()->id->toEqual($published->id);
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Entry;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
it('only returns entries for seating with forSeating scope', function () {
|
||||
// Arrange
|
||||
Entry::factory()->advanceOnly()->create();
|
||||
$seatingEntry = Entry::factory()->create();
|
||||
|
||||
// Act & Assert
|
||||
expect(Entry::forSeating()->get())
|
||||
->toHaveCount(1)
|
||||
->first()->id->toEqual($seatingEntry->id);
|
||||
});
|
||||
|
||||
it('only returns entries for advancement with for forAdvancement scope', function () {
|
||||
// Arrange
|
||||
Entry::factory()->seatingOnly()->create();
|
||||
$advancementEntry = Entry::factory()->create();
|
||||
|
||||
// Act & Assert
|
||||
expect(Entry::forAdvancement()->get())
|
||||
->toHaveCount(1)
|
||||
->first()->id->toEqual($advancementEntry->id);
|
||||
});
|
||||
|
||||
it('only returns entries that do not have a declined, no-show, or failed-prelim flag with available scope',
|
||||
function () {
|
||||
// Arrange
|
||||
$availableEntry = Entry::factory()->create();
|
||||
$declinedEntry = Entry::factory()->create();
|
||||
$noShowEntry = Entry::factory()->create();
|
||||
$failedPrelimEntry = Entry::factory()->create();
|
||||
$declinedEntry->addFlag('declined');
|
||||
$noShowEntry->addFlag('no-show');
|
||||
$failedPrelimEntry->addFlag('failed-prelim');
|
||||
|
||||
// Act & Assert
|
||||
expect(Entry::available()->get())
|
||||
->toHaveCount(1)
|
||||
->first()->id->toEqual($availableEntry->id);
|
||||
|
||||
});
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
use function Pest\Laravel\get;
|
||||
|
|
@ -16,7 +17,7 @@ it('shows appropriate screens when not logged in', function () {
|
|||
]);
|
||||
});
|
||||
|
||||
it('shows a registration page', function () {
|
||||
it('shows a registration page only if not logged in', function () {
|
||||
// Act & Assert
|
||||
get('/register')
|
||||
->assertStatus(200)
|
||||
|
|
@ -24,13 +25,35 @@ it('shows a registration page', function () {
|
|||
'Registration Code',
|
||||
'Email address',
|
||||
]);
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
get('/register')
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('dashboard'));
|
||||
});
|
||||
|
||||
it('shows a login page', function () {
|
||||
it('shows a login page only if not logged in', function () {
|
||||
get('/login')
|
||||
->assertStatus(200)
|
||||
->assertSeeText([
|
||||
'Log In',
|
||||
'Click here to register',
|
||||
]);
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
get('/register')
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('dashboard'));
|
||||
});
|
||||
|
||||
it('shows dashboard only if logged in', function () {
|
||||
get(route('dashboard'))
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('home'));
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
get(route('dashboard'))
|
||||
->assertStatus(200)
|
||||
->assertSeeText('My School')
|
||||
->assertSeeText('Dashboard');
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue