Compare commits

..

2 Commits

Author SHA1 Message Date
Lethary 25b1749bdd fix : fixtures users
Auto Tag Develop / tag (push) Has been cancelled
2026-05-07 23:15:20 +02:00
Lethary fa1f0ccaa4 feat : add role guest
Auto Tag Develop / tag (push) Has been cancelled
2026-05-05 15:51:58 +02:00
16 changed files with 98 additions and 29 deletions
+1
View File
@@ -7,6 +7,7 @@
"php": ">=8.4",
"ext-ctype": "*",
"ext-iconv": "*",
"ext-soap": "*",
"api-platform/doctrine-orm": "^4.2",
"api-platform/symfony": "^4.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",
"This file is @generated automatically"
],
"content-hash": "9c04091eea0e10c19713a1d882b04f91",
"content-hash": "9a85291a52081179f427fa0c2b60d061",
"packages": [
{
"name": "api-platform/doctrine-common",
@@ -11664,7 +11664,8 @@
"platform": {
"php": ">=8.4",
"ext-ctype": "*",
"ext-iconv": "*"
"ext-iconv": "*",
"ext-soap": "*"
},
"platform-dev": {},
"plugin-api-version": "2.9.0"
@@ -18,7 +18,8 @@
<div
v-for="item in items"
: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 }"
role="button"
tabindex="0"
@@ -50,8 +51,10 @@ const props = withDefaults(defineProps<{
items: any[]
routePrefix: string
showActions?: boolean
canOpenItems?: boolean
}>(), {
showActions: false
showActions: false,
canOpenItems: true
})
const router = useRouter()
@@ -62,6 +65,9 @@ const gridCols = computed(() => {
})
const goToItem = (id: number) => {
if (!props.canOpenItems) {
return
}
router.push(`${props.routePrefix}/${id}`)
}
+11
View File
@@ -2,6 +2,13 @@ import { useAuthStore } from '~/stores/auth'
export default defineNuxtRouteMiddleware(async (to) => {
const auth = useAuthStore()
const guestAllowedPaths = [
'/',
'/reception/waiting-reception',
'/reception/finish-reception',
'/shipment/waiting-shipment',
'/shipment/finish-shipment'
]
if (to.path === '/login') {
return
@@ -14,4 +21,8 @@ export default defineNuxtRouteMiddleware(async (to) => {
if (!auth.isAuthenticated) {
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
form.username = user.username ?? ''
const roles = user.roles ?? []
const hasAdmin = roles.includes('ROLE_ADMIN')
form.role = hasAdmin ? 'ROLE_ADMIN' : 'ROLE_USER'
form.role = ROLE.find((role) => roles.includes(role.value))?.value ?? 'ROLE_USER'
form.password = ''
isHydrating.value = false
}
+8 -5
View File
@@ -1,10 +1,13 @@
<script setup lang="ts">
import { useAuthStore } from '~/stores/auth'
const auth = useAuthStore()
</script>
<template>
<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 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="NOUVELLE RÉCEPTION" link="/reception" iconName="mdi:truck-outline" />
<card-link v-if="auth.canUseWorkflow" label="NOUVELLE EXPÉDITION" link="/shipment" iconName="mdi:truck-fast-outline" />
<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">
<template #label>
Réceptions<br>EN ATTENTE
@@ -15,10 +18,10 @@
EXPÉDITIONS<br>EN ATTENTE
</template>
</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="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>
PASSEPORT<br>DU BOVIN
</template>
@@ -17,7 +17,8 @@
<div
v-for="reception in receptionList"
: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"
tabindex="0"
@click="goToReception(reception.id)"
@@ -36,10 +37,11 @@
<script setup lang="ts">
import type {ReceptionData} from "~/services/dto/reception-data";
import {getReceptionList} from "~/services/reception";
import type {ShipmentData} from "~/services/dto/shipment-data";
import { useAuthStore } from '~/stores/auth'
const receptionList = ref<ReceptionData[]>()
const router = useRouter()
const auth = useAuthStore()
const formatDate = (date: string | null) => {
if (!date) return '—'
@@ -66,6 +68,7 @@ const formatWeighing = (reception: ReceptionData) => {
}
const goToReception = (id: number) => {
if (!auth.canUseWorkflow) return
router.push(`/reception/update/${id}`)
}
@@ -4,7 +4,8 @@
:columns="columns"
:items="receptionList ?? []"
route-prefix="/reception"
show-actions
:show-actions="auth.canUseWorkflow"
:can-open-items="auth.canUseWorkflow"
>
<template #cell-receptionDate="{ item }">
{{ formatDate(item.receptionDate) }}
@@ -23,6 +24,9 @@
<script setup lang="ts">
import type { ReceptionData } from '~/services/dto/reception-data'
import { getReceptionList, deleteReception } from '~/services/reception'
import { useAuthStore } from '~/stores/auth'
const auth = useAuthStore()
const columns = [
{ key: 'receptionDate', label: 'Date et heure' },
+5 -1
View File
@@ -18,7 +18,8 @@
v-for="shipment in shipmentList"
:key="shipment
.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"
tabindex="0"
@click="goShipment(shipment.id)"
@@ -47,9 +48,11 @@
<script setup lang="ts">
import type {ShipmentData} from "~/services/dto/shipment-data";
import {getShipmentList} from "~/services/shipment";
import { useAuthStore } from '~/stores/auth'
const shipmentList = ref<ShipmentData[]>()
const router = useRouter()
const auth = useAuthStore()
const formatWeighing = (shipment: ShipmentData) => {
const gross = shipment.weights?.find((weight) => weight.type === 'gross')?.weight
@@ -76,6 +79,7 @@ const formatShipmentLines = (shipment: ShipmentData) => {
}
const goShipment = (id: number) => {
if (!auth.canUseWorkflow) return
router.push(`/shipment/update/${id}`)
}
+5 -1
View File
@@ -4,7 +4,8 @@
:columns="columns"
:items="shipmentList ?? []"
route-prefix="/shipment"
show-actions
:show-actions="auth.canUseWorkflow"
:can-open-items="auth.canUseWorkflow"
>
<template #cell-shipmentDate="{ item }">
{{ formatDate(item.shipmentDate) }}
@@ -35,6 +36,9 @@
<script setup lang="ts">
import type { ShipmentData } from '~/services/dto/shipment-data'
import { getShipmentList, deleteShipment } from '~/services/shipment'
import { useAuthStore } from '~/stores/auth'
const auth = useAuthStore()
const columns = [
{ key: 'shipmentDate', label: 'Date et heure' },
+6 -1
View File
@@ -12,7 +12,12 @@ export const useAuthStore = defineStore('auth', {
}),
getters: {
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: {
clearSession() {
+2 -1
View File
@@ -10,7 +10,8 @@ export const MERCHANDISE_TYPE_CODES = {
export const ROLE = [
{ label: 'Administrateur', value: 'ROLE_ADMIN' },
{ label: 'Utilisateur', value: 'ROLE_USER' }
{ label: 'Utilisateur', value: 'ROLE_USER' },
{ label: 'Visiteur', value: 'ROLE_GUEST' }
]
export const SUPPLIER_CODE = {
LIOT: 'LIOT'
+26 -8
View File
@@ -12,16 +12,34 @@ class UserFixtures extends Fixture
{
public function load(ObjectManager $manager): void
{
$admin = new User()
->setUsername('admin')
->setRoles(['ROLE_ADMIN'])
;
$users = [
[
'username' => 'Administrateur',
'roles' => ['ROLE_ADMIN'],
'password' => '$2a$12$YN8atYluuyp8LmsbeH0/Ku6ok3uOKEpozcuSaEHK7LxCOuAtMsaYC',
],
[
'username' => 'Bob',
'roles' => ['ROLE_USER'],
'password' => '$2a$12$zHYAOoGhLvYR6Ve.X24aae40i/bUoz6FKAqehqSwM/82igLIH/zY2',
],
[
'username' => 'Pierre',
'roles' => ['ROLE_GUEST'],
'password' => '$2a$12$PCh5L9MkutIHSZ21rVv8sOIxRAr2MJMXpmsg7q.xDcVuFm50BldrO',
],
];
$admin->setPassword(
'$2y$13$ZuB4LRD1i5Arc34CEO54FeUyQaIf3jamLf6caFK9v8TBMA5RcmIke'
);
foreach ($users as $userData) {
$user = new User()
->setUsername($userData['username'])
->setRoles($userData['roles'])
->setPassword($userData['password'])
;
$manager->persist($user);
}
$manager->persist($admin);
$manager->flush();
}
}
+3
View File
@@ -35,9 +35,11 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
new Get(
requirements: ['id' => '\d+'],
normalizationContext: ['groups' => ['reception:read']],
security: "is_granted('ROLE_USER') or is_granted('ROLE_GUEST')",
),
new GetCollection(
normalizationContext: ['groups' => ['reception:read']],
security: "is_granted('ROLE_USER') or is_granted('ROLE_GUEST')",
),
new Post(
normalizationContext: ['groups' => ['reception:read']],
@@ -70,6 +72,7 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
),
output: false,
provider: ReceptionReceiptProvider::class,
security: "is_granted('ROLE_USER') or is_granted('ROLE_GUEST')",
),
],
security: "is_granted('ROLE_USER')",
+3
View File
@@ -35,9 +35,11 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
new Get(
requirements: ['id' => '\d+'],
normalizationContext: ['groups' => ['shipment:read']],
security: "is_granted('ROLE_USER') or is_granted('ROLE_GUEST')",
),
new GetCollection(
normalizationContext: ['groups' => ['shipment:read']],
security: "is_granted('ROLE_USER') or is_granted('ROLE_GUEST')",
),
new Post(
normalizationContext: ['groups' => ['shipment:read']],
@@ -70,6 +72,7 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
),
output: false,
provider: ShipmentReceiptProvider::class,
security: "is_granted('ROLE_USER') or is_granted('ROLE_GUEST')",
),
],
security: "is_granted('ROLE_USER')",
+6 -3
View File
@@ -23,7 +23,7 @@ use Symfony\Component\Serializer\Attribute\Groups;
new Get(
uriTemplate: '/me',
normalizationContext: ['groups' => ['user:read']],
security: "is_granted('ROLE_USER')",
security: "is_granted('ROLE_USER') or is_granted('ROLE_GUEST')",
provider: MeProvider::class
),
new Get(
@@ -100,8 +100,11 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
public function getRoles(): array
{
$roles = $this->roles;
$roles[] = 'ROLE_USER';
$roles = $this->roles;
if (!in_array('ROLE_GUEST', $roles, true)) {
$roles[] = 'ROLE_USER';
}
return array_unique($roles);
}