diff --git a/app/Http/Controllers/Dashboard/SettingController.php b/app/Http/Controllers/Dashboard/SettingController.php index b838e54..1fb1db0 100644 --- a/app/Http/Controllers/Dashboard/SettingController.php +++ b/app/Http/Controllers/Dashboard/SettingController.php @@ -8,6 +8,7 @@ use App\Http\Requests\SettingRequest; use App\Models\Setting; use Illuminate\Http\RedirectResponse; +use Illuminate\Support\Facades\Storage; use Inertia\Response; class SettingController extends Controller @@ -21,11 +22,42 @@ public function edit(): Response public function update(SettingRequest $request): RedirectResponse { - Setting::query()->first() - ->update($request->validated()); + $settings = Setting::query()->firstOrFail(); + $settings->fill($request->getData()); + + if ($request->file("logo")) { + if ($settings->logo) { + Storage::disk("public")->delete($settings->logo); + } + $file = $request->file("logo"); + $fileName = $file->getClientOriginalName(); + $path = "/logo"; + + $fullPath = Storage::disk("public")->putFileAs($path, $file, $fileName); + $settings->logo = $fullPath; + } + + $settings->save(); return redirect() ->back() ->with("success", "Zaktualizowano ustawienia"); } + + public function removeLogo(): RedirectResponse + { + $settings = Setting::query()->firstOrFail(); + + if ($settings->logo) { + $res = Storage::disk("public")->delete($settings->logo); + $settings->logo = null; + $settings->save(); + + return redirect() + ->back() + ->with("success", "Usunięto logo"); + } + + abort(404); + } } diff --git a/app/Http/Requests/SettingRequest.php b/app/Http/Requests/SettingRequest.php index 3a4f223..ae103e1 100644 --- a/app/Http/Requests/SettingRequest.php +++ b/app/Http/Requests/SettingRequest.php @@ -16,6 +16,22 @@ public function rules(): array "teacher_titles" => ["required", "max:255"], "university_name" => ["required", "max:255"], "department_name" => ["required", "max:255"], + "primary_color" => ["required", "regex:/^#([A-Fa-f0-9]{6})$/"], + "secondary_color" => ["required", "regex:/^#([A-Fa-f0-9]{6})$/"], + "logo" => ["nullable", "image", "max:1024"], + ]; + } + + public function getData(): array + { + return [ + "teacher_name" => $this->input("teacher_name"), + "teacher_email" => $this->input("teacher_email"), + "teacher_titles" => $this->input("teacher_titles"), + "university_name" => $this->input("university_name"), + "department_name" => $this->input("department_name"), + "primary_color" => $this->input("primary_color"), + "secondary_color" => $this->input("secondary_color"), ]; } } diff --git a/app/Models/Setting.php b/app/Models/Setting.php index ecb6a98..bb4dc61 100644 --- a/app/Models/Setting.php +++ b/app/Models/Setting.php @@ -30,5 +30,8 @@ class Setting extends Model "teacher_titles", "university_name", "department_name", + "primary_color", + "secondary_color", + "logo", ]; } diff --git a/database/factories/SettingFactory.php b/database/factories/SettingFactory.php index 876e117..89664ef 100644 --- a/database/factories/SettingFactory.php +++ b/database/factories/SettingFactory.php @@ -16,6 +16,8 @@ public function definition(): array "teacher_email" => fake()->email, "department_name" => "Zakład Informatyki, Wydział Nauk Technicznych i Ekonomicznych", "university_name" => "Collegium Witelona Uczelnia Państwowa", + "primary_color" => "#000000", + "secondary_color" => "#ffffff", ]; } } diff --git a/database/migrations/2024_08_07_075139_add_fields_to_settings_table.php b/database/migrations/2024_08_07_075139_add_fields_to_settings_table.php new file mode 100644 index 0000000..edc1f8d --- /dev/null +++ b/database/migrations/2024_08_07_075139_add_fields_to_settings_table.php @@ -0,0 +1,27 @@ +string("primary_color")->nullable(); + $table->string("secondary_color")->nullable(); + $table->string("logo")->nullable(); + }); + } + + public function down(): void + { + Schema::table("settings", function (Blueprint $table): void { + $table->dropColumn("primary_color"); + $table->dropColumn("secondary_color"); + $table->dropColumn("logo"); + }); + } +}; diff --git a/environment/dev/app/Dockerfile b/environment/dev/app/Dockerfile index 1024bc8..a45f0a0 100644 --- a/environment/dev/app/Dockerfile +++ b/environment/dev/app/Dockerfile @@ -41,7 +41,9 @@ RUN apt-get update \ && echo "deb https://nginx.org/packages/mainline/debian bullseye nginx" | tee /etc/apt/sources.list.d/nginx.list \ && apt-get update && apt-get install --assume-yes \ nginx=${NGINX_VERSION} \ + gnupg \ libzip-dev \ + libpng-dev \ libpq-dev \ supervisor \ cron \ @@ -49,6 +51,7 @@ RUN apt-get update \ && docker-php-ext-install \ zip \ pdo_pgsql \ + gd \ && docker-php-ext-enable \ redis diff --git a/environment/dev/app/nginx.conf b/environment/dev/app/nginx.conf index 0350a9f..ddeabbe 100644 --- a/environment/dev/app/nginx.conf +++ b/environment/dev/app/nginx.conf @@ -26,6 +26,8 @@ http { listen 80 default; server_name keating-nginx; + client_max_body_size 20M; + access_log /dev/stdout; error_log /dev/stderr; diff --git a/environment/dev/app/php.ini b/environment/dev/app/php.ini index 8ffeea5..1d16a3e 100644 --- a/environment/dev/app/php.ini +++ b/environment/dev/app/php.ini @@ -1,5 +1,7 @@ [PHP] memory_limit = 256M +upload_max_filesize = 20m +post_max_size = 20m [xdebug] xdebug.client_host=xdebug://gateway diff --git a/resources/js/Pages/Dashboard/Setting/Edit.vue b/resources/js/Pages/Dashboard/Setting/Edit.vue index bebafa1..0666a81 100644 --- a/resources/js/Pages/Dashboard/Setting/Edit.vue +++ b/resources/js/Pages/Dashboard/Setting/Edit.vue @@ -9,6 +9,9 @@ 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 ColorInput from '../../../Shared/Forms/ColorInput.vue' +import { ref } from 'vue' +import { Method } from '@inertiajs/inertia' const props = defineProps({ settings: Object, @@ -20,10 +23,29 @@ const form = useForm({ teacher_titles: props.settings.teacher_titles, university_name: props.settings.university_name, department_name: props.settings.department_name, + primary_color: props.settings.primary_color, + secondary_color: props.settings.secondary_color, + logo: null, }) +const imageUrl = ref('') + function updateSettings() { - form.patch('/dashboard/settings') + form.post('/dashboard/settings') +} + +function onFileSelected(event) { + const file = event.target?.files[0] + + if (file.size > 1024 * 1024) { + form.errors.logo = 'Plik nie może być większy niż 1MB' + + return + } + + form.logo = file + imageUrl.value = URL.createObjectURL(event.target?.files[0]) + form.errors.logo = '' } @@ -40,7 +62,7 @@ function updateSettings() { -
+
@@ -78,6 +100,55 @@ function updateSettings() { + + + Kolor główny + + + + + + + Kolor dodatkowy + + + + + + + Logo + + + + + +
+ + Aktualne logo + + Usuń + + + +
+
+ + Przesłane logo + + Image preview +
+
Zapisz diff --git a/resources/js/Pages/Public/Home.vue b/resources/js/Pages/Public/Home.vue index 94dc2d0..526b6ab 100644 --- a/resources/js/Pages/Public/Home.vue +++ b/resources/js/Pages/Public/Home.vue @@ -24,7 +24,7 @@ defineProps({
- +

diff --git a/resources/js/Pages/Public/Login.vue b/resources/js/Pages/Public/Login.vue index eb831e0..cb2f8c7 100644 --- a/resources/js/Pages/Public/Login.vue +++ b/resources/js/Pages/Public/Login.vue @@ -22,7 +22,7 @@ function attemptLogin() {
- +
diff --git a/resources/js/Shared/Forms/ColorInput.vue b/resources/js/Shared/Forms/ColorInput.vue new file mode 100644 index 0000000..eb4f74a --- /dev/null +++ b/resources/js/Shared/Forms/ColorInput.vue @@ -0,0 +1,32 @@ + + + diff --git a/routes/web.php b/routes/web.php index 782d153..c21b994 100644 --- a/routes/web.php +++ b/routes/web.php @@ -124,7 +124,8 @@ }); Route::controller(SettingController::class)->group(function (): void { Route::get("/settings", "edit")->name("settings.edit"); - Route::patch("/settings", "update")->name("settings.update"); + Route::post("/settings", "update")->name("settings.update"); + Route::delete("/settings/remove-logo", "removeLogo")->name("settings.remove.logo"); }); Route::controller(SectionController::class)->group(function (): void { Route::get("/sections", "show")->name("sections.show"); diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php index 940210c..0a01957 100644 --- a/tests/Feature/ExampleTest.php +++ b/tests/Feature/ExampleTest.php @@ -10,6 +10,13 @@ class ExampleTest extends TestCase { + protected function tearDown(): void + { + Setting::query()->delete(); + + parent::tearDown(); + } + public function testTheApplicationReturnsASuccessfulResponse(): void { Setting::factory()->create(); diff --git a/tests/Feature/SettingsTest.php b/tests/Feature/SettingsTest.php index f86add0..f252b8c 100644 --- a/tests/Feature/SettingsTest.php +++ b/tests/Feature/SettingsTest.php @@ -2,11 +2,13 @@ declare(strict_types=1); -namespace Feature; +namespace Tests\Feature; use App\Models\Setting; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Http\UploadedFile; +use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; use Tests\TestCase; @@ -25,6 +27,8 @@ protected function setUp(): void "teacher_titles" => "dr inż.", "university_name" => "CWUP", "department_name" => "IT department", + "primary_color" => "#000000", + "secondary_color" => "#ffffff", ]); $this->actingAs($this->user); } @@ -37,14 +41,19 @@ public function testSettingsCanBeUpdated(): void "teacher_titles" => "dr inż.", "university_name" => "CWUP", "department_name" => "IT department", + "primary_color" => "#000000", + "secondary_color" => "#ffffff", + "logo" => null, ]); - $this->patch("/dashboard/settings", [ + $this->post("/dashboard/settings", [ "teacher_name" => "John Doe", "teacher_email" => "john.doe@exmple.com", "teacher_titles" => "dr", "university_name" => "SWPS", "department_name" => "Psychology department", + "primary_color" => "#11ffff", + "secondary_color" => "#110000", ])->assertSessionHasNoErrors(); $this->assertDatabaseHas("settings", [ @@ -53,6 +62,9 @@ public function testSettingsCanBeUpdated(): void "teacher_titles" => "dr", "university_name" => "SWPS", "department_name" => "Psychology department", + "primary_color" => "#11ffff", + "secondary_color" => "#110000", + "logo" => null, ]); } @@ -64,14 +76,19 @@ public function testSettingsCannotBeUpdatedWithInvalidData(): void "teacher_titles" => "dr inż.", "university_name" => "CWUP", "department_name" => "IT department", + "primary_color" => "#000000", + "secondary_color" => "#ffffff", + "logo" => null, ]); - $this->patch("/dashboard/settings", [ + $this->post("/dashboard/settings", [ "teacher_name" => Str::random(256), "teacher_email" => "john.doe", "teacher_titles" => Str::random(256), "university_name" => Str::random(256), "department_name" => Str::random(256), + "primary_color" => "000000", + "secondary_color" => "ffffff", ])->assertSessionHasErrors() ->assertInvalid([ "teacher_name", @@ -79,6 +96,8 @@ public function testSettingsCannotBeUpdatedWithInvalidData(): void "teacher_titles", "university_name", "department_name", + "primary_color", + "secondary_color", ]); $this->assertDatabaseHas("settings", [ @@ -87,6 +106,9 @@ public function testSettingsCannotBeUpdatedWithInvalidData(): void "teacher_titles" => "dr inż.", "university_name" => "CWUP", "department_name" => "IT department", + "primary_color" => "#000000", + "secondary_color" => "#ffffff", + "logo" => null, ]); } @@ -98,14 +120,19 @@ public function testSettingsCannotBeUpdatedWithEmptyData(): void "teacher_titles" => "dr inż.", "university_name" => "CWUP", "department_name" => "IT department", + "primary_color" => "#000000", + "secondary_color" => "#ffffff", + "logo" => null, ]); - $this->patch("/dashboard/settings", [ + $this->post("/dashboard/settings", [ "teacher_name" => "", "teacher_email" => "", "teacher_titles" => "", "university_name" => "", "department_name" => "", + "primary_color" => "", + "secondary_color" => "", ])->assertSessionHasErrors() ->assertInvalid([ "teacher_name", @@ -113,6 +140,8 @@ public function testSettingsCannotBeUpdatedWithEmptyData(): void "teacher_titles", "university_name", "department_name", + "primary_color", + "secondary_color", ]); $this->assertDatabaseHas("settings", [ @@ -121,6 +150,104 @@ public function testSettingsCannotBeUpdatedWithEmptyData(): void "teacher_titles" => "dr inż.", "university_name" => "CWUP", "department_name" => "IT department", + "primary_color" => "#000000", + "secondary_color" => "#ffffff", + "logo" => null, + ]); + } + + public function testLogoCanBeUploadedAndRemoved(): void + { + Storage::fake("public"); + $this->assertDatabaseHas("settings", [ + "teacher_name" => "Ty Doe", + "teacher_email" => "ty.doe@exmple.com", + "teacher_titles" => "dr inż.", + "university_name" => "CWUP", + "department_name" => "IT department", + "primary_color" => "#000000", + "secondary_color" => "#ffffff", + "logo" => null, + ]); + $logo = UploadedFile::fake()->image("logo.png"); + + $this->post("/dashboard/settings", [ + "teacher_name" => "John Doe", + "teacher_email" => "john.doe@exmple.com", + "teacher_titles" => "dr", + "university_name" => "SWPS", + "department_name" => "Psychology department", + "primary_color" => "#11ffff", + "secondary_color" => "#110000", + "logo" => $logo, + ])->assertSessionHasNoErrors(); + + $this->assertDatabaseHas("settings", [ + "teacher_name" => "John Doe", + "teacher_email" => "john.doe@exmple.com", + "teacher_titles" => "dr", + "university_name" => "SWPS", + "department_name" => "Psychology department", + "primary_color" => "#11ffff", + "secondary_color" => "#110000", + "logo" => "logo/logo.png", + ]); + + Storage::disk("public")->assertExists("logo/logo.png"); + + $this->delete("/dashboard/settings/remove-logo")->assertSessionHasNoErrors(); + + $this->assertDatabaseHas("settings", [ + "teacher_name" => "John Doe", + "teacher_email" => "john.doe@exmple.com", + "teacher_titles" => "dr", + "university_name" => "SWPS", + "department_name" => "Psychology department", + "primary_color" => "#11ffff", + "secondary_color" => "#110000", + "logo" => null, + ]); + + Storage::disk("public")->assertMissing("logo/logo.png"); + } + + public function testSettingsCannotBeUpdatedWithTooBigLogoFile(): void + { + $this->assertDatabaseHas("settings", [ + "teacher_name" => "Ty Doe", + "teacher_email" => "ty.doe@exmple.com", + "teacher_titles" => "dr inż.", + "university_name" => "CWUP", + "department_name" => "IT department", + "primary_color" => "#000000", + "secondary_color" => "#ffffff", + "logo" => null, + ]); + $logo = UploadedFile::fake()->image("logo.png")->size(2049); + + $this->post("/dashboard/settings", [ + "teacher_name" => "John Doe", + "teacher_email" => "john.doe@exmple.com", + "teacher_titles" => "dr", + "university_name" => "SWPS", + "department_name" => "Psychology department", + "primary_color" => "#11ffff", + "secondary_color" => "#110000", + "logo" => $logo, + ])->assertSessionHasErrors() + ->assertInvalid([ + "logo", + ]); + + $this->assertDatabaseHas("settings", [ + "teacher_name" => "Ty Doe", + "teacher_email" => "ty.doe@exmple.com", + "teacher_titles" => "dr inż.", + "university_name" => "CWUP", + "department_name" => "IT department", + "primary_color" => "#000000", + "secondary_color" => "#ffffff", + "logo" => null, ]); } }