fix(rbac) : enforce granular permissions on business resources
Les ressources métier (ProjectManagement, Directory, TimeTracking) étaient
gardées par is_granted('ROLE_USER')/'ROLE_ADMIN', ignorant les permissions
RBAC granulaires déclarées par les modules : un utilisateur sans permission
voyait quand même projets, tâches, clients, etc.
- PermissionVoter : le regex excluait les tirets, donc project-management.* et
time-tracking.* n'étaient supportées par aucun voter (refus pour tous, admin
compris car le bypass ROLE_ADMIN est interne au voter). Ajout du tiret.
- Câblage des permissions *.view (lecture) / *.manage (écriture) sur les 17
ressources métier. Métadonnées tâches lisibles via projects.view OR tasks.view.
Directory partagé client/prospect via clients.* OR prospects.*. TimeEntry
conserve le self-service (object.getUser() == user).
- Sidebar : gating par permission effective des onglets Projets / Mes tâches /
Suivi du temps (config/sidebar.php).
- Test fonctionnel ProjectAccessControlTest (0 perm -> 403, view -> 200,
view ne donne pas l'écriture -> 403).
This commit is contained in:
@@ -14,7 +14,9 @@ use Symfony\Component\Security\Core\Authorization\Voter\Voter;
|
||||
*/
|
||||
final class PermissionVoter extends Voter
|
||||
{
|
||||
private const string PATTERN = '/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/';
|
||||
// Les codes de permission sont au format module.resource.action où chaque
|
||||
// segment peut contenir des tirets (ex. project-management, time-tracking).
|
||||
private const string PATTERN = '/^[a-z][a-z0-9_-]*(\.[a-z][a-z0-9_-]*)+$/';
|
||||
|
||||
protected function supports(string $attribute, mixed $subject): bool
|
||||
{
|
||||
|
||||
@@ -23,11 +23,11 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
#[Auditable]
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new Post(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')"),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('directory.clients.view') or is_granted('directory.prospects.view')"),
|
||||
new Get(security: "is_granted('directory.clients.view') or is_granted('directory.prospects.view')"),
|
||||
new Post(security: "is_granted('directory.clients.manage') or is_granted('directory.prospects.manage')"),
|
||||
new Patch(security: "is_granted('directory.clients.manage') or is_granted('directory.prospects.manage')"),
|
||||
new Delete(security: "is_granted('directory.clients.manage') or is_granted('directory.prospects.manage')"),
|
||||
],
|
||||
normalizationContext: ['groups' => ['address:read']],
|
||||
denormalizationContext: ['groups' => ['address:write']],
|
||||
|
||||
@@ -25,11 +25,11 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
#[Auditable]
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new Post(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')"),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('directory.clients.view')"),
|
||||
new Get(security: "is_granted('directory.clients.view')"),
|
||||
new Post(security: "is_granted('directory.clients.manage')"),
|
||||
new Patch(security: "is_granted('directory.clients.manage')"),
|
||||
new Delete(security: "is_granted('directory.clients.manage')"),
|
||||
],
|
||||
normalizationContext: ['groups' => ['client:read']],
|
||||
denormalizationContext: ['groups' => ['client:write']],
|
||||
|
||||
@@ -26,11 +26,11 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new Post(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')"),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('directory.clients.view') or is_granted('directory.prospects.view')"),
|
||||
new Get(security: "is_granted('directory.clients.view') or is_granted('directory.prospects.view')"),
|
||||
new Post(security: "is_granted('directory.clients.manage') or is_granted('directory.prospects.manage')"),
|
||||
new Patch(security: "is_granted('directory.clients.manage') or is_granted('directory.prospects.manage')"),
|
||||
new Delete(security: "is_granted('directory.clients.manage') or is_granted('directory.prospects.manage')"),
|
||||
],
|
||||
normalizationContext: ['groups' => ['commercial_report:read']],
|
||||
denormalizationContext: ['groups' => ['commercial_report:write']],
|
||||
|
||||
@@ -23,11 +23,11 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
#[Auditable]
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new Post(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')"),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('directory.clients.view') or is_granted('directory.prospects.view')"),
|
||||
new Get(security: "is_granted('directory.clients.view') or is_granted('directory.prospects.view')"),
|
||||
new Post(security: "is_granted('directory.clients.manage') or is_granted('directory.prospects.manage')"),
|
||||
new Patch(security: "is_granted('directory.clients.manage') or is_granted('directory.prospects.manage')"),
|
||||
new Delete(security: "is_granted('directory.clients.manage') or is_granted('directory.prospects.manage')"),
|
||||
],
|
||||
normalizationContext: ['groups' => ['contact:read']],
|
||||
denormalizationContext: ['groups' => ['contact:write']],
|
||||
|
||||
@@ -27,14 +27,14 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
#[Auditable]
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new Post(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')"),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('directory.prospects.view')"),
|
||||
new Get(security: "is_granted('directory.prospects.view')"),
|
||||
new Post(security: "is_granted('directory.prospects.manage')"),
|
||||
new Patch(security: "is_granted('directory.prospects.manage')"),
|
||||
new Delete(security: "is_granted('directory.prospects.manage')"),
|
||||
new Post(
|
||||
uriTemplate: '/prospects/{id}/convert',
|
||||
security: "is_granted('ROLE_ADMIN')",
|
||||
security: "is_granted('directory.prospects.manage')",
|
||||
processor: ConvertProspectProcessor::class,
|
||||
),
|
||||
],
|
||||
|
||||
@@ -20,14 +20,14 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('directory.clients.view') or is_granted('directory.prospects.view')"),
|
||||
new Get(security: "is_granted('directory.clients.view') or is_granted('directory.prospects.view')"),
|
||||
new Post(
|
||||
security: "is_granted('ROLE_ADMIN')",
|
||||
security: "is_granted('directory.clients.manage') or is_granted('directory.prospects.manage')",
|
||||
processor: ReportDocumentProcessor::class,
|
||||
deserialize: false,
|
||||
),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('directory.clients.manage') or is_granted('directory.prospects.manage')"),
|
||||
],
|
||||
normalizationContext: ['groups' => ['report_document:read']],
|
||||
denormalizationContext: ['groups' => ['report_document:write']],
|
||||
|
||||
@@ -30,18 +30,18 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('project-management.projects.view')"),
|
||||
new Get(security: "is_granted('project-management.projects.view')"),
|
||||
new Post(
|
||||
security: "is_granted('ROLE_ADMIN')",
|
||||
security: "is_granted('project-management.projects.manage')",
|
||||
denormalizationContext: ['groups' => ['project:write', 'project:create']],
|
||||
),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Patch(security: "is_granted('project-management.projects.manage')"),
|
||||
new Delete(security: "is_granted('project-management.projects.manage')"),
|
||||
new Post(
|
||||
uriTemplate: '/projects/{id}/switch-workflow',
|
||||
uriVariables: ['id' => new Link(fromClass: Project::class)],
|
||||
security: "is_granted('ROLE_ADMIN')",
|
||||
security: "is_granted('project-management.projects.manage')",
|
||||
input: false,
|
||||
output: SwitchWorkflowOutput::class,
|
||||
normalizationContext: ['groups' => ['switch_workflow:read']],
|
||||
|
||||
@@ -33,11 +33,11 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new Post(security: "is_granted('ROLE_ADMIN')", processor: TaskNumberProcessor::class),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN')", processor: TaskCalendarProcessor::class),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')", processor: TaskCalendarProcessor::class),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('project-management.tasks.view')"),
|
||||
new Get(security: "is_granted('project-management.tasks.view')"),
|
||||
new Post(security: "is_granted('project-management.tasks.manage')", processor: TaskNumberProcessor::class),
|
||||
new Patch(security: "is_granted('project-management.tasks.manage')", processor: TaskCalendarProcessor::class),
|
||||
new Delete(security: "is_granted('project-management.tasks.manage')", processor: TaskCalendarProcessor::class),
|
||||
],
|
||||
normalizationContext: ['groups' => ['task:read']],
|
||||
denormalizationContext: ['groups' => ['task:write']],
|
||||
|
||||
@@ -21,14 +21,14 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')", provider: TaskDocumentProvider::class),
|
||||
new Get(security: "is_granted('ROLE_USER')", provider: TaskDocumentProvider::class),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('project-management.tasks.view')", provider: TaskDocumentProvider::class),
|
||||
new Get(security: "is_granted('project-management.tasks.view')", provider: TaskDocumentProvider::class),
|
||||
new Post(
|
||||
security: "is_granted('ROLE_ADMIN')",
|
||||
security: "is_granted('project-management.tasks.manage')",
|
||||
processor: TaskDocumentProcessor::class,
|
||||
deserialize: false,
|
||||
),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('project-management.tasks.manage')"),
|
||||
],
|
||||
normalizationContext: ['groups' => ['task_document:read']],
|
||||
denormalizationContext: ['groups' => ['task_document:write']],
|
||||
|
||||
@@ -16,11 +16,11 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new Post(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')"),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('project-management.projects.view') or is_granted('project-management.tasks.view')"),
|
||||
new Get(security: "is_granted('project-management.projects.view') or is_granted('project-management.tasks.view')"),
|
||||
new Post(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
new Patch(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
new Delete(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
],
|
||||
normalizationContext: ['groups' => ['task_effort:read']],
|
||||
denormalizationContext: ['groups' => ['task_effort:write']],
|
||||
|
||||
@@ -19,11 +19,11 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new Post(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')"),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('project-management.projects.view') or is_granted('project-management.tasks.view')"),
|
||||
new Get(security: "is_granted('project-management.projects.view') or is_granted('project-management.tasks.view')"),
|
||||
new Post(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
new Patch(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
new Delete(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
],
|
||||
normalizationContext: ['groups' => ['task_group:read']],
|
||||
denormalizationContext: ['groups' => ['task_group:write']],
|
||||
|
||||
@@ -16,11 +16,11 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new Post(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')"),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('project-management.projects.view') or is_granted('project-management.tasks.view')"),
|
||||
new Get(security: "is_granted('project-management.projects.view') or is_granted('project-management.tasks.view')"),
|
||||
new Post(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
new Patch(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
new Delete(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
],
|
||||
normalizationContext: ['groups' => ['task_priority:read']],
|
||||
denormalizationContext: ['groups' => ['task_priority:write']],
|
||||
|
||||
@@ -20,11 +20,11 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new Post(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')"),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('project-management.projects.view') or is_granted('project-management.tasks.view')"),
|
||||
new Get(security: "is_granted('project-management.projects.view') or is_granted('project-management.tasks.view')"),
|
||||
new Post(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
new Patch(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
new Delete(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
],
|
||||
normalizationContext: ['groups' => ['task_recurrence:read']],
|
||||
denormalizationContext: ['groups' => ['task_recurrence:write']],
|
||||
|
||||
@@ -18,11 +18,11 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new Post(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')"),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('project-management.projects.view') or is_granted('project-management.tasks.view')"),
|
||||
new Get(security: "is_granted('project-management.projects.view') or is_granted('project-management.tasks.view')"),
|
||||
new Post(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
new Patch(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
new Delete(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
],
|
||||
normalizationContext: ['groups' => ['task_status:read']],
|
||||
denormalizationContext: ['groups' => ['task_status:write']],
|
||||
|
||||
@@ -17,11 +17,11 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new Post(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')"),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('project-management.projects.view') or is_granted('project-management.tasks.view')"),
|
||||
new Get(security: "is_granted('project-management.projects.view') or is_granted('project-management.tasks.view')"),
|
||||
new Post(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
new Patch(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
new Delete(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
],
|
||||
normalizationContext: ['groups' => ['task_tag:read']],
|
||||
denormalizationContext: ['groups' => ['task_tag:write']],
|
||||
|
||||
@@ -21,11 +21,11 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new Post(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN')"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN')", processor: WorkflowDeleteProcessor::class),
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('project-management.projects.view') or is_granted('project-management.tasks.view')"),
|
||||
new Get(security: "is_granted('project-management.projects.view') or is_granted('project-management.tasks.view')"),
|
||||
new Post(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
new Patch(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')"),
|
||||
new Delete(security: "is_granted('project-management.projects.manage') or is_granted('project-management.tasks.manage')", processor: WorkflowDeleteProcessor::class),
|
||||
],
|
||||
normalizationContext: ['groups' => ['workflow:read']],
|
||||
denormalizationContext: ['groups' => ['workflow:write']],
|
||||
|
||||
@@ -31,13 +31,13 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(security: "is_granted('ROLE_USER')"),
|
||||
new GetCollection(security: "is_granted('time-tracking.entries.view')"),
|
||||
new GetCollection(
|
||||
name: 'time_entries_range',
|
||||
uriTemplate: '/time_entries/range',
|
||||
description: 'List time entries for a bounded date range without pagination (used by the time-tracking calendar)',
|
||||
paginationEnabled: false,
|
||||
security: "is_granted('ROLE_USER')",
|
||||
security: "is_granted('time-tracking.entries.view')",
|
||||
),
|
||||
new GetCollection(
|
||||
name: 'active_time_entry',
|
||||
@@ -45,12 +45,12 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
provider: ActiveTimeEntryProvider::class,
|
||||
description: 'Get the active timer for the current user',
|
||||
paginationEnabled: false,
|
||||
security: "is_granted('ROLE_USER')",
|
||||
security: "is_granted('time-tracking.entries.view')",
|
||||
),
|
||||
new Get(security: "is_granted('ROLE_USER')"),
|
||||
new Post(security: "is_granted('ROLE_USER')"),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN') or object.getUser() == user"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN') or object.getUser() == user"),
|
||||
new Get(security: "is_granted('time-tracking.entries.view')"),
|
||||
new Post(security: "is_granted('time-tracking.entries.view')"),
|
||||
new Patch(security: "is_granted('ROLE_ADMIN') or (is_granted('time-tracking.entries.view') and object.getUser() == user)"),
|
||||
new Delete(security: "is_granted('ROLE_ADMIN') or (is_granted('time-tracking.entries.view') and object.getUser() == user)"),
|
||||
],
|
||||
normalizationContext: ['groups' => ['time_entry:read']],
|
||||
denormalizationContext: ['groups' => ['time_entry:write']],
|
||||
|
||||
Reference in New Issue
Block a user