From d5514f520f154eae8558b2ca69abc9c5597bd34f Mon Sep 17 00:00:00 2001 From: Kamil Date: Tue, 3 Oct 2023 11:24:47 +0200 Subject: [PATCH 01/11] #10 - crud for courses --- .../Dashboard/CourseController.php | 65 +++++++++++++ app/Http/Requests/CourseRequest.php | 20 ++++ app/Models/Course.php | 41 ++++++++ database/factories/CourseFactory.php | 20 ++++ ...2023_10_03_193906_create_courses_table.php | 26 +++++ .../js/Pages/Dashboard/Course/Create.vue | 87 +++++++++++++++++ resources/js/Pages/Dashboard/Course/Edit.vue | 93 ++++++++++++++++++ resources/js/Pages/Dashboard/Course/Index.vue | 95 +++++++++++++++++++ routes/web.php | 9 ++ 9 files changed, 456 insertions(+) create mode 100644 app/Http/Controllers/Dashboard/CourseController.php create mode 100644 app/Http/Requests/CourseRequest.php create mode 100644 app/Models/Course.php create mode 100644 database/factories/CourseFactory.php create mode 100644 database/migrations/2023_10_03_193906_create_courses_table.php create mode 100644 resources/js/Pages/Dashboard/Course/Create.vue create mode 100644 resources/js/Pages/Dashboard/Course/Edit.vue create mode 100644 resources/js/Pages/Dashboard/Course/Index.vue diff --git a/app/Http/Controllers/Dashboard/CourseController.php b/app/Http/Controllers/Dashboard/CourseController.php new file mode 100644 index 0000000..cff6b26 --- /dev/null +++ b/app/Http/Controllers/Dashboard/CourseController.php @@ -0,0 +1,65 @@ +orderBy("semester") + ->get(); + + return inertia("Dashboard/Course/Index", [ + "courses" => $courses, + "total" => Course::query()->count(), + "lastUpdate" => Course::query()->orderByDesc("updated_at")->first()?->updated_at->diffForHumans(), + ]); + } + + public function create(): Response + { + return inertia("Dashboard/Course/Create"); + } + + public function store(CourseRequest $request): RedirectResponse + { + Course::query()->create($request->validated()); + + return redirect() + ->route("courses.index") + ->with("success", "Dodano kurs"); + } + + public function edit(Course $course): Response + { + return inertia("Dashboard/Course/Edit", [ + "course" => $course, + ]); + } + + public function update(CourseRequest $request, Course $course): RedirectResponse + { + $course->update($request->validated()); + + return redirect() + ->route("courses.index") + ->with("success", "Zaktualizowano kurs"); + } + + public function destroy(Course $course): RedirectResponse + { + $course->delete(); + + return redirect()->back() + ->with("success", "Usunięto kurs"); + } +} diff --git a/app/Http/Requests/CourseRequest.php b/app/Http/Requests/CourseRequest.php new file mode 100644 index 0000000..ef0dff0 --- /dev/null +++ b/app/Http/Requests/CourseRequest.php @@ -0,0 +1,20 @@ + ["required", "max:255"], + "abbreviation" => ["required", "max:255"], + "description" => ["nullable", "max:65000"], + "semester" => ["required", "max:255"], + ]; + } +} diff --git a/app/Models/Course.php b/app/Models/Course.php new file mode 100644 index 0000000..c887787 --- /dev/null +++ b/app/Models/Course.php @@ -0,0 +1,41 @@ + Purify::clean($value), + ); + } +} diff --git a/database/factories/CourseFactory.php b/database/factories/CourseFactory.php new file mode 100644 index 0000000..125804a --- /dev/null +++ b/database/factories/CourseFactory.php @@ -0,0 +1,20 @@ + fake()->asciify("******"), + "abbreviation" => fake()->asciify("*"), + "description" => fake()->text, + "semester" => fake()->numberBetween(1, 7), + ]; + } +} diff --git a/database/migrations/2023_10_03_193906_create_courses_table.php b/database/migrations/2023_10_03_193906_create_courses_table.php new file mode 100644 index 0000000..43c0ae0 --- /dev/null +++ b/database/migrations/2023_10_03_193906_create_courses_table.php @@ -0,0 +1,26 @@ +ulid("id")->primary(); + $table->string("abbreviation"); + $table->string("name"); + $table->longText("description"); + $table->string("semester"); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists("courses"); + } +}; diff --git a/resources/js/Pages/Dashboard/Course/Create.vue b/resources/js/Pages/Dashboard/Course/Create.vue new file mode 100644 index 0000000..9b07314 --- /dev/null +++ b/resources/js/Pages/Dashboard/Course/Create.vue @@ -0,0 +1,87 @@ + + + diff --git a/resources/js/Pages/Dashboard/Course/Edit.vue b/resources/js/Pages/Dashboard/Course/Edit.vue new file mode 100644 index 0000000..e539cc6 --- /dev/null +++ b/resources/js/Pages/Dashboard/Course/Edit.vue @@ -0,0 +1,93 @@ + + + diff --git a/resources/js/Pages/Dashboard/Course/Index.vue b/resources/js/Pages/Dashboard/Course/Index.vue new file mode 100644 index 0000000..655e1e9 --- /dev/null +++ b/resources/js/Pages/Dashboard/Course/Index.vue @@ -0,0 +1,95 @@ + + + diff --git a/routes/web.php b/routes/web.php index c596dd5..0f8b993 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use App\Http\Controllers\Dashboard\CourseController; use App\Http\Controllers\Dashboard\DashboardController; use App\Http\Controllers\Dashboard\FieldController; use App\Http\Controllers\Dashboard\LogoutController; @@ -60,4 +61,12 @@ Route::patch("/faqs/{faq}", "update")->name("faqs.update"); Route::delete("/faqs/{faq}", "destroy")->name("faqs.destroy"); }); + Route::controller(CourseController::class)->group(function (): void { + Route::get("/courses", "index")->name("courses.index"); + Route::get("/courses/create", "create")->name("courses.create"); + Route::post("/courses", "store")->name("courses.store"); + Route::get("/courses/{course}/edit", "edit")->name("courses.edit"); + Route::patch("/courses/{course}", "update")->name("courses.update"); + Route::delete("/courses/{course}", "destroy")->name("courses.destroy"); + }); }); From c6561e2e51d0fee5fa828442e0708b3fb43bd940 Mon Sep 17 00:00:00 2001 From: Kamil Date: Tue, 3 Oct 2023 14:21:56 +0200 Subject: [PATCH 02/11] #10 - wip: added some enums and edit/create view for courses --- app/Actions/ActivateSemesterAction.php | 35 ----- app/Enums/ClassType.php | 19 +++ app/Enums/StudyForm.php | 19 +++ .../Dashboard/CourseController.php | 13 +- .../Dashboard/SemesterController.php | 15 +- app/Http/Requests/CourseRequest.php | 5 + app/Models/Course.php | 4 + composer.json | 1 + composer.lock | 134 +++++++++++++++++- ...2023_10_03_193906_create_courses_table.php | 2 + lang/pl.json | 6 + resources/js/Layouts/DashboardLayout.vue | 2 +- .../js/Pages/Dashboard/Course/Create.vue | 27 +++- resources/js/Pages/Dashboard/Course/Edit.vue | 24 +++- resources/js/Pages/Dashboard/Course/Index.vue | 12 ++ .../js/Pages/Dashboard/Semester/Index.vue | 5 +- resources/js/Shared/Forms/Select.vue | 52 +++++++ routes/web.php | 2 +- tests/Feature/SemesterTest.php | 13 +- 19 files changed, 331 insertions(+), 59 deletions(-) delete mode 100644 app/Actions/ActivateSemesterAction.php create mode 100644 app/Enums/ClassType.php create mode 100644 app/Enums/StudyForm.php create mode 100644 lang/pl.json create mode 100644 resources/js/Shared/Forms/Select.vue diff --git a/app/Actions/ActivateSemesterAction.php b/app/Actions/ActivateSemesterAction.php deleted file mode 100644 index aca7191..0000000 --- a/app/Actions/ActivateSemesterAction.php +++ /dev/null @@ -1,35 +0,0 @@ -db->beginTransaction(); - - Semester::getActive()?->update(["active" => 0]); - $semester->update(["active" => 1]); - - $this->db->commit(); - } catch (Exception $exception) { - $this->db->rollBack(); - - throw $exception; - } - } -} diff --git a/app/Enums/ClassType.php b/app/Enums/ClassType.php new file mode 100644 index 0000000..f4d54b8 --- /dev/null +++ b/app/Enums/ClassType.php @@ -0,0 +1,19 @@ + __("laboratory"), + "lecture" => __("lecture"), + ]; + } +} diff --git a/app/Enums/StudyForm.php b/app/Enums/StudyForm.php new file mode 100644 index 0000000..188f0e4 --- /dev/null +++ b/app/Enums/StudyForm.php @@ -0,0 +1,19 @@ + __("stationary"), + "part-time" => __("part-time"), + ]; + } +} diff --git a/app/Http/Controllers/Dashboard/CourseController.php b/app/Http/Controllers/Dashboard/CourseController.php index cff6b26..efb962b 100644 --- a/app/Http/Controllers/Dashboard/CourseController.php +++ b/app/Http/Controllers/Dashboard/CourseController.php @@ -4,11 +4,15 @@ namespace App\Http\Controllers\Dashboard; +use App\Enums\ClassType; +use App\Enums\StudyForm; use App\Http\Controllers\Controller; use App\Http\Requests\CourseRequest; use App\Models\Course; +use App\Models\Semester; use Illuminate\Http\RedirectResponse; use Inertia\Response; +use Spatie\LaravelOptions\Options; class CourseController extends Controller { @@ -27,7 +31,11 @@ public function index(): Response public function create(): Response { - return inertia("Dashboard/Course/Create"); + return inertia("Dashboard/Course/Create", [ + "semesters" => Semester::all(["id", "name"]), + "classTypes" => Options::forEnum(ClassType::class)->toArray(), + "studyForms" => Options::forEnum(StudyForm::class)->toArray(), + ]); } public function store(CourseRequest $request): RedirectResponse @@ -43,6 +51,9 @@ public function edit(Course $course): Response { return inertia("Dashboard/Course/Edit", [ "course" => $course, + "semesters" => Semester::all(["id", "name"]), + "classTypes" => Options::forEnum(ClassType::class)->toArray(), + "studyForms" => Options::forEnum(StudyForm::class)->toArray(), ]); } diff --git a/app/Http/Controllers/Dashboard/SemesterController.php b/app/Http/Controllers/Dashboard/SemesterController.php index 38cb5e7..70330fc 100644 --- a/app/Http/Controllers/Dashboard/SemesterController.php +++ b/app/Http/Controllers/Dashboard/SemesterController.php @@ -4,11 +4,9 @@ namespace App\Http\Controllers\Dashboard; -use App\Actions\ActivateSemesterAction; use App\Http\Controllers\Controller; use App\Http\Requests\SemesterRequest; use App\Models\Semester; -use Exception; use Illuminate\Http\RedirectResponse; use Inertia\Response; @@ -65,16 +63,11 @@ public function destroy(Semester $semester): RedirectResponse ->with("success", "Usunięto semestr"); } - public function toggleActive(Semester $semester, ActivateSemesterAction $activateSemesterAction): RedirectResponse + public function toggleActive(Semester $semester): RedirectResponse { - try { - $activateSemesterAction->execute($semester); + $semester->update(["active" => !$semester->active]); - return redirect()->back() - ->with("success", "Semestr aktywny"); - } catch (Exception $e) { - return redirect()->back() - ->with("error", "Wystąpił nieoczekiwany problem"); - } + return redirect()->back() + ->with("success", "Semestr aktywny"); } } diff --git a/app/Http/Requests/CourseRequest.php b/app/Http/Requests/CourseRequest.php index ef0dff0..2ddb3ac 100644 --- a/app/Http/Requests/CourseRequest.php +++ b/app/Http/Requests/CourseRequest.php @@ -4,7 +4,10 @@ namespace App\Http\Requests; +use App\Enums\ClassType; +use App\Enums\StudyForm; use Illuminate\Foundation\Http\FormRequest; +use Illuminate\Validation\Rules\Enum; class CourseRequest extends FormRequest { @@ -15,6 +18,8 @@ public function rules(): array "abbreviation" => ["required", "max:255"], "description" => ["nullable", "max:65000"], "semester" => ["required", "max:255"], + "type" => ["required", new Enum(ClassType::class)], + "form" => ["required", new Enum(StudyForm::class)], ]; } } diff --git a/app/Models/Course.php b/app/Models/Course.php index c887787..a04505e 100644 --- a/app/Models/Course.php +++ b/app/Models/Course.php @@ -17,6 +17,8 @@ * @property string $abbreviation * @property string $description * @property string $semester + * @property string $type + * @property string $form * @property Carbon $created_at * @property Carbon $updated_at */ @@ -30,6 +32,8 @@ class Course extends Model "abbreviation", "description", "semester", + "type", + "form", ]; protected function description(): Attribute diff --git a/composer.json b/composer.json index 42b536f..036cc2d 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ "laravel/framework": "^10.13.0", "laravel/sanctum": "^3.2.5", "laravel/tinker": "^2.8.1", + "spatie/laravel-options": "^1.1", "stevebauman/purify": "^6.0" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 6a790f5..4a3539f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fcf62ce422bb2cb212a713e68f7df8f8", + "content-hash": "78a9206548f38467774be801ed237211", "packages": [ { "name": "brick/math", @@ -3226,6 +3226,138 @@ ], "time": "2023-04-15T23:01:58+00:00" }, + { + "name": "spatie/laravel-options", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-options.git", + "reference": "5bed29084853dd97355ea055c017c27614900b2c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-options/zipball/5bed29084853dd97355ea055c017c27614900b2c", + "reference": "5bed29084853dd97355ea055c017c27614900b2c", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^8.81|^9.0|^10.0", + "php": "^8.1", + "spatie/laravel-package-tools": "^1.9.2" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.8", + "myclabs/php-enum": "^1.6", + "nunomaduro/collision": "^6.0|^5.0", + "nunomaduro/larastan": "^2.0.1|^1.0.3", + "orchestra/testbench": "^7.0|^v6.24.1|^8.0", + "pestphp/pest": "^v1.21.3", + "pestphp/pest-plugin-laravel": "^1.1", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^9.5", + "spatie/enum": "^3.13", + "spatie/laravel-model-states": "^2.0", + "spatie/laravel-ray": "^1.26" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\LaravelOptions\\OptionsServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\LaravelOptions\\": "src", + "Spatie\\LaravelOptions\\Database\\Factories\\": "database/factories" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ruben Van Assche", + "email": "ruben@spatie.be", + "role": "Developer" + } + ], + "description": "Create arrays of options from different sources", + "homepage": "https://github.com/spatie/laravel-options", + "keywords": [ + "laravel", + "options", + "spatie" + ], + "support": { + "source": "https://github.com/spatie/laravel-options/tree/1.1.0" + }, + "time": "2023-02-09T15:07:29+00:00" + }, + { + "name": "spatie/laravel-package-tools", + "version": "1.16.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-package-tools.git", + "reference": "cc7c991555a37f9fa6b814aa03af73f88026a83d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/cc7c991555a37f9fa6b814aa03af73f88026a83d", + "reference": "cc7c991555a37f9fa6b814aa03af73f88026a83d", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^9.28|^10.0", + "php": "^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.5", + "orchestra/testbench": "^7.7|^8.0", + "pestphp/pest": "^1.22", + "phpunit/phpunit": "^9.5.24", + "spatie/pest-plugin-test-time": "^1.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\LaravelPackageTools\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "Tools for creating Laravel packages", + "homepage": "https://github.com/spatie/laravel-package-tools", + "keywords": [ + "laravel-package-tools", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-package-tools/issues", + "source": "https://github.com/spatie/laravel-package-tools/tree/1.16.1" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2023-08-23T09:04:39+00:00" + }, { "name": "stevebauman/purify", "version": "v6.0.2", diff --git a/database/migrations/2023_10_03_193906_create_courses_table.php b/database/migrations/2023_10_03_193906_create_courses_table.php index 43c0ae0..fa8628e 100644 --- a/database/migrations/2023_10_03_193906_create_courses_table.php +++ b/database/migrations/2023_10_03_193906_create_courses_table.php @@ -15,6 +15,8 @@ public function up(): void $table->string("name"); $table->longText("description"); $table->string("semester"); + $table->string("type"); + $table->string("form"); $table->timestamps(); }); } diff --git a/lang/pl.json b/lang/pl.json new file mode 100644 index 0000000..a539eba --- /dev/null +++ b/lang/pl.json @@ -0,0 +1,6 @@ +{ + "lecture": "wykład", + "laboratory": "laboratorium", + "stationary": "stacjonarny", + "part-time": "niestacjonarny" +} diff --git a/resources/js/Layouts/DashboardLayout.vue b/resources/js/Layouts/DashboardLayout.vue index a73c745..c8440ba 100644 --- a/resources/js/Layouts/DashboardLayout.vue +++ b/resources/js/Layouts/DashboardLayout.vue @@ -46,7 +46,7 @@ const navigation = [ { title: 'Słowniki', elements: [ - { name: 'Kursy', href: '#', icon: BriefcaseIcon, current: false }, + { name: 'Kursy', href: '/dashboard/courses', icon: BriefcaseIcon, current: false }, { name: 'Kierunki i specjalności', href: '/dashboard/fields', icon: MagnifyingGlassIcon, current: false }, { name: 'Semestry', href: '/dashboard/semesters', icon: ClipboardIcon, current: false }, ], diff --git a/resources/js/Pages/Dashboard/Course/Create.vue b/resources/js/Pages/Dashboard/Course/Create.vue index 9b07314..dddf47a 100644 --- a/resources/js/Pages/Dashboard/Course/Create.vue +++ b/resources/js/Pages/Dashboard/Course/Create.vue @@ -4,18 +4,27 @@ import Section from '@/Shared/Components/Section.vue' import SubmitButton from '@/Shared/Components/Buttons/SubmitButton.vue' import FormGroup from '@/Shared/Forms/FormGroup.vue' import FormLabel from '@/Shared/Forms/FormLabel.vue' +import Select from '@/Shared/Forms/Select.vue' import TextInput from '@/Shared/Forms/TextInput.vue' import { useForm } from '@inertiajs/inertia-vue3' import FormError from '@/Shared/Forms/FormError.vue' import ManagementHeader from '@/Shared/Components/ManagementHeader.vue' import ManagementHeaderItem from '@/Shared/Components/ManagementHeaderItem.vue' -import TextAreaEditor from '../../../Shared/Forms/TextAreaEditor.vue' +import TextAreaEditor from '@/Shared/Forms/TextAreaEditor.vue' + +defineProps({ + semesters: Array, + classTypes: Array, + studyForms: Array, +}) const form = useForm({ name: '', abbreviation: '', description: '', semester: '', + type: '', + form: '', }) function createCourse() { @@ -64,9 +73,23 @@ function createCourse() { Semestr - + + + + + + Tryb zajęć + + - - - Tryb zajęć - -