From 0f14f26fd343a2e427556d8bf315be45955ebd78 Mon Sep 17 00:00:00 2001
From: Matthieu
Date: Wed, 24 Jun 2026 10:06:25 +0200
Subject: [PATCH] refactor(directory) : gate report actions via RBAC
permissions + guard report deletion
- replace hardcoded ROLE_ADMIN check with usePermissions().can('directory.{clients,prospects}.manage')
- rename misleading isAdmin prop to canManage in CommercialReportTab and ReportDocumentList
- add busy guard on delete confirmation modal to prevent duplicate DELETE on double-click
---
.../ui/ConfirmDeleteReportModal.vue | 7 ++++-
.../components/CommercialReportTab.vue | 31 ++++++++++++-------
.../components/ReportDocumentList.vue | 4 +--
.../pages/directory/clients/[id].vue | 6 ++--
.../pages/directory/prospects/[id].vue | 6 ++--
5 files changed, 33 insertions(+), 21 deletions(-)
diff --git a/frontend/components/ui/ConfirmDeleteReportModal.vue b/frontend/components/ui/ConfirmDeleteReportModal.vue
index 7aa6311..5010d48 100644
--- a/frontend/components/ui/ConfirmDeleteReportModal.vue
+++ b/frontend/components/ui/ConfirmDeleteReportModal.vue
@@ -13,12 +13,14 @@
variant="tertiary"
:label="$t('common.cancel')"
button-class="w-auto px-4"
+ :disabled="busy"
@click="cancel"
/>
@@ -29,8 +31,10 @@
diff --git a/frontend/modules/directory/components/CommercialReportTab.vue b/frontend/modules/directory/components/CommercialReportTab.vue
index c1c778d..54d406b 100644
--- a/frontend/modules/directory/components/CommercialReportTab.vue
+++ b/frontend/modules/directory/components/CommercialReportTab.vue
@@ -6,7 +6,7 @@
{{ $t('directory.reports.count', { n: reports.length }, reports.length) }}
{{ $t('directory.reports.empty') }}
{{ $t('directory.reports.emptyHint') }}
· {{ report.author.username }}
-
+
@@ -107,11 +107,11 @@
removeDocument(docId)"
/>
@@ -129,6 +129,7 @@
/>
@@ -141,7 +142,7 @@ import { useReportDocumentService } from '~/modules/directory/services/report-do
const props = defineProps<{
owner: { client?: string, prospect?: string }
- isAdmin: boolean
+ canManage: boolean
}>()
const reportService = useCommercialReportService()
@@ -155,6 +156,7 @@ const editing = ref(null)
const confirmOpen = ref(false)
const pendingDelete = ref(null)
+const deleting = ref(false)
// Le plus récent en haut (l'API ne garantit pas l'ordre).
const sortedReports = computed(() =>
@@ -208,11 +210,16 @@ function askDelete(report: CommercialReport): void {
}
async function confirmDelete(): Promise {
- if (!pendingDelete.value) return
- await reportService.remove(pendingDelete.value.id)
- confirmOpen.value = false
- pendingDelete.value = null
- await reload()
+ if (!pendingDelete.value || deleting.value) return
+ deleting.value = true
+ try {
+ await reportService.remove(pendingDelete.value.id)
+ confirmOpen.value = false
+ pendingDelete.value = null
+ await reload()
+ } finally {
+ deleting.value = false
+ }
}
async function removeDocument(id: number): Promise {
diff --git a/frontend/modules/directory/components/ReportDocumentList.vue b/frontend/modules/directory/components/ReportDocumentList.vue
index 705f9dd..83fda90 100644
--- a/frontend/modules/directory/components/ReportDocumentList.vue
+++ b/frontend/modules/directory/components/ReportDocumentList.vue
@@ -15,7 +15,7 @@
{{ doc.originalName }}
()
+defineProps<{ documents: ReportDocument[], canManage: boolean }>()
defineEmits<{ delete: [id: number] }>()
const { getDownloadUrl } = useReportDocumentService()
diff --git a/frontend/modules/directory/pages/directory/clients/[id].vue b/frontend/modules/directory/pages/directory/clients/[id].vue
index 6f223ca..264e733 100644
--- a/frontend/modules/directory/pages/directory/clients/[id].vue
+++ b/frontend/modules/directory/pages/directory/clients/[id].vue
@@ -99,7 +99,7 @@
-
+
@@ -137,8 +137,8 @@ const {
load,
} = useDirectoryDetail(owner)
-const authStore = useAuthStore()
-const isAdmin = computed(() => authStore.user?.roles?.includes('ROLE_ADMIN') ?? false)
+const { can } = usePermissions()
+const canManage = computed(() => can('directory.clients.manage'))
const client = ref(null)
const loading = ref(true)
diff --git a/frontend/modules/directory/pages/directory/prospects/[id].vue b/frontend/modules/directory/pages/directory/prospects/[id].vue
index 2141cb7..4d03db5 100644
--- a/frontend/modules/directory/pages/directory/prospects/[id].vue
+++ b/frontend/modules/directory/pages/directory/prospects/[id].vue
@@ -119,7 +119,7 @@
-
+
@@ -157,8 +157,8 @@ const {
load,
} = useDirectoryDetail(owner)
-const authStore = useAuthStore()
-const isAdmin = computed(() => authStore.user?.roles?.includes('ROLE_ADMIN') ?? false)
+const { can } = usePermissions()
+const canManage = computed(() => can('directory.prospects.manage'))
const prospect = ref(null)
const loading = ref(true)