فهرست منبع

resolve conflicts

Olivier Massot 2 سال پیش
والد
کامیت
4b40ff9463
100فایلهای تغییر یافته به همراه964 افزوده شده و 648 حذف شده
  1. 2 2
      .env
  2. 6 1
      .gitignore
  3. 3 1
      .gitlab-ci.yml
  4. 73 28
      composer.json
  5. 0 26
      config/api_platform/Access/access.yaml
  6. 10 8
      config/bundles.php
  7. 16 0
      config/opentalent/modulesbyconditions.yaml
  8. 2 1
      config/opentalent/products.yaml
  9. 0 5
      config/packages/debug.yaml
  10. 2 0
      config/packages/docker/hautelook_alice.yaml
  11. 9 0
      config/packages/docker/nelmio_alice.yaml
  12. 4 0
      config/packages/docker/zenstruck_foundry.yaml
  13. 0 4
      config/packages/framework.yaml
  14. 0 5
      config/packages/hautelook_alice.yaml
  15. 0 9
      config/packages/messenger.yaml
  16. 0 44
      config/packages/monolog.yaml
  17. 0 12
      config/packages/nelmio_alice.yaml
  18. 0 8
      config/packages/prod/deprecations.yaml
  19. 0 13
      config/packages/security.yaml
  20. 4 0
      config/packages/staging/debug.yaml
  21. 2 0
      config/packages/staging/hautelook_alice.yaml
  22. 9 0
      config/packages/staging/nelmio_alice.yaml
  23. 4 0
      config/packages/staging/zenstruck_foundry.yaml
  24. 11 0
      config/packages/test/security.yaml
  25. 0 6
      config/packages/test/web_profiler.yaml
  26. 0 17
      config/packages/web_profiler.yaml
  27. 0 7
      config/packages/zenstruck_foundry.yaml
  28. 0 4
      config/routes/framework.yaml
  29. 0 0
      config/routes/prod/.gitkeep
  30. 3 0
      config/routes/staging/framework.yaml
  31. 0 0
      config/routes/test/.gitkeep
  32. 0 8
      config/routes/web_profiler.yaml
  33. 9 34
      config/services.yaml
  34. 21 0
      config/services/api-platform.yaml
  35. 7 0
      config/services/monolog.yaml
  36. 3 0
      doc/internal_requests.md
  37. 186 0
      doc/security.md
  38. 2 2
      public/index.php
  39. 1 1
      sql/schema-extensions/002-view_federation_structures.sql
  40. 1 14
      src/ApiResources/Access/AdminAccess.php
  41. 10 9
      src/ApiResources/Cotisation/Cotisation.php
  42. 59 0
      src/ApiResources/OnlineRegistration/RegistrationAvailability.php
  43. 48 0
      src/ApiResources/OnlineRegistration/RegistrationStatus.php
  44. 3 3
      src/ApiResources/Profile/OrganizationProfile.php
  45. 37 7
      src/Doctrine/AbstractExtension.php
  46. 0 11
      src/Doctrine/Access/AccessExtensionInterface.php
  47. 15 0
      src/Doctrine/Access/AdditionalExtension/AdditionalAccessExtensionInterface.php
  48. 6 3
      src/Doctrine/Access/AdditionalExtension/DateTimeConstraintExtensionAdditional.php
  49. 7 4
      src/Doctrine/Access/AdditionalExtension/StudentsExtensionAdditional.php
  50. 6 32
      src/Doctrine/Access/CurrentAccessExtension.php
  51. 7 7
      src/Doctrine/Access/CurrentUserPersonalizedListExtension.php
  52. 7 6
      src/Doctrine/Billing/CurrentResidenceAreaExtension.php
  53. 7 6
      src/Doctrine/Booking/CurrentCoursesExtension.php
  54. 6 5
      src/Doctrine/Core/AllowedAddressPostalExtension.php
  55. 7 6
      src/Doctrine/Core/CurrentUserNotificationExtension.php
  56. 7 6
      src/Doctrine/Core/CurrentUserNotificationUserExtension.php
  57. 6 7
      src/Doctrine/Education/CurrentCycleExtension.php
  58. 7 6
      src/Doctrine/Education/CurrentEducationNotationConfigExtension.php
  59. 7 6
      src/Doctrine/Education/CurrentEducationTimingExtension.php
  60. 7 6
      src/Doctrine/Network/CurrentNetworkOrganizationExtension.php
  61. 7 6
      src/Doctrine/Organization/CurrentOrganizationAddressPostalExtension.php
  62. 7 6
      src/Doctrine/Organization/CurrentOrganizationArticleExtension.php
  63. 6 5
      src/Doctrine/Organization/CurrentOrganizationExtension.php
  64. 32 7
      src/Entity/Access/Access.php
  65. 2 8
      src/Entity/Access/AccessFamily.php
  66. 1 1
      src/Entity/Access/OrganizationFunction.php
  67. 6 1
      src/Entity/Access/PersonalizedList.php
  68. 44 2
      src/Entity/AccessWish/AccessFamilyWish.php
  69. 55 2
      src/Entity/AccessWish/AccessWish.php
  70. 40 1
      src/Entity/AccessWish/EducationStudentWish.php
  71. 2 8
      src/Entity/Billing/AccessBilling.php
  72. 1 1
      src/Entity/Billing/AccessIntangible.php
  73. 1 7
      src/Entity/Billing/AccessPayer.php
  74. 2 8
      src/Entity/Billing/Bill.php
  75. 1 7
      src/Entity/Billing/BillAccounting.php
  76. 2 8
      src/Entity/Billing/BillCredit.php
  77. 2 8
      src/Entity/Billing/BillLine.php
  78. 1 7
      src/Entity/Billing/BillingIntangibleExcludeDate.php
  79. 1 5
      src/Entity/Billing/BillingSetting.php
  80. 2 8
      src/Entity/Billing/EducationalProjectPayer.php
  81. 2 8
      src/Entity/Billing/FamilyQuotient.php
  82. 5 18
      src/Entity/Billing/ResidenceArea.php
  83. 2 8
      src/Entity/Booking/Attendance.php
  84. 1 7
      src/Entity/Booking/AttendanceBooking.php
  85. 5 9
      src/Entity/Booking/Course.php
  86. 2 8
      src/Entity/Booking/EducationalProject.php
  87. 1 7
      src/Entity/Booking/Event.php
  88. 2 8
      src/Entity/Booking/EventUser.php
  89. 2 8
      src/Entity/Booking/Examen.php
  90. 3 1
      src/Entity/Booking/ExamenConvocation.php
  91. 2 8
      src/Entity/Booking/OrganizationHoliday.php
  92. 2 8
      src/Entity/Booking/PersonHoliday.php
  93. 1 1
      src/Entity/Core/AbstractInformation.php
  94. 7 8
      src/Entity/Core/AddressPostal.php
  95. 4 15
      src/Entity/Core/BankAccount.php
  96. 4 15
      src/Entity/Core/ContactPoint.php
  97. 46 6
      src/Entity/Core/File.php
  98. 4 1
      src/Entity/Core/Notification.php
  99. 3 0
      src/Entity/Core/NotificationUser.php
  100. 2 8
      src/Entity/Core/Tagg.php

+ 2 - 2
.env

@@ -66,7 +66,7 @@ MAILER_DSN=smtp://localhost
 ###< symfony/mailer ###
 
 ###> bindfile populate buffer file
-BIND_FILE_BUFFER_FILE=/env/subdomain.txt
+BIND_FILE_BUFFER_FILE=var/subdomain.txt
 ###< bindfile populate buffer file
 
 ###> elasticsearch ###
@@ -106,5 +106,5 @@ LOG_FILE_NAME=undefined
 
 ### Internal requests (@see doc/internal_requests.md)
 INTERNAL_REQUESTS_TOKEN=sRyfu6SZLR9StpnSKYRdl6i9wr5qs1bJQzro4DUiVyYJ2jknl
-INTERNAL_FILES_DOWNLOAD_URI=https://api.opentalent.fr/_internal/secure/files
+INTERNAL_FILES_DOWNLOAD_URI=https://local.api.opentalent.fr/_internal/secure/files
 ###

+ 6 - 1
.gitignore

@@ -40,4 +40,9 @@ symfony.lock
 
 ###> phpstan ###
 .phpstan.neon
-###< phpstan ###
+###< phpstan ###
+public/phpstorm_debug_validator.phar
+
+public/phpstorm_debug.php
+
+public/phpstorm_index.php

+ 3 - 1
.gitlab-ci.yml

@@ -16,7 +16,9 @@ before_script:
 
 static_analysis:
   script:
-    - php --version && php -d memory_limit=512M vendor/bin/phpstan analyse -c phpstan.neon.dist --error-format gitlab > phpstan.json
+    - php --version
+    - php -d memory_limit=512M vendor/bin/phpstan analyse -c phpstan.neon.dist --error-format gitlab > phpstan.json  # Display code quality in MR
+    - php -d memory_limit=512M vendor/bin/phpstan analyse -c phpstan.neon.dist  # Display in console
   artifacts:
     when: always
     reports:

+ 73 - 28
composer.json

@@ -15,7 +15,7 @@
     "php": ">=8.1",
     "ext-ctype": "*",
     "ext-iconv": "*",
-    "api-platform/core": "^3.1",
+    "api-platform/core": "3.1.7",
     "beberlei/doctrineextensions": "^1.3",
     "blackfire/php-sdk": "^1.23",
     "composer/package-versions-deprecated": "^1.11",
@@ -36,33 +36,33 @@
     "phpdocumentor/reflection-docblock": "^5.2",
     "ramsey/uuid": "^4.2",
     "ramsey/uuid-doctrine": "^2.0",
-    "symfony/asset": "6.2.*",
-    "symfony/console": "6.2.*",
-    "symfony/doctrine-messenger": "6.2.*",
-    "symfony/dotenv": "6.2.*",
-    "symfony/error-handler": "6.2.*",
-    "symfony/expression-language": "6.2.*",
+    "symfony/asset": "6.3.*",
+    "symfony/console": "6.3.*",
+    "symfony/doctrine-messenger": "6.3.*",
+    "symfony/dotenv": "6.3.*",
+    "symfony/error-handler": "6.3.*",
+    "symfony/expression-language": "6.3.*",
     "symfony/flex": "^1.3.1",
-    "symfony/framework-bundle": "6.2.*",
-    "symfony/http-client": "6.2.*",
-    "symfony/intl": "6.2.*",
-    "symfony/lock": "6.2.*",
-    "symfony/mailer": "6.2.*",
+    "symfony/framework-bundle": "6.3.*",
+    "symfony/http-client": "6.3.*",
+    "symfony/intl": "6.3.*",
+    "symfony/lock": "6.3.*",
+    "symfony/mailer": "6.3.*",
     "symfony/mercure": "^0.6.1",
     "symfony/mercure-bundle": "^0.3.4",
-    "symfony/messenger": "6.2.*",
+    "symfony/messenger": "6.3.*",
     "symfony/monolog-bundle": "^3.7",
     "symfony/polyfill-intl-icu": "^1.21",
     "symfony/polyfill-intl-messageformatter": "^1.24",
-    "symfony/property-access": "6.2.*",
-    "symfony/property-info": "6.2.*",
-    "symfony/security-bundle": "6.2.*",
-    "symfony/serializer": "6.2.*",
-    "symfony/translation": "6.2.*",
-    "symfony/twig-bundle": "6.2.*",
-    "symfony/uid": "6.2.*",
-    "symfony/validator": "6.2.*",
-    "symfony/yaml": "6.2.*",
+    "symfony/property-access": "6.3.*",
+    "symfony/property-info": "6.3.*",
+    "symfony/security-bundle": "6.3.*",
+    "symfony/serializer": "6.3.*",
+    "symfony/translation": "6.3.*",
+    "symfony/twig-bundle": "6.3.*",
+    "symfony/uid": "6.3.*",
+    "symfony/validator": "6.3.*",
+    "symfony/yaml": "6.3.*",
     "twig/cssinliner-extra": "^3.4",
     "twig/extra-bundle": "^3.4",
     "twig/inky-extra": "^3.4",
