diff --git a/backend/app/Http/Controllers/AdminController.php b/backend/app/Http/Controllers/AdminController.php index 879201c..9a4b7e6 100644 --- a/backend/app/Http/Controllers/AdminController.php +++ b/backend/app/Http/Controllers/AdminController.php @@ -10,6 +10,7 @@ use Illuminate\Support\Str; use App\Models\User; use App\Models\Role; use App\Models\Permission; +use App\Models\Option; class AdminController extends Controller { @@ -316,6 +317,47 @@ class AdminController extends Controller ]); } + public function getOptions() { + if(!request()->user()->hasPermission("admin-options-read")) abort(401); + + return response()->json(Option::all()); + } + + public function updateOption(Request $request, Option $option) { + if(!request()->user()->hasPermission("admin-options-update")) abort(401); + + switch($option->type) { + case 'number': + $type_validation = 'numeric'; + if($option->min) $type_validation .= '|min:'.$option->min; + if($option->max) $type_validation .= '|max:'.$option->max; + break; + case 'boolean': + $type_validation = 'boolean'; + break; + case 'select': + $type_validation = 'in:'.implode(',', $option->options); + break; + default: + $type_validation = 'string'; + break; + } + + $request->validate([ + 'value' => [ + 'required', + $type_validation + ] + ]); + + $option->value = request()->input('value'); + $option->save(); + + return response()->json([ + 'message' => 'Option updated successfully' + ]); + } + public function getPermissionsAndRoles() { if(!request()->user()->hasPermission("admin-roles-read")) abort(401); return response()->json([ diff --git a/backend/app/Models/Option.php b/backend/app/Models/Option.php new file mode 100644 index 0000000..8cbc11a --- /dev/null +++ b/backend/app/Models/Option.php @@ -0,0 +1,16 @@ + 'array' + ]; +} diff --git a/backend/config/laratrust_seeder.php b/backend/config/laratrust_seeder.php index 1da57d1..0bde93b 100644 --- a/backend/config/laratrust_seeder.php +++ b/backend/config/laratrust_seeder.php @@ -22,6 +22,7 @@ return [ 'admin' => 'r', 'admin-info' => 'r,u', 'admin-maintenance' => 'r,u', + 'admin-options' => 'r,u', 'admin-roles' => 'r,u' ], 'admin' => [ @@ -33,6 +34,7 @@ return [ 'logs' => 'lr', 'admin' => 'r', 'admin-info' => 'r,u', + 'admin-options' => 'r,u', 'admin-roles' => 'r,u' ], 'chief' => [ diff --git a/backend/database/migrations/2024_01_18_005858_create_options_table.php b/backend/database/migrations/2024_01_18_005858_create_options_table.php new file mode 100644 index 0000000..1db04c7 --- /dev/null +++ b/backend/database/migrations/2024_01_18_005858_create_options_table.php @@ -0,0 +1,34 @@ +id(); + $table->string('name')->unique(); + $table->text('value')->nullable(); + $table->text('default')->nullable(); + $table->enum('type', ['number', 'string', 'boolean', 'select'])->default('string'); + $table->json('options')->nullable(); + $table->float('min')->nullable(); + $table->float('max')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('options'); + } +}; diff --git a/backend/database/seeders/OptionsSeeder.php b/backend/database/seeders/OptionsSeeder.php new file mode 100644 index 0000000..6bd177e --- /dev/null +++ b/backend/database/seeders/OptionsSeeder.php @@ -0,0 +1,28 @@ + 'service_place_selection_manual', + 'value' => true, + 'type' => 'boolean' + ] + ]; + + foreach ($options as $option) { + $option['default'] = $option['value']; + \App\Models\Option::create($option); + } + } +} diff --git a/backend/routes/api.php b/backend/routes/api.php index 102b5c4..d4e1ca4 100644 --- a/backend/routes/api.php +++ b/backend/routes/api.php @@ -117,6 +117,9 @@ Route::middleware('auth:sanctum')->group( function () { Route::post('/admin/telegramBot/setWebhook', [AdminController::class, 'setTelegramWebhook']); Route::post('/admin/telegramBot/unsetWebhook', [AdminController::class, 'unsetTelegramWebhook']); + Route::get('/admin/options', [AdminController::class, 'getOptions']); + Route::put('/admin/options/{option}', [AdminController::class, 'updateOption']); + Route::get('/admin/permissionsAndRoles', [AdminController::class, 'getPermissionsAndRoles']); Route::post('/admin/roles', [AdminController::class, 'updateRoles']); }); diff --git a/frontend/src/app/_routes/admin/admin-routing.module.ts b/frontend/src/app/_routes/admin/admin-routing.module.ts index 71121dd..e09d6d7 100644 --- a/frontend/src/app/_routes/admin/admin-routing.module.ts +++ b/frontend/src/app/_routes/admin/admin-routing.module.ts @@ -19,6 +19,12 @@ const routes: Routes = [{ canActivate: [AuthorizeGuard], data: {permissionsRequired: ['admin-read', 'admin-maintenance-read']} }, + { + path: 'options', + loadChildren: () => import('./options/admin-options.module').then(m => m.AdminOptionsModule), + canActivate: [AuthorizeGuard], + data: {permissionsRequired: ['admin-read', 'admin-options-read']} + }, { path: 'roles', loadChildren: () => import('./roles/admin-roles.module').then(m => m.AdminRolesModule), diff --git a/frontend/src/app/_routes/admin/admin.component.ts b/frontend/src/app/_routes/admin/admin.component.ts index c487eea..0e44b8d 100644 --- a/frontend/src/app/_routes/admin/admin.component.ts +++ b/frontend/src/app/_routes/admin/admin.component.ts @@ -21,6 +21,7 @@ export class AdminComponent implements OnInit { tabs: ITab[] = [ { title: 'info', id: 'info', active: false, permissionsRequired: ['admin-read', 'admin-info-read'] }, { title: 'maintenance', id: 'maintenance', active: false, permissionsRequired: ['admin-read', 'admin-maintenance-read'] }, + { title: 'options', id: 'options', active: false, permissionsRequired: ['admin-read', 'admin-options-read'] }, { title: 'roles', id: 'roles', active: false, permissionsRequired: ['admin-read', 'admin-roles-read'] } ]; diff --git a/frontend/src/app/_routes/admin/options/admin-options-routing.module.ts b/frontend/src/app/_routes/admin/options/admin-options-routing.module.ts new file mode 100644 index 0000000..fa67651 --- /dev/null +++ b/frontend/src/app/_routes/admin/options/admin-options-routing.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { AdminOptionsComponent } from './admin-options.component'; + +const routes: Routes = [{ path: '', component: AdminOptionsComponent }]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class AdminOptionsRoutingModule { } diff --git a/frontend/src/app/_routes/admin/options/admin-options.component.html b/frontend/src/app/_routes/admin/options/admin-options.component.html new file mode 100644 index 0000000..b5e1b95 --- /dev/null +++ b/frontend/src/app/_routes/admin/options/admin-options.component.html @@ -0,0 +1,48 @@ +
{{ 'name'|translate|ftitlecase }} | +{{ 'value'|translate|ftitlecase }} | +{{ 'action'|translate|ftitlecase }} | +|||
---|---|---|---|---|---|
{{ 'options.'+option.name|translate }} | + + ++ + | ++ + | +
+
+
+
+ |
+
+
+
+ {{ 'options.no_selection_available'|translate }}
+
+ |
+
+ + + | +