fix(absences) : durcissement RGPD des données RH des utilisateurs
Suite à la revue de conformité du module absences.
Fuite corrigée : GET /api/users et /api/users/{id} n'avaient aucun contrôle
d'accès alors que le groupe user:list exposait les données RH/familiales
(date d'embauche, contrat, soldes de CP, rôles…). Tout utilisateur authentifié
pouvait donc lire ces informations sur tous ses collègues.
- chaque champ RH (isEmployee, hireDate, endDate, contractType, workTimeRatio,
annualLeaveDays, referencePeriodStart, initialLeaveBalance) ainsi que roles
est désormais exposé via #[ApiProperty(security: "is_granted('ROLE_ADMIN') or
object == user")] : visible uniquement par un admin ou par l'utilisateur
lui-même. id et username restent publics (sélecteurs d'assigné, avatars).
Minimisation : suppression de familySituation et nbChildren, collectés et
exposés (form RH, API, outil MCP) mais utilisés par aucun calcul.
- entité User + enum FamilySituation + migration de drop des colonnes
- Serializer MCP, update-user (MCP), EmployeeDrawer, DTO, fixtures, i18n
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,13 +24,6 @@
|
|||||||
empty-option-label="—"
|
empty-option-label="—"
|
||||||
group-class="w-full"
|
group-class="w-full"
|
||||||
/>
|
/>
|
||||||
<MalioSelect
|
|
||||||
v-model="form.familySituation"
|
|
||||||
:label="$t('absences.admin.employees.fields.familySituation')"
|
|
||||||
:options="familyOptions"
|
|
||||||
empty-option-label="—"
|
|
||||||
group-class="w-full"
|
|
||||||
/>
|
|
||||||
<MalioInputText
|
<MalioInputText
|
||||||
v-model="form.workTimeRatio"
|
v-model="form.workTimeRatio"
|
||||||
:label="$t('absences.admin.employees.fields.workTimeRatio')"
|
:label="$t('absences.admin.employees.fields.workTimeRatio')"
|
||||||
@@ -51,11 +44,6 @@
|
|||||||
:label="$t('absences.admin.employees.fields.initialLeaveBalance')"
|
:label="$t('absences.admin.employees.fields.initialLeaveBalance')"
|
||||||
input-class="w-full"
|
input-class="w-full"
|
||||||
/>
|
/>
|
||||||
<MalioInputText
|
|
||||||
v-model="form.nbChildren"
|
|
||||||
:label="$t('absences.admin.employees.fields.nbChildren')"
|
|
||||||
input-class="w-full"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="col-span-full mt-2 flex justify-end">
|
<div class="col-span-full mt-2 flex justify-end">
|
||||||
<MalioButton
|
<MalioButton
|
||||||
@@ -70,7 +58,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ContractType, FamilySituation, UserData } from '~/services/dto/user-data'
|
import type { ContractType, UserData } from '~/services/dto/user-data'
|
||||||
import { useUserService } from '~/services/users'
|
import { useUserService } from '~/services/users'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -101,24 +89,14 @@ const contractOptions = [
|
|||||||
{ label: t('absences.admin.employees.contract.autre'), value: 'AUTRE' },
|
{ label: t('absences.admin.employees.contract.autre'), value: 'AUTRE' },
|
||||||
]
|
]
|
||||||
|
|
||||||
const familyOptions = [
|
|
||||||
{ label: t('absences.admin.employees.family.celibataire'), value: 'CELIBATAIRE' },
|
|
||||||
{ label: t('absences.admin.employees.family.marie'), value: 'MARIE' },
|
|
||||||
{ label: t('absences.admin.employees.family.pacse'), value: 'PACSE' },
|
|
||||||
{ label: t('absences.admin.employees.family.divorce'), value: 'DIVORCE' },
|
|
||||||
{ label: t('absences.admin.employees.family.veuf'), value: 'VEUF' },
|
|
||||||
]
|
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
hireDate: null as string | null,
|
hireDate: null as string | null,
|
||||||
endDate: null as string | null,
|
endDate: null as string | null,
|
||||||
contractType: null as ContractType | null,
|
contractType: null as ContractType | null,
|
||||||
familySituation: null as FamilySituation | null,
|
|
||||||
workTimeRatio: '1.0',
|
workTimeRatio: '1.0',
|
||||||
annualLeaveDays: '25',
|
annualLeaveDays: '25',
|
||||||
referencePeriodStart: '06-01',
|
referencePeriodStart: '06-01',
|
||||||
initialLeaveBalance: '0',
|
initialLeaveBalance: '0',
|
||||||
nbChildren: '0',
|
|
||||||
})
|
})
|
||||||
|
|
||||||
function hydrate(u: UserData | null) {
|
function hydrate(u: UserData | null) {
|
||||||
@@ -126,12 +104,10 @@ function hydrate(u: UserData | null) {
|
|||||||
form.hireDate = u.hireDate ? u.hireDate.slice(0, 10) : null
|
form.hireDate = u.hireDate ? u.hireDate.slice(0, 10) : null
|
||||||
form.endDate = u.endDate ? u.endDate.slice(0, 10) : null
|
form.endDate = u.endDate ? u.endDate.slice(0, 10) : null
|
||||||
form.contractType = u.contractType ?? null
|
form.contractType = u.contractType ?? null
|
||||||
form.familySituation = u.familySituation ?? null
|
|
||||||
form.workTimeRatio = String(u.workTimeRatio ?? 1)
|
form.workTimeRatio = String(u.workTimeRatio ?? 1)
|
||||||
form.annualLeaveDays = String(u.annualLeaveDays ?? 25)
|
form.annualLeaveDays = String(u.annualLeaveDays ?? 25)
|
||||||
form.referencePeriodStart = u.referencePeriodStart ?? '06-01'
|
form.referencePeriodStart = u.referencePeriodStart ?? '06-01'
|
||||||
form.initialLeaveBalance = String(u.initialLeaveBalance ?? 0)
|
form.initialLeaveBalance = String(u.initialLeaveBalance ?? 0)
|
||||||
form.nbChildren = String(u.nbChildren ?? 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => props.modelValue, (isOpen) => {
|
watch(() => props.modelValue, (isOpen) => {
|
||||||
@@ -147,12 +123,10 @@ async function save() {
|
|||||||
hireDate: form.hireDate || null,
|
hireDate: form.hireDate || null,
|
||||||
endDate: form.endDate || null,
|
endDate: form.endDate || null,
|
||||||
contractType: form.contractType,
|
contractType: form.contractType,
|
||||||
familySituation: form.familySituation,
|
|
||||||
workTimeRatio: Number(form.workTimeRatio) || 1,
|
workTimeRatio: Number(form.workTimeRatio) || 1,
|
||||||
annualLeaveDays: Number(form.annualLeaveDays) || 0,
|
annualLeaveDays: Number(form.annualLeaveDays) || 0,
|
||||||
referencePeriodStart: form.referencePeriodStart || '06-01',
|
referencePeriodStart: form.referencePeriodStart || '06-01',
|
||||||
initialLeaveBalance: Number(form.initialLeaveBalance) || 0,
|
initialLeaveBalance: Number(form.initialLeaveBalance) || 0,
|
||||||
nbChildren: Number(form.nbChildren) || 0,
|
|
||||||
})
|
})
|
||||||
emit('saved')
|
emit('saved')
|
||||||
open.value = false
|
open.value = false
|
||||||
|
|||||||
@@ -703,12 +703,10 @@
|
|||||||
"hireDate": "Date d'embauche",
|
"hireDate": "Date d'embauche",
|
||||||
"endDate": "Date de sortie",
|
"endDate": "Date de sortie",
|
||||||
"contractType": "Type de contrat",
|
"contractType": "Type de contrat",
|
||||||
"familySituation": "Situation familiale",
|
|
||||||
"workTimeRatio": "Temps de travail (ex : 1.0)",
|
"workTimeRatio": "Temps de travail (ex : 1.0)",
|
||||||
"annualLeaveDays": "CP annuels (jours)",
|
"annualLeaveDays": "CP annuels (jours)",
|
||||||
"referencePeriodStart": "Début période réf. (MM-DD)",
|
"referencePeriodStart": "Début période réf. (MM-DD)",
|
||||||
"initialLeaveBalance": "Solde CP initial",
|
"initialLeaveBalance": "Solde CP initial"
|
||||||
"nbChildren": "Nombre d'enfants"
|
|
||||||
},
|
},
|
||||||
"contract": {
|
"contract": {
|
||||||
"cdi": "CDI",
|
"cdi": "CDI",
|
||||||
@@ -716,13 +714,6 @@
|
|||||||
"stage": "Stage",
|
"stage": "Stage",
|
||||||
"alternance": "Alternance",
|
"alternance": "Alternance",
|
||||||
"autre": "Autre"
|
"autre": "Autre"
|
||||||
},
|
|
||||||
"family": {
|
|
||||||
"celibataire": "Célibataire",
|
|
||||||
"marie": "Marié(e)",
|
|
||||||
"pacse": "Pacsé(e)",
|
|
||||||
"divorce": "Divorcé(e)",
|
|
||||||
"veuf": "Veuf(ve)"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
export type ContractType = 'CDI' | 'CDD' | 'STAGE' | 'ALTERNANCE' | 'AUTRE'
|
export type ContractType = 'CDI' | 'CDD' | 'STAGE' | 'ALTERNANCE' | 'AUTRE'
|
||||||
export type FamilySituation = 'CELIBATAIRE' | 'MARIE' | 'PACSE' | 'DIVORCE' | 'VEUF'
|
|
||||||
|
|
||||||
export type UserData = {
|
export type UserData = {
|
||||||
id: number
|
id: number
|
||||||
@@ -17,8 +16,6 @@ export type UserData = {
|
|||||||
annualLeaveDays?: number
|
annualLeaveDays?: number
|
||||||
referencePeriodStart?: string
|
referencePeriodStart?: string
|
||||||
initialLeaveBalance?: number
|
initialLeaveBalance?: number
|
||||||
familySituation?: FamilySituation | null
|
|
||||||
nbChildren?: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserWrite = {
|
export type UserWrite = {
|
||||||
@@ -34,6 +31,4 @@ export type UserWrite = {
|
|||||||
annualLeaveDays?: number
|
annualLeaveDays?: number
|
||||||
referencePeriodStart?: string
|
referencePeriodStart?: string
|
||||||
initialLeaveBalance?: number
|
initialLeaveBalance?: number
|
||||||
familySituation?: FamilySituation | null
|
|
||||||
nbChildren?: number
|
|
||||||
}
|
}
|
||||||
|
|||||||
33
migrations/Version20260522140000.php
Normal file
33
migrations/Version20260522140000.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGPD / minimisation : suppression des colonnes user.family_situation et
|
||||||
|
* user.nb_children. Ces données (situation familiale, nombre d'enfants)
|
||||||
|
* étaient collectées et exposées mais n'étaient utilisées par aucun calcul.
|
||||||
|
*/
|
||||||
|
final class Version20260522140000 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Drop unused HR fields user.family_situation and user.nb_children (data minimisation)';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE "user" DROP COLUMN IF EXISTS family_situation');
|
||||||
|
$this->addSql('ALTER TABLE "user" DROP COLUMN IF EXISTS nb_children');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE "user" ADD family_situation VARCHAR(16) DEFAULT NULL');
|
||||||
|
$this->addSql('ALTER TABLE "user" ADD nb_children INT NOT NULL DEFAULT 0');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,6 @@ use App\Entity\ZimbraConfiguration;
|
|||||||
use App\Enum\AbsenceStatus;
|
use App\Enum\AbsenceStatus;
|
||||||
use App\Enum\AbsenceType;
|
use App\Enum\AbsenceType;
|
||||||
use App\Enum\ContractType;
|
use App\Enum\ContractType;
|
||||||
use App\Enum\FamilySituation;
|
|
||||||
use App\Enum\RecurrenceType;
|
use App\Enum\RecurrenceType;
|
||||||
use App\Enum\StatusCategory;
|
use App\Enum\StatusCategory;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
@@ -670,20 +669,15 @@ class AppFixtures extends Fixture
|
|||||||
$admin->setIsEmployee(true);
|
$admin->setIsEmployee(true);
|
||||||
$admin->setHireDate(new DateTimeImmutable('2020-01-15'));
|
$admin->setHireDate(new DateTimeImmutable('2020-01-15'));
|
||||||
$admin->setContractType(ContractType::Cdi);
|
$admin->setContractType(ContractType::Cdi);
|
||||||
$admin->setFamilySituation(FamilySituation::Married);
|
|
||||||
$admin->setNbChildren(2);
|
|
||||||
|
|
||||||
$userAlice->setIsEmployee(true);
|
$userAlice->setIsEmployee(true);
|
||||||
$userAlice->setHireDate(new DateTimeImmutable('2022-09-01'));
|
$userAlice->setHireDate(new DateTimeImmutable('2022-09-01'));
|
||||||
$userAlice->setContractType(ContractType::Cdi);
|
$userAlice->setContractType(ContractType::Cdi);
|
||||||
$userAlice->setFamilySituation(FamilySituation::Single);
|
|
||||||
|
|
||||||
$userBob->setIsEmployee(true);
|
$userBob->setIsEmployee(true);
|
||||||
$userBob->setHireDate(new DateTimeImmutable('2023-03-10'));
|
$userBob->setHireDate(new DateTimeImmutable('2023-03-10'));
|
||||||
$userBob->setContractType(ContractType::Cdd);
|
$userBob->setContractType(ContractType::Cdd);
|
||||||
$userBob->setWorkTimeRatio(0.8);
|
$userBob->setWorkTimeRatio(0.8);
|
||||||
$userBob->setFamilySituation(FamilySituation::Pacsed);
|
|
||||||
$userBob->setNbChildren(1);
|
|
||||||
|
|
||||||
// Paid-leave balances for the current reference period (June 1st → May 31st)
|
// Paid-leave balances for the current reference period (June 1st → May 31st)
|
||||||
$cpPeriod = '2025-2026';
|
$cpPeriod = '2025-2026';
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Entity;
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use ApiPlatform\Metadata\ApiProperty;
|
||||||
use ApiPlatform\Metadata\ApiResource;
|
use ApiPlatform\Metadata\ApiResource;
|
||||||
use ApiPlatform\Metadata\Delete;
|
use ApiPlatform\Metadata\Delete;
|
||||||
use ApiPlatform\Metadata\Get;
|
use ApiPlatform\Metadata\Get;
|
||||||
@@ -11,7 +12,6 @@ use ApiPlatform\Metadata\GetCollection;
|
|||||||
use ApiPlatform\Metadata\Patch;
|
use ApiPlatform\Metadata\Patch;
|
||||||
use ApiPlatform\Metadata\Post;
|
use ApiPlatform\Metadata\Post;
|
||||||
use App\Enum\ContractType;
|
use App\Enum\ContractType;
|
||||||
use App\Enum\FamilySituation;
|
|
||||||
use App\Repository\UserRepository;
|
use App\Repository\UserRepository;
|
||||||
use App\State\MeProvider;
|
use App\State\MeProvider;
|
||||||
use App\State\UserPasswordHasherProcessor;
|
use App\State\UserPasswordHasherProcessor;
|
||||||
@@ -57,6 +57,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
|||||||
|
|
||||||
/** @var list<string> */
|
/** @var list<string> */
|
||||||
#[ORM\Column]
|
#[ORM\Column]
|
||||||
|
#[ApiProperty(security: "is_granted('ROLE_ADMIN') or object == user")]
|
||||||
#[Groups(['me:read', 'user:list', 'user:write'])]
|
#[Groups(['me:read', 'user:list', 'user:write'])]
|
||||||
private array $roles = [];
|
private array $roles = [];
|
||||||
|
|
||||||
@@ -76,54 +77,54 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
|||||||
#[ORM\Column(length: 255, nullable: true)]
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
private ?string $avatarFileName = null;
|
private ?string $avatarFileName = null;
|
||||||
|
|
||||||
// --- HR / absence management fields ---
|
// --- HR / absence management fields (readable only by an admin or the user themselves) ---
|
||||||
|
|
||||||
/** Whether this user is an employee subject to absence management. */
|
/** Whether this user is an employee subject to absence management. */
|
||||||
#[ORM\Column]
|
#[ORM\Column]
|
||||||
|
#[ApiProperty(security: "is_granted('ROLE_ADMIN') or object == user")]
|
||||||
#[Groups(['me:read', 'user:list', 'user:write'])]
|
#[Groups(['me:read', 'user:list', 'user:write'])]
|
||||||
private bool $isEmployee = false;
|
private bool $isEmployee = false;
|
||||||
|
|
||||||
/** Hiring date — start of paid-leave acquisition. */
|
/** Hiring date — start of paid-leave acquisition. */
|
||||||
#[ORM\Column(type: Types::DATE_IMMUTABLE, nullable: true)]
|
#[ORM\Column(type: Types::DATE_IMMUTABLE, nullable: true)]
|
||||||
|
#[ApiProperty(security: "is_granted('ROLE_ADMIN') or object == user")]
|
||||||
#[Groups(['me:read', 'user:list', 'user:write'])]
|
#[Groups(['me:read', 'user:list', 'user:write'])]
|
||||||
private ?DateTimeImmutable $hireDate = null;
|
private ?DateTimeImmutable $hireDate = null;
|
||||||
|
|
||||||
#[ORM\Column(type: Types::DATE_IMMUTABLE, nullable: true)]
|
#[ORM\Column(type: Types::DATE_IMMUTABLE, nullable: true)]
|
||||||
|
#[ApiProperty(security: "is_granted('ROLE_ADMIN') or object == user")]
|
||||||
#[Groups(['me:read', 'user:list', 'user:write'])]
|
#[Groups(['me:read', 'user:list', 'user:write'])]
|
||||||
private ?DateTimeImmutable $endDate = null;
|
private ?DateTimeImmutable $endDate = null;
|
||||||
|
|
||||||
#[ORM\Column(type: Types::STRING, length: 16, nullable: true, enumType: ContractType::class)]
|
#[ORM\Column(type: Types::STRING, length: 16, nullable: true, enumType: ContractType::class)]
|
||||||
|
#[ApiProperty(security: "is_granted('ROLE_ADMIN') or object == user")]
|
||||||
#[Groups(['me:read', 'user:list', 'user:write'])]
|
#[Groups(['me:read', 'user:list', 'user:write'])]
|
||||||
private ?ContractType $contractType = null;
|
private ?ContractType $contractType = null;
|
||||||
|
|
||||||
/** Work-time ratio: 1.0 = full time, 0.8 = 4 days out of 5. */
|
/** Work-time ratio: 1.0 = full time, 0.8 = 4 days out of 5. */
|
||||||
#[ORM\Column(type: Types::FLOAT)]
|
#[ORM\Column(type: Types::FLOAT)]
|
||||||
|
#[ApiProperty(security: "is_granted('ROLE_ADMIN') or object == user")]
|
||||||
#[Groups(['me:read', 'user:list', 'user:write'])]
|
#[Groups(['me:read', 'user:list', 'user:write'])]
|
||||||
private float $workTimeRatio = 1.0;
|
private float $workTimeRatio = 1.0;
|
||||||
|
|
||||||
/** Yearly paid-leave entitlement in worked days (default 25 = jours ouvrés). */
|
/** Yearly paid-leave entitlement in worked days (default 25 = jours ouvrés). */
|
||||||
#[ORM\Column(type: Types::FLOAT)]
|
#[ORM\Column(type: Types::FLOAT)]
|
||||||
|
#[ApiProperty(security: "is_granted('ROLE_ADMIN') or object == user")]
|
||||||
#[Groups(['me:read', 'user:list', 'user:write'])]
|
#[Groups(['me:read', 'user:list', 'user:write'])]
|
||||||
private float $annualLeaveDays = 25.0;
|
private float $annualLeaveDays = 25.0;
|
||||||
|
|
||||||
/** Reference period start as MM-DD (default 06-01, 1st of June). */
|
/** Reference period start as MM-DD (default 06-01, 1st of June). */
|
||||||
#[ORM\Column(length: 5)]
|
#[ORM\Column(length: 5)]
|
||||||
|
#[ApiProperty(security: "is_granted('ROLE_ADMIN') or object == user")]
|
||||||
#[Groups(['me:read', 'user:list', 'user:write'])]
|
#[Groups(['me:read', 'user:list', 'user:write'])]
|
||||||
private string $referencePeriodStart = '06-01';
|
private string $referencePeriodStart = '06-01';
|
||||||
|
|
||||||
/** Paid-leave already acquired when the module is rolled out. */
|
/** Paid-leave already acquired when the module is rolled out. */
|
||||||
#[ORM\Column(type: Types::FLOAT)]
|
#[ORM\Column(type: Types::FLOAT)]
|
||||||
|
#[ApiProperty(security: "is_granted('ROLE_ADMIN') or object == user")]
|
||||||
#[Groups(['me:read', 'user:list', 'user:write'])]
|
#[Groups(['me:read', 'user:list', 'user:write'])]
|
||||||
private float $initialLeaveBalance = 0.0;
|
private float $initialLeaveBalance = 0.0;
|
||||||
|
|
||||||
#[ORM\Column(type: Types::STRING, length: 16, nullable: true, enumType: FamilySituation::class)]
|
|
||||||
#[Groups(['me:read', 'user:list', 'user:write'])]
|
|
||||||
private ?FamilySituation $familySituation = null;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['me:read', 'user:list', 'user:write'])]
|
|
||||||
private int $nbChildren = 0;
|
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->createdAt = new DateTimeImmutable();
|
$this->createdAt = new DateTimeImmutable();
|
||||||
@@ -338,28 +339,4 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFamilySituation(): ?FamilySituation
|
|
||||||
{
|
|
||||||
return $this->familySituation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setFamilySituation(?FamilySituation $familySituation): static
|
|
||||||
{
|
|
||||||
$this->familySituation = $familySituation;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNbChildren(): int
|
|
||||||
{
|
|
||||||
return $this->nbChildren;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setNbChildren(int $nbChildren): static
|
|
||||||
{
|
|
||||||
$this->nbChildren = $nbChildren;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Enum;
|
|
||||||
|
|
||||||
enum FamilySituation: string
|
|
||||||
{
|
|
||||||
case Single = 'CELIBATAIRE';
|
|
||||||
case Married = 'MARIE';
|
|
||||||
case Pacsed = 'PACSE';
|
|
||||||
case Divorced = 'DIVORCE';
|
|
||||||
case Widowed = 'VEUF';
|
|
||||||
|
|
||||||
public function label(): string
|
|
||||||
{
|
|
||||||
return match ($this) {
|
|
||||||
self::Single => 'Célibataire',
|
|
||||||
self::Married => 'Marié(e)',
|
|
||||||
self::Pacsed => 'Pacsé(e)',
|
|
||||||
self::Divorced => 'Divorcé(e)',
|
|
||||||
self::Widowed => 'Veuf(ve)',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||||||
namespace App\Mcp\Tool\Reference;
|
namespace App\Mcp\Tool\Reference;
|
||||||
|
|
||||||
use App\Enum\ContractType;
|
use App\Enum\ContractType;
|
||||||
use App\Enum\FamilySituation;
|
|
||||||
use App\Mcp\Tool\Serializer;
|
use App\Mcp\Tool\Serializer;
|
||||||
use App\Repository\UserRepository;
|
use App\Repository\UserRepository;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
@@ -17,7 +16,7 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
|||||||
|
|
||||||
use function sprintf;
|
use function sprintf;
|
||||||
|
|
||||||
#[McpTool(name: 'update-user', description: 'Update a user HR/profile fields (admin). Does NOT change password or roles. contractType = CDI|CDD|STAGE|ALTERNANCE|AUTRE. familySituation = CELIBATAIRE|MARIE|PACSE|DIVORCE|VEUF. hireDate/endDate as YYYY-MM-DD. referencePeriodStart as MM-DD (e.g. 06-01).')]
|
#[McpTool(name: 'update-user', description: 'Update a user HR/profile fields (admin). Does NOT change password or roles. contractType = CDI|CDD|STAGE|ALTERNANCE|AUTRE. hireDate/endDate as YYYY-MM-DD. referencePeriodStart as MM-DD (e.g. 06-01).')]
|
||||||
class UpdateUserTool
|
class UpdateUserTool
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@@ -36,8 +35,6 @@ class UpdateUserTool
|
|||||||
?float $annualLeaveDays = null,
|
?float $annualLeaveDays = null,
|
||||||
?string $referencePeriodStart = null,
|
?string $referencePeriodStart = null,
|
||||||
?float $initialLeaveBalance = null,
|
?float $initialLeaveBalance = null,
|
||||||
?string $familySituation = null,
|
|
||||||
?int $nbChildren = null,
|
|
||||||
): string {
|
): string {
|
||||||
if (!$this->security->isGranted('ROLE_ADMIN')) {
|
if (!$this->security->isGranted('ROLE_ADMIN')) {
|
||||||
throw new AccessDeniedException('Access denied: ROLE_ADMIN required.');
|
throw new AccessDeniedException('Access denied: ROLE_ADMIN required.');
|
||||||
@@ -75,15 +72,6 @@ class UpdateUserTool
|
|||||||
if (null !== $initialLeaveBalance) {
|
if (null !== $initialLeaveBalance) {
|
||||||
$user->setInitialLeaveBalance($initialLeaveBalance);
|
$user->setInitialLeaveBalance($initialLeaveBalance);
|
||||||
}
|
}
|
||||||
if (null !== $familySituation) {
|
|
||||||
$user->setFamilySituation(
|
|
||||||
FamilySituation::tryFrom($familySituation)
|
|
||||||
?? throw new InvalidArgumentException(sprintf('Unknown family situation "%s".', $familySituation)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (null !== $nbChildren) {
|
|
||||||
$user->setNbChildren($nbChildren);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->entityManager->flush();
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
|||||||
@@ -389,8 +389,6 @@ final class Serializer
|
|||||||
'annualLeaveDays' => $u->getAnnualLeaveDays(),
|
'annualLeaveDays' => $u->getAnnualLeaveDays(),
|
||||||
'referencePeriodStart' => $u->getReferencePeriodStart(),
|
'referencePeriodStart' => $u->getReferencePeriodStart(),
|
||||||
'initialLeaveBalance' => $u->getInitialLeaveBalance(),
|
'initialLeaveBalance' => $u->getInitialLeaveBalance(),
|
||||||
'familySituation' => $u->getFamilySituation()?->value,
|
|
||||||
'nbChildren' => $u->getNbChildren(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user