@@ -84,13 +84,13 @@
     "phpstan/phpstan-symfony": "^1.2",
     "phpunit/phpunit": "^9.6",
     "rector/rector": "^0.15.13",
-    "symfony/browser-kit": "6.2.*",
-    "symfony/css-selector": "6.2.*",
-    "symfony/debug-bundle": "6.2.*",
+    "symfony/browser-kit": "6.3.*",
+    "symfony/css-selector": "6.3.*",
+    "symfony/debug-bundle": "6.3.*",
     "symfony/maker-bundle": "^1.48",
     "symfony/phpunit-bridge": "^6.2",
-    "symfony/stopwatch": "6.2.*",
-    "symfony/web-profiler-bundle": "6.2.*",
+    "symfony/stopwatch": "6.3.*",
+    "symfony/web-profiler-bundle": "6.3.*",
     "timeweb/phpstan-enum": "^3.1",
     "zenstruck/foundry": "^1.31"
   },
@@ -110,6 +110,51 @@
     "psr-4": {
       "App\\": "src/"
     },
+    "classmap": [
+      "vendor/opentalent/phpdocx/Classes/Phpdocx/Create/CreateDocx.php",
+      "vendor/opentalent/phpdocx/Classes/Phpdocx/Create/CreateDocxFromTemplate.php"
+    ],
+    "autoload-dev": {
+        "psr-4": {
+            "DataFixtures\\": "tests/Fixture",
+            "App\\Tests\\": "tests/"
+        }
+    },
+    "replace": {
+        "paragonie/random_compat": "2.*",
+        "symfony/polyfill-ctype": "*",
+        "symfony/polyfill-iconv": "*",
+        "symfony/polyfill-php72": "*",
+        "symfony/polyfill-php71": "*",
+        "symfony/polyfill-php70": "*",
+        "symfony/polyfill-php56": "*"
+    },
+    "scripts": {
+        "auto-scripts": {
+            "cache:clear": "symfony-cmd",
+            "assets:install %PUBLIC_DIR%": "symfony-cmd"
+        },
+        "post-install-cmd": [
+            "@auto-scripts"
+        ],
+        "post-update-cmd": [
+            "@auto-scripts"
+        ]
+    },
+    "conflict": {
+        "symfony/symfony": "*"
+    },
+    "extra": {
+        "symfony": {
+            "allow-contrib": false,
+            "require": "6.3.*"
+        },
+        "phpstan": {
+            "includes": [
+                "extension.neon"
+            ]
+        }
+    }
     "classmap": [
       "vendor/opentalent/phpdocx/Classes/Phpdocx/Create/CreateDocx.php",
       "vendor/opentalent/phpdocx/Classes/Phpdocx/Create/CreateDocxFromTemplate.php"
@@ -156,4 +201,4 @@
       ]
     }
   }
-}
+}

+ 0 - 26
config/api_platform/Access/access.yaml

@@ -1,35 +1,9 @@
 resources:
   App\Entity\Access\Access:
     - operations:
-        ApiPlatform\Metadata\GetCollection: ~
-
         ApiPlatform\Metadata\Get:
           security: '(is_granted("ROLE_USERS_VIEW") and object.getOrganization().getId() == user.getOrganization().getId()) or (object.getId() == user.getId())'
 
         ApiPlatform\Metadata\Put:
           security: 'is_granted("ROLE_USERS") or (object.getId() == user.getId())'
 
-        ApiPlatform\Metadata\Delete: ~
-
-    - operations:
-        ApiPlatform\Metadata\GetCollection:
-          name: 'cget_students'
-          uriTemplate: '/students'
-          security: 'is_granted("ROLE_USERS_VIEW")'
-
-    - operations:
-        ApiPlatform\Metadata\GetCollection:
-          name: 'cget_access_person_ref'
-          uriTemplate: '/access_people'
-          normalization_context:
-            groups: [ 'access_people_ref' ]
-
-    - operations:
-        ApiPlatform\Metadata\Get:
-          name: 'get_access_address'
-          uriTemplate: '/access_addresses/{id}'
-          requirements:
-            id: '\d+'
-          normalization_context:
-            groups: [ 'access_address', 'address' ] ]
-          security: 'object.getOrganization().getId() == user.getOrganization().getId()'

+ 10 - 8
config/bundles.php

@@ -1,9 +1,10 @@
 <?php
 
+$devEnvs = ['dev' => true, 'docker' => true, 'test' => false, 'staging' => true];
+
 return [
     Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
     Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
-    Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'docker' => true, 'test' => true, 'staging' => true],
     Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
     Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
     Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
@@ -12,17 +13,18 @@ return [
     Jb\Bundle\PhumborBundle\JbPhumborBundle::class => ['all' => true],
     Misd\PhoneNumberBundle\MisdPhoneNumberBundle::class => ['all' => true],
     Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
-    Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true, 'docker' => true, 'staging' => true],
     FOS\ElasticaBundle\FOSElasticaBundle::class => ['all' => true],
     Knp\Bundle\SnappyBundle\KnpSnappyBundle::class => ['all' => true],
     Knp\Bundle\GaufretteBundle\KnpGaufretteBundle::class => ['all' => true],
     Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
-    Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'docker' => true, 'test' => true, 'staging' => true],
     Symfony\Bundle\MercureBundle\MercureBundle::class => ['all' => true],
     Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
-    Nelmio\Alice\Bridge\Symfony\NelmioAliceBundle::class => ['dev' => true, 'staging' => true],
-    Fidry\AliceDataFixtures\Bridge\Symfony\FidryAliceDataFixturesBundle::class => ['staging' => true],
-    Hautelook\AliceBundle\HautelookAliceBundle::class => ['staging' => true],
-    Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['staging' => true],
-    Zenstruck\Foundry\ZenstruckFoundryBundle::class => ['staging' => true],
+    Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => $devEnvs,
+    Symfony\Bundle\MakerBundle\MakerBundle::class => $devEnvs,
+    Symfony\Bundle\DebugBundle\DebugBundle::class => $devEnvs,
+    Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => $devEnvs,
+    Zenstruck\Foundry\ZenstruckFoundryBundle::class => $devEnvs,
+    Nelmio\Alice\Bridge\Symfony\NelmioAliceBundle::class => $devEnvs,
+    Fidry\AliceDataFixtures\Bridge\Symfony\FidryAliceDataFixturesBundle::class => $devEnvs,
+    Hautelook\AliceBundle\HautelookAliceBundle::class => $devEnvs,
 ];

+ 16 - 0
config/opentalent/modulesbyconditions.yaml

@@ -1,5 +1,21 @@
 parameters:
     opentalent.modulesbyconditions:
+        ConsultOwnPedagogicResult:
+          conditions:
+            service:
+              name: App\Service\Education\Utils
+              function: isConsultOwnPedagogicResult
+        TeacherContactList:
+          conditions:
+            service:
+              name: App\Service\Education\Utils
+              function: isConsultTeacherListing
+        PeriodValidation:
+          conditions:
+            service:
+              name: App\Service\Education\Utils
+              function: isPeriodValidation
+
         CotisationCall:
             roles:
                 - ROLE_COTISATION

+ 2 - 1
config/opentalent/products.yaml

@@ -228,6 +228,8 @@ parameters:
             - AccessTmp
             - EducationStudentWish
             - OnlineRegistrationSettings
+            - RegistrationStatus
+            - RegistrationAvailability
           roles:
             - ROLE_ONLINEREGISTRATION_ADMINISTRATION
 
@@ -283,7 +285,6 @@ parameters:
           - Messages
           - Tagg
           - Statistic
-          - Cotisation
           - Dolibarr
 
       artist_premium:

+ 0 - 5
config/packages/debug.yaml

@@ -1,5 +0,0 @@
-when@dev:
-    debug:
-        # Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser.
-        # See the "server:dump" command to start a new server.
-        dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%"

+ 2 - 0
config/packages/docker/hautelook_alice.yaml

@@ -0,0 +1,2 @@
+hautelook_alice:
+    fixtures_path: fixtures

+ 9 - 0
config/packages/docker/nelmio_alice.yaml

@@ -0,0 +1,9 @@
+nelmio_alice:
+    functions_blacklist:
+        - 'current'
+        - 'shuffle'
+        - 'date'
+        - 'time'
+        - 'file'
+        - 'md5'
+        - 'sha1'

+ 4 - 0
config/packages/docker/zenstruck_foundry.yaml

@@ -0,0 +1,4 @@
+# See full configuration: https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#full-default-bundle-configuration
+zenstruck_foundry:
+    # Whether to auto-refresh proxies by default (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#auto-refresh)
+    auto_refresh_proxies: true

+ 0 - 4
config/packages/framework.yaml

@@ -40,7 +40,3 @@ framework:
                     Content-Type: 'application/json'
             apiLegacyClient:
                 base_uri: '%env(API_LEG_BASE_URL)%'
-
-when@staging:
-    framework:
-        test: true

+ 0 - 5
config/packages/hautelook_alice.yaml

@@ -1,5 +0,0 @@
-when@dev: &dev
-    hautelook_alice:
-        fixtures_path: fixtures
-
-when@staging: *dev

+ 0 - 9
config/packages/messenger.yaml

@@ -17,12 +17,3 @@ framework:
             'App\Message\Command\Typo3\Typo3UpdateCommand': async
             'App\Message\Command\Typo3\Typo3DeleteCommand': async
             'App\Message\Command\Typo3\Typo3UndeleteCommand': async
-
-
-# when@test:
-#    framework:
-#        messenger:
-#            transports:
-#                # replace with your transport name here (e.g., my_transport: 'in-memory://')
-#                # For more Messenger testing tools, see https://github.com/zenstruck/messenger-test
-#                async: 'in-memory://'

+ 0 - 44
config/packages/monolog.yaml

@@ -1,47 +1,3 @@
 monolog:
     channels:
         - deprecation # Deprecations are logged in the dedicated "deprecation" channel when it exists
-
-when@dev:
-    monolog:
-        handlers:
-            main:
-                type: stream
-                path: "%kernel.logs_dir%/%kernel.environment%.log"
-                level: debug
-                channels: ["!event"]
-            # uncomment to get logging in your browser
-            # you may have to allow bigger header sizes in your Web server configuration
-            #firephp:
-            #    type: firephp
-            #    level: info
-            #chromephp:
-            #    type: chromephp
-            #    level: info
-            console:
-                type: console
-                process_psr_3_messages: false
-                channels: ["!event", "!doctrine", "!console"]
-
-when@prod:
-    monolog:
-        handlers:
-            main:
-                type: fingers_crossed
-                action_level: error
-                handler: nested
-                excluded_http_codes: [404, 405]
-                buffer_size: 50 # How many messages should be saved? Prevent memory leaks
-            nested:
-                type: stream
-                path: php://stderr
-                level: debug
-                formatter: monolog.formatter.json
-            console:
-                type: console
-                process_psr_3_messages: false
-                channels: ["!event", "!doctrine"]
-            deprecation:
-                type: stream
-                channels: [deprecation]
-                path: php://stderr

+ 0 - 12
config/packages/nelmio_alice.yaml

@@ -1,12 +0,0 @@
-when@dev: &dev
-    nelmio_alice:
-        functions_blacklist:
-            - 'current'
-            - 'shuffle'
-            - 'date'
-            - 'time'
-            - 'file'
-            - 'md5'
-            - 'sha1'
-
-when@staging: *dev

+ 0 - 8
config/packages/prod/deprecations.yaml

