feat : add role guest
Auto Tag Develop / tag (push) Has been cancelled

This commit is contained in:
Lethary
2026-05-05 15:51:58 +02:00
parent 1c0cdeb085
commit fa1f0ccaa4
15 changed files with 72 additions and 21 deletions
+1
View File
@@ -7,6 +7,7 @@
"php": ">=8.4", "php": ">=8.4",
"ext-ctype": "*", "ext-ctype": "*",
"ext-iconv": "*", "ext-iconv": "*",
"ext-soap": "*",
"api-platform/doctrine-orm": "^4.2", "api-platform/doctrine-orm": "^4.2",
"api-platform/symfony": "^4.2", "api-platform/symfony": "^4.2",
"doctrine/doctrine-bundle": "^3.2", "doctrine/doctrine-bundle": "^3.2",
Generated
+3 -2
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "9c04091eea0e10c19713a1d882b04f91", "content-hash": "9a85291a52081179f427fa0c2b60d061",
"packages": [ "packages": [
{ {
"name": "api-platform/doctrine-common", "name": "api-platform/doctrine-common",
@@ -11664,7 +11664,8 @@
"platform": { "platform": {
"php": ">=8.4", "php": ">=8.4",
"ext-ctype": "*", "ext-ctype": "*",
"ext-iconv": "*" "ext-iconv": "*",
"ext-soap": "*"
}, },
"platform-dev": {}, "platform-dev": {},
"plugin-api-version": "2.9.0" "plugin-api-version": "2.9.0"
@@ -18,7 +18,8 @@
<div <div
v-for="item in items" v-for="item in items"
:key="item.id" :key="item.id"
class="grid gap-4 px-4 py-3 text-sm hover:bg-slate-50 cursor-pointer border-t border-slate-200" class="grid gap-4 px-4 py-3 text-sm border-t border-slate-200"
:class="canOpenItems ? 'hover:bg-slate-50 cursor-pointer' : ''"
:style="{ gridTemplateColumns: gridCols }" :style="{ gridTemplateColumns: gridCols }"
role="button" role="button"
tabindex="0" tabindex="0"
@@ -50,8 +51,10 @@ const props = withDefaults(defineProps<{
items: any[] items: any[]
routePrefix: string routePrefix: string
showActions?: boolean showActions?: boolean
canOpenItems?: boolean
}>(), { }>(), {
showActions: false showActions: false,
canOpenItems: true
}) })
const router = useRouter() const router = useRouter()
@@ -62,6 +65,9 @@ const gridCols = computed(() => {
}) })
const goToItem = (id: number) => { const goToItem = (id: number) => {
if (!props.canOpenItems) {
return
}
router.push(`${props.routePrefix}/${id}`) router.push(`${props.routePrefix}/${id}`)
} }
+11
View File
@@ -2,6 +2,13 @@ import { useAuthStore } from '~/stores/auth'
export default defineNuxtRouteMiddleware(async (to) => { export default defineNuxtRouteMiddleware(async (to) => {
const auth = useAuthStore() const auth = useAuthStore()
const guestAllowedPaths = [
'/',
'/reception/waiting-reception',
'/reception/finish-reception',
'/shipment/waiting-shipment',
'/shipment/finish-shipment'
]
if (to.path === '/login') { if (to.path === '/login') {
return return
@@ -14,4 +21,8 @@ export default defineNuxtRouteMiddleware(async (to) => {
if (!auth.isAuthenticated) { if (!auth.isAuthenticated) {
return navigateTo('/login') return navigateTo('/login')
} }
if (auth.isGuest && !guestAllowedPaths.includes(to.path)) {
return navigateTo('/')
}
}) })
+1 -2
View File
@@ -96,8 +96,7 @@ const hydrateFromUser = (user: UserData | null) => {
isHydrating.value = true isHydrating.value = true
form.username = user.username ?? '' form.username = user.username ?? ''
const roles = user.roles ?? [] const roles = user.roles ?? []
const hasAdmin = roles.includes('ROLE_ADMIN') form.role = ROLE.find((role) => roles.includes(role.value))?.value ?? 'ROLE_USER'
form.role = hasAdmin ? 'ROLE_ADMIN' : 'ROLE_USER'
form.password = '' form.password = ''
isHydrating.value = false isHydrating.value = false
} }
+8 -5
View File
@@ -1,10 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { useAuthStore } from '~/stores/auth'
const auth = useAuthStore()
</script> </script>
<template> <template>
<div class="flex flex-wrap justify-center pb-16 gap-12"> <div class="flex flex-wrap justify-center pb-16 gap-12">
<card-link label="NOUVELLE RÉCEPTION" link="/reception" iconName="mdi:truck-outline" /> <card-link v-if="auth.canUseWorkflow" label="NOUVELLE RÉCEPTION" link="/reception" iconName="mdi:truck-outline" />
<card-link label="NOUVELLE EXPÉDITION" link="/shipment" iconName="mdi:truck-fast-outline" /> <card-link v-if="auth.canUseWorkflow" label="NOUVELLE EXPÉDITION" link="/shipment" iconName="mdi:truck-fast-outline" />
<card-link label="PLAN DE SITE" link="/infrastructure/building" iconName="material-symbols:warehouse-outline-rounded" /> <card-link v-if="auth.canUseWorkflow" label="PLAN DE SITE" link="/infrastructure/building" iconName="material-symbols:warehouse-outline-rounded" />
<card-link link="/reception/waiting-reception" iconName="mdi:truck-remove-outline"> <card-link link="/reception/waiting-reception" iconName="mdi:truck-remove-outline">
<template #label> <template #label>
Réceptions<br>EN ATTENTE Réceptions<br>EN ATTENTE
@@ -15,10 +18,10 @@
EXPÉDITIONS<br>EN ATTENTE EXPÉDITIONS<br>EN ATTENTE
</template> </template>
</card-link> </card-link>
<card-link label="CASES" link="/infrastructure/case" iconName="material-symbols:bottom-sheets-outline" /> <card-link v-if="auth.canUseWorkflow" label="CASES" link="/infrastructure/case" iconName="material-symbols:bottom-sheets-outline" />
<card-link label="RÉCEPTIONS FINIES" link="/reception/finish-reception" iconName="mdi:truck-check-outline" /> <card-link label="RÉCEPTIONS FINIES" link="/reception/finish-reception" iconName="mdi:truck-check-outline" />
<card-link label="EXPÉDITIONS FINIES" link="/shipment/finish-shipment" iconName="mdi:truck-delivery-outline" /> <card-link label="EXPÉDITIONS FINIES" link="/shipment/finish-shipment" iconName="mdi:truck-delivery-outline" />
<card-link link="/" iconName="mdi:cow"> <card-link v-if="auth.canUseWorkflow" link="/" iconName="mdi:cow">
<template #label> <template #label>
PASSEPORT<br>DU BOVIN PASSEPORT<br>DU BOVIN
</template> </template>
@@ -17,7 +17,8 @@
<div <div
v-for="reception in receptionList" v-for="reception in receptionList"
:key="reception.id" :key="reception.id"
class="grid grid-cols-6 gap-4 px-4 py-3 text-sm hover:bg-slate-50 cursor-pointer border-t border-slate-200" class="grid grid-cols-6 gap-4 px-4 py-3 text-sm border-t border-slate-200"
:class="auth.canUseWorkflow ? 'hover:bg-slate-50 cursor-pointer' : ''"
role="button" role="button"
tabindex="0" tabindex="0"
@click="goToReception(reception.id)" @click="goToReception(reception.id)"
@@ -36,10 +37,11 @@
<script setup lang="ts"> <script setup lang="ts">
import type {ReceptionData} from "~/services/dto/reception-data"; import type {ReceptionData} from "~/services/dto/reception-data";
import {getReceptionList} from "~/services/reception"; import {getReceptionList} from "~/services/reception";
import type {ShipmentData} from "~/services/dto/shipment-data"; import { useAuthStore } from '~/stores/auth'
const receptionList = ref<ReceptionData[]>() const receptionList = ref<ReceptionData[]>()
const router = useRouter() const router = useRouter()
const auth = useAuthStore()
const formatDate = (date: string | null) => { const formatDate = (date: string | null) => {
if (!date) return '—' if (!date) return '—'
@@ -66,6 +68,7 @@ const formatWeighing = (reception: ReceptionData) => {
} }
const goToReception = (id: number) => { const goToReception = (id: number) => {
if (!auth.canUseWorkflow) return
router.push(`/reception/update/${id}`) router.push(`/reception/update/${id}`)
} }
@@ -4,7 +4,8 @@
:columns="columns" :columns="columns"
:items="receptionList ?? []" :items="receptionList ?? []"
route-prefix="/reception" route-prefix="/reception"
show-actions :show-actions="auth.canUseWorkflow"
:can-open-items="auth.canUseWorkflow"
> >
<template #cell-receptionDate="{ item }"> <template #cell-receptionDate="{ item }">
{{ formatDate(item.receptionDate) }} {{ formatDate(item.receptionDate) }}
@@ -23,6 +24,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ReceptionData } from '~/services/dto/reception-data' import type { ReceptionData } from '~/services/dto/reception-data'
import { getReceptionList, deleteReception } from '~/services/reception' import { getReceptionList, deleteReception } from '~/services/reception'
import { useAuthStore } from '~/stores/auth'
const auth = useAuthStore()
const columns = [ const columns = [
{ key: 'receptionDate', label: 'Date et heure' }, { key: 'receptionDate', label: 'Date et heure' },
+5 -1
View File
@@ -18,7 +18,8 @@
v-for="shipment in shipmentList" v-for="shipment in shipmentList"
:key="shipment :key="shipment
.id" .id"
class="grid grid-cols-6 gap-4 px-4 py-3 text-sm hover:bg-slate-50 cursor-pointer border-t border-slate-200" class="grid grid-cols-6 gap-4 px-4 py-3 text-sm border-t border-slate-200"
:class="auth.canUseWorkflow ? 'hover:bg-slate-50 cursor-pointer' : ''"
role="button" role="button"
tabindex="0" tabindex="0"
@click="goShipment(shipment.id)" @click="goShipment(shipment.id)"
@@ -47,9 +48,11 @@
<script setup lang="ts"> <script setup lang="ts">
import type {ShipmentData} from "~/services/dto/shipment-data"; import type {ShipmentData} from "~/services/dto/shipment-data";
import {getShipmentList} from "~/services/shipment"; import {getShipmentList} from "~/services/shipment";
import { useAuthStore } from '~/stores/auth'
const shipmentList = ref<ShipmentData[]>() const shipmentList = ref<ShipmentData[]>()
const router = useRouter() const router = useRouter()
const auth = useAuthStore()
const formatWeighing = (shipment: ShipmentData) => { const formatWeighing = (shipment: ShipmentData) => {
const gross = shipment.weights?.find((weight) => weight.type === 'gross')?.weight const gross = shipment.weights?.find((weight) => weight.type === 'gross')?.weight
@@ -76,6 +79,7 @@ const formatShipmentLines = (shipment: ShipmentData) => {
} }
const goShipment = (id: number) => { const goShipment = (id: number) => {
if (!auth.canUseWorkflow) return
router.push(`/shipment/update/${id}`) router.push(`/shipment/update/${id}`)
} }
+5 -1
View File
@@ -4,7 +4,8 @@
:columns="columns" :columns="columns"
:items="shipmentList ?? []" :items="shipmentList ?? []"
route-prefix="/shipment" route-prefix="/shipment"
show-actions :show-actions="auth.canUseWorkflow"
:can-open-items="auth.canUseWorkflow"
> >
<template #cell-shipmentDate="{ item }"> <template #cell-shipmentDate="{ item }">
{{ formatDate(item.shipmentDate) }} {{ formatDate(item.shipmentDate) }}
@@ -35,6 +36,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ShipmentData } from '~/services/dto/shipment-data' import type { ShipmentData } from '~/services/dto/shipment-data'
import { getShipmentList, deleteShipment } from '~/services/shipment' import { getShipmentList, deleteShipment } from '~/services/shipment'
import { useAuthStore } from '~/stores/auth'
const auth = useAuthStore()
const columns = [ const columns = [
{ key: 'shipmentDate', label: 'Date et heure' }, { key: 'shipmentDate', label: 'Date et heure' },
+6 -1
View File
@@ -12,7 +12,12 @@ export const useAuthStore = defineStore('auth', {
}), }),
getters: { getters: {
isAuthenticated: (state) => Boolean(state.user), isAuthenticated: (state) => Boolean(state.user),
isAdmin: (state) => Boolean(state.user?.roles?.includes(ROLE[0].value)) isAdmin: (state) => Boolean(state.user?.roles?.includes(ROLE[0].value)),
isGuest: (state) => Boolean(state.user?.roles?.includes('ROLE_GUEST')),
canUseWorkflow: (state) => Boolean(
state.user?.roles?.includes(ROLE[0].value) ||
state.user?.roles?.includes('ROLE_USER')
)
}, },
actions: { actions: {
clearSession() { clearSession() {
+2 -1
View File
@@ -10,7 +10,8 @@ export const MERCHANDISE_TYPE_CODES = {
export const ROLE = [ export const ROLE = [
{ label: 'Administrateur', value: 'ROLE_ADMIN' }, { label: 'Administrateur', value: 'ROLE_ADMIN' },
{ label: 'Utilisateur', value: 'ROLE_USER' } { label: 'Utilisateur', value: 'ROLE_USER' },
{ label: 'Visiteur', value: 'ROLE_GUEST' }
] ]
export const SUPPLIER_CODE = { export const SUPPLIER_CODE = {
LIOT: 'LIOT' LIOT: 'LIOT'
+3
View File
@@ -35,9 +35,11 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
new Get( new Get(
requirements: ['id' => '\d+'], requirements: ['id' => '\d+'],
normalizationContext: ['groups' => ['reception:read']], normalizationContext: ['groups' => ['reception:read']],
security: "is_granted('ROLE_USER') or is_granted('ROLE_GUEST')",
), ),
new GetCollection( new GetCollection(
normalizationContext: ['groups' => ['reception:read']], normalizationContext: ['groups' => ['reception:read']],
security: "is_granted('ROLE_USER') or is_granted('ROLE_GUEST')",
), ),
new Post( new Post(
normalizationContext: ['groups' => ['reception:read']], normalizationContext: ['groups' => ['reception:read']],
@@ -70,6 +72,7 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
), ),
output: false, output: false,
provider: ReceptionReceiptProvider::class, provider: ReceptionReceiptProvider::class,
security: "is_granted('ROLE_USER') or is_granted('ROLE_GUEST')",
), ),
], ],
security: "is_granted('ROLE_USER')", security: "is_granted('ROLE_USER')",
+3
View File
@@ -35,9 +35,11 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
new Get( new Get(
requirements: ['id' => '\d+'], requirements: ['id' => '\d+'],
normalizationContext: ['groups' => ['shipment:read']], normalizationContext: ['groups' => ['shipment:read']],
security: "is_granted('ROLE_USER') or is_granted('ROLE_GUEST')",
), ),
new GetCollection( new GetCollection(
normalizationContext: ['groups' => ['shipment:read']], normalizationContext: ['groups' => ['shipment:read']],
security: "is_granted('ROLE_USER') or is_granted('ROLE_GUEST')",
), ),
new Post( new Post(
normalizationContext: ['groups' => ['shipment:read']], normalizationContext: ['groups' => ['shipment:read']],
@@ -70,6 +72,7 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
), ),
output: false, output: false,
provider: ShipmentReceiptProvider::class, provider: ShipmentReceiptProvider::class,
security: "is_granted('ROLE_USER') or is_granted('ROLE_GUEST')",
), ),
], ],
security: "is_granted('ROLE_USER')", security: "is_granted('ROLE_USER')",
+6 -3
View File
@@ -23,7 +23,7 @@ use Symfony\Component\Serializer\Attribute\Groups;
new Get( new Get(
uriTemplate: '/me', uriTemplate: '/me',
normalizationContext: ['groups' => ['user:read']], normalizationContext: ['groups' => ['user:read']],
security: "is_granted('ROLE_USER')", security: "is_granted('ROLE_USER') or is_granted('ROLE_GUEST')",
provider: MeProvider::class provider: MeProvider::class
), ),
new Get( new Get(
@@ -100,8 +100,11 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
public function getRoles(): array public function getRoles(): array
{ {
$roles = $this->roles; $roles = $this->roles;
$roles[] = 'ROLE_USER';
if (!in_array('ROLE_GUEST', $roles, true)) {
$roles[] = 'ROLE_USER';
}
return array_unique($roles); return array_unique($roles);
} }