refactor(auth): centralize role checks into utility
Removed direct user role string checks and replaced with type-safe utils.
This commit is contained in:
@@ -34,7 +34,7 @@ const navLinks = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const { isAuthenticated, user, logout } = useAuth()
|
const { isAuthenticated, user, logout } = useAuth()
|
||||||
const panelLabel = computed(() => user.value?.role?.toUpperCase() === 'ADMIN' ? 'Pannello' : 'Dashboard')
|
const panelLabel = computed(() => isAdmin(user.value?.role) ? 'Pannello' : 'Dashboard')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
+3
-12
@@ -20,19 +20,10 @@ export default defineNuxtRouteMiddleware(async (to) => {
|
|||||||
const requiredRole = to.meta.auth?.role
|
const requiredRole = to.meta.auth?.role
|
||||||
|
|
||||||
if (requiredRole && auth.user.value) {
|
if (requiredRole && auth.user.value) {
|
||||||
const userRole = auth.user.value.role.toUpperCase()
|
const userRole = auth.user.value.role
|
||||||
|
|
||||||
const roleLevels: Record<string, number> = {
|
if (!hasMinimumRole(userRole, requiredRole)) {
|
||||||
'CITIZEN': 1,
|
console.warn(`[Auth] User role ${userRole} insufficient for required ${requiredRole}`)
|
||||||
'OPERATOR': 2,
|
|
||||||
'ADMIN': 3
|
|
||||||
}
|
|
||||||
|
|
||||||
const userLevel = roleLevels[userRole] || 0
|
|
||||||
const requiredLevel = roleLevels[requiredRole] || 0
|
|
||||||
|
|
||||||
if (userLevel < requiredLevel) {
|
|
||||||
console.warn(`[Auth] User role ${userRole} (level ${userLevel}) insufficient for required ${requiredRole} (level ${requiredLevel})`)
|
|
||||||
return navigateTo('/')
|
return navigateTo('/')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const banError = ref('')
|
|||||||
const roleError = ref('')
|
const roleError = ref('')
|
||||||
const pendingBanUser = ref<any | null>(null)
|
const pendingBanUser = ref<any | null>(null)
|
||||||
const isUpdatingBan = ref(false)
|
const isUpdatingBan = ref(false)
|
||||||
const parseRoles = (roles?: string) => roles ? roles.split(',').map((r) => r.trim().toUpperCase()).filter(Boolean) : []
|
const parseRoles = (roles?: string) => roles ? roles.split(',').map(normalizeRole).filter(Boolean) : []
|
||||||
const banConfirmMessage = computed(() =>
|
const banConfirmMessage = computed(() =>
|
||||||
pendingBanUser.value
|
pendingBanUser.value
|
||||||
? `Vuoi ${pendingBanUser.value.banned ? 'sbloccare' : 'bannare'} utente ${pendingBanUser.value.first_name} ${pendingBanUser.value.last_name}?`
|
? `Vuoi ${pendingBanUser.value.banned ? 'sbloccare' : 'bannare'} utente ${pendingBanUser.value.first_name} ${pendingBanUser.value.last_name}?`
|
||||||
|
|||||||
@@ -10,24 +10,21 @@ import OperatorDashboard from '~/components/dashboard/OperatorDashboard.vue'
|
|||||||
import AdminDashboard from '~/components/dashboard/AdminDashboard.vue'
|
import AdminDashboard from '~/components/dashboard/AdminDashboard.vue'
|
||||||
|
|
||||||
const currentDashboard = computed(() => {
|
const currentDashboard = computed(() => {
|
||||||
const role = user.value?.role?.toUpperCase()
|
if (isCitizen(user.value?.role)) return CitizenDashboard
|
||||||
if (role === 'CITIZEN') return CitizenDashboard
|
if (isOperator(user.value?.role)) return OperatorDashboard
|
||||||
if (role === 'OPERATOR') return OperatorDashboard
|
if (isAdmin(user.value?.role)) return AdminDashboard
|
||||||
if (role === 'ADMIN') return AdminDashboard
|
|
||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
|
|
||||||
const heroTitle = computed(() => {
|
const heroTitle = computed(() => {
|
||||||
const role = user.value?.role?.toUpperCase()
|
if (isAdmin(user.value?.role)) return 'Pannello Admin'
|
||||||
if (role === 'ADMIN') return 'Pannello Admin'
|
if (isOperator(user.value?.role)) return 'Gestione Operativa'
|
||||||
if (role === 'OPERATOR') return 'Gestione Operativa'
|
|
||||||
return 'Dashboard'
|
return 'Dashboard'
|
||||||
})
|
})
|
||||||
|
|
||||||
const heroSubtitle = computed(() => {
|
const heroSubtitle = computed(() => {
|
||||||
const role = user.value?.role?.toUpperCase()
|
if (isAdmin(user.value?.role)) return 'Accesso amministrativo per configurazioni, utenti e moderazione'
|
||||||
if (role === 'ADMIN') return 'Accesso amministrativo per configurazioni, utenti e moderazione'
|
if (isOperator(user.value?.role)) return 'Prendi in carico e gestisci le segnalazioni in corso'
|
||||||
if (role === 'OPERATOR') return 'Prendi in carico e gestisci le segnalazioni in corso'
|
|
||||||
return 'Riepilogo rapido delle tue segnalazioni e dei punti cittadino'
|
return 'Riepilogo rapido delle tue segnalazioni e dei punti cittadino'
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -129,7 +129,9 @@ const handleStatusUpdate = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleAssignTeam = async () => {
|
const handleAssignTeam = async () => {
|
||||||
|
if (isAdmin(user.value?.role)) return
|
||||||
if (!selectedTeamId.value) return
|
if (!selectedTeamId.value) return
|
||||||
|
|
||||||
isAssigning.value = true
|
isAssigning.value = true
|
||||||
try {
|
try {
|
||||||
const res = await assignTeam(reportId, {
|
const res = await assignTeam(reportId, {
|
||||||
@@ -229,6 +231,8 @@ const handleSendMessage = async (msgText: string, files: File[]) => {
|
|||||||
|
|
||||||
const canFlagMessage = (message: Message) => {
|
const canFlagMessage = (message: Message) => {
|
||||||
if (!user.value) return false
|
if (!user.value) return false
|
||||||
|
if (isAdmin(user.value?.role)) return false
|
||||||
|
|
||||||
const isCitizenMessage = message.user_id !== user.value.id && message.user_id === report.value?.user_id
|
const isCitizenMessage = message.user_id !== user.value.id && message.user_id === report.value?.user_id
|
||||||
const isAlreadyFlagged = flaggedMessageIds.value.includes(message.id)
|
const isAlreadyFlagged = flaggedMessageIds.value.includes(message.id)
|
||||||
return isCitizenMessage && !isAlreadyFlagged
|
return isCitizenMessage && !isAlreadyFlagged
|
||||||
@@ -408,7 +412,7 @@ const formattedInterventionLinkExpiry = computed(() =>
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body pt-0">
|
<div v-if="!isAdmin(user?.role)" class="card-body pt-0">
|
||||||
<button class="btn btn-outline-primary w-100" @click="isAssignModalOpen = true" :disabled="teams.length === 0">
|
<button class="btn btn-outline-primary w-100" @click="isAssignModalOpen = true" :disabled="teams.length === 0">
|
||||||
Assegna team
|
Assegna team
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ const formatDate = (dateString: string) =>
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-0">
|
<div class="col-md-6 mb-0">
|
||||||
<small class="text-muted d-block">Ruolo</small>
|
<small class="text-muted d-block">Ruolo</small>
|
||||||
<span class="badge bg-info">{{ user?.role }}</span>
|
<span class="badge bg-info">{{ normalizeRole(user?.role) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
export const ROLES = {
|
||||||
|
CITIZEN: 'CITIZEN',
|
||||||
|
OPERATOR: 'OPERATOR',
|
||||||
|
ADMIN: 'ADMIN'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type Role = keyof typeof ROLES
|
||||||
|
|
||||||
|
export const ROLE_LEVELS: Record<string, number> = {
|
||||||
|
[ROLES.CITIZEN]: 1,
|
||||||
|
[ROLES.OPERATOR]: 2,
|
||||||
|
[ROLES.ADMIN]: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeRole(role?: string | null): string {
|
||||||
|
return role?.trim().toUpperCase() ?? ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isRole(userRole: string | undefined | null, targetRole: string): boolean {
|
||||||
|
return normalizeRole(userRole) === targetRole.toUpperCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasMinimumRole(userRole: string | undefined | null, requiredRole: string): boolean {
|
||||||
|
const userLvl = ROLE_LEVELS[normalizeRole(userRole)] || 0
|
||||||
|
const reqLvl = ROLE_LEVELS[requiredRole.toUpperCase()] || 0
|
||||||
|
return userLvl >= reqLvl
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isAdmin(userRole?: string | null): boolean {
|
||||||
|
return isRole(userRole, ROLES.ADMIN)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isOperator(userRole?: string | null): boolean {
|
||||||
|
return isRole(userRole, ROLES.OPERATOR)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isCitizen(userRole?: string | null): boolean {
|
||||||
|
return isRole(userRole, ROLES.CITIZEN)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canAccess(userRole: string | undefined | null, requiredRole: string): boolean {
|
||||||
|
return hasMinimumRole(userRole, requiredRole)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user