@@ -1,8 +0,0 @@
-# As of Symfony 5.1, deprecations are logged in the dedicated "deprecation" channel when it exists
-#monolog:
-#    channels: [deprecation]
-#    handlers:
-#        deprecation:
-#            type: stream
-#            channels: [deprecation]
-#            path: php://stderr

+ 0 - 13
config/packages/security.yaml

@@ -172,16 +172,3 @@ security:
         - { path: ^/api/internal, roles: INTERNAL_REQUEST }
         - { path: ^/api/internal, roles: ROLE_NO_ACCESS }
         - { path: ^/api/, roles: IS_HAVING_MODULE }
-
-when@test:
-    security:
-        password_hashers:
-            # By default, password hashers are resource intensive and take time. This is
-            # important to generate secure password hashes. In tests however, secure hashes
-            # are not important, waste resources and increase test times. The following
-            # reduces the work factor to the lowest possible values.
-            Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
-                algorithm: auto
-                cost: 4 # Lowest possible value for bcrypt
-                time_cost: 3 # Lowest possible value for argon
-                memory_cost: 10 # Lowest possible value for argon

+ 4 - 0
config/packages/staging/debug.yaml

@@ -0,0 +1,4 @@
+debug:
+    # Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser.
+    # See the "server:dump" command to start a new server.
+    dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%"

+ 2 - 0
config/packages/staging/hautelook_alice.yaml

@@ -0,0 +1,2 @@
+hautelook_alice:
+    fixtures_path: fixtures

+ 9 - 0
config/packages/staging/nelmio_alice.yaml

@@ -0,0 +1,9 @@
+nelmio_alice:
+    functions_blacklist:
+        - 'current'
+        - 'shuffle'
+        - 'date'
+        - 'time'
+        - 'file'
+        - 'md5'
+        - 'sha1'

+ 4 - 0
config/packages/staging/zenstruck_foundry.yaml

@@ -0,0 +1,4 @@
+# See full configuration: https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#full-default-bundle-configuration
+zenstruck_foundry:
+    # Whether to auto-refresh proxies by default (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#auto-refresh)
+    auto_refresh_proxies: true

+ 11 - 0
config/packages/test/security.yaml

@@ -0,0 +1,11 @@
+security:
+  password_hashers:
+    # By default, password hashers are resource intensive and take time. This is
+    # important to generate secure password hashes. In tests however, secure hashes
+    # are not important, waste resources and increase test times. The following
+    # reduces the work factor to the lowest possible values.
+    Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
+      algorithm: auto
+      cost: 4 # Lowest possible value for bcrypt
+      time_cost: 3 # Lowest possible value for argon
+      memory_cost: 10 # Lowest possible value for argon

+ 0 - 6
config/packages/test/web_profiler.yaml

@@ -1,6 +0,0 @@
-web_profiler:
-    toolbar: false
-    intercept_redirects: false
-
-framework:
-    profiler: { collect: false }

+ 0 - 17
config/packages/web_profiler.yaml

@@ -1,17 +0,0 @@
-when@dev:
-    web_profiler:
-        toolbar: true
-        intercept_redirects: false
-
-    framework:
-        profiler:
-            only_exceptions: false
-            collect_serializer_data: true
-
-when@test:
-    web_profiler:
-        toolbar: false
-        intercept_redirects: false
-
-    framework:
-        profiler: { collect: false }

+ 0 - 7
config/packages/zenstruck_foundry.yaml

@@ -1,7 +0,0 @@
-when@dev: &dev
-    # See full configuration: https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#full-default-bundle-configuration
-    zenstruck_foundry:
-        # Whether to auto-refresh proxies by default (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#auto-refresh)
-        auto_refresh_proxies: true
-
-when@staging: *dev

+ 0 - 4
config/routes/framework.yaml

@@ -1,4 +0,0 @@
-when@dev:
-    _errors:
-        resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
-        prefix: /_error

+ 0 - 0
config/routes/prod/.gitkeep


+ 3 - 0
config/routes/staging/framework.yaml

@@ -0,0 +1,3 @@
+_errors:
+    resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
+    prefix: /_error

+ 0 - 0
config/routes/test/.gitkeep


+ 0 - 8
config/routes/web_profiler.yaml

@@ -1,8 +0,0 @@
-when@dev:
-    web_profiler_wdt:
-        resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
-        prefix: /_wdt
-
-    web_profiler_profiler:
-        resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
-        prefix: /_profiler

+ 9 - 34
config/services.yaml

