From 4fc7fdd7cde42f4fa8cf86df7f46d9e25af28baa Mon Sep 17 00:00:00 2001 From: jeremy bayse Date: Sat, 21 Feb 2026 17:38:04 +0100 Subject: [PATCH] =?UTF-8?q?Impl=C3=A9mantation=20de=20la=20gestion=20des?= =?UTF-8?q?=20Services=20pouvant=20avoir=20des=20taches?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/DashboardController.php | 13 +- app/Http/Controllers/PermissionController.php | 82 +++++++++++ app/Http/Controllers/ServiceController.php | 136 ++++++++++++++++++ public/favicon.ico | Bin 0 -> 1934 bytes public/favicon.png | Bin 0 -> 1934 bytes resources/js/Layouts/AuthenticatedLayout.vue | 28 ++++ resources/js/Pages/Permission/Create.vue | 54 +++++++ resources/js/Pages/Permission/Edit.vue | 58 ++++++++ resources/js/Pages/Permission/Index.vue | 60 ++++++++ resources/js/Pages/Service/Create.vue | 76 ++++++++++ resources/js/Pages/Service/Edit.vue | 80 +++++++++++ resources/js/Pages/Service/Index.vue | 73 ++++++++++ resources/views/app.blade.php | 1 + routes/web.php | 2 + 14 files changed, 661 insertions(+), 2 deletions(-) create mode 100644 app/Http/Controllers/PermissionController.php create mode 100644 app/Http/Controllers/ServiceController.php create mode 100644 public/favicon.png create mode 100644 resources/js/Pages/Permission/Create.vue create mode 100644 resources/js/Pages/Permission/Edit.vue create mode 100644 resources/js/Pages/Permission/Index.vue create mode 100644 resources/js/Pages/Service/Create.vue create mode 100644 resources/js/Pages/Service/Edit.vue create mode 100644 resources/js/Pages/Service/Index.vue diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 20abd9b..7d90f3f 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -7,6 +7,7 @@ use App\Models\ServiceTask; use App\Enums\IntegrationStatus; use App\Enums\ServiceTaskStatus; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; use Inertia\Inertia; class DashboardController extends Controller @@ -24,7 +25,7 @@ class DashboardController extends Controller } // If user has a service role - $serviceRoles = ['DSI', 'Batiment', 'Parc Auto']; + $serviceRoles = \App\Models\Service::pluck('name')->toArray(); foreach ($serviceRoles as $role) { if ($user->hasRole($role)) { return $this->serviceDashboard($role); @@ -40,9 +41,17 @@ class DashboardController extends Controller protected function adminDashboard() { + $driver = DB::connection()->getDriverName(); + $diffQuery = 'TIMESTAMPDIFF(DAY, created_at, completed_at)'; + if ($driver === 'pgsql') { + $diffQuery = 'EXTRACT(EPOCH FROM (completed_at - created_at)) / 86400'; + } elseif ($driver === 'sqlite') { + $diffQuery = 'CAST(julianday(completed_at) - julianday(created_at) AS INTEGER)'; + } + $avgCompletionTime = IntegrationRequest::where('status', IntegrationStatus::Completed) ->whereNotNull('completed_at') - ->selectRaw('AVG(TIMESTAMPDIFF(DAY, created_at, completed_at)) as avg_days') + ->selectRaw("AVG({$diffQuery}) as avg_days") ->value('avg_days') ?? 0; $serviceDistribution = \App\Models\Service::withCount('serviceTasks')->get()->map(function ($service) { diff --git a/app/Http/Controllers/PermissionController.php b/app/Http/Controllers/PermissionController.php new file mode 100644 index 0000000..19013e3 --- /dev/null +++ b/app/Http/Controllers/PermissionController.php @@ -0,0 +1,82 @@ +user()->hasRole('Admin')) { + abort(403); + } + + return Inertia::render('Permission/Index', [ + 'permissions' => Permission::all(), + ]); + } + + public function create() + { + if (!auth()->user()->hasRole('Admin')) { + abort(403); + } + + return Inertia::render('Permission/Create'); + } + + public function store(Request $request) + { + if (!auth()->user()->hasRole('Admin')) { + abort(403); + } + + $validated = $request->validate([ + 'name' => 'required|string|unique:permissions,name', + ]); + + Permission::create(['name' => $validated['name']]); + + return redirect()->route('permissions.index')->with('success', 'Permission créée avec succès.'); + } + + public function edit(Permission $permission) + { + if (!auth()->user()->hasRole('Admin')) { + abort(403); + } + + return Inertia::render('Permission/Edit', [ + 'permission' => $permission, + ]); + } + + public function update(Request $request, Permission $permission) + { + if (!auth()->user()->hasRole('Admin')) { + abort(403); + } + + $validated = $request->validate([ + 'name' => 'required|string|unique:permissions,name,' . $permission->id, + ]); + + $permission->update(['name' => $validated['name']]); + + return redirect()->route('permissions.index')->with('success', 'Permission mise à jour avec succès.'); + } + + public function destroy(Permission $permission) + { + if (!auth()->user()->hasRole('Admin')) { + abort(403); + } + + $permission->delete(); + + return redirect()->route('permissions.index')->with('success', 'Permission supprimée avec succès.'); + } +} diff --git a/app/Http/Controllers/ServiceController.php b/app/Http/Controllers/ServiceController.php new file mode 100644 index 0000000..ac5a4df --- /dev/null +++ b/app/Http/Controllers/ServiceController.php @@ -0,0 +1,136 @@ +user()->hasRole('Admin')) { + abort(403); + } + + return Inertia::render('Service/Index', [ + 'services' => Service::all(), + ]); + } + + public function create() + { + if (!auth()->user()->hasRole('Admin')) { + abort(403); + } + + return Inertia::render('Service/Create'); + } + + public function store(Request $request) + { + if (!auth()->user()->hasRole('Admin')) { + abort(403); + } + + $validated = $request->validate([ + 'name' => 'required|string|max:255|unique:services,name', + 'code' => 'required|string|max:50|unique:services,code', + 'is_active' => 'boolean', + ]); + + $service = Service::create([ + 'name' => $validated['name'], + 'code' => strtolower($validated['code']), + 'is_active' => $validated['is_active'] ?? true, + ]); + + // Création de la Permission (tâche) + $permissionName = 'manage ' . strtolower($service->name) . ' tasks'; + Permission::firstOrCreate(['name' => $permissionName]); + + // Création du Rôle pour ce Service + $role = Role::firstOrCreate(['name' => $service->name]); + $role->givePermissionTo([ + $permissionName, + 'view dashboard', + ]); + + return redirect()->route('services.index')->with('success', 'Service créé avec succès.'); + } + + public function edit(Service $service) + { + if (!auth()->user()->hasRole('Admin')) { + abort(403); + } + + return Inertia::render('Service/Edit', [ + 'service' => $service, + ]); + } + + public function update(Request $request, Service $service) + { + if (!auth()->user()->hasRole('Admin')) { + abort(403); + } + + $validated = $request->validate([ + 'name' => 'required|string|max:255|unique:services,name,' . $service->id, + 'code' => 'required|string|max:50|unique:services,code,' . $service->id, + 'is_active' => 'boolean', + ]); + + $oldName = $service->name; + + $service->update([ + 'name' => $validated['name'], + 'code' => strtolower($validated['code']), + 'is_active' => $validated['is_active'] ?? true, + ]); + + // Si le nom du service change, on met à jour le rôle et la permission correspondante + if ($oldName !== $service->name) { + $oldPermissionName = 'manage ' . strtolower($oldName) . ' tasks'; + $newPermissionName = 'manage ' . strtolower($service->name) . ' tasks'; + + $permission = Permission::where('name', $oldPermissionName)->first(); + if ($permission) { + $permission->update(['name' => $newPermissionName]); + } + + $role = Role::where('name', $oldName)->first(); + if ($role) { + $role->update(['name' => $service->name]); + } + } + + return redirect()->route('services.index')->with('success', 'Service mis à jour avec succès.'); + } + + public function destroy(Service $service) + { + if (!auth()->user()->hasRole('Admin')) { + abort(403); + } + + $permissionName = 'manage ' . strtolower($service->name) . ' tasks'; + $permission = Permission::where('name', $permissionName)->first(); + if ($permission) { + $permission->delete(); + } + + $role = Role::where('name', $service->name)->first(); + if ($role) { + $role->delete(); + } + + $service->delete(); + + return redirect()->route('services.index')->with('success', 'Service supprimé avec succès.'); + } +} diff --git a/public/favicon.ico b/public/favicon.ico index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3427eb589c41c2be8a99d588fa4ec812f56052c6 100644 GIT binary patch literal 1934 zcmV;92XXj`P)vJrWQrsQ4CY3$`OaUa&>N3NB%WL=B zx5`Rf&$f42A4j4UfGc@E0C<2XPzv~gUZ4mt0SgE!rCL8H1n8+2f$6|@;7#B?)8*dO zI??S{u%f{l+^!?$A?N~JN~x$2!l{(OB2C}R1G9P-?M?*WOWV6 z3N+wtz`j^oyj+7XCcoPz5T7X2dLSwUe^5$n(gas**yjMJfQ3@29H4q621tr70emE| z8o)NCI2IQKfysaiRBtlRHX+q%CHQ_^(F)A4VJwMuG!G||Dm)1SYAeu1qPGA(0XFb; z6u(Zc$>eKJk`};I!0&;70|m)KQbsxgj{?^~97TvaEgnB4HSN2=MkOc)iV$oiL8T-q z{!JxBVKV0tU?b2^g5bGy21J@Em?OZi63OQQwID*E3X^mil2l9}1QaLNTnXb;B*`oW zjsu~wjm@dR($tp)BbIk>H7Q`yx4A25BK&idy2&6Qy zKNxC`D0NhU^k~|cHrsB!W!u5>j10>LSs$|so^WS51992Z6ORYHn&uBm8SrV^xhx@! zm{JEUls(3wj|oWG;nlP$o8e|Et&}a8ndLnAc0t}sr4)`ITG1X?p8d<3H=J&HY|C>$E`0ThzSH>#j@vl}f}i&E?Kx#e*4;A!uh8tu zOalqHZz`v;q1QZZXX?|w5HVLxyjc<7?=Df9B5|>#YSIgiih`C4t|v|LNWf{_Fw$x*&J!DDuH_WJ(t!(rCOfodvRqSnHTEQjU)uD0~5Fn{$Eqe~`elF+4%_Z~V z3MqS2>xlH@o|-_fDv(V}Cps%u*30-Ahb_A`J=X{@+SRVBh`8qaLAWZo&^P01?*nUB zUwVSR*}xlm>i*^}$_BU#u(3YA$vfR6_fUY-NJEE$dU=5fd0xhVk8rU}+ zuHb8K*P?<`!FTI6Yhu1+Xy<=6;tG32223TdOF+2QmHLMtENvbbAMK0gQq?x!XbP4Y z&SztxPy3sp49`D9^1UT%r2M;*e z$7fX*UeIbfW)EHGY6})OHuX>P)IU8n5Z>)IjoE{sp{c>t)AmU;W`(3YJt6~u|98iy z{>#v<*1FEhij9@;hAKzZgkGxr)uBO^F(cRL>;0&8v2n6}QG;G0)1*kiI2(X;>e8wkF}?FZG= zMu#B)z+!jSFMji2{@S8f}ybX1w&u`PG8Tlevy9119ZnFuXOs4oCuq% zKPx_5+=~H#(4m3QiVYpzJL_VWyt@GcI2Vn{=i57XCM!4ZF>eCR-N$g@5@OlryqxQo zCX7?JCXQE^CX7=r=VrHL3bA~oI!dXL8%Ty{T!y}7UAFgnv950=@y}?)g({`^KVWNt Ud26dR`Tzg`07*qoM6N<$f@ngflK=n! literal 0 HcmV?d00001 diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..3427eb589c41c2be8a99d588fa4ec812f56052c6 GIT binary patch literal 1934 zcmV;92XXj`P)vJrWQrsQ4CY3$`OaUa&>N3NB%WL=B zx5`Rf&$f42A4j4UfGc@E0C<2XPzv~gUZ4mt0SgE!rCL8H1n8+2f$6|@;7#B?)8*dO zI??S{u%f{l+^!?$A?N~JN~x$2!l{(OB2C}R1G9P-?M?*WOWV6 z3N+wtz`j^oyj+7XCcoPz5T7X2dLSwUe^5$n(gas**yjMJfQ3@29H4q621tr70emE| z8o)NCI2IQKfysaiRBtlRHX+q%CHQ_^(F)A4VJwMuG!G||Dm)1SYAeu1qPGA(0XFb; z6u(Zc$>eKJk`};I!0&;70|m)KQbsxgj{?^~97TvaEgnB4HSN2=MkOc)iV$oiL8T-q z{!JxBVKV0tU?b2^g5bGy21J@Em?OZi63OQQwID*E3X^mil2l9}1QaLNTnXb;B*`oW zjsu~wjm@dR($tp)BbIk>H7Q`yx4A25BK&idy2&6Qy zKNxC`D0NhU^k~|cHrsB!W!u5>j10>LSs$|so^WS51992Z6ORYHn&uBm8SrV^xhx@! zm{JEUls(3wj|oWG;nlP$o8e|Et&}a8ndLnAc0t}sr4)`ITG1X?p8d<3H=J&HY|C>$E`0ThzSH>#j@vl}f}i&E?Kx#e*4;A!uh8tu zOalqHZz`v;q1QZZXX?|w5HVLxyjc<7?=Df9B5|>#YSIgiih`C4t|v|LNWf{_Fw$x*&J!DDuH_WJ(t!(rCOfodvRqSnHTEQjU)uD0~5Fn{$Eqe~`elF+4%_Z~V z3MqS2>xlH@o|-_fDv(V}Cps%u*30-Ahb_A`J=X{@+SRVBh`8qaLAWZo&^P01?*nUB zUwVSR*}xlm>i*^}$_BU#u(3YA$vfR6_fUY-NJEE$dU=5fd0xhVk8rU}+ zuHb8K*P?<`!FTI6Yhu1+Xy<=6;tG32223TdOF+2QmHLMtENvbbAMK0gQq?x!XbP4Y z&SztxPy3sp49`D9^1UT%r2M;*e z$7fX*UeIbfW)EHGY6})OHuX>P)IU8n5Z>)IjoE{sp{c>t)AmU;W`(3YJt6~u|98iy z{>#v<*1FEhij9@;hAKzZgkGxr)uBO^F(cRL>;0&8v2n6}QG;G0)1*kiI2(X;>e8wkF}?FZG= zMu#B)z+!jSFMji2{@S8f}ybX1w&u`PG8Tlevy9119ZnFuXOs4oCuq% zKPx_5+=~H#(4m3QiVYpzJL_VWyt@GcI2Vn{=i57XCM!4ZF>eCR-N$g@5@OlryqxQo zCX7?JCXQE^CX7=r=VrHL3bA~oI!dXL8%Ty{T!y}7UAFgnv950=@y}?)g({`^KVWNt Ud26dR`Tzg`07*qoM6N<$f@ngflK=n! literal 0 HcmV?d00001 diff --git a/resources/js/Layouts/AuthenticatedLayout.vue b/resources/js/Layouts/AuthenticatedLayout.vue index de9c84d..29e6a70 100644 --- a/resources/js/Layouts/AuthenticatedLayout.vue +++ b/resources/js/Layouts/AuthenticatedLayout.vue @@ -53,6 +53,20 @@ const showingNavigationDropdown = ref(false); > Rôles + + Permissions + + + Services + @@ -174,6 +188,20 @@ const showingNavigationDropdown = ref(false); > Rôles + + Permissions + + + Services + diff --git a/resources/js/Pages/Permission/Create.vue b/resources/js/Pages/Permission/Create.vue new file mode 100644 index 0000000..7736af4 --- /dev/null +++ b/resources/js/Pages/Permission/Create.vue @@ -0,0 +1,54 @@ + + + diff --git a/resources/js/Pages/Permission/Edit.vue b/resources/js/Pages/Permission/Edit.vue new file mode 100644 index 0000000..8b40bc5 --- /dev/null +++ b/resources/js/Pages/Permission/Edit.vue @@ -0,0 +1,58 @@ + + + diff --git a/resources/js/Pages/Permission/Index.vue b/resources/js/Pages/Permission/Index.vue new file mode 100644 index 0000000..247a8e8 --- /dev/null +++ b/resources/js/Pages/Permission/Index.vue @@ -0,0 +1,60 @@ + + + diff --git a/resources/js/Pages/Service/Create.vue b/resources/js/Pages/Service/Create.vue new file mode 100644 index 0000000..bbcedeb --- /dev/null +++ b/resources/js/Pages/Service/Create.vue @@ -0,0 +1,76 @@ + + + diff --git a/resources/js/Pages/Service/Edit.vue b/resources/js/Pages/Service/Edit.vue new file mode 100644 index 0000000..64d0ff9 --- /dev/null +++ b/resources/js/Pages/Service/Edit.vue @@ -0,0 +1,80 @@ + + + diff --git a/resources/js/Pages/Service/Index.vue b/resources/js/Pages/Service/Index.vue new file mode 100644 index 0000000..d262a27 --- /dev/null +++ b/resources/js/Pages/Service/Index.vue @@ -0,0 +1,73 @@ + + + diff --git a/resources/views/app.blade.php b/resources/views/app.blade.php index 334627a..78a27f0 100644 --- a/resources/views/app.blade.php +++ b/resources/views/app.blade.php @@ -5,6 +5,7 @@ {{ config('app.name', 'Laravel') }} + diff --git a/routes/web.php b/routes/web.php index 5724f98..5902997 100644 --- a/routes/web.php +++ b/routes/web.php @@ -41,6 +41,8 @@ Route::middleware('auth')->group(function () { Route::resource('users', \App\Http\Controllers\UserController::class); Route::resource('roles', \App\Http\Controllers\RoleController::class); + Route::resource('permissions', \App\Http\Controllers\PermissionController::class); + Route::resource('services', \App\Http\Controllers\ServiceController::class); }); require __DIR__.'/auth.php';