From 3fe0bbf71ef9e3f1a5cd6c6ef6606c533e414481 Mon Sep 17 00:00:00 2001 From: tristan Date: Tue, 28 Apr 2026 11:52:18 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20modification=20de=20la=20gestion=20des?= =?UTF-8?q?=20r=C3=B4les=20+=20ajout=20r=C3=B4le=20d'un=20bureau=20(!52)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit | Numéro du ticket | Titre du ticket | |------------------|-----------------| | | | ## Description de la PR ## Modification du .env ## Check list - [ ] Pas de régression - [ ] TU/TI/TF rédigée - [ ] TU/TI/TF OK - [ ] CHANGELOG modifié Reviewed-on: https://gitea.malio.fr/MALIO-DEV/Ferme/pulls/52 Co-authored-by: tristan Co-committed-by: tristan --- config/packages/security.yaml | 7 ++++ frontend/composables/useBovineColumns.ts | 23 ++++++----- frontend/middleware/admin-guard.global.ts | 27 +++++++++++++ frontend/pages/inventory.vue | 4 +- frontend/stores/auth.ts | 6 ++- frontend/utils/constants.ts | 1 + frontend/utils/roles.ts | 38 +++++++++++++++++++ src/ApiResource/BovineInventoryExport.php | 2 +- src/ApiResource/BovineSyncInventoryResult.php | 2 +- src/Entity/Bovine.php | 4 +- src/Entity/Reception.php | 1 + src/Entity/Shipment.php | 1 + 12 files changed, 99 insertions(+), 17 deletions(-) create mode 100644 frontend/middleware/admin-guard.global.ts create mode 100644 frontend/utils/roles.ts diff --git a/config/packages/security.yaml b/config/packages/security.yaml index cc32766..56050e8 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -1,4 +1,11 @@ security: + # Hiérarchie des rôles : ADMIN inclut BUREAU qui inclut USER. + # Ajouter un nouveau rôle = ajouter une ligne ici (et son équivalent côté + # front dans utils/roles.ts). + role_hierarchy: + ROLE_BUREAU: ROLE_USER + ROLE_ADMIN: ROLE_BUREAU + # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords password_hashers: App\Entity\User: 'auto' diff --git a/frontend/composables/useBovineColumns.ts b/frontend/composables/useBovineColumns.ts index a4866cd..7c4d978 100644 --- a/frontend/composables/useBovineColumns.ts +++ b/frontend/composables/useBovineColumns.ts @@ -18,13 +18,15 @@ export interface UseBovineColumnsOptions { /** * Définition partagée des colonnes des tableaux bovins (inventory + case). - * Variants distincts pour chaque écran et chaque rôle (admin/user) afin de - * pouvoir ajuster les largeurs indépendamment. + * 4 variants : avec/sans colonnes prix × inventory/case. + * + * Les colonnes Prix/kg et Prix total sont visibles pour les rôles BUREAU + * et ADMIN (BUREAU hérite ses droits price-visibility, ADMIN hérite de BUREAU). */ export const useBovineColumns = (options: UseBovineColumnsOptions = {}) => { const auth = useAuthStore() - const adminColumnsInventory: BovineColumn[] = [ + const withPricesInventory: BovineColumn[] = [ { key: 'nationalNumber', label: 'N° National', width: '80px' }, { key: 'workNumber', label: 'N° Travail', width: '60px' }, { key: 'sex', label: 'Sexe', width: '70px' }, @@ -38,7 +40,7 @@ export const useBovineColumns = (options: UseBovineColumnsOptions = {}) => { { key: 'finalPrice', label: 'Prix total', width: '80px' } ] - const userColumnsInventory: BovineColumn[] = [ + const withoutPricesInventory: BovineColumn[] = [ { key: 'nationalNumber', label: 'N° National', width: '80px' }, { key: 'workNumber', label: 'N° Travail', width: '60px' }, { key: 'sex', label: 'Sexe', width: '70px' }, @@ -50,7 +52,7 @@ export const useBovineColumns = (options: UseBovineColumnsOptions = {}) => { { key: 'arrivalDate', label: 'Entrée le', width: '90px' } ] - const adminColumnsCase: BovineColumn[] = [ + const withPricesCase: BovineColumn[] = [ { key: 'nationalNumber', label: 'N° National', width: '110px' }, { key: 'workNumber', label: 'N° Travail', width: '85px' }, { key: 'sex', label: 'Sexe', width: '90px' }, @@ -62,7 +64,7 @@ export const useBovineColumns = (options: UseBovineColumnsOptions = {}) => { { key: 'finalPrice', label: 'Prix total', width: '105px' } ] - const userColumnsCase: BovineColumn[] = [ + const withoutPricesCase: BovineColumn[] = [ { key: 'nationalNumber', label: 'N° National', width: '130px' }, { key: 'workNumber', label: 'N° Travail', width: '100px' }, { key: 'sex', label: 'Sexe', width: '110px' }, @@ -73,10 +75,13 @@ export const useBovineColumns = (options: UseBovineColumnsOptions = {}) => { ] const columns = computed(() => { - if (options.variant === 'case') { - return auth.isAdmin ? adminColumnsCase : userColumnsCase + const isCase = options.variant === 'case' + const seePrice = auth.isBureau + + if (isCase) { + return seePrice ? withPricesCase : withoutPricesCase } - return auth.isAdmin ? adminColumnsInventory : userColumnsInventory + return seePrice ? withPricesInventory : withoutPricesInventory }) return { columns } diff --git a/frontend/middleware/admin-guard.global.ts b/frontend/middleware/admin-guard.global.ts new file mode 100644 index 0000000..e911f74 --- /dev/null +++ b/frontend/middleware/admin-guard.global.ts @@ -0,0 +1,27 @@ +import { useAuthStore } from '~/stores/auth' + +/** + * Garde-fou global : empêche les utilisateurs non-admin d'accéder aux pages + * sous /admin/*. Renvoie vers la home pour les utilisateurs authentifiés + * non-admin, et vers /login pour les non authentifiés. + * + * L'API back rejette de toute façon les actions admin avec un 403, mais ce + * middleware évite l'affichage des pages vides / en erreur quand un user + * tape directement l'URL /admin/... + */ +export default defineNuxtRouteMiddleware(async (to) => { + if (!to.path.startsWith('/admin')) { + return + } + + const auth = useAuthStore() + await auth.ensureSession() + + if (!auth.isAuthenticated) { + return navigateTo('/login') + } + + if (!auth.isAdmin) { + return navigateTo('/') + } +}) diff --git a/frontend/pages/inventory.vue b/frontend/pages/inventory.vue index 7f3fabe..9a1579b 100644 --- a/frontend/pages/inventory.vue +++ b/frontend/pages/inventory.vue @@ -13,7 +13,7 @@

Inventaire bovins

({{ totalItems }} bovin{{ totalItems > 1 ? 's' : '' }})