@@ -1,35 +1,13 @@
 # config/services.yaml
 imports:
     - { resource: opentalent/* }
+    - { resource: services/* }
 
 # Put parameters here that don't need to change on each machine where the app is deployed
 # https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
 parameters:
 
 services:
-    ########### Speeds up api-platform cache build substantially ###########
-    #### see https://github.com/api-platform/core/issues/4975  ####
-    api_platform.cache.metadata.property:
-        parent: cache.system
-        tags: [ cache.pool ]
-    api_platform.cache.metadata.resource:
-        parent: cache.system
-        tags: [ cache.pool ]
-    api_platform.cache.metadata.resource_collection:
-        parent: cache.system
-        tags: [ cache.pool ]
-    api_platform.cache.route_name_resolver:
-        parent: cache.system
-        tags: [ cache.pool ]
-    api_platform.cache.identifiers_extractor:
-        parent: cache.system
-        tags: [ cache.pool ]
-    api_platform.elasticsearch.cache.metadata.document:
-        parent: cache.system
-        tags: [ cache.pool ]
-
-    ########### End Speeds up api-platform cache build substantially ###########
-
     # default configuration for services in *this* file
     _defaults:
         autowire: true      # Automatically injects dependencies in your services.
@@ -43,13 +21,6 @@ services:
             $removeProcessor: '@api_platform.doctrine.orm.state.remove_processor'
             $opentalentNoReplyEmailAddress: 'noreply@opentalent.fr'
 
-    # Logging: a shorter version of the default monolog line formatter
-    monolog.formatter.message:
-        class: Monolog\Formatter\LineFormatter
-        arguments:
-            - "[%%datetime%%] %%level_name%% : %%message%%\n"
-            - "Y-m-d H:i:s.v"
-
     # makes classes in src/ available to be used as services
     # this creates a service per class whose id is the fully-qualified class name
     App\:
@@ -68,6 +39,9 @@ services:
     App\Service\Cotisation\Utils:
         public: true
 
+    App\Service\Education\Utils:
+        public: true
+
     App\Service\Network\Utils:
         public: true
 
@@ -76,10 +50,14 @@ services:
 
     Gaufrette\Filesystem: '@knp_gaufrette.filesystem_map'
 
+    # To use the test fixtures
+    App\Tests\Fixture\:
+        resource: '%kernel.project_dir%/tests/Fixture/*'
+
     #########################################
     ##  TAG Services ##
     _instanceof:
-        App\Doctrine\Access\AccessExtensionInterface:
+        App\Doctrine\Access\AdditionalExtension\AdditionalAccessExtensionInterface:
             tags: ['app.extensions.access']
         App\Service\Access\OptionalsRolesInterface:
             tags: ['app.optionalsroles']
@@ -139,6 +117,3 @@ services:
     Symfony\Component\DependencyInjection\ContainerInterface: '@service_container'
     #########################################
 
-    # To use the test fixtures
-    App\Tests\Fixture\:
-        resource: '%kernel.project_dir%/tests/Fixture/*'

+ 21 - 0
config/services/api-platform.yaml

@@ -0,0 +1,21 @@
+services:
+    # Speeds up api-platform cache build substantially
+    # @see https://github.com/api-platform/core/issues/4975
+    api_platform.cache.metadata.property:
+      parent: cache.system
+      tags: [ cache.pool ]
+    api_platform.cache.metadata.resource:
+      parent: cache.system
+      tags: [ cache.pool ]
+    api_platform.cache.metadata.resource_collection:
+      parent: cache.system
+      tags: [ cache.pool ]
+    api_platform.cache.route_name_resolver:
+      parent: cache.system
+      tags: [ cache.pool ]
+    api_platform.cache.identifiers_extractor:
+      parent: cache.system
+      tags: [ cache.pool ]
+    api_platform.elasticsearch.cache.metadata.document:
+      parent: cache.system
+      tags: [ cache.pool ]

+ 7 - 0
config/services/monolog.yaml

@@ -0,0 +1,7 @@
+services:
+    # Logging: a shorter version of the default monolog line formatter
+    monolog.formatter.message:
+      class: Monolog\Formatter\LineFormatter
+      arguments:
+        - "[%%datetime%%] %%level_name%% : %%message%%\n"
+        - "Y-m-d H:i:s.v"

+ 3 - 0
doc/internal_requests.md

@@ -46,6 +46,9 @@ Les appels à cette route ne sont autorisés que si :
 
 Si ces deux conditions ne sont pas remplies, la requête est rejetée, et ce même si l'utilisateur est authentifié.
 
+Les routes internal sont configurées ici : `config/packages/security.yaml`
+
+
 
 ### Valider le fonctionnement
 

+ 186 - 0
doc/security.md

@@ -0,0 +1,186 @@
+# Security
+
+## Authentification Symfony
+
+### Fonctionnement de base
+
+L'authentification se fait via une requête POST envoyée à l'adresse `/login_check` avec le body suivant : 
+
+    {
+        "username": "login",
+        "password": "password"
+    }
+
+En cas de succès, la requête renvoie un token qui servira ensuite à l'utilisateur à s'identifier.
+
+Les requêtes suivantes devront posséder les headers suivants : 
+
+* `x-accessid` : l'id de l'utilisateur (ou Access)
+* `authorization` : une chaine de caractères de la forme "BEARER XXXXX", où XXXXX est le token retourné par la requête de login
+
+### Connexion Switch
+
+Certains utilisateurs (admins, familles) peuvent prendre le rôle d'un autre utilisateur via la connexion switch.
+
+Pour ce faire, un nouveau header doit être ajouté aux requêtes : 
+
+* `x-switch-user`: l'id de l'utilisateur dont on veut prendre le rôle
+
+
+
+## Roles et Modules
+
+Les droits d'un utilisateur sont conditionnés à différents critères, dont : 
+
+* Les **modules** que possède l'organisation à laquelle il est appartient
+* Les **rôles** de cet utilisateur au sein de cette organisation
+
+On peut obtenir la liste des modules de l'organisation et des rôles de l'utilisateur actif en son sein au moyen de la 
+requête : `/api/my_profile`
+
+
+### Modules
+
+Les modules d'une organisation dépendent du produit acheté par celle-ci et des éventuels modules complémentaires. Ces deux 
+informations sont stoquées dans la table `Settings`.
+
+Le fichier `config/opentalent/products.yaml` définit :
+
+- L'appartenance des _modules_ aux _products_
+- L'appartenance des _entities_ aux _modules_
+
+De plus, le fichier `config/opentalent/modulesbyconditions.yaml` complète cette configuration en définissant des modules
+présentant des conditions particulières (appartenance à la CMF en particulier)
+
+A chaque requête effectuée, la classe `\App\Security\Voter\ModuleVoter` vérifie si la ressource demandée appartient à un
+module possédé par l'organisation de l'utilisateur. Si ce n'est pas le cas, une erreur `AccessDeniedHttpException` est levée.
+
+
+## Différentes méthodes de sécurisation
+
+### Les annotations Api-Platform
+
+La sécurité des ApiResources peut être définie de manière globale pour la ressource, ou pour chaque opération (Get, 
+GetCollection, Put, Post, Delete) via les annotations.
+
+Exemple : 
+
+    #[ApiResource(
+        operations: [
+            new Get(
+                security: '(is_granted("ROLE_ORGANIZATION_VIEW") or is_granted("ROLE_ORGANIZATION")) and object.getOrganization().getId() == user.getOrganization().getId()'
+            ),
+            new Put(
+                security: 'is_granted("ROLE_ORGANIZATION") and object.getOrganization().getId() == user.getOrganization().getId()'
+            )
+        ],
+    )]
+
+Dans certains cas plus complexes (ex: Access), cette configuration peut être déplacée dans un fichier de configuration
+situé dans le répertoire `~/config/api_platform/` et portant le nom de la ressource.
+
+> Voir plus : https://api-platform.com/docs/core/security/
+
+
+### Voters
+
+Les voters permettent de contrôler l'accès à certaines ressources, selon le type d'opération.
+
+Ils implémentent essentiellement deux méthodes : `supports` et `voteOnAttribute` qui prennent en paramètres la ressource 
+et le type d'opération. `supports` retourne `true` si le voter doit s'appliquer dans ce cas. Si oui, `voteOnAttribute`
+est appellée et retourne `true` si l'opération est autorisée.
+
+> TODO: quand faut-il retourner false et quand faut-il lever une AccessDeniedHttpException ?
+
+Pour qu'un Voter soit appellé, il faut configurer la sécurité de la ressource via son annotation et utiliser la méthode 
+`is_granted` combinée à une des constantes : 
+
+Exemple : 
+
+    #[ApiResource(
+        operations: [
+            new Get(security: "is_granted('READ', object)"),
+            new Put(security: "is_granted('EDIT', object)"),
+            new Post(security: "is_granted('CREATE', object)"),
+            new Delete(security: "is_granted('DELETE', object)"),
+        ]
+    )]
+    class File
+
+    
+
+Les voters custom sont enregistrés dans le répertoire `src/Security/Voter`.
+
+> Voir plus : https://symfony.com/doc/current/security/voters.html
+
+
+### Extensions Doctrine
+
+Le framework Api-Platform propose un système d'extensions doctrine pour ajouter des filtres automatiques aux opérations
+réalisées sur des ressources voulues.
+
+Concrètement, l'extension ajoutera une condition au `WHERE` de la requête SQL.
+
+Une extension implémente trois méthodes : 
+
+* `applyToCollection`
+* `applyToItem`
+* `addWhere`
+
+Les deux premières permettent de tester si l'extension doit s'appliquer à la ressource.
+
+La dernière ajoute la condition en question.
+
+> Voir : https://api-platform.com/docs/core/extensions/
+
+
+### Quand utiliser les annotations, un Voter ou une Extension Doctrine ?
+
+Si la sécurité doit pouvoir s'appliquer à une collection et filtrer le résultat de celle-ci (exemple: les notifications 
+d'un utilisateur) : on utilisera une _Extension Doctrine_
+
+Sinon, si les conditions d'accès peuvent s'écrire facilement avec l'expression language des annotations
+api-platform, on utilisera les _annotations Api-platform_.
+
+Si aucune des conditions précédentes n'est remplie, on utilisera un _Voter Symfony_.
+
+
+## Internal Requests
+
+Certaines routes de la forme `/internal/...` permettent d'accepter des requêtes sans que le client ne
+soit authentifié (cf `config/packages/security.yaml`), en se basant sur un contrôle de l'IP et un token. 
+
+> Voir: https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/doc/internal_requests.md
+
+
+
+## Cas particuliers 
+
+### Les Fichiers
+
+Le client est autorisé à consulter l'enregistrement si l'une de ces conditions est vraie :
+
+* pas de date de disponibilité ou date de disponibilité antérieure à Now
+* date de disponibilité postérieure à Now, mais utilisateur a le rôle ROLE_BILLACCOUNTING et le fichier est de type BILL (facture)
+* visibilité est 'EVERYBODY' 
+* requête interne
+* est connecté et fait partie des AccessPersons du fichier
+* est connecté et est le propriétaire du fichier
+* est connecté et a le rôle ROLE_FILE et fichier appartient à l'utilisateur ou à son organisation
+* est connecté et fichier a des accessRoles et user a un des roles présents dans accessRoles et fichier appartient à l'utilisateur ou à son organisation (deprecated)
+
+
+Est autorisé à éditer si :
+
+* pas de date de disponibilité ou date de disponibilité antérieure à Now
+* date de disponibilité postérieure à Now, mais utilisateur a le rôle ROLE_BILLACCOUNTING et le fichier est de type BILL (facture)
+* est connecté et a le rôle ROLE_FILE et fichier appartient à l'utilisateur ou à son organisation
+* est connecté et est le propriétaire du fichier
+
+Est autorisé à créer si :
+
+* est connecté
+
+Est autorisé à supprimer si :
+
+* est connecté et est autorisé à éditer

+ 2 - 2
public/index.php

@@ -42,10 +42,10 @@ $response->send();
 $kernel->terminate($request, $response);
 
 // If the header is set
-//if (isset($_SERVER['HTTP_BLACKFIRETRIGGER'])) {
+if (isset($_SERVER['HTTP_BLACKFIRETRIGGER'])) {
     // When runtime shuts down, let's finish the profiling session
     register_shutdown_function(function () use ($blackfire, $probe) {
         // See the PHP SDK documentation for using the $profile object
         $profile = $blackfire->endProbe($probe);
     });
-//}
+}

+ 1 - 1
sql/schema-extensions/002-view_federation_structures.sql

@@ -1,6 +1,6 @@
 CREATE OR REPLACE VIEW view_federation_structures
 AS
-    SELECT o.id, o.name, o.logo_id as logoId, o.description, o.image_id as imageId, o.principalType as type, p.otherWebsite as website,
+    SELECT o.id, o.name, o.logo_id as logoId, o.description, o.image_id as imageId, o.principalType as type, p.website as website,
            CONCAT('[', GROUP_CONCAT(COLUMN_JSON(COLUMN_CREATE(
                    'type', oa.type, 'latitude', a.latitude, 'longitude', a.longitude,
                    'streetAddress', TRIM(BOTH '\n' FROM CONCAT_WS('\n', a.streetAddress, a.streetAddressSecond, a.streetAddressThird)),

+ 1 - 14
src/ApiResources/Access/AdminAccess.php

@@ -15,20 +15,7 @@ use Symfony\Component\Validator\Constraints as Assert;
 /**
  * Classe resource qui contient les champs d'un compte admin
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            uriTemplate: '/admin/{id}',
-            defaults: ['id' => 0],
-            provider: AdminAccessProvider::class
-        ),
-        new Put(
-            uriTemplate: '/admin/{id}',
-            defaults: ['id' => 0],
-            processor: AdminAccessProcessor::class
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 class AdminAccess implements ApiResourcesInterface
 {
     #[ApiProperty(identifier: true)]

+ 10 - 9
src/ApiResources/Cotisation/Cotisation.php

@@ -12,16 +12,17 @@ use Symfony\Component\Validator\Constraints as Assert;
 
 /**
  * Classe resource qui contient les informations des cotisations de la 5.9
+ *
+ * Security :
+ *   * @see App\Security\Voter\CotisationVoter
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            uriTemplate: '/cotisations/{organizationId}',
-            security: 'is_granted("ROLE_COTISATION", object) and object.getOrganizationId() == user.getOrganization().getId()',
-            provider: CotisationProvider::class
-        )
-    ]
-)]
+#[ApiResource(operations: [
+    new Get(
+        uriTemplate: '/cotisations/{organizationId}',
+        security: 'is_granted("ROLE_COTISATION", object) and object.getOrganizationId() == user.getOrganization().getId()',
+        provider: CotisationProvider::class
+    )
+])]
 class Cotisation implements ApiResourcesInterface
 {
     #[ApiProperty(identifier: true)]

+ 59 - 0
src/ApiResources/OnlineRegistration/RegistrationAvailability.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace App\ApiResources\OnlineRegistration;
+
+use ApiPlatform\Metadata\ApiProperty;
+use ApiPlatform\Metadata\ApiResource;
+use ApiPlatform\Metadata\Get;
+use App\ApiResources\ApiResourcesInterface;
+use App\State\Provider\OnlineRegistration\RegistrationAvailabilityProvider;
+
+#[ApiResource(
+    operations: [
+        new Get(
+            uriTemplate: '/online_registration/availability/{accessId}',
+            requirements: ['accessId' => '\\d+'],
+            defaults: ['accessId' => 0],
+            provider: RegistrationAvailabilityProvider::class
+        )
+    ]
+)]
+class RegistrationAvailability implements ApiResourcesInterface
+{
+    #[ApiProperty(identifier: true)]
+    private int $accessId;
+
+    private bool $available;
+
+    private ?string $message = null;
+
+    public function getAccessId(): int
+    {
+        return $this->accessId;
+    }
+
+    public function setAccessId(int $accessId): void
+    {
+        $this->accessId = $accessId;
+    }
+
+    public function isAvailable(): bool
+    {
+        return $this->available;
+    }
+
+    public function setAvailable(bool $available): void
+    {
+        $this->available = $available;
+    }
+
+    public function getMessage(): ?string
+    {
+        return $this->message;
+    }
+
+    public function setMessage(?string $message): void
+    {
+        $this->message = $message;
+    }
+}

+ 48 - 0
src/ApiResources/OnlineRegistration/RegistrationStatus.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace App\ApiResources\OnlineRegistration;
+
+use ApiPlatform\Metadata\ApiProperty;
+use ApiPlatform\Metadata\ApiResource;
+use ApiPlatform\Metadata\Get;
+use App\ApiResources\ApiResourcesInterface;
+use App\State\Provider\OnlineRegistration\RegistrationStatusProvider;
+use Symfony\Component\Serializer\Annotation\Groups;
+
+#[ApiResource(
+    operations: [
+        new Get(
+            uriTemplate: '/online_registration/status/{accessId}',
+            requirements: ['accessId' => '\\d+'],
+            defaults: ['accessId' => 0],
+            provider: RegistrationStatusProvider::class
+        )
+    ]
+)]
+class RegistrationStatus implements ApiResourcesInterface
+{
+    #[ApiProperty(identifier: true)]
+    private int $accessId;
+
+    private ?string $status = null;
+
+    public function getAccessId(): int
+    {
+        return $this->accessId;
+    }
+
+    public function setAccessId(int $accessId): void
+    {
+        $this->accessId = $accessId;
+    }
+
+    public function getStatus(): ?string
+    {
+        return $this->status;
+    }
+
+    public function setStatus(?string $status): void
+    {
+        $this->status = $status;
+    }
+}

+ 3 - 3
src/ApiResources/Profile/OrganizationProfile.php

@@ -40,14 +40,14 @@ class OrganizationProfile implements ApiResourcesInterface
     #[Groups('access_profile_read')]
     private ?string $website = null;
 
-    /** @var list<string>|null $modules  */
+    /** @var list<string> $modules  */
     #[Groups('access_profile_read')]
     private ?array $modules = [];
 
     #[Groups('access_profile_read')]
     private bool $hasChildren = false;
 
-    /** @var list<Organization>|null  */
+    /** @var list<OrganizationProfile>  */
     #[Groups('access_profile_read')]
     private ?array $parents = [];
 
@@ -160,7 +160,7 @@ class OrganizationProfile implements ApiResourcesInterface
     }
 
     /**
-     * @return list<Organization>
+     * @return list<OrganizationProfile>
      */
     public function getParents(): array
     {

+ 37 - 7
src/Doctrine/AbstractExtension.php

@@ -11,11 +11,13 @@ use Doctrine\ORM\QueryBuilder;
 use Exception;
 
 /**
- * Classe ... qui ...
+ * Base class for custom doctrine extensions
  */
 abstract class AbstractExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
 {
     /**
+     * Called by doctrine when getting a collection
+     *
      * @param QueryBuilder $queryBuilder
      * @param QueryNameGeneratorInterface $queryNameGenerator
      * @param string $resourceClass
@@ -26,10 +28,12 @@ abstract class AbstractExtension implements QueryCollectionExtensionInterface, Q
      */
     public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, Operation $operation = null, array $context = []): void
     {
-        $this->addWhere($queryBuilder, $resourceClass);
+        $this->apply($queryBuilder, $resourceClass, $operation);
     }
 
     /**
+     * Called by doctrine when getting an item
+     *
      * @param QueryBuilder $queryBuilder
      * @param QueryNameGeneratorInterface $queryNameGenerator
      * @param string $resourceClass
@@ -41,11 +45,37 @@ abstract class AbstractExtension implements QueryCollectionExtensionInterface, Q
      */
     public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, Operation $operation = null, array $context = []): void
     {
-        $this->addWhere($queryBuilder, $resourceClass);
+        $this->apply($queryBuilder, $resourceClass, $operation);
     }
 
