From 557e8161d3a79ed80406cdc92f655ab8114cb7b8 Mon Sep 17 00:00:00 2001 From: Sofiane Lasri-Trienpont <alasri250@gmail.com> Date: Sun, 23 Feb 2025 15:29:15 +0100 Subject: [PATCH 1/4] feat: add database configuration management - Introduced `DbConfig` model for handling dynamic configuration values. - Created migration for `db_configs` table. - Added `DbConfigFactory` for generating test data. - Implemented website configuration management views. - Updated `SettingsController` to manage website settings including maintenance mode and website name. - Enhanced error and success messaging in views. --- .../Controllers/Admin/SettingsController.php | 72 ++++++++++++--- app/Models/DbConfig.php | 91 +++++++++++++++++++ database/factories/DbConfigFactory.php | 19 ++++ ...5_02_23_145044_create_db_configs_table.php | 22 +++++ .../views/admin/settings/general.blade.php | 40 ++++---- .../views/admin/settings/users.blade.php | 3 +- .../admin/settings/website-config.blade.php | 48 ++++++++++ routes/web.php | 2 + 8 files changed, 266 insertions(+), 31 deletions(-) create mode 100644 app/Models/DbConfig.php create mode 100644 database/factories/DbConfigFactory.php create mode 100644 database/migrations/2025_02_23_145044_create_db_configs_table.php create mode 100644 resources/views/admin/settings/website-config.blade.php diff --git a/app/Http/Controllers/Admin/SettingsController.php b/app/Http/Controllers/Admin/SettingsController.php index 8829ecf..065a1bf 100644 --- a/app/Http/Controllers/Admin/SettingsController.php +++ b/app/Http/Controllers/Admin/SettingsController.php @@ -4,6 +4,7 @@ use App\Http\Controllers\Controller; use App\Mail\AdminInvitationMail; +use App\Models\DbConfig; use App\Models\User; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; @@ -22,16 +23,30 @@ class SettingsController extends Controller 'label' => 'Général', 'icon' => 'circle-user', ], - [ - 'route' => 'admin.settings.users', - 'label' => 'Utilisateurs', - 'icon' => 'users', - ], ]; + protected bool $isSuperAdmin; + + public function __construct() + { + $this->isSuperAdmin = Auth::user()->email === config('app.protected_account_email'); + + if ($this->isSuperAdmin) { + $this->headerRoutes[] = [ + 'route' => 'admin.settings.users', + 'label' => 'Utilisateurs', + 'icon' => 'users', + ]; + $this->headerRoutes[] = [ + 'route' => 'admin.settings.website-config', + 'label' => 'Configuration du site', + 'icon' => 'gear', + ]; + } + } + public function userListPage(): View { - $isSuperAdmin = auth()->user()->email === config('app.protected_account_email'); $users = User::all(); foreach ($users as $user) { @@ -41,7 +56,7 @@ public function userListPage(): View return view('admin.settings.users', [ 'headerRoutes' => $this->headerRoutes, 'users' => $users, - 'isSuperAdmin' => $isSuperAdmin, + 'isSuperAdmin' => $this->isSuperAdmin, ]); } @@ -52,9 +67,7 @@ public function createUser(Request $request): RedirectResponse 'email' => 'required|string|email|max:255|unique:users', ]); - $isSuperAdmin = Auth::user()->email === config('app.protected_account_email'); - - if (! $isSuperAdmin) { + if (! $this->isSuperAdmin) { return redirect()->route('admin.settings.users') ->with('error', 'Vous n\'avez pas les droits pour effectuer cette action.'); } @@ -73,9 +86,7 @@ public function createUser(Request $request): RedirectResponse public function deleteUser(int $id): RedirectResponse { - $isSuperAdmin = auth()->user()->email === config('app.protected_account_email'); - - if (! $isSuperAdmin) { + if (! $this->isSuperAdmin) { return redirect()->route('admin.settings.users') ->with('error', 'Vous n\'avez pas les droits pour effectuer cette action.'); } @@ -140,4 +151,39 @@ public function updateUserInfos(Request $request): RedirectResponse return redirect()->route('admin.settings.general')->with('success', 'Informations mises à jour.'); } + + public function websiteConfigPage(): RedirectResponse|View + { + if (! $this->isSuperAdmin) { + return redirect()->route('admin.settings.general') + ->with('error', 'Vous n\'avez pas les droits pour effectuer cette action.'); + } + + return view('admin.settings.website-config', [ + 'headerRoutes' => $this->headerRoutes, + ]); + } + + public function updateWebsiteConfig(Request $request): RedirectResponse + { + $request->validate([ + 'maintenance_mode' => 'sometimes|nullable|string|in:true,false', + 'website_name' => 'sometimes|nullable|string|max:255', + ]); + + if (! $this->isSuperAdmin) { + return redirect()->route('admin.settings.general') + ->with('error', 'Vous n\'avez pas les droits pour effectuer cette action.'); + } + + if ($request->filled('maintenance_mode')) { + DbConfig::set('maintenance_mode', $request->maintenance_mode); + } + + if ($request->filled('website_name')) { + DbConfig::set('website_name', $request->website_name); + } + + return redirect()->route('admin.settings.website-config')->with('success', 'Configuration mise à jour.'); + } } diff --git a/app/Models/DbConfig.php b/app/Models/DbConfig.php new file mode 100644 index 0000000..3bd061f --- /dev/null +++ b/app/Models/DbConfig.php @@ -0,0 +1,91 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\Cache; + +class DbConfig extends Model +{ + use HasFactory; + + public $timestamps = false; + + protected $fillable = [ + 'key', + 'value', + ]; + + /** + * Get a configuration value by its key. + * Value types casts: + * - 'true' => true + * - 'false' => false + * - integers => int + * - floats => float + * - strings => string + * + * @param string $key The key of the configuration value. Example: 'app.name' + * @param float|bool|int|string|null $default The default value to return if the configuration does not exist. + * @return float|bool|int|string|null The value of the configuration. + */ + public static function get(string $key, float|bool|int|string|null $default = null): float|bool|int|string|null + { + $config = Cache::rememberForever('config_'.$key, function () use ($key) { + return self::where('key', $key)->first(); + }); + + if (empty($config) || ! $config->exists || $config->value === null) { + return $default; + } + + // Cast to boolean if the value is a boolean + if ($config->value === 'true') { + return true; + } elseif ($config->value === 'false') { + return false; + } + + // Cast to integer if the value is an integer + if (is_numeric($config->value)) { + if (is_float($config->value)) { + return (float) $config->value; + } else { + return (int) $config->value; + } + } + + return $config->value; + } + + /** + * Set a configuration value by its key. + * + * @param string $key The key of the configuration value. Example: 'app.name' + * @param string|int|float|bool $value The value of the configuration. + */ + public static function set(string $key, float|bool|int|string $value): void + { + if (Cache::has('config_'.$key)) { + Cache::forget('config_'.$key); + } + + $config = self::where('key', $key)->first(); + + if ($config === null) { + self::create([ + 'key' => $key, + 'value' => $value, + ]); + } else { + $config->update([ + 'value' => $value, + ]); + } + + Cache::rememberForever('config_'.$key, function () use ($key) { + return self::where('key', $key)->first(); + }); + } +} diff --git a/database/factories/DbConfigFactory.php b/database/factories/DbConfigFactory.php new file mode 100644 index 0000000..d1d7eae --- /dev/null +++ b/database/factories/DbConfigFactory.php @@ -0,0 +1,19 @@ +<?php + +namespace Database\Factories; + +use App\Models\DbConfig; +use Illuminate\Database\Eloquent\Factories\Factory; + +class DbConfigFactory extends Factory +{ + protected $model = DbConfig::class; + + public function definition(): array + { + return [ + 'key' => $this->faker->word(), + 'value' => $this->faker->word(), + ]; + } +} diff --git a/database/migrations/2025_02_23_145044_create_db_configs_table.php b/database/migrations/2025_02_23_145044_create_db_configs_table.php new file mode 100644 index 0000000..0950635 --- /dev/null +++ b/database/migrations/2025_02_23_145044_create_db_configs_table.php @@ -0,0 +1,22 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +return new class extends Migration +{ + public function up(): void + { + Schema::create('db_configs', function (Blueprint $table) { + $table->id(); + $table->string('key')->unique(); + $table->string('value'); + }); + } + + public function down(): void + { + Schema::dropIfExists('db_configs'); + } +}; diff --git a/resources/views/admin/settings/general.blade.php b/resources/views/admin/settings/general.blade.php index ef891f7..6ea34cd 100644 --- a/resources/views/admin/settings/general.blade.php +++ b/resources/views/admin/settings/general.blade.php @@ -3,10 +3,32 @@ @section('content') <div class="grid"> <div class="g-col-12 g-col-md-6"> + @if (!empty($errors) && $errors->any()) + <x-bs.alert type="danger" class="mt-3"> + <ul> + @foreach ($errors->all() as $error) + <li>{{ $error }}</li> + @endforeach + </ul> + </x-bs.alert> + @endif + + @if (session('success')) + <x-bs.alert type="success" class="mt-3"> + {{ session('success') }} + </x-bs.alert> + @endif + + @if (session('error')) + <x-bs.alert type="danger" class="mt-3"> + {{ session('error') }} + </x-bs.alert> + @endif + <h5>Information</h5> <p>Ne remplissez que les champs que vous souhaitez mettre à jour.</p> <form action="{{ route('admin.settings.update-user-infos') }}" - method="post"> + method="post"> @csrf @method('PUT') @@ -48,22 +70,6 @@ class="mb-3" <x-bs.button type="submit">Enregistrer</x-bs.button> </form> - - @if (!empty($errors) && $errors->any()) - <x-bs.alert type="danger" class="mt-3"> - <ul> - @foreach ($errors->all() as $error) - <li>{{ $error }}</li> - @endforeach - </ul> - </x-bs.alert> - @endif - - @if (session('success')) - <x-bs.alert type="success" class="mt-3"> - {{ session('success') }} - </x-bs.alert> - @endif </div> </div> @endsection diff --git a/resources/views/admin/settings/users.blade.php b/resources/views/admin/settings/users.blade.php index 57713da..a3bc900 100644 --- a/resources/views/admin/settings/users.blade.php +++ b/resources/views/admin/settings/users.blade.php @@ -7,7 +7,8 @@ par email.</p> <p><span class="fw-bold text-danger">Attention !</span> Pour des raisons de simplicité, ces personnes auront les - mêmes droits que vous (sauf toutes les actions liées à cette page, y compris son accès). + mêmes droits que vous (sauf toutes les actions liées à cette page et à la configuration du site, y compris + leur accès). <strong>Soyez bien certains d'avoir confiance en elles !</strong></p> <x-bs.button data-bs-toggle="modal" data-bs-target="#addUserModal" size="sm" variant="primary"> diff --git a/resources/views/admin/settings/website-config.blade.php b/resources/views/admin/settings/website-config.blade.php new file mode 100644 index 0000000..9199ffb --- /dev/null +++ b/resources/views/admin/settings/website-config.blade.php @@ -0,0 +1,48 @@ +@extends('layouts.admin', ['title' => 'Configuration', 'headerRoutes' => $headerRoutes]) + +@section('content') + <div class="grid"> + <div class="g-col-12 g-col-md-6"> + @if (!empty($errors) && $errors->any()) + <x-bs.alert type="danger" class="mt-3"> + <ul> + @foreach ($errors->all() as $error) + <li>{{ $error }}</li> + @endforeach + </ul> + </x-bs.alert> + @endif + + @if (session('success')) + <x-bs.alert type="success" class="mt-3"> + {{ session('success') }} + </x-bs.alert> + @endif + + <h5>Configuration</h5> + <p>Modifiez les paramètres du site internet.</p> + <form action="{{ route('admin.settings.update-website-config') }}" + method="post"> + @csrf + @method('PUT') + + <x-bs.select label="Statut du mode maintenance" + name="maintenance_mode" + class="mb-3" + :options="['false' => 'Désactivé', 'true' => 'Activé']" + :selected="old('maintenance_mode', \App\Models\DbConfig::get('maintenance_mode', 'false'))" + data-form-type="other" + /> + + <x-bs.input label="Nom du site internet" + name="website_name" + class="mb-3" + :value="old('website_name', \App\Models\DbConfig::get('website_name', config('app.name')))" + data-form-type="other" + /> + + <x-bs.button type="submit">Enregistrer</x-bs.button> + </form> + </div> + </div> +@endsection diff --git a/routes/web.php b/routes/web.php index d006a19..3049d6c 100644 --- a/routes/web.php +++ b/routes/web.php @@ -113,6 +113,8 @@ Route::match(['GET', 'DELETE'], '/users/{id}/delete', [SettingsController::class, 'deleteUser'])->name('delete-user'); Route::get('/general', [SettingsController::class, 'generalPage'])->name('general'); Route::put('/general', [SettingsController::class, 'updateUserInfos'])->name('update-user-infos'); + Route::get('/website-configuration', [SettingsController::class, 'websiteConfigPage'])->name('website-config'); + Route::put('/website-configuration', [SettingsController::class, 'updateWebsiteConfig'])->name('update-website-config'); }); Route::prefix('prestations')->name('prestations.')->group(function () { -- GitLab From 8701a5f6feceb356055347c20f725ed0cab44a1c Mon Sep 17 00:00:00 2001 From: Sofiane Lasri-Trienpont <alasri250@gmail.com> Date: Sun, 23 Feb 2025 15:38:44 +0100 Subject: [PATCH 2/4] feat: update website name retrieval and configuration handling - Changed the retrieval of the website name in the sidebar component to use the `DbConfig` model for dynamic configuration. - Updated the `set` method in the `DbConfig` model to allow null values for configuration. - Refactored the public layout to use the website name from `DbConfig` instead of a hardcoded value. - Adjusted the default value for maintenance mode and website name in the settings view to match the new configuration method. - Modified the middleware to check the maintenance mode from the `DbConfig` model. - Updated the `SettingsController` to use `has` instead of `filled` for checking request inputs related to maintenance mode and website name. --- app/Http/Controllers/Admin/SettingsController.php | 4 ++-- app/Http/Middleware/CheckPrivateModeMiddleware.php | 3 ++- app/Models/DbConfig.php | 8 +++++++- resources/views/admin/settings/website-config.blade.php | 4 ++-- resources/views/components/admin/sidebar.blade.php | 2 +- resources/views/layouts/public.blade.php | 8 ++++++-- 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/Admin/SettingsController.php b/app/Http/Controllers/Admin/SettingsController.php index 065a1bf..557a1f8 100644 --- a/app/Http/Controllers/Admin/SettingsController.php +++ b/app/Http/Controllers/Admin/SettingsController.php @@ -176,11 +176,11 @@ public function updateWebsiteConfig(Request $request): RedirectResponse ->with('error', 'Vous n\'avez pas les droits pour effectuer cette action.'); } - if ($request->filled('maintenance_mode')) { + if ($request->has('maintenance_mode')) { DbConfig::set('maintenance_mode', $request->maintenance_mode); } - if ($request->filled('website_name')) { + if ($request->has('website_name')) { DbConfig::set('website_name', $request->website_name); } diff --git a/app/Http/Middleware/CheckPrivateModeMiddleware.php b/app/Http/Middleware/CheckPrivateModeMiddleware.php index 7cf8140..ca09e19 100644 --- a/app/Http/Middleware/CheckPrivateModeMiddleware.php +++ b/app/Http/Middleware/CheckPrivateModeMiddleware.php @@ -2,6 +2,7 @@ namespace App\Http\Middleware; +use App\Models\DbConfig; use Closure; use Illuminate\Http\Request; @@ -9,7 +10,7 @@ class CheckPrivateModeMiddleware { public function handle(Request $request, Closure $next) { - $privateModeEnabled = config('app.private_mode'); + $privateModeEnabled = DbConfig::get('maintenance_mode', 'true'); $privateModeSecret = config('app.private_mode_secret'); $userSecretInput = $request->input('secret'); $secretIsUsable = ! empty($privateModeSecret) && $privateModeSecret === $userSecretInput; diff --git a/app/Models/DbConfig.php b/app/Models/DbConfig.php index 3bd061f..cddde72 100644 --- a/app/Models/DbConfig.php +++ b/app/Models/DbConfig.php @@ -65,7 +65,7 @@ public static function get(string $key, float|bool|int|string|null $default = nu * @param string $key The key of the configuration value. Example: 'app.name' * @param string|int|float|bool $value The value of the configuration. */ - public static function set(string $key, float|bool|int|string $value): void + public static function set(string $key, float|bool|int|string|null $value): void { if (Cache::has('config_'.$key)) { Cache::forget('config_'.$key); @@ -73,6 +73,12 @@ public static function set(string $key, float|bool|int|string $value): void $config = self::where('key', $key)->first(); + if ($value === null) { + $config?->delete(); + + return; + } + if ($config === null) { self::create([ 'key' => $key, diff --git a/resources/views/admin/settings/website-config.blade.php b/resources/views/admin/settings/website-config.blade.php index 9199ffb..4e15c67 100644 --- a/resources/views/admin/settings/website-config.blade.php +++ b/resources/views/admin/settings/website-config.blade.php @@ -30,14 +30,14 @@ name="maintenance_mode" class="mb-3" :options="['false' => 'Désactivé', 'true' => 'Activé']" - :selected="old('maintenance_mode', \App\Models\DbConfig::get('maintenance_mode', 'false'))" + :selected="old('maintenance_mode', \App\Models\DbConfig::get('maintenance_mode', 'true'))" data-form-type="other" /> <x-bs.input label="Nom du site internet" name="website_name" class="mb-3" - :value="old('website_name', \App\Models\DbConfig::get('website_name', config('app.name')))" + :value="old('website_name', \App\Models\DbConfig::get('website_name', 'Rann Graphic Design'))" data-form-type="other" /> diff --git a/resources/views/components/admin/sidebar.blade.php b/resources/views/components/admin/sidebar.blade.php index 8358c73..383a4b3 100644 --- a/resources/views/components/admin/sidebar.blade.php +++ b/resources/views/components/admin/sidebar.blade.php @@ -8,7 +8,7 @@ <a class="website-name" href="{{ route('admin.home') }}"> <img class="logo" src="{{ asset('favicon.svg') }}" alt="Website Logo"/> <span> - {{ config('app.name') }} + {{ \App\Models\DbConfig::get('website_name', "Rann Graphic Design") }} </span> </a> </div> diff --git a/resources/views/layouts/public.blade.php b/resources/views/layouts/public.blade.php index c465a55..51d9b8e 100644 --- a/resources/views/layouts/public.blade.php +++ b/resources/views/layouts/public.blade.php @@ -1,15 +1,19 @@ +@php + $websiteName = \App\Models\DbConfig::get('website_name', "Rann Graphic Design") +@endphp + <!DOCTYPE html> <html lang="{{ config('app.locale') }}"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>{{ !empty($title) ? $title . ' - Rann Graphic Design' : 'Rann Graphic Design' }}</title> + <title>{{ !empty($title) ? $title . ' - ' . $websiteName : $websiteName }}</title> <link rel="icon" type="image/svg+xml" href="{{ asset('favicon.svg') }}"/> <meta property="og:locale" content="{{ config('app.locale') }}"> <meta property="og:locale:alternate" content="{{ config('app.fallback_locale') }}"> - <meta property="og:title" content="{{ !empty($title) ? $title : 'Rann Graphic Design' }}"> + <meta property="og:title" content="{{ !empty($title) ? $title : $websiteName }}"> <meta property="og:type" content="website"> <meta property="og:url" content="{{ url()->current() }}"> @if(!empty($description)) -- GitLab From 095477b846ee7a5a3f10bc7baa4da1c94dbce8ce Mon Sep 17 00:00:00 2001 From: Sofiane Lasri-Trienpont <alasri250@gmail.com> Date: Sun, 23 Feb 2025 15:48:15 +0100 Subject: [PATCH 3/4] feat: add maintenance mode alert to admin home page - Commented out the 'private_mode' configuration in app.php - Added an alert in the admin home view to notify users when maintenance mode is active, guiding them to the settings page to disable it. --- config/app.php | 2 +- resources/views/admin/home.blade.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/config/app.php b/config/app.php index 9ea28a0..5044bc0 100644 --- a/config/app.php +++ b/config/app.php @@ -127,7 +127,7 @@ 'protected_account_email' => env('PROTECTED_ACCOUNT_EMAIL', ''), - 'private_mode' => env('APP_PRIVATE_MODE', false), + // 'private_mode' => env('APP_PRIVATE_MODE', false), 'imagick' => [ 'max_width' => env('IMAGICK_MAX_WIDTH', 16000), // 16k diff --git a/resources/views/admin/home.blade.php b/resources/views/admin/home.blade.php index 65c1ae2..7ab23f5 100644 --- a/resources/views/admin/home.blade.php +++ b/resources/views/admin/home.blade.php @@ -2,6 +2,14 @@ @section('content') <div class="container" id="admin-home"> + @if(\App\Models\DbConfig::get('maintenance_mode', 'true')) + <x-bs.alert type="warning" :dismissible="false" icon="info" title="Information" style="max-width: none;"> + Le site est masqué au public car le mode maintenance est activé.<br> + <a href="{{ route('admin.settings.update-website-config') }}" class="alert-link"> + Rendez-vous sur la page de configuration du site pour le désactiver. + </a> + </x-bs.alert> + @endif <h3 class="mb-4">Statistiques des Visites uniques</h3> <div class="grid mb-4"> -- GitLab From d40897309869ae1aaa5c584bcb0eb8baea5f10a3 Mon Sep 17 00:00:00 2001 From: Sofiane Lasri-Trienpont <alasri250@gmail.com> Date: Sun, 23 Feb 2025 15:51:09 +0100 Subject: [PATCH 4/4] feat: remove ExampleTest.php file This commit deletes the ExampleTest.php file from the tests/Feature directory, which contained a basic test for the application. --- tests/Feature/ExampleTest.php | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 tests/Feature/ExampleTest.php diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php deleted file mode 100644 index 22ef0c5..0000000 --- a/tests/Feature/ExampleTest.php +++ /dev/null @@ -1,21 +0,0 @@ -<?php - -namespace Tests\Feature; - -use Illuminate\Foundation\Testing\RefreshDatabase; -use Tests\TestCase; - -class ExampleTest extends TestCase -{ - use RefreshDatabase; - - /** - * A basic test example. - */ - public function test_the_application_returns_a_successful_response(): void - { - $response = $this->get('/'); - - $response->assertStatus(200); - } -} -- GitLab