Entries listing page nearly complete

This commit is contained in:
Matt Young 2024-05-31 01:07:01 -05:00
parent a452234c44
commit 7edf166985
13 changed files with 174 additions and 51 deletions

View File

@ -3,8 +3,14 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class EntryController extends Controller class EntryController extends Controller
{ {
// // TODO authorization policies
public function index()
{
$entries = Auth::user()->entries()->with(['student','audition'])->get();
return view('entries.index',['entries' => $entries]);
}
} }

View File

@ -19,7 +19,7 @@ class StudentController extends Controller
*/ */
public function index() public function index()
{ {
$students = Auth::user()->students; $students = Auth::user()->students()->with('entries')->get();
return view('students.index',['students' => $students]); return view('students.index',['students' => $students]);
} }

View File

@ -5,6 +5,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
class School extends Model class School extends Model
{ {
@ -36,4 +37,10 @@ class School extends Model
{ {
return $this->hasMany(Student::class); return $this->hasMany(Student::class);
} }
public function entries(): HasManyThrough
{
return $this->hasManyThrough(Entry::class,Student::class);
}
} }

View File

@ -5,6 +5,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\HasManyThrough;
@ -22,6 +23,11 @@ class Student extends Model
return $this->hasManyThrough(User::class, School::class); return $this->hasManyThrough(User::class, School::class);
} }
public function entries(): HasMany
{
return $this->hasMany(Entry::class);
}
public function full_name(Bool $last_name_first = false): String public function full_name(Bool $last_name_first = false): String
{ {
if ($last_name_first) return $this->last_name . ', ' . $this->first_name; if ($last_name_first) return $this->last_name . ', ' . $this->first_name;

View File

@ -78,6 +78,17 @@ class User extends Authenticatable implements MustVerifyEmail
->orderBy('first_name'); ->orderBy('first_name');
} }
public function entries(): HasManyThrough
{
return $this->hasManyThrough(
Entry::class,
Student::class,
'school_id',
'student_id',
'school_id',
'id'
);
}
/** /**
* Return an array of schools using the users email domain * Return an array of schools using the users email domain

View File

@ -5,6 +5,7 @@ namespace App\Policies;
use App\Models\Entry; use App\Models\Entry;
use App\Models\User; use App\Models\User;
use Illuminate\Auth\Access\Response; use Illuminate\Auth\Access\Response;
use function is_null;
class EntryPolicy class EntryPolicy
{ {
@ -21,7 +22,8 @@ class EntryPolicy
*/ */
public function view(User $user, Entry $entry): bool public function view(User $user, Entry $entry): bool
{ {
// if($user->is_admin) return true;
return $user->school_id == $entry->student()->school_id;
} }
/** /**
@ -29,7 +31,8 @@ class EntryPolicy
*/ */
public function create(User $user): bool public function create(User $user): bool
{ {
// if($user->is_admin) return true;
return ! is_null($user->school_id);
} }
/** /**
@ -37,7 +40,8 @@ class EntryPolicy
*/ */
public function update(User $user, Entry $entry): bool public function update(User $user, Entry $entry): bool
{ {
// if($user->is_admin) return true;
return $user->school_id == $entry->student()->school_id;
} }
/** /**
@ -45,7 +49,8 @@ class EntryPolicy
*/ */
public function delete(User $user, Entry $entry): bool public function delete(User $user, Entry $entry): bool
{ {
// if($user->is_admin) return true;
return $user->school_id == $entry->student()->school_id;
} }
/** /**

View File

@ -17,7 +17,8 @@ class EntryFactory extends Factory
public function definition(): array public function definition(): array
{ {
return [ return [
// 'student_id' => 3,
'audition_id' =>3
]; ];
} }
} }

View File

@ -17,6 +17,7 @@ return new class extends Migration
$table->id(); $table->id();
$table->foreignIdFor(Student::class)->constrained()->restrictOnDelete()->cascadeOnUpdate(); $table->foreignIdFor(Student::class)->constrained()->restrictOnDelete()->cascadeOnUpdate();
$table->foreignIdFor(Audition::class)->constrained()->restrictOnDelete()->cascadeOnUpdate(); $table->foreignIdFor(Audition::class)->constrained()->restrictOnDelete()->cascadeOnUpdate();
$table->unique(['student_id','audition_id']);
$table->timestamps(); $table->timestamps();
}); });
} }

View File

@ -2,8 +2,13 @@
namespace Database\Seeders; namespace Database\Seeders;
use App\Models\Audition;
use App\Models\Entry;
use App\Models\Student;
use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
use function rand;
use function random_int;
class EntrySeeder extends Seeder class EntrySeeder extends Seeder
{ {
@ -12,6 +17,47 @@ class EntrySeeder extends Seeder
*/ */
public function run(): void public function run(): void
{ {
// $students = Student::all();
$hs_auditions = Audition::where('maximum_grade', '=', '12');
$freshman_auditions = Audition::where('maximum_grade', '>', '8');
$jh_auditions = Audition::where('maximum_grade', '=', '9');
$seventh_auditions = Audition::where('maximum_grade', '=', '7');
foreach ($students as $student) {
if($student->grade > 9) $audition = Audition::where('maximum_grade','=','12')->inRandomOrder()->first();
if($student->grade == 9) $audition = Audition::where('maximum_grade','>','8')->inRandomOrder()->first();
if($student->grade == 8) $audition = Audition::where('maximum_grade','=','9')->inRandomOrder()->first();
if($student->grade == 7) $audition = Audition::where('maximum_grade','=','7')->inRandomOrder()->first();
Entry::factory()->create([
'student_id' => $student->id,
'audition_id' => $audition->id
]);
if (random_int(1,100) > 80) {
if($student->grade > 9) $audition2 = Audition::where('maximum_grade','=','12')->where('id','!=',$audition->id)->inRandomOrder()->first();
if($student->grade == 9) $audition2 = Audition::where('maximum_grade','>','8')->where('id','!=',$audition->id)->inRandomOrder()->first();
if($student->grade == 8) $audition2 = Audition::where('maximum_grade','=','9')->where('id','!=',$audition->id)->inRandomOrder()->first();
if($student->grade == 7) $audition2 = Audition::where('maximum_grade','=','7')->where('id','!=',$audition->id)->inRandomOrder()->first();
Entry::factory()->create([
'student_id' => $student->id,
'audition_id' => $audition2->id
]);
}
if (random_int(1,100) > 80) {
if($student->grade > 9) $audition3 = Audition::where('maximum_grade','=','12')->where('id','!=',$audition->id)->where('id','!=',$audition2->id)->inRandomOrder()->first();
if($student->grade == 9) $audition3 = Audition::where('maximum_grade','>','8')->where('id','!=',$audition->id)->where('id','!=',$audition2->id)->inRandomOrder()->first();
if($student->grade == 8) $audition3 = Audition::where('maximum_grade','=','9')->where('id','!=',$audition->id)->where('id','!=',$audition2->id)->inRandomOrder()->first();
if($student->grade == 7) $audition3 = Audition::where('maximum_grade','=','7')->where('id','!=',$audition->id)->where('id','!=',$audition2->id)->inRandomOrder()->first();
Entry::factory()->create([
'student_id' => $student->id,
'audition_id' => $audition3->id
]);
}
}
} }
} }