-    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
-    {
-        throw new Exception('need override addWhere function', 500);
+    /**
+     * Generic application of the extension
+     *
+     * @param $queryBuilder
+     * @param $resourceClass
+     * @return void
+     */
+    protected function apply(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void {
+        if (!$this->supports($resourceClass, $operation)) {
+            return;
+        }
+        $this->addWhere($queryBuilder, $resourceClass, $operation);
     }
-}
+
+    /**
+     * Returns true if the extension supports the given resource
+     *
+     * @param string $resourceClass
+     * @return bool
+     */
+    abstract protected function supports(string $resourceClass, ?Operation $operation): bool;
+
+    /**
+     * Add one or more filters to the query
+     *
+     * @param QueryBuilder $queryBuilder
+     * @param string $resourceClass
+     * @return void
+     */
+    abstract protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void;
+}

+ 0 - 11
src/Doctrine/Access/AccessExtensionInterface.php

@@ -1,11 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace App\Doctrine\Access;
-
-use Doctrine\ORM\QueryBuilder;
-
-interface AccessExtensionInterface{
-    public function support(string $name): bool;
-    public function addWhere(QueryBuilder $queryBuilder): void;
-}

+ 15 - 0
src/Doctrine/Access/AdditionalExtension/AdditionalAccessExtensionInterface.php

@@ -0,0 +1,15 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Doctrine\Access\AdditionalExtension;
+
+use Doctrine\ORM\QueryBuilder;
+
+/**
+ * Complément d'extension pour CurrentAccessExtension.
+ * Les classes implémentant cette interface seront appellées par le service CurrentAccessExtensionIterator
+ */
+interface AdditionalAccessExtensionInterface{
+    public function support(string $name): bool;
+    public function addWhere(QueryBuilder $queryBuilder): void;
+}

+ 6 - 3
src/Doctrine/Access/Extensions/DateTimeConstraintExtension.php → src/Doctrine/Access/AdditionalExtension/DateTimeConstraintExtensionAdditional.php

@@ -1,13 +1,16 @@
 <?php
 declare(strict_types=1);
 
-namespace App\Doctrine\Access\Extensions;
+namespace App\Doctrine\Access\AdditionalExtension;
 
-use App\Doctrine\Access\AccessExtensionInterface;
 use Doctrine\ORM\QueryBuilder;
 use Symfony\Component\HttpFoundation\RequestStack;
 
-class DateTimeConstraintExtension implements AccessExtensionInterface {
+/**
+ * Contrainte supplémentaire pour CurrentAccessExtension.
+ * Ajoute un critère de dates
+ */
+class DateTimeConstraintExtensionAdditional implements AdditionalAccessExtensionInterface {
     public function __construct(
         private RequestStack $requestStack
     ){

+ 7 - 4
src/Doctrine/Access/Extensions/StudentsExtension.php → src/Doctrine/Access/AdditionalExtension/StudentsExtensionAdditional.php

@@ -1,12 +1,15 @@
 <?php
 declare(strict_types=1);
 
-namespace App\Doctrine\Access\Extensions;
+namespace App\Doctrine\Access\AdditionalExtension;
 
-use App\Doctrine\Access\AccessExtensionInterface;
 use Doctrine\ORM\QueryBuilder;
 
-class StudentsExtension implements AccessExtensionInterface {
+/**
+ * Contrainte supplémentaire pour CurrentAccessExtension.
+ *
+ */
+class StudentsExtensionAdditional implements AdditionalAccessExtensionInterface {
 
     public function support(string $name): bool
     {
@@ -16,4 +19,4 @@ class StudentsExtension implements AccessExtensionInterface {
     public function addWhere(QueryBuilder $queryBuilder): void
     {
     }
-}
+}

+ 6 - 32
src/Doctrine/Access/CurrentAccessExtension.php

@@ -7,6 +7,7 @@ use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
 use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface;
 use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
 use ApiPlatform\Metadata\Operation;
+use App\Doctrine\AbstractExtension;
 use App\Entity\Access\Access;
 use App\Service\ServiceIterator\CurrentAccessExtensionIterator;
 use Doctrine\ORM\QueryBuilder;
@@ -16,7 +17,7 @@ use Symfony\Bundle\SecurityBundle\Security;
  * Class CurrentAccessExtension : Filtre de sécurité par défaut pour une resource Access
  * @package App\Doctrine\Access
  */
-final class CurrentAccessExtension  implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
+final class CurrentAccessExtension extends AbstractExtension
 {
     public function __construct(
         private Security $security,
@@ -24,39 +25,12 @@ final class CurrentAccessExtension  implements QueryCollectionExtensionInterface
     )
     { }
 
-    /**
-     * @param QueryBuilder $queryBuilder
-     * @param QueryNameGeneratorInterface $queryNameGenerator
-     * @param string $resourceClass
-     * @param Operation|null $operation
-     * @param mixed[] $context
-     * @return void
-     */
-    public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, Operation $operation = null, array $context = []): void
-    {
-        $this->addWhere($queryBuilder, $resourceClass, $operation?->getName());
+    public function supports(string $resourceClass, ?Operation $operation): bool {
+        return $resourceClass === Access::class;
     }
 
-    /**
-     * @param QueryBuilder $queryBuilder
-     * @param QueryNameGeneratorInterface $queryNameGenerator
-     * @param string $resourceClass
-     * @param list<int> $identifiers
-     * @param Operation|null $operation
-     * @param mixed[] $context
-     * @return void
-     */
-    public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, Operation $operation = null, array $context = []): void
+    public function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void
     {
-        $this->addWhere($queryBuilder, $resourceClass, $operation?->getName());
-    }
-
-    public function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?string $operationName): void
-    {
-        if (Access::class !== $resourceClass) {
-            return;
-        }
-
         /** @var Access $currentUser */
         $currentUser = $this->security->getUser();
         $rootAlias = $queryBuilder->getRootAliases()[0];
@@ -65,6 +39,6 @@ final class CurrentAccessExtension  implements QueryCollectionExtensionInterface
             ->setParameter('current_organization', $currentUser->getOrganization())
         ;
 
-        $this->currentAccessExtensionIterator->addWhere($queryBuilder, $operationName);
+        $this->currentAccessExtensionIterator->addWhere($queryBuilder, $operation?->getName());
     }
 }

+ 7 - 7
src/Doctrine/Access/CurrentUserPersonalizedListExtension.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Doctrine\Access;
 
+use ApiPlatform\Metadata\Operation;
 use App\Doctrine\AbstractExtension;
 use App\Entity\Access\PersonalizedList;
 use Doctrine\ORM\QueryBuilder;
@@ -17,16 +18,15 @@ final class CurrentUserPersonalizedListExtension extends AbstractExtension
     public function __construct(private Security $security)
     { }
 
-    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
-    {
-        if (PersonalizedList::class !== $resourceClass) {
-            return;
-        }
+    public function supports(string $resourceClass, ?Operation $operation): bool {
+        return $resourceClass === PersonalizedList::class;
+    }
 
-        /** @var PersonalizedList $currentUser */
+    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void
+    {
         $currentUser = $this->security->getUser();
         $rootAlias = $queryBuilder->getRootAliases()[0];
         $queryBuilder->andWhere(sprintf('%s.access = :current_access', $rootAlias));
         $queryBuilder->setParameter('current_access', $currentUser);
     }
-}
+}

+ 7 - 6
src/Doctrine/Billing/CurrentResidenceAreaExtension.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Doctrine\Billing;
 
+use ApiPlatform\Metadata\Operation;
 use App\Doctrine\AbstractExtension;
 use App\Entity\Access\Access;
 use App\Entity\Billing\ResidenceArea;
@@ -18,12 +19,12 @@ final class CurrentResidenceAreaExtension extends AbstractExtension
     public function __construct(private Security $security)
     { }
 
-    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
-    {
-        if (ResidenceArea::class !== $resourceClass) {
-            return;
-        }
+    public function supports(string $resourceClass, ?Operation $operation): bool {
+        return $resourceClass === ResidenceArea::class;
+    }
 
+    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void
+    {
         /** @var Access $currentUser */
         $currentUser = $this->security->getUser();
         $rootAlias = $queryBuilder->getRootAliases()[0];
@@ -32,4 +33,4 @@ final class CurrentResidenceAreaExtension extends AbstractExtension
             ->setParameter('billingSetting', $currentUser->getOrganization()->getBillingSetting())
         ;
     }
-}
+}

+ 7 - 6
src/Doctrine/Booking/CurrentCoursesExtension.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Doctrine\Booking;
 
+use ApiPlatform\Metadata\Operation;
 use App\Doctrine\AbstractExtension;
 use App\Entity\Access\Access;
 use App\Entity\Booking\Course;
@@ -18,15 +19,15 @@ final class CurrentCoursesExtension extends AbstractExtension
     public function __construct(private Security $security)
     { }
 
+    public function supports(string $resourceClass, ?Operation $operation): bool {
+        return $resourceClass === Course::class;
+    }
+
     /**
      * @todo : A la suite de la migration, il faut supprimer le where avec le discr.
      */
-    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
+    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void
     {
-        if (Course::class !== $resourceClass) {
-            return;
-        }
-
         /** @var Access $currentUser */
         $currentUser = $this->security->getUser();
         $rootAlias = $queryBuilder->getRootAliases()[0];
@@ -37,4 +38,4 @@ final class CurrentCoursesExtension extends AbstractExtension
             ->setParameter('organization', $currentUser->getOrganization())
         ;
     }
-}
+}

+ 6 - 5
src/Doctrine/Core/AllowedAddressPostalExtension.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Doctrine\Core;
 
+use ApiPlatform\Metadata\Operation;
 use App\Doctrine\AbstractExtension;
 use App\Entity\Access\Access;
 use App\Entity\Core\AddressPostal;
@@ -18,12 +19,12 @@ final class AllowedAddressPostalExtension extends AbstractExtension
     public function __construct(private Security $security)
     { }
 
-    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
-    {
-        if (AddressPostal::class !== $resourceClass) {
-            return;
-        }
+    public function supports(string $resourceClass, ?Operation $operation): bool {
+        return $resourceClass === AddressPostal::class;
+    }
 
+    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void
+    {
         /** @var Access $currentUser */
         $currentUser = $this->security->getUser();
         $rootAlias = $queryBuilder->getRootAliases()[0];

+ 7 - 6
src/Doctrine/Core/CurrentUserNotificationExtension.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Doctrine\Core;
 
+use ApiPlatform\Metadata\Operation;
 use App\Doctrine\AbstractExtension;
 use App\Entity\Access\Access;
 use App\Entity\Core\Notification;
@@ -10,7 +11,7 @@ use Doctrine\ORM\QueryBuilder;
 use Symfony\Bundle\SecurityBundle\Security;
 
 /**
- * Class NotificationExtension : Filtre de sécurité par défaut pour une resource Notification
+ * Filtre de sécurité par défaut pour une resource Notification
  * @package App\Doctrine\Core
  */
 final class CurrentUserNotificationExtension extends AbstractExtension
@@ -18,15 +19,15 @@ final class CurrentUserNotificationExtension extends AbstractExtension
     public function __construct(private Security $security)
     { }
 
+    public function supports(string $resourceClass, ?Operation $operation): bool {
+        return $resourceClass === Notification::class;
+    }
+
     /**
      * @todo : A la suite de la migration, il faut supprimer le where avec le discr.
      */
-    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
+    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void
     {
-        if (Notification::class !== $resourceClass) {
-            return;
-        }
-
         /** @var Access $currentUser */
         $currentUser = $this->security->getUser();
         $rootAlias = $queryBuilder->getRootAliases()[0];

+ 7 - 6
src/Doctrine/Core/CurrentNotificationUserExtension.php → src/Doctrine/Core/CurrentUserNotificationUserExtension.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Doctrine\Core;
 
+use ApiPlatform\Metadata\Operation;
 use App\Doctrine\AbstractExtension;
 use App\Entity\Access\Access;
 use App\Entity\Core\NotificationUser;
@@ -14,20 +15,20 @@ use Symfony\Bundle\SecurityBundle\Security;
  *
  * @package App\Doctrine\Core
  */
-final class CurrentNotificationUserExtension extends AbstractExtension
+final class CurrentUserNotificationUserExtension extends AbstractExtension
 {
     public function __construct(private Security $security)
     { }
 
+    public function supports(string $resourceClass, ?Operation $operation): bool {
+        return $resourceClass === NotificationUser::class;
+    }
+
     /**
      * @todo : A la suite de la migration, il faut supprimer le where avec le discr.
      */
-    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
+    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void
     {
-        if (NotificationUser::class !== $resourceClass) {
-            return;
-        }
-
         /** @var Access $currentUser */
         $currentUser = $this->security->getUser();
         $rootAlias = $queryBuilder->getRootAliases()[0];

+ 6 - 7
src/Doctrine/Education/CurrentCycleExtension.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Doctrine\Education;
 
+use ApiPlatform\Metadata\Operation;
 use App\Doctrine\AbstractExtension;
 use App\Entity\Access\Access;
 use App\Entity\Education\Cycle;
@@ -18,13 +19,11 @@ final class CurrentCycleExtension extends AbstractExtension
     public function __construct(private Security $security)
     { }
 
-
-    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
+    public function supports(string $resourceClass, ?Operation $operation): bool {
+        return $resourceClass === Cycle::class;
+    }
+    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void
     {
-        if (Cycle::class !== $resourceClass) {
-            return;
-        }
-
         /** @var Access $currentUser */
         $currentUser = $this->security->getUser();
         $rootAlias = $queryBuilder->getRootAliases()[0];
@@ -33,4 +32,4 @@ final class CurrentCycleExtension extends AbstractExtension
             ->setParameter('organization', $currentUser->getOrganization())
         ;
     }
-}
+}

+ 7 - 6
src/Doctrine/Education/CurrentEducationNotationConfigExtension.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Doctrine\Education;
 
+use ApiPlatform\Metadata\Operation;
 use App\Doctrine\AbstractExtension;
 use App\Entity\Access\Access;
 use App\Entity\Education\EducationNotationConfig;
@@ -18,12 +19,12 @@ final class CurrentEducationNotationConfigExtension extends AbstractExtension
     public function __construct(private Security $security)
     { }
 
-    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
-    {
-        if (EducationNotationConfig::class !== $resourceClass) {
-            return;
-        }
+    public function supports(string $resourceClass, ?Operation $operation): bool {
+        return $resourceClass === EducationNotationConfig::class;
+    }
 
+    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void
+    {
         /** @var Access $currentUser */
         $currentUser = $this->security->getUser();
         $rootAlias = $queryBuilder->getRootAliases()[0];
@@ -32,4 +33,4 @@ final class CurrentEducationNotationConfigExtension extends AbstractExtension
             ->setParameter('organization', $currentUser->getOrganization())
         ;
     }
-}
+}

+ 7 - 6
src/Doctrine/Education/CurrentEducationTimingExtension.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Doctrine\Education;
 
+use ApiPlatform\Metadata\Operation;
 use App\Doctrine\AbstractExtension;
 use App\Entity\Access\Access;
 use App\Entity\Education\EducationTiming;
@@ -18,12 +19,12 @@ final class CurrentEducationTimingExtension extends AbstractExtension
     public function __construct(private Security $security)
     { }
 
-    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
-    {
-        if (EducationTiming::class !== $resourceClass) {
-            return;
-        }
+    public function supports(string $resourceClass, ?Operation $operation): bool {
+        return $resourceClass === EducationTiming::class;
+    }
 
+    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void
+    {
         /** @var Access $currentUser */
         $currentUser = $this->security->getUser();
         $rootAlias = $queryBuilder->getRootAliases()[0];
@@ -32,4 +33,4 @@ final class CurrentEducationTimingExtension extends AbstractExtension
             ->setParameter('organization', $currentUser->getOrganization())
         ;
     }
-}
+}

+ 7 - 6
src/Doctrine/Network/CurrentNetworkOrganizationExtension.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Doctrine\Network;
 
+use ApiPlatform\Metadata\Operation;
 use App\Doctrine\AbstractExtension;
 use App\Entity\Access\Access;
 use App\Entity\Network\NetworkOrganization;
@@ -18,12 +19,12 @@ final class CurrentNetworkOrganizationExtension extends AbstractExtension
     public function __construct(private Security $security)
     { }
 
-    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
-    {
-        if (NetworkOrganization::class !== $resourceClass) {
-            return;
-        }
+    public function supports(string $resourceClass, ?Operation $operation): bool {
+        return $resourceClass === NetworkOrganization::class;
+    }
 
+    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void
+    {
         /** @var Access $currentUser */
         $currentUser = $this->security->getUser();
         $rootAlias = $queryBuilder->getRootAliases()[0];
@@ -32,4 +33,4 @@ final class CurrentNetworkOrganizationExtension extends AbstractExtension
             ->setParameter('organization', $currentUser->getOrganization())
         ;
     }
-}
+}

+ 7 - 6
src/Doctrine/Organization/CurrentOrganizationAddressPostalExtension.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Doctrine\Organization;
 
+use ApiPlatform\Metadata\Operation;
 use App\Doctrine\AbstractExtension;
 use App\Entity\Access\Access;
 use App\Entity\Organization\OrganizationAddressPostal;
@@ -18,12 +19,12 @@ final class CurrentOrganizationAddressPostalExtension extends AbstractExtension
     public function __construct(private Security $security)
     { }
 
-    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
-    {
-        if (OrganizationAddressPostal::class !== $resourceClass) {
-            return;
-        }
+    public function supports(string $resourceClass, ?Operation $operation): bool {
+        return $resourceClass === OrganizationAddressPostal::class;
+    }
 
+    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void
+    {
         /** @var Access $currentUser */
         $currentUser = $this->security->getUser();
         $rootAlias = $queryBuilder->getRootAliases()[0];
@@ -32,4 +33,4 @@ final class CurrentOrganizationAddressPostalExtension extends AbstractExtension
             ->setParameter('organization', $currentUser->getOrganization())
         ;
     }
-}
+}

+ 7 - 6
src/Doctrine/Organization/CurrentOrganizationArticleExtension.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Doctrine\Organization;
 
+use ApiPlatform\Metadata\Operation;
 use App\Doctrine\AbstractExtension;
 use App\Entity\Access\Access;
 use App\Entity\Organization\OrganizationArticle;
@@ -18,12 +19,12 @@ final class CurrentOrganizationArticleExtension extends AbstractExtension
     public function __construct(private Security $security)
     { }
 
-    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
-    {
-        if (OrganizationArticle::class !== $resourceClass) {
-            return;
-        }
+    public function supports(string $resourceClass, ?Operation $operation): bool {
+        return $resourceClass === OrganizationArticle::class;
+    }
 
+    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void
+    {
         /** @var Access $currentUser */
         $currentUser = $this->security->getUser();
         $rootAlias = $queryBuilder->getRootAliases()[0];
@@ -32,4 +33,4 @@ final class CurrentOrganizationArticleExtension extends AbstractExtension
             ->setParameter('organization', $currentUser->getOrganization())
         ;
     }
-}
+}

+ 6 - 5
src/Doctrine/Organization/CurrentOrganizationExtension.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Doctrine\Organization;
 
+use ApiPlatform\Metadata\Operation;
 use App\Doctrine\AbstractExtension;
 use App\Entity\Access\Access;
 use App\Entity\Organization\Organization;
@@ -18,12 +19,12 @@ final class CurrentOrganizationExtension extends AbstractExtension
     public function __construct(private Security $security)
     { }
 
-    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
-    {
-        if (Organization::class !== $resourceClass) {
-            return;
-        }
+    public function supports(string $resourceClass, ?Operation $operation): bool {
+        return $resourceClass === Organization::class;
+    }
 
+    protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass, ?Operation $operation): void
+    {
         /** @var Access $currentUser */
         $currentUser = $this->security->getUser();
         $rootAlias = $queryBuilder->getRootAliases()[0];

+ 32 - 7
src/Entity/Access/Access.php

@@ -65,14 +65,13 @@ use Symfony\Component\Serializer\Annotation\Groups;
 
 /**
  * Fais le lien entre une Person et une Organization
- * @see : config/api_platform/Access/access.yaml
+ *
+ * Security :
+ *
+ *     @see ~/config/api_platform/Access/access.yaml
+ *     @see App\Doctrine\Access\CurrentAccessExtension
  */
-#[ApiResource(
-    operations: [
-        new Get(security: 'object.getId() == user.getId()'),
-        new Put(security: 'object.getId() == user.getId()'),
-    ]
-)]
+#[ApiResource]
 //#[Auditable]
 #[ORM\Entity(repositoryClass: AccessRepository::class)]
 #[ApiFilter(filterClass: BooleanFilter::class, properties: ['person.isPhysical'])]
@@ -196,6 +195,12 @@ class Access implements UserInterface, PasswordAuthenticatedUserInterface
     #[ORM\JoinColumn(referencedColumnName: 'id', nullable: false, onDelete: "SET NULL")]
     private AccessFamily $accessFamily;
 
+    #[ORM\Column]
+    private bool $newAccess = false;
+
+    #[ORM\Column]
+    private bool $ielEnabled = false;
+
     #[ORM\OneToMany(mappedBy: 'educationalProjectPayer', targetEntity: EducationalProjectPayer::class, cascade: ['persist'], orphanRemoval: true)]
     private Collection $billingEducationalProjectPayers;
 
@@ -1037,6 +1042,26 @@ class Access implements UserInterface, PasswordAuthenticatedUserInterface
         return $this;
     }
 
+    public function isNewAccess(): bool
+    {
+        return $this->newAccess;
+    }
+
+    public function setNewAccess(bool $newAccess): void
+    {
+        $this->newAccess = $newAccess;
+    }
+
+    public function isIelEnabled(): bool
+    {
+        return $this->ielEnabled;
+    }
+
+    public function setIelEnabled(bool $ielEnabled): void
+    {
+        $this->ielEnabled = $ielEnabled;
+    }
+
     /**
      * @return Collection<int, EducationalProjectPayer>
      */

+ 2 - 8
src/Entity/Access/AccessFamily.php

@@ -14,13 +14,7 @@ use Doctrine\ORM\Mapping as ORM;
 /**
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\')'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 class AccessFamily
@@ -102,4 +96,4 @@ class AccessFamily
         }
         return $this;
     }
-}
+}

+ 1 - 1
src/Entity/Access/OrganizationFunction.php

@@ -15,7 +15,7 @@ use Symfony\Component\Validator\Constraints as Assert;
 /**
  * Fonction d'un Access dans une Organization sur une période donnée
  */
-#[ApiResource]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity(repositoryClass: OrganizationFunctionRepository::class)]
 #[DateTimeConstraintAware(startDateFieldName: "startDate", endDateFieldName: "endDate")]

+ 6 - 1
src/Entity/Access/PersonalizedList.php