View File

@ -0,0 +1,64 @@
@php use Illuminate\Support\Facades\Auth; @endphp
@push('scripts')
{{-- Code from https://codepen.io/ryangjchandler/pen/WNQQKeR--}}
<script src="{{ asset('js/sort_table_by_column.js') }}"></script>
@endpush
<x-layout.app>
<x-slot:page_title>Entries</x-slot:page_title>
<x-layout.page-section-container>
<x-layout.page-section>
<x-slot:section_name>Add Entry</x-slot:section_name>
<x-form.form method="POST" action="/students">
<x-form.body-grid columns="8" class="max-w-full">
<x-form.field name="first_name" label_text="First Name" colspan="3" />
<x-form.field name="last_name" label_text="Last Name" colspan="3" />
<x-form.field name="grade" label_text="Grade" colspan="1" />
{{-- TODO make grade a dropdown --}}
<x-form.button class="mt-6">Save</x-form.button>
</x-form.body-grid>
</x-form.form>
</x-layout.page-section>
<x-layout.page-section>
<x-slot:section_name>Entry Listing</x-slot:section_name>
<div class="px-4">
<x-table.table>
<thead>
<tr>
<x-table.th first>Name</x-table.th>
<x-table.th>Grade</x-table.th>
<x-table.th>Audition</x-table.th>
<x-table.th spacer_only>
<span class="sr-only">Edit</span>
</x-table.th>
</tr>
</thead>
<x-table.body>
@foreach($entries as $entry)
<tr>
<x-table.td first>{{ $entry->student->full_name(true) }}</x-table.td>
<x-table.td>{{ $entry->student->grade }}</x-table.td>
<x-table.td>{{ $entry->audition->name }}</x-table.td>
{{-- <x-table.td for_button>--}}
{{-- <x-table.button href="/students/{{ $student->id }}/edit">Edit</x-table.button>--}}
{{-- |--}}
{{-- <form method="POST" action="/students/{{ $student->id }}" class="inline">--}}
{{-- @csrf--}}
{{-- @method('DELETE')--}}
{{-- <x-table.button--}}
{{-- onclick="return confirm('Please confirm you would like to delete the student {{ $student->full_name() }}');"--}}
{{-- >Delete</x-table.button>--}}
{{-- </form>--}}
{{-- </x-table.td>--}}
</tr>
@endforeach
</x-table.body>
</x-table.table>
</div>
</x-layout.page-section>
</x-layout.page-section-container>
</x-layout.app>

View File

@ -29,6 +29,7 @@
<tr> <tr>
<x-table.th first>Name</x-table.th> <x-table.th first>Name</x-table.th>
<x-table.th>Grade</x-table.th> <x-table.th>Grade</x-table.th>
<x-table.th>Entries</x-table.th>
<x-table.th spacer_only> <x-table.th spacer_only>
<span class="sr-only">Edit</span> <span class="sr-only">Edit</span>
</x-table.th> </x-table.th>
@ -39,6 +40,7 @@
<tr> <tr>
<x-table.td first>{{ $student->full_name(true) }}</x-table.td> <x-table.td first>{{ $student->full_name(true) }}</x-table.td>
<x-table.td>{{ $student->grade }}</x-table.td> <x-table.td>{{ $student->grade }}</x-table.td>
<x-table.td>{{ $student->entries->count() }}</x-table.td>
<x-table.td for_button> <x-table.td for_button>
<x-table.button href="/students/{{ $student->id }}/edit">Edit</x-table.button> <x-table.button href="/students/{{ $student->id }}/edit">Edit</x-table.button>
| |

View File

@ -1,49 +1,14 @@
@php use App\Models\School;use App\Models\SchoolEmailDomain;use App\Models\User;use Illuminate\Support\Facades\Auth; @endphp @php use App\Models\School;use App\Models\SchoolEmailDomain;use App\Models\User;use Illuminate\Support\Facades\Auth; @endphp
<x-layout.app> <x-layout.app>
<x-slot:page_title>Test Page</x-slot:page_title> <x-slot:page_title>Test Page</x-slot:page_title>
@php
$entries = Auth::user()->entries()->with(['student','audition'])->get();
// dd($entries->first()->student->full_name())
@endphp
<x-card.card class="px-4 pt-6" mw="3xl"> @foreach ($entries as $e)
<x-table.table with_title_area with_button> {{ $e->student->full_name() }} is entered on {{ $e->audition->name }}<br/>
<x-slot:title>Users</x-slot:title> @endforeach
<x-slot:subtitle>A list of all the users in your account including their name, title, email and role.</x-slot:subtitle>
<x-slot:title_block_right><x-form.button>Add User</x-form.button></x-slot:title_block_right>
<thead>
<tr>
<x-table.th first>Name</x-table.th>
<x-table.th>Title</x-table.th>
<x-table.th>Email</x-table.th>
<x-table.th>Role</x-table.th>
<x-table.th spacer_only>
<span class="sr-only">Edit</span>
</x-table.th>
</tr>
</thead>
<x-table.body>
<tr>
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-0">Lindsay Walton</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">Front-end Developer</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">lindsay.walton@example.com</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">Member</td>
<td class="relative whitespace-nowrap py-4 px-3 text-right text-sm sm:pr-0">
<a href="#" class="text-indigo-600 hover:text-indigo-900 font-medium">Edit<span class="sr-only">, Lindsay Walton</span></a>
</td>
</tr>
<tr>
<x-table.td first emphasis>Lindsay Walton</x-table.td>
<x-table.td>Front-end Developer</x-table.td>
<x-table.td>lindsay.walton@example.com</x-table.td>
<x-table.td>Member</x-table.td>
<x-table.td for_button>
<x-table.button href="#" aria_data=", Lindsay Walton">Edit</x-table.button>
</x-table.td>
</tr>
<!-- More people... -->
</x-table.body>
</x-table.table>
</x-card.card>
</x-layout.app> </x-layout.app>

View File

@ -1,6 +1,7 @@
<?php <?php
use App\Http\Controllers\DashboardController; use App\Http\Controllers\DashboardController;
use App\Http\Controllers\EntryController;
use App\Http\Controllers\SchoolController; use App\Http\Controllers\SchoolController;
use App\Http\Controllers\StudentController; use App\Http\Controllers\StudentController;
use App\Http\Controllers\UserController; use App\Http\Controllers\UserController;
@ -19,7 +20,15 @@ Route::middleware(['auth','verified'])->group(function () {
}); });
// Entry Related Routes // Entry Related Routes
Route::middleware(['auth','verified'])->controller(EntryController::class)->group(function() {
Route::get('/entries','index');
Route::get('/entries/create','create');
Route::get('/entries/{entry}', 'show');
Route::post('/entries', 'store');
Route::get('/entries/{entry}/edit', 'edit');
Route::patch('/entries/{entry}', 'update');
Route::delete('/entries/{entry}', 'destroy');
});
// User Related Routes // User Related Routes
Route::middleware(['auth','verified'])->controller(UserController::class)->group(function() { Route::middleware(['auth','verified'])->controller(UserController::class)->group(function() {