@@ -14,6 +14,11 @@ use Symfony\Component\Serializer\Annotation\Groups;
 
 /**
  * Liste personnalisées
+ *
+ * Security :
+ *
+ *     @see \App\Doctrine\Access\CurrentUserPersonalizedListExtension
+ *
  */
 #[ApiResource(
     operations: [
@@ -25,7 +30,7 @@ use Symfony\Component\Serializer\Annotation\Groups;
         )
     ],
     paginationEnabled: false
-)]
+)] // @see App\Doctrine\Access\CurrentUserPersonalizedListExtension
 #[ORM\Entity(repositoryClass: PersonalizedListRepository::class)]
 class PersonalizedList
 {

+ 44 - 2
src/Entity/AccessWish/AccessFamilyWish.php

@@ -9,7 +9,7 @@ use Doctrine\ORM\Mapping as ORM;
 use Doctrine\Common\Collections\Collection;
 
 /**
- * Classe ... qui ...
+ * Famille à laquelle est rattaché un AccessWish
  */
 //#[Auditable]
 #[ORM\Entity]
@@ -23,6 +23,19 @@ class AccessFamilyWish
     #[ORM\OneToMany(mappedBy: 'accessFamilyWish', targetEntity: AccessWish::class, cascade: ['remove'])]
     private Collection $accessWishes;
 
+    /**
+     * Date de dernière mise à jour de l'entité
+     * @var \DateTimeInterface
+     */
+    #[ORM\Column(type: 'datetime', nullable: true)]
+    private \DateTimeInterface $updateDate;
+
+    #[ORM\Column]
+    private bool $registrationCompleted = false;
+
+    #[ORM\Column]
+    private bool $closeRegistration = false;
+
     public function __construct()
     {
         $this->accessWishes = new ArrayCollection();
@@ -63,4 +76,33 @@ class AccessFamilyWish
         return $this;
     }
 
-}
+    public function getUpdateDate(): \DateTimeInterface
+    {
+        return $this->updateDate;
+    }
+
+    public function setUpdateDate(\DateTimeInterface $updateDate): void
+    {
+        $this->updateDate = $updateDate;
+    }
+
+    public function isRegistrationCompleted(): bool
+    {
+        return $this->registrationCompleted;
+    }
+
+    public function setRegistrationCompleted(bool $registrationCompleted): void
+    {
+        $this->registrationCompleted = $registrationCompleted;
+    }
+
+    public function isCloseRegistration(): bool
+    {
+        return $this->closeRegistration;
+    }
+
+    public function setCloseRegistration(bool $closeRegistration): void
+    {
+        $this->closeRegistration = $closeRegistration;
+    }
+}

+ 55 - 2
src/Entity/AccessWish/AccessWish.php

@@ -3,20 +3,25 @@ declare(strict_types=1);
 
 namespace App\Entity\AccessWish;
 
+use ApiPlatform\Metadata\ApiResource;
 use App\Entity\Access\Access;
 use App\Entity\Core\Country;
 use App\Entity\Core\File;
 use App\Entity\Core\Tagg;
 use App\Entity\Organization\Organization;
 //use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
+use App\Enum\OnlineRegistration\ValidationStateEnum;
 use Doctrine\Common\Collections\ArrayCollection;
 use Doctrine\ORM\Mapping as ORM;
 use Doctrine\Common\Collections\Collection;
+use \DateTime;
+use Symfony\Component\Validator\Constraints as Assert;
 
 /**
- * Classe ... qui ...
+ * Demande d'inscription d'un Access via l'IEL
  */
 //#[Auditable]
+#[ApiResource(operations: [])]
 #[ORM\Entity]
 class AccessWish
 {
@@ -58,6 +63,24 @@ class AccessWish
     #[ORM\InverseJoinColumn(name: 'tag_id', referencedColumnName: 'id')]
     private Collection $tags;
 
+    #[ORM\Column(length: 50)]
+    #[Assert\Choice(callback: [ValidationStateEnum::class, 'toArray'])]
+    private string $validationState;
+
+    /**
+     * Date de création dde l'entité
+     * @var DateTime
+     */
+    #[ORM\Column(type: 'datetime', nullable: true)]
+    private \DateTimeInterface $createDate;
+
+    /**
+     * Date de dernière mise à jour de l'entité
+     * @var DateTime
+     */
+    #[ORM\Column(type: 'datetime', nullable: true)]
+    private \DateTimeInterface $updateDate;
+
     public function __construct()
     {
         $this->educationStudentWishes = new ArrayCollection();
@@ -244,4 +267,34 @@ class AccessWish
 
         return $this;
     }
-}
+
+    public function getCreateDate(): DateTime
+    {
+        return $this->createDate;
+    }
+
+    public function setCreateDate(DateTime $createDate): void
+    {
+        $this->createDate = $createDate;
+    }
+
+    public function getUpdateDate(): DateTime
+    {
+        return $this->updateDate;
+    }
+
+    public function setUpdateDate(DateTime $updateDate): void
+    {
+        $this->updateDate = $updateDate;
+    }
+
+    public function getValidationState(): string
+    {
+        return $this->validationState;
+    }
+
+    public function setValidationState(string $validationState): void
+    {
+        $this->validationState = $validationState;
+    }
+}

+ 40 - 1
src/Entity/AccessWish/EducationStudentWish.php

@@ -8,7 +8,10 @@ use App\Entity\Education\EducationCurriculum;
 use App\Entity\Education\EducationStudent;
 use App\Entity\Education\EducationTiming;
 //use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
+use App\Enum\OnlineRegistration\RegistrationStatusEnum;
+use App\Enum\OnlineRegistration\WishRegistrationEnum;
 use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Validator\Constraints as Assert;
 
 /**
  * Classe ... qui ...
@@ -22,6 +25,22 @@ class EducationStudentWish
     #[ORM\GeneratedValue]
     private ?int $id = null;
 
+    /**
+     * TODO: Documenter
+     * @var string|null
+     */
+    #[ORM\Column(length: 50)]
+    #[Assert\Choice(callback: [WishRegistrationEnum::class, 'toArray'])]
+    private ?string $wishRegistration = null;
+
+    /**
+     * Statut de l'enregistrement en ligne
+     * @var string|null
+     */
+    #[ORM\Column(length: 50)]
+    #[Assert\Choice(callback: [RegistrationStatusEnum::class, 'toArray'])]
+    private ?string $registrationStatus = null;
+
     #[ORM\ManyToOne]
     #[ORM\JoinColumn(referencedColumnName: 'id' ,nullable: true, onDelete: 'SET NULL')]
     private Education $educationWish;
@@ -49,6 +68,26 @@ class EducationStudentWish
         return $this->id;
     }
 
+    public function getWishRegistration(): ?string
+    {
+        return $this->wishRegistration;
+    }
+
+    public function setWishRegistration(?string $wishRegistration): void
+    {
+        $this->wishRegistration = $wishRegistration;
+    }
+
+    public function getRegistrationStatus(): ?string
+    {
+        return $this->registrationStatus;
+    }
+
+    public function setRegistrationStatus(?string $registrationStatus): void
+    {
+        $this->registrationStatus = $registrationStatus;
+    }
+
     public function getEducationWish(): ?Education
     {
         return $this->educationWish;
@@ -120,4 +159,4 @@ class EducationStudentWish
 
         return $this;
     }
-}
+}

+ 2 - 8
src/Entity/Billing/AccessBilling.php

@@ -14,13 +14,7 @@ use Doctrine\Common\Collections\Collection;
 /**
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getAccess().getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 class AccessBilling
@@ -179,4 +173,4 @@ class AccessBilling
         $this->access = $access;
         return $this;
     }
-}
+}

+ 1 - 1
src/Entity/Billing/AccessIntangible.php

@@ -14,7 +14,7 @@ use Doctrine\Common\Collections\Collection;
 /**
  * Enregistrement d'un produit à facturer par un Access
  */
-#[ApiResource]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity(repositoryClass: AccessIntangibleRepository::class)]
 class AccessIntangible extends AbstractBillingIntangible

+ 1 - 7
src/Entity/Billing/AccessPayer.php

@@ -17,13 +17,7 @@ use Doctrine\ORM\Mapping as ORM;
  * Fais le lien entre l'Access qui règle la facture et l'Access concerné
  *
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getAccessPayer().getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Table(name: 'BillingPayer')]
 #[ORM\Entity(repositoryClass: AccessPayerRepository::class)]

+ 2 - 8
src/Entity/Billing/Bill.php

@@ -13,13 +13,7 @@ use Doctrine\ORM\Mapping as ORM;
  * @todo : A la suite de la migration, il faut supprimer le nom de la table pour avoir une table Bill, et supprimer l'attribut discr.
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 #[ORM\Table(name: 'BillAccounting')]
@@ -42,4 +36,4 @@ class Bill extends BillAccounting implements BillAccountingInterface
         $this->access = $access;
         return $this;
     }
-}
+}

+ 1 - 7
src/Entity/Billing/BillAccounting.php

@@ -16,13 +16,7 @@ use Doctrine\Common\Collections\Collection;
  * @todo : A la suite de la migration, il faut supprimer le nom de la table pour avoir une table BillAccounting, et supprimer l'attribut discr.
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 class BillAccounting

+ 2 - 8
src/Entity/Billing/BillCredit.php

@@ -14,13 +14,7 @@ use Doctrine\ORM\Mapping as ORM;
  *
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 #[ORM\Table(name: 'BillAccounting')]
@@ -43,4 +37,4 @@ class BillCredit extends BillAccounting implements BillAccountingInterface
         $this->access = $access;
         return $this;
     }
-}
+}

+ 2 - 8
src/Entity/Billing/BillLine.php

@@ -14,13 +14,7 @@ use Doctrine\ORM\Mapping as ORM;
 /**
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getAccess().getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 class BillLine
@@ -91,4 +85,4 @@ class BillLine
         $this->equipmentLoan = $equipmentLoan;
         return $this;
     }
-}
+}

+ 1 - 7
src/Entity/Billing/BillingIntangibleExcludeDate.php

@@ -12,13 +12,7 @@ use Doctrine\ORM\Mapping as ORM;
 /**
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\')'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 class BillingIntangibleExcludeDate

+ 1 - 5
src/Entity/Billing/BillingSetting.php

@@ -13,11 +13,7 @@ use Doctrine\Common\Collections\Collection;
 use Doctrine\ORM\Mapping as ORM;
 use JetBrains\PhpStorm\Pure;
 
-#[ApiResource(
-    operations: [
-        new Get()
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity(repositoryClass: BillingSettingRepository::class)]
 class BillingSetting

+ 2 - 8
src/Entity/Billing/EducationalProjectPayer.php

@@ -15,13 +15,7 @@ use Doctrine\ORM\Mapping as ORM;
  *
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getEducationalProjectPayer().getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Table(name: 'BillingPayer')]
 #[ORM\Entity]
@@ -67,4 +61,4 @@ class EducationalProjectPayer
         $this->educationalProjectReceiver = $educationalProjectReceiver;
         return $this;
     }
-}
+}

+ 2 - 8
src/Entity/Billing/FamilyQuotient.php

@@ -14,13 +14,7 @@ use Doctrine\ORM\Mapping as ORM;
 /**
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getBillingSetting().getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 class FamilyQuotient
@@ -117,4 +111,4 @@ class FamilyQuotient
         }
         return $this;
     }
-}
+}

+ 5 - 18
src/Entity/Billing/ResidenceArea.php

@@ -19,25 +19,12 @@ use Doctrine\Common\Collections\Collection;
 
 /**
  * Zone de résidence d'un Access, telle que définie par l'Organization
+ *
+ * Security :
+ *
+ *     @see \App\Doctrine\Billing\CurrentResidenceAreaExtension
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ORGANIZATION_VIEW\') and object.getBillingSetting().getOrganization().getId() == user.getOrganization().getId()'
-        ),
-        new Put(
-            security: 'object.getBillingSetting().getOrganization().getId() == user.getOrganization().getId()'
-        ),
-        new Delete(
-            security: 'object.getBillingSetting().getOrganization().getId() == user.getOrganization().getId()'
-        ),
-        new GetCollection(
-            security: 'is_granted(\'ROLE_ORGANIZATION_VIEW\')'
-        ),
-        new Post()
-    ],
-    security: 'is_granted(\'ROLE_ORGANIZATION\')'
-)]
+#[ApiResource(operations: [])] // @see App\Doctrine\Billing\CurrentResidenceAreaExtension
 //#[Auditable]
 #[BillingSettingDefaultValue(fieldName: "billingSetting")]
 #[ORM\Entity(repositoryClass: ResidenceAreaRepository::class)]

+ 2 - 8
src/Entity/Booking/Attendance.php

@@ -15,13 +15,7 @@ use Doctrine\ORM\Mapping as ORM;
 /**
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 class Attendance
@@ -114,4 +108,4 @@ class Attendance
         }
         return $this;
     }
-}
+}

+ 1 - 7
src/Entity/Booking/AttendanceBooking.php

@@ -12,13 +12,7 @@ use Doctrine\ORM\Mapping as ORM;
 /**
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\')'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 class AttendanceBooking

+ 5 - 9
src/Entity/Booking/Course.php

@@ -25,15 +25,11 @@ use Doctrine\Common\Collections\Collection;
  * @todo : migration table tag_booking
  *
  * Classe Course qui permet de gérer les cours de la structure.
+ *
+ * Security :
+ *   * @see App\Doctrine\Booking\CurrentCoursesExtension
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_COURSE_VIEW\') and object.getOrganization().getId() == user.getOrganization().getId()'
-        ),
-        new GetCollection()
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity(repositoryClass: CourseRepository::class)]
 #[ORM\Table(name: 'Booking')]
@@ -401,4 +397,4 @@ class Course extends AbstractBooking
         $this->tags->removeElement($tag);
         return $this;
     }
-}
+}

+ 2 - 8
src/Entity/Booking/EducationalProject.php

@@ -24,13 +24,7 @@ use Doctrine\ORM\Mapping as ORM;
  * @todo : migration table tag_booking
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Table(name: 'Booking')]
 #[ORM\Entity]
@@ -461,4 +455,4 @@ class EducationalProject extends AbstractBooking
         $this->tags->removeElement($tag);
         return $this;
     }
-}
+}

+ 1 - 7
src/Entity/Booking/Event.php

@@ -23,13 +23,7 @@ use Symfony\Component\Validator\Constraints as Assert;
  * @todo : A la suite de la migration, il faut supprimer le nom de la table pour avoir une table Event, et supprimer l'attribut discr.
  * @todo : migration table tag_booking
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 #[ORM\Table(name: 'Booking')]

+ 2 - 8
src/Entity/Booking/EventUser.php

@@ -12,13 +12,7 @@ use Doctrine\ORM\Mapping as ORM;
 /**
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getAccess().getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 class EventUser
@@ -60,4 +54,4 @@ class EventUser
         $this->guest = $guest;
         return $this;
     }
-}
+}

+ 2 - 8
src/Entity/Booking/Examen.php

@@ -22,13 +22,7 @@ use Doctrine\ORM\Mapping as ORM;
  * @todo : migration table tag_booking
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 #[ORM\Table(name: 'Booking')]
@@ -324,4 +318,4 @@ class Examen extends AbstractBooking
         $this->tags->removeElement($tag);
         return $this;
     }
-}
+}

+ 3 - 1
src/Entity/Booking/ExamenConvocation.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Entity\Booking;
 
+use ApiPlatform\Metadata\ApiResource;
 use App\Entity\Access\Access;
 use App\Entity\Product\Equipment;
 //use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
@@ -14,6 +15,7 @@ use Doctrine\ORM\Mapping as ORM;
  * Classe ... qui ...
  */
 //#[Auditable]
+#[ApiResource(operations: [])]
 #[ORM\Entity]
 class ExamenConvocation
 {
@@ -91,4 +93,4 @@ class ExamenConvocation
 
         return $this;
     }
-}
+}

+ 2 - 8
src/Entity/Booking/OrganizationHoliday.php

@@ -16,13 +16,7 @@ use Doctrine\ORM\Mapping as ORM;
  *
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 #[ORM\Table(name: 'Booking')]
@@ -92,4 +86,4 @@ class OrganizationHoliday extends AbstractBooking
         $this->organization = $organization;
         return $this;
     }
-}
+}

+ 2 - 8
src/Entity/Booking/PersonHoliday.php

@@ -16,13 +16,7 @@ use Doctrine\ORM\Mapping as ORM;
  *
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getAccess().getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 #[ORM\Table(name: 'Booking')]
@@ -91,4 +85,4 @@ class PersonHoliday extends AbstractBooking
         $this->access = $access;
         return $this;
     }
-}
+}

+ 1 - 1
src/Entity/Core/AbstractInformation.php

@@ -26,7 +26,7 @@ use Symfony\Component\Serializer\Annotation\Context;
  *
  * Classe Notification. qui permet de gérer les notifications aux utilisateurs.
  */
-#[ApiResource]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 #[ORM\Table(name: 'Information')]

+ 7 - 8
src/Entity/Core/AddressPostal.php

@@ -17,14 +17,13 @@ use Doctrine\ORM\Mapping as ORM;
 use App\Entity\Person\PersonAddressPostal;
 use Symfony\Component\Serializer\Annotation\Groups;
 
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ORGANIZATION_VIEW\') and object.getOrganizationAddressPostal().getOrganization().getId() == user.getOrganization().getId()'
-        ),
-        new GetCollection()
-    ]
-)]
+/**
+ * Adresse postale d'une organisation ou d'une personne
+ *
+ * Security :
+ *   * @see App\Doctrine\Core\AllowedAddressPostalExtension
+ */
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity(repositoryClass: AddressPostalRepository::class)]
 class AddressPostal

+ 4 - 15
src/Entity/Core/BankAccount.php

@@ -21,22 +21,11 @@ use Symfony\Component\Validator\Constraints as Assert;
 
 /**
  * Données bancaire d'une Person ou d'une Organization
+ *
+ * Security :
+ *   * @see App\Security\Voter\BankAccountVoter
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted("BANK_ACCOUNT_READ", object)'
-        ),
-        new Put(
-            security: 'is_granted("BANK_ACCOUNT_EDIT", object)'
-        ),
-        new Delete(
-            security: 'is_granted("BANK_ACCOUNT_DELETE", object)'
-        ),
-        new Post(),
-        new GetCollection()
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity(repositoryClass: BankAccountRepository::class)]
 class BankAccount

+ 4 - 15
src/Entity/Core/ContactPoint.php

@@ -25,22 +25,11 @@ use App\Validator\Core as OpentalentAssert;
 
 /**
  * Données de contact d'une Person ou d'une Organization ou d'un lieu
+ *
+ * Security :
+ *   * @see App\Security\Voter\ContactPointVoter
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted("CONTACT_POINT_READ", object)'
-        ),
-        new Put(
-            security: 'is_granted("CONTACT_POINT_EDIT", object)'
-        ),
-        new Delete(
-            security: 'is_granted("CONTACT_POINT_DELETE", object)'
-        ),
-        new Post(),
-        new GetCollection()
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity(repositoryClass: ContactPointRepository::class)]
 #[OpentalentAssert\ContactPoint]

+ 46 - 6
src/Entity/Core/File.php

@@ -5,6 +5,8 @@ namespace App\Entity\Core;
 
 use ApiPlatform\Metadata\Put;
 use ApiPlatform\Metadata\Get;
+use ApiPlatform\Metadata\Post;
+use ApiPlatform\Metadata\Delete;
 use ApiPlatform\Metadata\ApiResource;
 use App\Entity\AccessWish\DocumentWish;
 use App\Entity\Booking\Event;
@@ -28,10 +30,18 @@ use Symfony\Component\Serializer\Annotation\Groups;
 use Symfony\Component\Validator\Constraints as Assert;
 use App\Enum\Core\FileStatusEnum;
 
+/**
+ * Fichier, généré ou uploadé, appartenant à une organisation ou à une personne.
+ *
+ * Security :
+ *   * @see App\Security\Voter\FileVoter
+ */
 #[ApiResource(
     operations: [
-        new Get(),
-        new Put()
+        new Get(security: "is_granted('READ', object)"),
+        new Put(security: "is_granted('EDIT', object)"),
+        new Post(security: "is_granted('CREATE', object)"),
+        new Delete(security: "is_granted('DELETE', object)")
     ]
 )]
 //#[Auditable]
@@ -172,10 +182,14 @@ class File
 
     //    #[ORM\Column]
     //    private ?int $eventReport_id;
-    //
-    //    #[ORM\Column]
-    //    private ?\DateTime $availabilityDate;
-    //
+
+    /**
+     * TODO: complete
+     * @var DateTime|null
+     */
+    #[ORM\Column]
+    private ?\DateTime $availabilityDate;
+
     //    #[ORM\Column]
     //    private ?int $documentWish_id;
     //
@@ -187,6 +201,7 @@ class File
     //
     //    #[ORM\Column]
     //    private ?int $work_id;
+
     #[ORM\ManyToMany(targetEntity: Person::class, inversedBy: 'personFiles')]
     #[Groups(['file_person'])]
     private Collection $accessPersons;
@@ -367,6 +382,15 @@ class File
         return $this;
     }
 
+    /**
+     * A priori inutilisé
+     * @deprecated
+     * @return Collection
+     */
+    public function getAccessRoles(): Collection {
+        return new ArrayCollection([]);
+    }
+
     /**
      * @return string
      */
@@ -604,6 +628,22 @@ class File
         return $this;
     }
 
+    /**
+     * @return DateTime|null
+     */
+    public function getAvailabilityDate(): ?DateTime
+    {
+        return $this->availabilityDate;
+    }
+
+    /**
+     * @param DateTime|null $availabilityDate
+     */
+    public function setAvailabilityDate(?DateTime $availabilityDate): void
+    {
+        $this->availabilityDate = $availabilityDate;
+    }
+
     /**
      * @return Collection<int, Person>
      */

+ 4 - 1
src/Entity/Core/Notification.php

@@ -24,7 +24,10 @@ use Symfony\Component\Serializer\Annotation\Context;
 /**
  * @todo : A la suite de la migration, il faut supprimer le nom de la table pour avoir une table Notification, et supprimer l'attribut discr.
  *
- * Classe Notification. qui permet de gérer les notifications aux utilisateurs.
+ * Notification à un utilisateur
+ *
+ * Security :
+ *   * @see App\Doctrine\Core\CurrentUserNotificationExtension
  */
 #[ApiResource(
     operations: [

+ 3 - 0
src/Entity/Core/NotificationUser.php

@@ -16,6 +16,9 @@ use Doctrine\ORM\Mapping as ORM;
 /**
  * Les NotificationUser permettent de garder la trace des notifications et des tips
  * qui ont été lues par les utilisateurs
+ *
+ * Security :
+ *   * @see App\Doctrine\Core\CurrentUserNotificationUserExtension
  */
 #[ApiResource(
     operations: [

+ 2 - 8
src/Entity/Core/Tagg.php

@@ -41,13 +41,7 @@ use Doctrine\ORM\Mapping as ORM;
 /**
  * Classe ... qui ...
  */
-#[ApiResource(
-    operations: [
-        new Get(
-            security: 'is_granted(\'ROLE_ADMIN\') and object.getOrganization().getId() == user.getOrganization().getId()'
-        )
-    ]
-)]
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Entity]
 class Tagg
@@ -863,4 +857,4 @@ class Tagg
         }
         return $this;
     }
-}
+}

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است