浏览代码

rights refactoring + unit test + docs

Vincent GUFFON 4 年之前
父节点
当前提交
ad613049fa
共有 66 个文件被更改,包括 1731 次插入690 次删除
  1. 1 1
      .env
  2. 5 0
      .env.test
  3. 10 0
      .gitignore
  4. 13 0
      bin/phpunit
  5. 2 0
      composer.json
  6. 144 1
      composer.lock
  7. 20 23
      config/opentalent/modulesbyconditions.yaml
  8. 1 1
      config/opentalent/products.yaml
  9. 3 2
      config/packages/api_platform.yaml
  10. 37 20
      config/packages/security.yaml
  11. 16 50
      config/packages/security/billing.yaml
  12. 13 50
      config/packages/security/booking.yaml
  13. 2 64
      config/packages/security/core.yaml
  14. 0 2
      config/packages/security/donors.yaml
  15. 3 18
      config/packages/security/equipments.yaml
  16. 3 27
      config/packages/security/generalConfig.yaml
  17. 0 2
      config/packages/security/medals.yaml
  18. 0 35
      config/packages/security/messages.yaml
  19. 8 37
      config/packages/security/pedagogics.yaml
  20. 10 92
      config/packages/security/users.yaml
  21. 1 1
      config/packages/security/viewaudit.yaml
  22. 5 1
      config/routes.yaml
  23. 9 0
      config/services/services.yaml
  24. 33 0
      phpunit.xml.dist
  25. 20 20
      src/ApiResources/Profile/AccessProfile.php
  26. 91 0
      src/ApiResources/Profile/OrganizationProfile.php
  27. 6 0
      src/DataPersister/Common/OpentalentDataPersister.php
  28. 88 0
      src/DataProvider/Access/AccessProfileDataProvider.php
  29. 0 65
      src/DataProvider/Access/MyProfileDataProvider.php
  30. 6 0
      src/DataProvider/Common/OpentalentCollectionDataProvider.php
  31. 6 0
      src/DataProvider/Common/OpentalentItemDataProvider.php
  32. 6 0
      src/Doctrine/Access/AccessExtension.php
  33. 6 4
      src/Entity/Access/Access.php
  34. 3 0
      src/Entity/Access/OrganizationFunction.php
  35. 84 0
      src/Entity/Network/Network.php
  36. 98 0
      src/Entity/Network/NetworkOrganization.php
  37. 84 2
      src/Entity/Organization/Organization.php
  38. 6 0
      src/Entity/Organization/Settings.php
  39. 3 0
      src/Entity/Person/Person.php
  40. 3 0
      src/Entity/Person/PersonActivity.php
  41. 18 0
      src/Enum/Network/LeadingCauseEnum.php
  42. 18 0
      src/Enum/Network/NetworkEnum.php
  43. 22 0
      src/Enum/Organization/PrincipalTypeEnum.php
  44. 18 0
      src/Enum/Organization/SettingsProductEnum.php
  45. 8 1
      src/EventListener/JWT/AuthenticationSuccessListener.php
  46. 0 82
      src/EventSubscriber/ModuleSecuritySubscriber.php
  47. 8 1
      src/Repository/Access/AccessRepository.php
  48. 2 1
      src/Repository/Access/OrganizationFunctionRepository.php
  49. 51 0
      src/Repository/Network/NetworkOrganizationRepository.php
  50. 51 0
      src/Repository/Network/NetworkRepository.php
  51. 43 26
      src/Repository/Organization/OrganizationRepository.php
  52. 2 1
      src/Repository/Organization/SettingsRepository.php
  53. 2 1
      src/Repository/Person/PersonActivityRepository.php
  54. 2 1
      src/Repository/Person/PersonRepository.php
  55. 32 6
      src/Security/ModuleVoter.php
  56. 115 0
      src/Service/Cotisation/Utils.php
  57. 48 0
      src/Service/Network/Utils.php
  58. 30 0
      src/Service/Organization/Utils.php
  59. 63 52
      src/Service/Security/Module.php
  60. 34 0
      src/Service/Utils/Reflection.php
  61. 30 0
      symfony.lock
  62. 93 0
      tests/Service/Cotisation/UtilsTest.php
  63. 77 0
      tests/Service/Network/UtilsTest.php
  64. 34 0
      tests/Service/Organization/UtilsTest.php
  65. 70 0
      tests/Service/Security/ModuleTest.php
  66. 11 0
      tests/bootstrap.php

+ 1 - 1
.env

@@ -14,7 +14,7 @@
 # https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
 
 ###> symfony/framework-bundle ###
-APP_ENV=prod
+APP_ENV=dev
 APP_SECRET=6a76497c8658bb23e2236f97a2627df3
 #TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
 #TRUSTED_HOSTS='^(localhost|example\.com)$'

+ 5 - 0
.env.test

@@ -0,0 +1,5 @@
+# define your env variables for the test env here
+KERNEL_CLASS='App\Kernel'
+APP_SECRET='$ecretf0rt3st'
+SYMFONY_DEPRECATIONS_HELPER=999999
+PANTHER_APP_ENV=panther

+ 10 - 0
.gitignore

@@ -12,3 +12,13 @@
 ###> lexik/jwt-authentication-bundle ###
 /config/jwt/*.pem
 ###< lexik/jwt-authentication-bundle ###
+
+###> symfony/phpunit-bridge ###
+.phpunit
+.phpunit.result.cache
+/phpunit.xml
+###< symfony/phpunit-bridge ###
+
+###> phpdocs ###
+src/.phpdoc/
+###< phpdocs ###

+ 13 - 0
bin/phpunit

@@ -0,0 +1,13 @@
+#!/usr/bin/env php
+<?php
+
+if (!file_exists(dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php')) {
+    echo "Unable to find the `simple-phpunit.php` script in `vendor/symfony/phpunit-bridge/bin/`.\n";
+    exit(1);
+}
+
+if (false === getenv('SYMFONY_PHPUNIT_DIR')) {
+    putenv('SYMFONY_PHPUNIT_DIR='.__DIR__.'/.phpunit');
+}
+
+require dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php';

+ 2 - 0
composer.json

@@ -20,6 +20,7 @@
         "doctrine/orm": "^2.7",
         "jbouzekri/phumbor-bundle": "^2.1",
         "lexik/jwt-authentication-bundle": "^2.8",
+        "myclabs/php-enum": "^1.7",
         "nelmio/cors-bundle": "^2.1",
         "odolbeau/phone-number-bundle": "^3.1",
         "phpdocumentor/reflection-docblock": "^5.2",
@@ -41,6 +42,7 @@
     },
     "require-dev": {
         "symfony/maker-bundle": "^1.21",
+        "symfony/phpunit-bridge": "^5.2",
         "symfony/stopwatch": "^5.2",
         "symfony/web-profiler-bundle": "^5.2"
     },

+ 144 - 1
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "63da95928452e808b0aaa14592a2d82d",
+    "content-hash": "8b42a96843bf635c7b95df1e4f526fb9",
     "packages": [
         {
             "name": "api-platform/core",
@@ -2350,6 +2350,66 @@
             ],
             "time": "2020-12-19T18:27:01+00:00"
         },
+        {
+            "name": "myclabs/php-enum",
+            "version": "1.7.7",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/myclabs/php-enum.git",
+                "reference": "d178027d1e679832db9f38248fcc7200647dc2b7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/myclabs/php-enum/zipball/d178027d1e679832db9f38248fcc7200647dc2b7",
+                "reference": "d178027d1e679832db9f38248fcc7200647dc2b7",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "php": ">=7.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^7",
+                "squizlabs/php_codesniffer": "1.*",
+                "vimeo/psalm": "^3.8"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "MyCLabs\\Enum\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP Enum contributors",
+                    "homepage": "https://github.com/myclabs/php-enum/graphs/contributors"
+                }
+            ],
+            "description": "PHP Enum implementation",
+            "homepage": "http://github.com/myclabs/php-enum",
+            "keywords": [
+                "enum"
+            ],
+            "support": {
+                "issues": "https://github.com/myclabs/php-enum/issues",
+                "source": "https://github.com/myclabs/php-enum/tree/1.7.7"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/mnapoli",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-11-14T18:14:52+00:00"
+        },
         {
             "name": "namshi/jose",
             "version": "7.2.3",
@@ -7070,6 +7130,89 @@
             ],
             "time": "2020-12-18T17:08:39+00:00"
         },
+        {
+            "name": "symfony/phpunit-bridge",
+            "version": "v5.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/phpunit-bridge.git",
+                "reference": "235823f6d215c9bd930a47a496e62c1354cde55b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/235823f6d215c9bd930a47a496e62c1354cde55b",
+                "reference": "235823f6d215c9bd930a47a496e62c1354cde55b",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9"
+            },
+            "conflict": {
+                "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0|<6.4,>=6.0|9.1.2"
+            },
+            "require-dev": {
+                "symfony/deprecation-contracts": "^2.1",
+                "symfony/error-handler": "^4.4|^5.0"
+            },
+            "suggest": {
+                "symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader"
+            },
+            "bin": [
+                "bin/simple-phpunit"
+            ],
+            "type": "symfony-bridge",
+            "extra": {
+                "thanks": {
+                    "name": "phpunit/phpunit",
+                    "url": "https://github.com/sebastianbergmann/phpunit"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Bridge\\PhpUnit\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony PHPUnit Bridge",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/phpunit-bridge/tree/v5.2.1"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-12-14T22:27:17+00:00"
+        },
         {
             "name": "symfony/web-profiler-bundle",
             "version": "v5.2.1",

+ 20 - 23
config/opentalent/modulesbyconditions.yaml

@@ -4,86 +4,85 @@ opentalent:
             roles:
                 - ROLE_COTISATION
             conditions:
-                service: 
+                service:
                     name: opentalent.cotisation.utils
                     function: isLastParentAndCMF
         CotisationStructure:
             roles:
                 - ROLE_COTISATION
             conditions:
-                service: 
+                service:
                     name: opentalent.cotisation.utils
                     function: isStructureAndCMF
         CotisationRate:
             roles:
                 - ROLE_COTISATION
             conditions:
-                service: 
+                service:
                     name: opentalent.cotisation.utils
                     function: isLastParentAndManagerCMFAndCMF
         CotisationTransmissionState:
             roles:
                 - ROLE_COTISATION
             conditions:
-                service: 
+                service:
                     name: opentalent.cotisation.utils
                     function: isManagerAndCMF
         CotisationTransmission:
             roles:
                 - ROLE_COTISATION
             conditions:
-                service: 
+                service:
                     name: opentalent.cotisation.utils
-                    function: isManagerAndNotLastParentAndCMF                    
+                    function: isManagerAndNotLastParentAndCMF
         CotisationCMFAdministration:
             roles:
                 - ROLE_COTISATION
             conditions:
-                service: 
+                service:
                     name: opentalent.cotisation.utils
-                    function: isCMFAdministration                    
+                    function: isCMFAdministration
 
         Admin2IOS:
             roles:
                 - ROLE_ADMIN2IOS
             conditions:
-                service: 
+                service:
                     name: opentalent.admin2IOS.utils
-                    function: isAdmin2IOS                                        
+                    function: isAdmin2IOS
         StatisticFederation:
             roles:
                 - ROLE_STATISTIC
             conditions:
-                service: 
+                service:
                     name: opentalent.cotisation.utils
-                    function: isManagerAndNotLastParentAndCMF                    
+                    function: isManagerAndNotLastParentAndCMF
         StatisticStructure:
             roles:
                 - ROLE_STATISTIC
             conditions:
-                service: 
+                service:
                     name: opentalent.cotisation.utils
-                    function: isManagerAndCMF                    
+                    function: isManagerAndCMF
         Statistic:
             roles:
                 - ROLE_STATISTIC
             conditions:
-                service: 
+                service:
                     name: opentalent.cotisation.utils
-                    function: isStructure                    
+                    function: isStructure
         Network:
             roles:
                 - ROLE_NETWORK
             conditions:
-                service: 
-                    name: opentalent.cotisation.utils
+                service:
+                    name: opentalent.network.utils
                     function: isCMF
         NetworkOrganization:
             conditions:
-                service: 
-                    name: opentalent.cotisation.utils
+                service:
+                    name: opentalent.network.utils
                     function: isCMF
-
         Pes:
             conditions:
                 service:
@@ -95,8 +94,6 @@ opentalent:
                 service:
                     name: opentalent.export.module.utils
                     function: isOrganizationWithBergerLevrault
-
-
         Jvs:
             conditions:
                 service:

+ 1 - 1
config/opentalent/products.yaml

@@ -2,7 +2,7 @@ opentalent:
     modules:
       Core:
         entities:
-          - MyProfile
+          - AccessProfile
           - Tips
           - Notification
           - ContactPoint

+ 3 - 2
config/packages/api_platform.yaml

@@ -1,6 +1,8 @@
 api_platform:
+    enable_swagger_ui: false
+    enable_re_doc: false
     mapping:
-        paths: ['%kernel.project_dir%/src/Entity']
+        paths: ['%kernel.project_dir%/src/Entity', '%kernel.project_dir%/src/ApiResources']
     patch_formats:
         json: ['application/merge-patch+json']
     swagger:
@@ -11,4 +13,3 @@ api_platform:
             items_per_page: 20
     resource_class_directories:
         - '%kernel.project_dir%/src/Entity'
-        - '%kernel.project_dir%/src/DTO'

+ 37 - 20
config/packages/security.yaml

@@ -3,7 +3,7 @@ imports:
 
 security:
     role_hierarchy:
-        ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH, ROLE_TIPS, ROLE_NETWORK]
+        ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE-ALLOWED-TO-SWITCH, ROLE_TIPS, ROLE_NETWORK]
 
         BASE_ROLE_ADMINISTRATION_CORE : &BASE_ROLE_ADMINISTRATION_CORE
             - ROLE_MEMBER_CORE
@@ -11,7 +11,7 @@ security:
             - ROLE_ORGANIZATION_VIEW
 
         ROLE_ADMIN:
-            - ROLE_CORE_CRUD
+            - ROLE_CORE-CRUD
             - ROLE_GENERAL_CONFIG
             - ROLE_PEDAGOGICS_ADMINISTRATION
             - ROLE_PEDAGOGICS_SEIZURE
@@ -25,11 +25,12 @@ security:
             - ROLE_COTISATION
             - ROLE_ONLINEREGISTRATION_ADMINISTRATION
             - ROLE_STATISTIQUE
+            - ROLE_ADMIN_CORE
 
         ROLE_ADMIN_CORE: *BASE_ROLE_ADMINISTRATION_CORE
 
         ROLE_ADMINISTRATIF_MANAGER:
-            - ROLE_CORE_CRUD
+            - ROLE_CORE-CRUD
             - ROLE_GENERAL_CONFIG
             - ROLE_PEDAGOGICS_ADMINISTRATION
             - ROLE_PEDAGOGICS_SEIZURE
@@ -42,11 +43,12 @@ security:
             - ROLE_NETWORK
             - ROLE_COTISATION
             - ROLE_ONLINEREGISTRATION_ADMINISTRATION
+            - ROLE_ADMINISTRATIF_MANAGER_CORE
 
         ROLE_ADMINISTRATIF_MANAGER_CORE: *BASE_ROLE_ADMINISTRATION_CORE
 
         ROLE_PEDAGOGICS_MANAGER:
-            - ROLE_CORE_CRUD
+            - ROLE_CORE-CRUD
             - ROLE_PEDAGOGICS_ADMINISTRATION
             - ROLE_PEDAGOGICS_SEIZURE
             - ROLE_EVENTS
@@ -56,22 +58,28 @@ security:
             - ROLE_BILLINGS_ADMINISTRATION_VIEW
             - ROLE_BILLINGS_SEIZURE-VIEW
             - ROLE_ONLINEREGISTRATION_ADMINISTRATION
+            - ROLE_PEDAGOGICS_MANAGER_CORE
+
         ROLE_PEDAGOGICS_MANAGER_CORE:
             - ROLE_MEMBER_CORE
+
         ROLE_FINANCIAL_MANAGER:
-            - ROLE_CORE_CRUD
+            - ROLE_CORE-CRUD
             - ROLE_EVENTS_VIEW
             - ROLE_COURSES_VIEW
             - ROLE_EXAMENS_VIEW
             - ROLE_EDUCATIONALPROJECTS_VIEW
             - ROLE_BILLINGS_ADMINISTRATION
             - ROLE_BILLINGS_SEIZURE
+            - ROLE_FINANCIAL_MANAGER_CORE
+
         ROLE_FINANCIAL_MANAGER_CORE:
             - ROLE_MEMBER_CORE
             - ROLE_PAYER
+
         ROLE_CA:
             - ROLE_GENERAL_CONFIG
-            - ROLE_CORE_CRUD
+            - ROLE_CORE-CRUD
             - ROLE_COTISATION
             - ROLE_EVENTS
             - ROLE_COURSES
@@ -79,27 +87,35 @@ security:
             - ROLE_EDUCATIONALPROJECTS
             - ROLE_BILLINGS_ADMINISTRATION_VIEW
             - ROLE_BILLINGS_SEIZURE_VIEW
+            - ROLE_CA_CORE
+
         ROLE_CA_CORE:
             - ROLE_MEMBER_CORE
-            - ROLE_USERS_WITH_COORDINATE_VIEW
+
+        ROLE_STUDENT :
+            - ROLE_STUDENT_CORE
+
         ROLE_STUDENT_CORE:
             - ROLE_MEMBER_CORE
-            - ROLE_WORKBYUSER
+            - ROLE_WORK-BY-USER
+
+        ROLE_TEACHER:
+            - ROLE_TEACHER_CORE
+
         ROLE_TEACHER_CORE:
             - ROLE_MEMBER_CORE
-            - ROLE_OWN_MY_STUDENT
-            - ROLE_OWN_EXPORT_PRESENCE-EVENT_ACTION
-            - ROLE_OWN_EXPORT_PRESENCE-COURSE_ACTION
-            - ROLE_OWN_EXPORT_PRESENCE-EXAMEN_ACTION
-            - ROLE_OWN_EVALUATETUDENTS_ACTION
-            - ROLE_COURSES_TEACHER
-            - ROLE_CRITERIANOTATION
-        ROLE_TEACHER:
-            - ROLE_TAGG_VIEW
+            - ROLE_OWN-MY-STUDENT
+
+        ROLE_MEMBER:
+            - ROLE_MEMBER_CORE
+
         ROLE_MEMBER_CORE:
             - ROLE_CORE
             - ROLE_CORE_ACTION
-            - ROLE_OWN_ADHERENT_CONTACT_ACCESS_VIEW
+
+        ROLE_OTHER:
+            - ROLE_OTHER_CORE
+
         ROLE_OTHER_CORE:
             - ROLE_CORE
             - ROLE_RULERZ_ACTION
@@ -154,5 +170,6 @@ security:
 
     # Easy way to control access for large sections of your site
     # Note: Only the *first* access control that matches will be used
-#    access_control:
-#        - { path: ^/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY } # Allows accessing the Swagger UI
+    access_control:
+        - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
+        - { path: ^/api, roles: IS_HAVING_MODULE }

+ 16 - 50
config/packages/security/billing.yaml

@@ -1,68 +1,34 @@
 security:
     role_hierarchy:
         ROLE_BILLINGS_ADMINISTRATION:
-          - ROLE_INTANGIBLE
-          - ROLE_RESIDENCEAREA
-          - ROLE_FAMILYQUOTIENT
-          - ROLE_BILL
-          - ROLE_BILLCREDIT
-          - ROLE_BILLACCOUNTING
-          - ROLE_BILLPAYMENT
-          - ROLE_BILLINGS_SEIZURE_REFERENCE
-          - ROLE_BILLINGS_ADMINISTRATION_ACTION
-          - ROLE_ACCESSPAYER
-          - ROLE_ACCESSINTANGIBLE
-          - ROLE_PES_ADMINISTRATION
-          - ROLE_BERGERLEVRAULT_ADMINISTRATION
-          - ROLE_PAYER
-          - ROLE_JVS_ADMINISTRATION
+          - ROLE_BILLINGS-SEIZURE_REFERENCE
+          - ROLE_BILLINGS-ADMINISTRATION_ACTION
+          - ROLE_PES-ADMINISTRATION
+          - ROLE_BERGERLEVRAULT-ADMINISTRATION
+          - ROLE_JVS-ADMINISTRATION
 
         ROLE_BILLINGS_ADMINISTRATION_VIEW:
-          - ROLE_INTANGIBLE_VIEW
-          - ROLE_RESIDENCEAREA_VIEW
-          - ROLE_FAMILYQUOTIENT_VIEW
-          - ROLE_BILL_VIEW
-          - ROLE_BILLCREDIT_VIEW
-          - ROLE_BILLACCOUNTING_VIEW
-          - ROLE_BILLPAYMENT_VIEW
-          - ROLE_BILLINGS_SEIZURE_REFERENCE
+          - ROLE_BILLINGS-SEIZURE_REFERENCE
 
-        ROLE_BILLINGS_ADMINISTRATION_ACTION:
-          - ROLE_BILLINGEDITION_ACTION
-          - ROLE_CREDITEDITION_ACTION
+        ROLE_BILLINGS-ADMINISTRATION_ACTION:
           - ROLE_RULERZ_ACTION
-          - ROLE_EXPORT_UNPAID-BILL_ACTION
-          - ROLE_EXPORT_UNPAID-BILL-EMAIL_ACTION
-          - ROLE_EXPORT_BILLING_ACTION
-          - ROLE_EXPORT_ALL-BILL_ACTION
-          - ROLE_EXPORT_PAID-BILL_ACTION
-          - ROLE_EXPORT_PAID-BILL-EMAIL_ACTION
-          - ROLE_EXPORT_BILL-BILLLINES_ACTION
-          - ROLE_EXPORT_BILL-PAYMENT-RECEIPT_ACTION
-          - ROLE_EXPORT_BILL-PAYMENT-DETAIL_ACTION
-          - ROLE_EXPORT_ALL-BILL-EMAIL_ACTION
 
         ROLE_BILLINGS_SEIZURE :
-          - ROLE_BILLINGS_SEIZURE_REFERENCE
+          - ROLE_BILLINGS-SEIZURE_REFERENCE
 
-        ROLE_BILLINGS_SEIZURE_REFERENCE:
+        ROLE_BILLINGS-SEIZURE_REFERENCE:
           - ROLE_ACCESS_REFERENCE
-          - ROLE_RESIDENCEAREA_REFERENCE
-          - ROLE_FAMILYQUOTIENT_REFERENCE
-          - ROLE_INTANGIBLE_REFERENCE
-          - ROLE_EDUCATIONCURRICULUM_REFERENCE
+          - ROLE_EDUCATION-CURRICULUM_REFERENCE
 
-        ROLE_PES_ADMINISTRATION:
+        ROLE_PES-ADMINISTRATION:
           - ROLE_PES
-          - ROLE_EXPORT_PES_ACTION
-          - ROLE_EXPORT_SEPA-DEBIT-MANDATE_ACTION
+          - ROLE_SEPA-DEBIT-MANDATE_EXPORT
 
-        ROLE_BERGERLEVRAULT_ADMINISTRATION:
+        ROLE_BERGERLEVRAULT-ADMINISTRATION:
           - ROLE_BERGERLEVRAULT
-          - ROLE_EXPORT_BERGER-LEVRAULT_ACTION
-          - ROLE_EXPORT_SEPA-DEBIT-MANDATE_ACTION
+          - ROLE_SEPA-DEBIT-MANDATE_EXPORT
 
 
-        ROLE_JVS_ADMINISTRATION:
+        ROLE_JVS-ADMINISTRATION:
           - ROLE_JVS
-          - ROLE_EXPORT_SEPA-DEBIT-MANDATE_ACTION
+          - ROLE_SEPA-DEBIT-MANDATE_EXPORT

+ 13 - 50
config/packages/security/booking.yaml

@@ -1,116 +1,79 @@
 security:
     role_hierarchy:
         ROLE_EVENTS:
-          - ROLE_EVENT
-          - ROLE_EVENTREPORT
-          - ROLE_EVENTGENDER_VIEW
-          - ROLE_EVENTUSER
+          - ROLE_EVENT-GENDER_VIEW
           - ROLE_CATEGORIES_VIEW
           - ROLE_EVENT_ACTION
           - ROLE_EVENT_REFERENCE
-          - ROLE_EVENTINVITATION_ACTION
 
         ROLE_EVENTS_VIEW:
-          - ROLE_EVENT_VIEW
-          - ROLE_EVENTREPORT_VIEW
-          - ROLE_EVENTUSER_VIEW
-          - ROLE_EVENTGENDER_VIEW
+          - ROLE_EVENT-GENDER_VIEW
           - ROLE_CATEGORIES_VIEW
           - ROLE_EVENT_ACTION
           - ROLE_EVENT_REFERENCE
 
         ROLE_EVENT_ACTION:
           - ROLE_RULERZ_ACTION
-          - ROLE_EXPORT_PRESENCE-EVENT_ACTION
 
         ROLE_EVENT_REFERENCE:
-          - ROLE_PLACE_REFERENCE
-          - ROLE_EQUIPMENT_REFERENCE
           - ROLE_ACCESS_REFERENCE
 
         ROLE_COURSES:
-          - ROLE_COURSE
-          - ROLE_WORK
           - ROLE_EDUCATIONSTUDENT_VIEW
           - ROLE_COURSE_REFERENCE
           - ROLE_COURSE_ACTION
           - ROLE_ORGANIZATION_VIEW
 
         ROLE_COURSE_ACTION:
-          - ROLE_DUPLICATECOURSES_ACTION
-          - ROLE_EXPORT_PRESENCE-COURSE_ACTION
+          - ROLE_PRESENCE-COURSE_EXPORT
 
         ROLE_COURSES_VIEW:
-          - ROLE_COURSE_VIEW
-          - ROLE_WORK_VIEW
           - ROLE_COURSE_REFERENCE
 
-        ROLE_COURSES_TEACHER:
-          - ROLE_OWN_COURSE
-          - ROLE_OWN_WORK
-          - ROLE_EDUCATIONSTUDENT_REFERENCE
+        ROLE_COURSES-TEACHER:
           - ROLE_COURSE_REFERENCE
 
         ROLE_COURSE_REFERENCE:
           - ROLE_EDUCATION_REFERENCE
           - ROLE_PLACE_REFERENCE
           - ROLE_ROOM_REFERENCE
-          - ROLE_EDUCATIONCURRIRULUM_REFERENCE
+          - ROLE_EDUCATION-CURRIRULUM_REFERENCE
           - ROLE_ACCESS_REFERENCE
           - ROLE_EQUIPMENT_REFERENCE
 
         ROLE_EXAMENS:
-          - ROLE_EXAMEN
-          - ROLE_JURY
           - ROLE_EXAMEN_REFERENCE
-          - ROLE_EXAMEN_ACTION
-
-        ROLE_EXAMEN_ACTION:
-          - ROLE_EXAMENCONVOCATION_ACTION
-          - ROLE_EXPORT_PRESENCE-EXAMEN_ACTION
+          - ROLE_PRESENCE-EXAMEN_EXPORT
 
         ROLE_EXAMENS_VIEW:
-          - ROLE_EXAMEN_VIEW
           - ROLE_COURSE_REFERENCE
 
         ROLE_EXAMEN_REFERENCE:
           - ROLE_EDUCATION_REFERENCE
           - ROLE_PLACE_REFERENCE
           - ROLE_ROOM_REFERENCE
-          - ROLE_EDUCATIONCURRIRULUM_REFERENCE
+          - ROLE_EDUCATION-CURRIRULUM_REFERENCE
           - ROLE_EDUCATION_REFERENCE
           - ROLE_ACCESS_REFERENCE
           - ROLE_EQUIPMENT_REFERENCE
-          - ROLE_JURY_REFERENCE
 
         ROLE_EDUCATIONALPROJECTS:
-          - ROLE_EDUCATIONALPROJECT
-          - ROLE_EDUCATIONALPROJECTPUBLIC
-          - ROLE_EDUCATIONALPROJECT_REFERENCE
-          - ROLE_EDUCATIONALPROJECT_ACTION
+          - ROLE_EDUCATIONAL-PROJECT_REFERENCE
+          - ROLE_ROADMAP_EXPORT
 
         ROLE_EDUCATIONALPROJECTS_VIEW:
-          - ROLE_EDUCATIONALPROJECT_VIEW
-          - ROLE_EDUCATIONALPROJECTPUBLIC_VIEW
-          - ROLE_EDUCATIONALPROJECT_REFERENCE
+          - ROLE_EDUCATIONAL-PROJECT_REFERENCE
 
-        ROLE_EDUCATIONALPROJECT_REFERENCE:
+        ROLE_EDUCATIONAL-PROJECT_REFERENCE:
           - ROLE_ACCESS_REFERENCE
           - ROLE_PLACE_REFERENCE
           - ROLE_ROOM_REFERENCE
           - ROLE_EQUIPMENT_REFERENCE
 
-        ROLE_EDUCATIONALPROJECT_ACTION:
-          - ROLE_EXPORT_ROAD-MAP_ACTION
-
         ROLE_ATTENDANCES:
-          - ROLE_ATTENDANCE
-          - ROLE_ATTENDANCEBOOKING
-          - ROLE_ORGANIZATIONFUNCTION_VIEW
+          - ROLE_ORGANIZATION-FUNCTION_VIEW
           - ROLE_ACCESS_REFERENCE
-          - ROLE_EXPORT_PRESENCE-COURSE_ACTION
+          - ROLE_PRESENCE-COURSE_EXPORT
 
         ROLE_ATTENDANCES_VIEW:
-          - ROLE_ATTENDANCE_VIEW
-          - ROLE_ATTENDANCEBOOKING_VIEW
           - ROLE_ACCESS_REFERENCE

+ 2 - 64
config/packages/security/core.yaml

@@ -1,7 +1,6 @@
 security:
     role_hierarchy:
-        ROLE_CORE_CRUD:
-          - ROLE_PLANNING
+        ROLE_CORE-CRUD:
           - ROLE_USERS
           - ROLE_COMMISSIONS
           - ROLE_MEDALS
@@ -10,73 +9,12 @@ security:
           - ROLE_EMAILS
           - ROLE_EQUIPMENTS
           - ROLE_ATTENDANCES
-          - ROLE_STATS_VIEW
           - ROLE_ACCOUNTS
           - ROLE_TAGG
 
-        ROLE_ACCOUNTS:
-          - ROLE_CREATEACCOUNTS_ACTION
-          - ROLE_DELETEACCOUNTS_ACTION
-
         ROLE_CORE:
-          - ROLE_PERSONALIZEDLIST
-          - ROLE_TIPS
-          - ROLE_NOTIFICATION_VIEW
-          - ROLE_OWN_EVENT_VIEW
-          - ROLE_OWN_MY_ACCESS
           - ROLE_FILE
-          - ROLE_OWN_COURSE_VIEW
-          - ROLE_OWN_EXAMEN_VIEW
-          - ROLE_OWN_EDUCATIONALPROJECT_VIEW
-          - ROLE_PLANNING_SETTINGS
-          - ROLE_OWN_PLANNING
-          - ROLE_OWN_EVENTUSER
-          - ROLE_OWN_ATTENDANCEBOOKING
-          - ROLE_WEBSITE
-          - ROLE_VIEWAUDIT
-          - ROLE_OWN_BILL_VIEW
-          - ROLE_PERSONALIZEDLIST_VIEW
-          - ROLE_NETWORKORGANIZATION
-          - ROLE_RULES_ACCESS_VIEW
-          - ROLE_EMAIL_CREATE
-          - ROLE_ONLINEREGISTRATIONSETTINGS_VIEW
           - ROLE_EDUCATION_REFERENCE
-          - ROLE_CITY_VIEW
-          - ROLE_ACCESSWISH
-          - ROLE_ACCESSFAMILYWISH
-          - ROLE_IELPROVISIONALREGISTRATION_ACTION
 
         ROLE_CORE_ACTION:
-          - ROLE_EXPORT_LIST_ACTION
-          - ROLE_EXPORT_CARD_ACTION
-          - ROLE_EXPORT_LICENCE-CMF_ACTION
-          - ROLE_EXPORT_REPORT-ACTIVITY_ACTION
-          - ROLE_RULERZ_ACTION
-
-        ROLE_OWN_MY_ACCESS:
-          - ROLE_OWN_ACCESS
-          - ROLE_OWN_FAMILY_ACCESS
-          - ROLE_OWN_PERSONADDRESSPOSTAL
-          - ROLE_OWN_MEDAL_VIEW
-          - ROLE_OWN_DONOR_VIEW
-          - ROLE_OWN_BANKACCOUNT
-          - ROLE_OWN_BILL_VIEW
-          - ROLE_OWN_ACCESSNETWORKSETTING
-          - ROLE_OWN_ATTENDANCEBOOKING_VIEW
-          - ROLE_OWN_ORGANIZATIONFUNCTION_VIEW
-          - ROLE_OWN_PERSONACTIVITY_VIEW
-          - ROLE_OWN_MEDICAL_VIEW
-          - ROLE_OWN_ROLE_VIEW
-          - ROLE_OWN_ACCESSSOCIAL_VIEW
-          - ROLE_OWN_ACCESSCOMMUNICATION_VIEW
-          - ROLE_OWN_SCHOOLINGOTHERARTISTICPRACTICES
-          - ROLE_OWN_EDUCATIONNOTATION_VIEW
-          - ROLE_OWN_EDUCATIONSTUDENT_VIEW
-          - ROLE_OWN_PERSON_CONTACTPOINT
-          - ROLE_OWN_PERSONACTIVITY_VIEW
-          - ROLE_OWN_PERSONCOMPANY_VIEW
-          - ROLE_USERS_REFERENCE
-          - ROLE_BILLINGS_SEIZURE_REFERENCE
-          - ROLE_FUNCTIONTYPE_VIEW
-          - ROLE_CRITERIANOTATION_REFERENCE
-          
+          - ROLE_RULERZ_ACTION

+ 0 - 2
config/packages/security/donors.yaml

@@ -1,11 +1,9 @@
 security:
     role_hierarchy:
         ROLE_DONORS:
-          - ROLE_DONOR
           - ROLE_DONOR_REFERENCE
 
         ROLE_DONORS_VIEW:
-          - ROLE_DONOR_VIEW
           - ROLE_DONOR_REFERENCE
 
         ROLE_DONOR_REFERENCE:

+ 3 - 18
config/packages/security/equipments.yaml

@@ -1,29 +1,14 @@
 security:
     role_hierarchy:
         ROLE_EQUIPMENTS:
-          - ROLE_EQUIPMENT
-          - ROLE_EQUIPMENTCONTROL
-          - ROLE_EQUIPMENTLOAN
-          - ROLE_EQUIPMENTREPAIR
-          - ROLE_EQUIPMENTCOMPOSITION
           - ROLE_EQUIPMENT_REFERENCE
-          - ROLE_EQUIPMENTLIST_VIEW
-          - ROLE_EQUIPMENT_ACTION
+          - ROLE_EQUIPMENT-LIST_VIEW
 
         ROLE_EQUIPMENTS_VIEW:
-          - ROLE_EQUIPMENT_VIEW
-          - ROLE_EQUIPMENTCONTROL_VIEW
-          - ROLE_EQUIPMENTLOAN_VIEW
-          - ROLE_EQUIPMENTREPAIR_VIEW
-          - ROLE_EQUIPMENTCOMPOSITION_VIEW
           - ROLE_EQUIPMENT_REFERENCE
-          - ROLE_EQUIPMENTLIST_VIEW
+          - ROLE_EQUIPMENT-LIST_VIEW
 
         ROLE_EQUIPMENT_REFERENCE:
           - ROLE_PLACE_REFERENCE
           - ROLE_ROOM_REFERENCE
-          - ROLE_ACCESS_REFERENCE
-
-        ROLE_EQUIPMENT_ACTION:
-          - ROLE_EQUIPMENTLOANREMINDER_ACTION
-          - ROLE_EXPORT_EQUIPMENT-AVAILABILITY-FORM_ACTION
+          - ROLE_ACCESS_REFERENCE

+ 3 - 27
config/packages/security/generalConfig.yaml

@@ -4,67 +4,43 @@ security:
           - ROLE_PLACE
           - ROLE_ORGANIZATION_EDIT
           - ROLE_ORGANIZATION_VIEW
-          - ROLE_TYPEOFPRACTICE_VIEW
-          - ROLE_ORGANIZATIONHOLIDAY
           - ROLE_ACTIVITY
           - ROLE_FILE
 
         ROLE_GENERAL_CONFIG_VIEW:
           - ROLE_PLACE_VIEW
           - ROLE_ORGANIZATION_VIEW
-          - ROLE_ORGANIZATIONHOLIDAY_VIEW
           - ROLE_ACTIVITY_VIEW
 
         ROLE_PLACE:
-          - ROLE_PLACESYSTEM_VIEW
-          - ROLE_PLACECONTROL
-          - ROLE_PLACEREPAIR
-          - ROLE_ROOM
           - ROLE_PLACE_REFERENCE
-          - ROLE_PLACE_CONTACTPOINT
 
         ROLE_PLACE_VIEW:
-          - ROLE_PLACECONTROL_VIEW
-          - ROLE_PLACEREPAIR_VIEW
-          - ROLE_ROOM_VIEW
           - ROLE_PLACE_REFERENCE
 
         ROLE_PLACE_REFERENCE:
-          - ROLE_COUNTRY_REFERENCE
           - ROLE_ACCESS_REFERENCE
           - ROLE_EQUIPMENT_REFERENCE
-          - ROLE_ORGANIZATIONADDRESSPOSTAL_REFERENCE
 
         ROLE_ORGANIZATION_EDIT:
-          - ROLE_ORGANIZATIONADDRESSPOSTAL
-          - ROLE_CITY_VIEW
           - ROLE_ORGANIZATION_REFERENCE
-          - ROLE_ORGANIZATION_CONTACTPOINT
 
         ROLE_ORGANIZATION_VIEW:
-          - ROLE_ORGANIZATIONADDRESSPOSTAL_VIEW
           - ROLE_ORGANIZATION_REFERENCE
 
         ROLE_NETWORK:
           - ROLE_ORGANIZATION_VIEW
-          - ROLE_GENERATECREDENTIALS_ACTION
-          - ROLE_CHANGEEMAILADMIN_ACTION
-          - ROLE_TAKEOUTORGANIZATION_ACTION
 
         ROLE_NETWORK_VIEW:
           - ROLE_ORGANIZATION_VIEW
 
         ROLE_ORGANIZATION_REFERENCE:
           - ROLE_ACCESS_REFERENCE
-          - ROLE_COUNTRY_REFERENCE
 
         ROLE_ACTIVITY:
-          - ROLE_ACTIVITYTYPE_VIEW
+          - ROLE_ACTIVITY-TYPE_VIEW
           - ROLE_ACTIVITY_REFERENCE
 
         ROLE_ACTIVITY_VIEW:
-          - ROLE_ACTIVITYTYPE_VIEW
-          - ROLE_ACTIVITY_REFERENCE
-
-        ROLE_ACTIVITY_REFERENCE:
-          - ROLE_CATEGORIES_REFERENCE
+          - ROLE_ACTIVITY-TYPE_VIEW
+          - ROLE_ACTIVITY_REFERENCE

+ 0 - 2
config/packages/security/medals.yaml

@@ -1,11 +1,9 @@
 security:
     role_hierarchy:
         ROLE_MEDALS:
-          - ROLE_MEDAL
           - ROLE_MEDAL_REFERENCE
 
         ROLE_MEDALS_VIEW:
-          - ROLE_MEDAL_VIEW
           - ROLE_MEDAL_REFERENCE
 
         ROLE_MEDAL_REFERENCE:

+ 0 - 35
config/packages/security/messages.yaml

@@ -1,45 +1,10 @@
 security:
     role_hierarchy:
         ROLE_MAILS:
-          - ROLE_MAIL
-          - ROLE_MAIL_TEMPLATE
           - ROLE_MESSAGES_BASE
 
         ROLE_EMAILS:
-          - ROLE_EMAIL
-          - ROLE_EMAIL_TEMPLATE
           - ROLE_MESSAGES_BASE
 
-        ROLE_TEXTO:
-          - ROLE_SMS
-          - ROLE_SMS_TEMPLATE
-
         ROLE_MESSAGES_BASE:
-          - ROLE_MESSAGE
-          - ROLE_MESSAGE_TEMPLATE
-          - ROLE_TEMPLATE
-          - ROLE_REPORTMESSAGE
-          - ROLE_MESSAGES_ACTION
-
-        ROLE_MAILS_VIEW:
-          - ROLE_MAIL_VIEW
-          - ROLE_MAIL_TEMPLATE_VIEW
-          - ROLE_MESSAGES_BASE_VIEW
-
-        ROLE_EMAILS_VIEW:
-          - ROLE_EMAIL_VIEW
-          - ROLE_EMAIL_TEMPLATE_VIEW
-          - ROLE_MESSAGES_BASE_VIEW
-
-        ROLE_TEXTO_VIEW:
-          - ROLE_SMS_VIEW
-          - ROLE_SMS_TEMPLATE_VIEW
-
-        ROLE_MESSAGES_BASE_VIEW:
-          - ROLE_MESSAGE_VIEW
-          - ROLE_MESSAGE_TEMPLATE_VIEW
-          - ROLE_TEMPLATE_VIEW
-          - ROLE_REPORTMESSAGE_VIEW
-
-        ROLE_MESSAGES_ACTION:
           - ROLE_RULERZ_ACTION

+ 8 - 37
config/packages/security/pedagogics.yaml

@@ -1,51 +1,22 @@
 security:
     role_hierarchy:
         ROLE_PEDAGOGICS_ADMINISTRATION:
-          - ROLE_EDUCATIONTEACHER
-          - ROLE_EDUCATIONSTUDENT
-          - ROLE_EDUCATIONNOTATION
-          - ROLE_CRITERIANOTATION
-          - ROLE_EXAMENCONVOCATION
-          - ROLE_EDUCATION
-          - ROLE_CYCLE
-          - ROLE_EDUCATIONCURRICULUM
-          - ROLE_EDUCATIONCATEGORY
+          - ROLE_EDUCATION-NOTATION
           - ROLE_PEDAGOGICS_ACTION
           - ROLE_EDUCATION_REFERENCE
 
         ROLE_PEDAGOGICS_ADMINISTRATION_VIEW:
-          - ROLE_EDUCATIONTEACHER_VIEW
-          - ROLE_EDUCATIONSTUDENT_VIEW
-          - ROLE_EDUCATIONNOTATION_VIEW
-          - ROLE_CRITERIANOTATION_VIEW
-          - ROLE_EXAMENCONVOCATION_VIEW
-          - ROLE_EDUCATION_VIEW
-          - ROLE_EDUCATIONCURRICULUM_VIEW
-          - ROLE_EDUCATIONCATEGORY_VIEW
-          - ROLE_EDUCATION_VIEW
+          - ROLE_EDUCATION-STUDENT_VIEW
           - ROLE_EDUCATION_REFERENCE
 
-        ROLE_EDUCATION_REFERENCE:
-          - ROLE_EDUCATIONCATEGORY_REFERENCE
-          - ROLE_EDUCATIONCOMPLEMENT_REFERENCE
-
-        ROLE_PEDAGOGICS_ACTION:
-          - ROLE_CYCLEUPDATING_ACTION
-          - ROLE_EXPORT_REPORT-CARD_ACTION
-
         ROLE_PEDAGOGICS_SEIZURE:
           - ROLE_ACCESS_VIEW
-          - ROLE_EDUCATIONSTUDENT_VIEW
-          - ROLE_CRITERIANOTATION_REFERENCE
-          - ROLE_EDUCATIONNOTATION
-          - ROLE_EDUCATIONNOTATION_FIELD
-          - ROLE_PEDAGOGICS_SEIZURE_ACTION
+          - ROLE_EDUCATION-STUDENT_VIEW
+          - ROLE_CRITERIA-NOTATION_REFERENCE
+          - ROLE_EDUCATION-NOTATION
+          - ROLE_PEDAGOGICS-SEIZURE_ACTION
 
         ROLE_PEDAGOGICS_SEIZURE_VIEW:
           - ROLE_ACCESS_VIEW
-          - ROLE_EDUCATIONSTUDENT_VIEW
-          - ROLE_CRITERIANOTATION_REFERENCE
-
-        ROLE_PEDAGOGICS_SEIZURE_ACTION:
-          - ROLE_EVALUATETUDENTS_ACTION
-
+          - ROLE_EDUCATION-STUDENT_VIEW
+          - ROLE_CRITERIA-NOTATION_REFERENCE

+ 10 - 92
config/packages/security/users.yaml

@@ -1,118 +1,36 @@
 security:
     role_hierarchy:
-        ROLE_USERS_ALL:
-          - ROLE_USERS
-        ROLE_USERS_ALL_VIEW:
-          - ROLE_USERS_VIEW
-
-        ROLE_USERS_GUARDIAN:
-          - ROLE_USERS
-        ROLE_USERS_GUARDIAN_VIEW:
-          - ROLE_USERS_VIEW
-
-        ROLE_USERS_ADHERENT:
-          - ROLE_USERS
-        ROLE_USERS_ADHERENT_VIEW:
-          - ROLE_USERS_VIEW
-
-        ROLE_USERS_STUDENT:
-          - ROLE_USERS
-        ROLE_USERS_STUDENT_VIEW:
-          - ROLE_USERS_VIEW
-
-        ROLE_USERS_TEACHER:
-          - ROLE_USERS
-        ROLE_USERS_TEACHER_VIEW:
-          - ROLE_USERS_VIEW
-
-        ROLE_USERS_PERSONNEL:
-          - ROLE_USERS
-        ROLE_USERS_PERSONNEL_VIEW:
-          - ROLE_USERS_VIEW
-
-        ROLE_USERS_MORAL:
-          - ROLE_USERS
-        ROLE_USERS_MORAL_VIEW:
-          - ROLE_USERS_VIEW
-
-        ROLE_USERS_CA:
-          - ROLE_USERS
-        ROLE_USERS_CA_VIEW:
-          - ROLE_USERS_VIEW
-
         ROLE_USERS:
-          - ROLE_ACCESS
           - ROLE_FILE
-          - ROLE_ORGANIZATIONFUNCTION
-          - ROLE_FUNCTIONTYPE_VIEW
+          - ROLE_FUNCTION-TYPE_VIEW
           - ROLE_USERS_REFERENCE
-          - ROLE_PERSONADDRESSPOSTAL
-          - ROLE_CITY_VIEW
-          - ROLE_PERSONHOLIDAY
-          - ROLE_ORGANIZATIONRESPONSABILITY
-          - ROLE_PERSONACTIVITY
-          - ROLE_PERSON_CONTACTPOINT
-          - ROLE_SHARINGCONTACT_ACTION
-          - ROLE_STUDENT_REGISTRATION
+          - ROLE_STUDENT-REGISTRATION
 
         ROLE_USERS_VIEW:
           - ROLE_ACCESS_VIEW
           - ROLE_ACCESS_REFERENCE
-          - ROLE_FILE_VIEW
-          - ROLE_ORGANIZATIONFUNCTION_VIEW
-          - ROLE_FUNCTIONTYPE_VIEW_VIEW
-          - ROLE_USERS_REFERENCE_VIEW
-          - ROLE_PERSONADDRESSPOSTAL_VIEW
-          - ROLE_CITY_VIEW_VIEW
-          - ROLE_PERSONHOLIDAY_VIEW
-          - ROLE_ORGANIZATIONRESPONSABILITY_VIEW
-          - ROLE_PERSONACTIVITY_VIEW
-          - ROLE_PERSON_CONTACTPOINT_VIEW
-          - ROLE_STUDENT_REGISTRATION_VIEW
+          - ROLE_ORGANIZATION-FUNCTION_VIEW
 
-        ROLE_OWN_MY_STUDENT:
-          - ROLE_OWN_MY_STUDENT_ACCESS_VIEW
-          - ROLE_OWN_MY_STUDENT_EDUCATIONNOTATION_VIEW
-          - ROLE_OWN_MY_STUDENT_EDUCATIONSTUDENT_VIEW
-          - ROLE_OWN_MY_STUDENT_EDUCATIONSTUDENT_EDIT
-          - ROLE_OWN_MY_STUDENT_EDUCATIONNOTATION
-          - ROLE_OWN_MY_STUDENT_ORGANIZATIONFUNCTION_VIEW
-          - ROLE_OWN_MY_STUDENT_CONFIDENTIALITY_VIEW
-          - ROLE_OWN_MY_STUDENT_MEDAL_VIEW
-          - ROLE_OWN_MY_STUDENT_PERSONADDRESSPOSTAL_VIEW
-          - ROLE_OWN_MY_STUDENT_PERSONACTIVITY_VIEW
-          - ROLE_OWN_MY_STUDENT_PERSONCOMPANY_VIEW
-          - ROLE_FUNCTIONTYPE_VIEW
+        ROLE_OWN-MY-STUDENT:
+          - ROLE_FUNCTION-TYPE_VIEW
           - ROLE_USERS_REFERENCE
-          - ROLE_EDUCATIONCURRICULUM_REFERENCE
-          - ROLE_OWN_MY_STUDENT_PEDA_EDUCATIONSTUDENT
-          - ROLE_CYCLE_REFERENCE
+          - ROLE_EDUCATION-CURRICULUM_REFERENCE
 
         ROLE_USERS_REFERENCE:
           - ROLE_ACCESS_REFERENCE
           - ROLE_EQUIPMENT_REFERENCE
-          - ROLE_EQUIPMENTLIST_REFERENCE
           - ROLE_ACTIVITY_REFERENCE
           - ROLE_PLACE_REFERENCE
           - ROLE_ROOM_REFERENCE
-          - ROLE_COUNTRY_REFERENCE
 
         ROLE_COMMISSIONS:
-          - ROLE_COMMISSION
           - ROLE_ACCESS_REFERENCE
 
         ROLE_COMMISSIONS_VIEW:
-          - ROLE_COMMISSION_VIEW
           - ROLE_ACCESS_REFERENCE
 
-        ROLE_STUDENT_REGISTRATION:
-          - ROLE_STUDENT_REGISTRATION_REFERENCE
-
-        ROLE_STUDENT_REGISTRATION_REFERENCE:
-          - ROLE_COUNTRY_REFERENCE
-          - ROLE_ACCESS_REFERENCE
+        ROLE_STUDENT-REGISTRATION:
+          - ROLE_STUDENTREGISTRATION_REFERENCE
 
-        ROLE_ONLINEREGISTRATION_ADMINISTRATION:
-          - ROLE_EDUCATIONSTUDENTWISH
-          - ROLE_SENDONLINEREGISTRATION_ACTION
-          - ROLE_VALIDATIONREGISTRATION_ACTION
+        ROLE_STUDENT-REGISTRATION_REFERENCE:
+          - ROLE_ACCESS_REFERENCE

+ 1 - 1
config/packages/security/viewaudit.yaml

@@ -1,4 +1,4 @@
 security:
     role_hierarchy:
-        ROLE_VIEW_AUDIT:
+        ROLE_VIEW-AUDIT:
           - ROLE_VIEWAUDIT_VIEW

+ 5 - 1
config/routes.yaml

@@ -1,3 +1,7 @@
 login_check:
   path: /login_check
-  methods: ['POST']
+  methods: ['POST']
+
+swagger_ui:
+  path: /docs
+  controller: api_platform.swagger.action.ui

+ 9 - 0
config/services/services.yaml

@@ -0,0 +1,9 @@
+services:
+  opentalent.cotisation.utils:
+    class: App\Service\Cotisation\Utils
+    public: true
+    autowire: true
+  opentalent.network.utils:
+    class: App\Service\Network\Utils
+    public: true
+    autowire: true

+ 33 - 0
phpunit.xml.dist

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:noNamespaceSchemaLocation="bin/.phpunit/phpunit.xsd"
+         backupGlobals="false"
+         colors="true"
+         bootstrap="tests/bootstrap.php"
+>
+    <php>
+        <ini name="error_reporting" value="-1" />
+        <server name="APP_ENV" value="test" force="true" />
+        <server name="SHELL_VERBOSITY" value="-1" />
+        <server name="SYMFONY_PHPUNIT_REMOVE" value="" />
+        <server name="SYMFONY_PHPUNIT_VERSION" value="8.5" />
+    </php>
+
+    <testsuites>
+        <testsuite name="Project Test Suite">
+            <directory>tests</directory>
+        </testsuite>
+    </testsuites>
+
+    <filter>
+        <whitelist processUncoveredFilesFromWhitelist="true">
+            <directory suffix=".php">src</directory>
+        </whitelist>
+    </filter>
+
+    <listeners>
+        <listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
+    </listeners>
+</phpunit>

+ 20 - 20
src/DTO/Access/MyProfile.php → src/ApiResources/Profile/AccessProfile.php

@@ -1,11 +1,14 @@
 <?php
+declare(strict_types=1);
 
-namespace App\DTO\Access;
+namespace App\ApiResources\Profile;
 
 use ApiPlatform\Core\Annotation\ApiProperty;
 use ApiPlatform\Core\Annotation\ApiResource;
 
 /**
+ * Classe resource qui contient les champs disponibles lors d'un appel à my_profile.
+ *
  * @ApiResource(
  *     collectionOperations={},
  *     itemOperations={
@@ -16,7 +19,7 @@ use ApiPlatform\Core\Annotation\ApiResource;
  *     }
  * )
  */
-class MyProfile
+class AccessProfile
 {
     /**
      * @ApiProperty(identifier=true)
@@ -38,10 +41,11 @@ class MyProfile
      */
     private $roles = [];
 
+
     /**
-     * @var array
+     * @var OrganizationProfile
      */
-    private $modules = [];
+    private $organization;
 
     public function __construct()
     {
@@ -59,6 +63,18 @@ class MyProfile
         return $this;
     }
 
+    public function getOrganization(): ?OrganizationProfile
+    {
+        return $this->organization;
+    }
+
+    public function setOrganization(?OrganizationProfile $organization): self
+    {
+        $this->organization = $organization;
+
+        return $this;
+    }
+
     public function getName(): ?string
     {
         return $this->name;
@@ -98,20 +114,4 @@ class MyProfile
         $this->roles = $roles;
         return $this;
     }
-
-    /**
-     * @inheritDoc
-     */
-    public function getModules()
-    {
-        $modules = $this->modules;
-        return array_unique($modules);
-    }
-
-    public function setModules(array $modules): self
-    {
-        $this->modules = $modules;
-
-        return $this;
-    }
 }

+ 91 - 0
src/ApiResources/Profile/OrganizationProfile.php

@@ -0,0 +1,91 @@
+<?php
+declare(strict_types=1);
+
+namespace App\ApiResources\Profile;
+
+/**
+ * Classe resource qui contient les champs relatifs aux organizations présentent dans la requete my_profile.
+ * @package App\ApiResources\Profile
+ */
+class OrganizationProfile
+{
+
+    /**
+     * @var string
+     */
+    private $name;
+
+    /**
+     * @var string
+     */
+    private $product;
+
+    /**
+     * @var array
+     */
+    private $modules = [];
+
+    /**
+     * @var bool
+     */
+    private $hasChildren;
+
+    public function __construct()
+    {
+    }
+
+    public function getName(): ?string
+    {
+        return $this->name;
+    }
+
+    public function setName(?string $name): self
+    {
+        $this->name = $name;
+
+        return $this;
+    }
+
+    public function getProduct(): ?string
+    {
+        return $this->product;
+    }
+
+    public function setProduct(?string $product): self
+    {
+        $this->product = $product;
+
+        return $this;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function getModules()
+    {
+        $modules = $this->modules;
+        return array_unique($modules);
+    }
+
+    public function setModules(array $modules): self
+    {
+        $this->modules = $modules;
+
+        return $this;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function getHasChildren(): bool
+    {
+        return $this->hasChildren;
+    }
+
+    public function setHasChildren(bool $hasChildren): self
+    {
+        $this->hasChildren = $hasChildren;
+
+        return $this;
+    }
+}

+ 6 - 0
src/DataPersister/Common/OpentalentDataPersister.php

@@ -1,8 +1,14 @@
 <?php
+declare(strict_types=1);
+
 namespace App\DataPersister\Common;
 
 use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
 
+/**
+ * Class OpentalentDataPersister : Décoration du dataPersister par défaut d'API Platform
+ * @package App\DataPersister\Common
+ */
 final class OpentalentDataPersister implements ContextAwareDataPersisterInterface
 {
     private $decorated;

+ 88 - 0
src/DataProvider/Access/AccessProfileDataProvider.php

@@ -0,0 +1,88 @@
+<?php
+declare(strict_types=1);
+
+namespace App\DataProvider\Access;
+
+use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
+use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
+use App\ApiResources\Profile\AccessProfile;
+use App\ApiResources\Profile\OrganizationProfile;
+use App\Entity\Access\Access;
+use App\Entity\Organization\Organization;
+use App\Service\Security\Module;
+use Symfony\Component\Security\Core\Role\Role;
+use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
+use Symfony\Component\Security\Core\Security;
+
+/**
+ * Class AccessProfileDataProvider : custom provider pour assurer l'alimentation de la réponse du GET my_profile
+ * @package App\DataProvider\Access
+ */
+final class AccessProfileDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface
+{
+    /** @var Security  */
+    private $security;
+
+    /** @var RoleHierarchyInterface  */
+    private $roleHierarchy;
+
+    /** @var Module  */
+    private $module;
+
+    public function __construct(
+        Security $security,
+        RoleHierarchyInterface $roleHierarchy,
+        Module $module
+    )
+    {
+        $this->security = $security;
+        $this->roleHierarchy = $roleHierarchy;
+        $this->module = $module;
+    }
+
+    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
+    {
+        return AccessProfile::class === $resourceClass;
+    }
+
+    public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): ?AccessProfile
+    {
+        /** @var Access $access */
+        $access = $this->security->getUser();
+
+        $myProfile = $this->setProfileFromAccess($access);
+        $myProfile->setRoles($this->roleHierarchy->getReachableRoleNames($this->security->getToken()->getRoleNames()));
+
+        $myProfile->setOrganization($this->setOrganizationProfileFromOrganization($access->getOrganization()));
+
+        return $myProfile;
+    }
+
+    /**
+     * Hydratation du profile de l'access connecté via la resource accessProfile
+     * @param Access $access
+     * @return AccessProfile
+     */
+    public function setProfileFromAccess(Access $access): AccessProfile
+    {
+        $accessProfile = new AccessProfile();
+        $accessProfile->setId($access->getId());
+        $accessProfile->setName($access->getPerson()->getName());
+        $accessProfile->setGivenName($access->getPerson()->getGivenName());
+        return $accessProfile;
+    }
+
+    /**
+     * Hydratation du profile des organizations auxquelles l'access connecté est inscrit
+     * @param Organization $organization
+     * @return OrganizationProfile
+     */
+    public function setOrganizationProfileFromOrganization(Organization $organization): OrganizationProfile{
+        $organizationProfile = new OrganizationProfile();
+        $organizationProfile->setName($organization->getName());
+        $organizationProfile->setModules($this->module->getOrganizationModules($organization));
+        $organizationProfile->setProduct($organization->getSettings()->getProduct());
+        $organizationProfile->setHasChildren($organization->getNetworkOrganizationChildren()->count() > 1);
+        return $organizationProfile;
+    }
+}

+ 0 - 65
src/DataProvider/Access/MyProfileDataProvider.php

@@ -1,65 +0,0 @@
-<?php
-namespace App\DataProvider\Access;
-
-use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
-use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
-use App\Entity\Access\Access;
-use App\DTO\Access\MyProfile;
-use App\Entity\Organization\Organization;
-use App\Service\Utils\Module;
-use Symfony\Component\Security\Core\Role\Role;
-use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
-use Symfony\Component\Security\Core\Security;
-
-final class MyProfileDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface
-{
-    /** @var Security  */
-    private $security;
-
-    /** @var RoleHierarchyInterface  */
-    private $roleHierarchy;
-
-    /** @var Module  */
-    private $module;
-
-    public function __construct(
-        Security $security,
-        RoleHierarchyInterface $roleHierarchy,
-        Module $module
-    )
-    {
-        $this->security = $security;
-        $this->roleHierarchy = $roleHierarchy;
-        $this->module = $module;
-    }
-
-    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
-    {
-        return MyProfile::class === $resourceClass;
-    }
-
-    public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): ?MyProfile
-    {
-        /** @var Access $access */
-        $access = $this->security->getUser();
-        $myProfile = $this->setProfileFromAccess($access);
-
-        $myProfile->setRoles($this->roleHierarchy->getReachableRoleNames($this->security->getToken()->getRoleNames()));
-        $myProfile->setModules($this->module->getOrganizationModules($access->getOrganization()));
-
-        return $myProfile;
-    }
-
-    /**
-     * @param Access $access
-     * @return MyProfile
-     */
-    public function setProfileFromAccess(Access $access): MyProfile
-    {
-        $myProfile = new MyProfile();
-        $myProfile->setId($access->getId());
-        $myProfile->setName($access->getPerson()->getName());
-        $myProfile->setGivenName($access->getPerson()->getGivenName());
-        return $myProfile;
-    }
-}

+ 6 - 0
src/DataProvider/Common/OpentalentCollectionDataProvider.php

@@ -1,9 +1,15 @@
 <?php
+declare(strict_types=1);
+
 namespace App\DataProvider\Common;
 
 use ApiPlatform\Core\DataProvider\ContextAwareCollectionDataProviderInterface;
 use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
 
+/**
+ * Class OpentalentCollectionDataProvider : : Décoration du dataProvider Collection par défaut d'API Platform
+ * @package App\DataProvider\Common
+ */
 final class OpentalentCollectionDataProvider implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface
 {
     /** @var ContextAwareCollectionDataProviderInterface  */

+ 6 - 0
src/DataProvider/Common/OpentalentItemDataProvider.php

@@ -1,9 +1,15 @@
 <?php
+declare(strict_types=1);
+
 namespace App\DataProvider\Common;
 
 use ApiPlatform\Core\DataProvider\DenormalizedIdentifiersAwareItemDataProviderInterface;
 use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
 
+/**
+ * Class OpentalentItemDataProvider : : Décoration du dataProvider item par défaut d'API Platform
+ * @package App\DataProvider\Common
+ */
 final class OpentalentItemDataProvider implements DenormalizedIdentifiersAwareItemDataProviderInterface, RestrictedDataProviderInterface
 {
     private $decorated;

+ 6 - 0
src/Doctrine/Access/AccessExtension.php

@@ -1,4 +1,6 @@
 <?php
+declare(strict_types=1);
+
 namespace App\Doctrine\Access;
 
 use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
@@ -8,6 +10,10 @@ use App\Entity\Access\Access;
 use Doctrine\ORM\QueryBuilder;
 use Symfony\Component\Security\Core\Security;
 
+/**
+ * Class AccessExtension : Filtre de sécurité par défaut pour une resource Access
+ * @package App\Doctrine\Access
+ */
 final class AccessExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
 {
     private $security;

+ 6 - 4
src/Entity/Access/Access.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 
 namespace App\Entity\Access;
 
@@ -14,14 +15,15 @@ use Doctrine\ORM\Mapping as ORM;
 use Symfony\Component\Security\Core\User\UserInterface;
 
 /**
+ * Fais le lien entre une Person et une Organization
  * @ApiResource(
  *     collectionOperations={
- *         "get"={"security"="is_granted('ROLE_ACCESS')"},
+ *         "get"={"security"="is_granted('ROLE_USER')"},
  *         "post"
  *     },
  *     itemOperations={
- *         "get"={"security"="is_granted('ROLE_ACCESS') or object.getId() == user.id"},
- *         "put"={"security"="is_granted('ROLE_ACCESS')"},
+ *         "get"={"security"="is_granted('ROLE_USER') or object.getId() == user.getId()"},
+ *         "put"={"security"="is_granted('ROLE_USER')"},
  *         "delete"
  *     }
  * )
@@ -34,7 +36,7 @@ class Access implements UserInterface
      * @ORM\GeneratedValue
      * @ORM\Column(type="integer")
      */
-    public $id;
+    private $id;
 
     /**
      * @ORM\ManyToOne(targetEntity=Person::class, cascade={"persist"})

+ 3 - 0
src/Entity/Access/OrganizationFunction.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 
 namespace App\Entity\Access;
 
@@ -7,6 +8,8 @@ use App\Repository\Access\OrganizationFunctionRepository;
 use Doctrine\ORM\Mapping as ORM;
 
 /**
+ * Fonction d'un Access dans une Organization sur une période donnée
+ *
  * @ApiResource()
  * @ORM\Entity(repositoryClass=OrganizationFunctionRepository::class)
  */

+ 84 - 0
src/Entity/Network/Network.php

@@ -0,0 +1,84 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Entity\Network;
+
+use App\Repository\Network\NetworkRepository;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * Enum des différents réseaux auxquels peut appartenir une Organization
+ *
+ * @ORM\Entity(repositoryClass=NetworkRepository::class)
+ */
+class Network
+{
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @ORM\Column(type="string", length=255)
+     */
+    private $name;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $logo;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $url;
+
+    public function setId($id): self
+    {
+        $this->id = $id;
+        return $this;
+    }
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function getName(): ?string
+    {
+        return $this->name;
+    }
+
+    public function setName(string $name): self
+    {
+        $this->name = $name;
+
+        return $this;
+    }
+
+    public function getLogo(): ?string
+    {
+        return $this->logo;
+    }
+
+    public function setLogo(?string $logo): self
+    {
+        $this->logo = $logo;
+
+        return $this;
+    }
+
+    public function getUrl(): ?string
+    {
+        return $this->url;
+    }
+
+    public function setUrl(?string $url): self
+    {
+        $this->url = $url;
+
+        return $this;
+    }
+}

+ 98 - 0
src/Entity/Network/NetworkOrganization.php

@@ -0,0 +1,98 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Entity\Network;
+
+use App\Entity\Organization\Organization;
+use App\Repository\Network\NetworkOrganizationRepository;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * Fait le lien entre une Organization et un Network
+ *
+ * @ORM\Entity(repositoryClass=NetworkOrganizationRepository::class)
+ */
+class NetworkOrganization
+{
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @ORM\ManyToOne(targetEntity=Network::class)
+     * @ORM\JoinColumn(nullable=false)
+     */
+    private $network;
+
+    /**
+     * @ORM\ManyToOne(targetEntity=Organization::class, inversedBy="networkOrganizations")
+     * @ORM\JoinColumn(nullable=false)
+     */
+    private $organization;
+
+    /**
+     * @ORM\ManyToOne(targetEntity=Organization::class, inversedBy="networkOrganizationChildren")
+     */
+    private $parent;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $leadingCause;
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function getNetwork(): ?Network
+    {
+        return $this->network;
+    }
+
+    public function setNetwork(?Network $network): self
+    {
+        $this->network = $network;
+
+        return $this;
+    }
+
+    public function getOrganization(): ?Organization
+    {
+        return $this->organization;
+    }
+
+    public function setOrganization(?Organization $organization): self
+    {
+        $this->organization = $organization;
+
+        return $this;
+    }
+
+    public function getParent(): ?Organization
+    {
+        return $this->parent;
+    }
+
+    public function setParent(?Organization $parent): self
+    {
+        $this->parent = $parent;
+
+        return $this;
+    }
+
+    public function getLeadingCause(): ?string
+    {
+        return $this->leadingCause;
+    }
+
+    public function setLeadingCause(?string $leadingCause): self
+    {
+        $this->leadingCause = $leadingCause;
+
+        return $this;
+    }
+}

+ 84 - 2
src/Entity/Organization/Organization.php

@@ -1,19 +1,25 @@
 <?php
+declare(strict_types=1);
 
 namespace App\Entity\Organization;
 
 use ApiPlatform\Core\Annotation\ApiResource;
+use App\Entity\Network\NetworkOrganization;
 use App\Repository\Organization\OrganizationRepository;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\Common\Collections\Collection;
 use Doctrine\ORM\Mapping as ORM;
 
 /**
+ * Structure, organisation
+ *
  * @ApiResource(
  *     collectionOperations={
  *         "get"={"security"="is_granted('ROLE_ORGANIZATION')"},
  *         "post"={"security"="is_granted('ROLE_ORGANIZATION_CREATE')"}
  *     },
  *     itemOperations={
- *         "get"={"security"="is_granted('ROLE_ORGANIZATION_EDIT') and object.getId() == user.organization.id"},
+ *         "get"={"security"="is_granted('ROLE_ORGANIZATION_EDIT') and object.getId() == user.organization.getId()"},
  *         "put"={"security"="is_granted('ROLE_ORGANIZATION_EDIT')"}
  *     }
  * )
@@ -26,7 +32,7 @@ class Organization
      * @ORM\GeneratedValue
      * @ORM\Column(type="integer")
      */
-    public $id;
+    private $id;
 
     /**
      * @ORM\Column(type="string", length=128)
@@ -53,6 +59,22 @@ class Organization
      */
     private $settings;
 
+    /**
+     * @ORM\OneToMany(targetEntity=NetworkOrganization::class, mappedBy="organization", orphanRemoval=true)
+     */
+    private $networkOrganizations;
+
+    /**
+     * @ORM\OneToMany(targetEntity=NetworkOrganization::class, mappedBy="parent")
+     */
+    private $networkOrganizationChildren;
+
+    public function __construct()
+    {
+        $this->networkOrganizations = new ArrayCollection();
+        $this->networkOrganizationChildren = new ArrayCollection();
+    }
+
     public function getId(): ?int
     {
         return $this->id;
@@ -122,4 +144,64 @@ class Organization
 
         return $this;
     }
+
+    /**
+     * @return Collection|NetworkOrganization[]
+     */
+    public function getNetworkOrganizations(): Collection
+    {
+        return $this->networkOrganizations;
+    }
+
+    public function addNetworkOrganization(NetworkOrganization $networkOrganization): self
+    {
+        if (!$this->networkOrganizations->contains($networkOrganization)) {
+            $this->networkOrganizations[] = $networkOrganization;
+            $networkOrganization->setOrganization($this);
+        }
+
+        return $this;
+    }
+
+    public function removeNetworkOrganization(NetworkOrganization $networkOrganization): self
+    {
+        if ($this->networkOrganizations->removeElement($networkOrganization)) {
+            // set the owning side to null (unless already changed)
+            if ($networkOrganization->getOrganization() === $this) {
+                $networkOrganization->setOrganization(null);
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * @return Collection|NetworkOrganization[]
+     */
+    public function getNetworkOrganizationChildren(): Collection
+    {
+        return $this->networkOrganizationChildren;
+    }
+
+    public function addNetworkOrganizationChild(NetworkOrganization $networkOrganizationChild): self
+    {
+        if (!$this->networkOrganizationChildren->contains($networkOrganizationChild)) {
+            $this->networkOrganizationChildren[] = $networkOrganizationChild;
+            $networkOrganizationChild->setParent($this);
+        }
+
+        return $this;
+    }
+
+    public function removeNetworkOrganizationChild(NetworkOrganization $networkOrganizationChild): self
+    {
+        if ($this->networkOrganizationChildren->removeElement($networkOrganizationChild)) {
+            // set the owning side to null (unless already changed)
+            if ($networkOrganizationChild->getParent() === $this) {
+                $networkOrganizationChild->setParent(null);
+            }
+        }
+
+        return $this;
+    }
 }

+ 6 - 0
src/Entity/Organization/Settings.php

@@ -1,12 +1,17 @@
 <?php
+declare(strict_types=1);
 
 namespace App\Entity\Organization;
 
 use ApiPlatform\Core\Annotation\ApiResource;
+use App\Enum\Organization\settingsProductEnum;
 use App\Repository\Organization\SettingsRepository;
 use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Validator\Constraints as Assert;
 
 /**
+ * Caractéristiques d'une Organization (produits, options...etc)
+ *
  * @ApiResource()
  * @ORM\Entity(repositoryClass=SettingsRepository::class)
  */
@@ -27,6 +32,7 @@ class Settings
 
     /**
      * @ORM\Column(type="string", length=255)
+     * @Assert\Choice(callback={"\App\Enum\Organization\SettingsProductEnum", "toArray"})
      */
     private $product;
 

+ 3 - 0
src/Entity/Person/Person.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 
 namespace App\Entity\Person;
 
@@ -9,6 +10,8 @@ use Doctrine\ORM\Mapping as ORM;
 use Symfony\Component\Security\Core\User\UserInterface;
 
 /**
+ * Personne physique ou morale
+ *
  * @ORM\Entity(repositoryClass=PersonRepository::class)
  */
 class Person implements UserInterface

+ 3 - 0
src/Entity/Person/PersonActivity.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 
 namespace App\Entity\Person;
 
@@ -8,6 +9,8 @@ use App\Repository\Person\PersonActivityRepository;
 use Doctrine\ORM\Mapping as ORM;
 
 /**
+ * Lien entre une Person et une Activity
+ *
  * @ApiResource()
  * @ORM\Entity(repositoryClass=PersonActivityRepository::class)
  */

+ 18 - 0
src/Enum/Network/LeadingCauseEnum.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace App\Enum\Network;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * Liste des cause de départ d'une structure dans un réseau
+ */
+class LeadingCauseEnum extends Enum
+{
+    private const DEPARTURE     = 'DEPARTURE';
+    private const RADIATION     = 'RADIATION';
+    private const DISSOLUTION   = 'DISSOLUTION';
+    private const FUSION        = 'FUSION';
+    private const OTHER         = 'OTHER';
+    private const SLEEP         = 'SLEEP';
+}

+ 18 - 0
src/Enum/Network/NetworkEnum.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace App\Enum\Network;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * Liste des réseaux disponibles
+ */
+class NetworkEnum extends Enum
+{
+    private const CMF     = 3;
+    private const FFEC     = 4;
+    private const YAV   = 5;
+    private const OUTOFNET  = 6;
+    private const CFBF = 7;
+    private const DEUXIOS = 8;
+}

+ 22 - 0
src/Enum/Organization/PrincipalTypeEnum.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace App\Enum\Organization;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * Types principaux d'une organisation
+ */
+class PrincipalTypeEnum extends Enum
+{
+    private const NATIONAL_FEDERATION = 'NATIONAL_FEDERATION';
+    private const REGIONAL_FEDERATION = 'REGIONAL_FEDERATION';
+    private const DEPARTEMENTAL_FEDERATION = 'DEPARTEMENTAL_FEDERATION';
+    private const LOCAL_FEDERATION = 'LOCAL_FEDERATION';
+    private const GROUPMENT = 'GROUPMENT';
+    private const DELEGATION = 'DELEGATION';
+    private const ARTISTIC_EDUCATION_ONLY = 'ARTISTIC_EDUCATION_ONLY';
+    private const ARTISTIC_PRACTICE_ONLY = 'ARTISTIC_PRACTICE_ONLY';
+    private const MUSIC_OPENTALENT = 'MUSIC_OPENTALENT';
+    private const ARTISTIC_PRACTICE_EDUCATION = 'ARTISTIC_PRACTICE_EDUCATION';
+}

+ 18 - 0
src/Enum/Organization/SettingsProductEnum.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace App\Enum\Organization;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * Type de produit disponible pour une organisation
+ */
+class SettingsProductEnum extends Enum
+{
+    const ARTIST = 'artist';
+    const ARTIST_PREMIUM = 'artist-premium';
+    const SCHOOL = 'school';
+    const SCHOOL_PREMIUM = 'school-premium';
+    const MANAGER = 'manager';
+    const MANAGER_PREMIUM = 'manager-premium';
+}

+ 8 - 1
src/EventListener/JWT/AuthenticationSuccessListener.php

@@ -1,14 +1,21 @@
 <?php
+declare(strict_types=1);
+
 namespace App\EventListener\JWT;
 
 use Lexik\Bundle\JWTAuthenticationBundle\Event\AuthenticationSuccessEvent;
 use Symfony\Component\Security\Core\User\UserInterface;
 
+/**
+ * Class AuthenticationSuccessListener : Listener appelé lors d'une authentification réussie ou ratée
+ * @package App\EventListener\JWT
+ */
 class AuthenticationSuccessListener {
     /**
+     * Appelé lors d'une authentification réussie
      * @param AuthenticationSuccessEvent $event
      */
-    public function onAuthenticationSuccessResponse(AuthenticationSuccessEvent $event)
+    public function onAuthenticationSuccessResponse(AuthenticationSuccessEvent $event): void
     {
         $data = $event->getData();
         $user = $event->getUser();

+ 0 - 82
src/EventSubscriber/ModuleSecuritySubscriber.php

@@ -1,82 +0,0 @@
-<?php
-
-namespace App\EventSubscriber;
-
-use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
-use ApiPlatform\Core\Util\RequestAttributesExtractor;
-use App\Service\Utils\Module;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\HttpKernel\Event\RequestEvent;
-use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
-use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\Security\Core\Security;
-
-final class ModuleSecuritySubscriber implements EventSubscriberInterface
-{
-    private $resourceMetadataFactory;
-
-    private $security;
-
-    private $module;
-
-    public function __construct(
-        ResourceMetadataFactoryInterface $resourceMetadataFactory,
-        Security $security,
-        Module $module
-    )
-    {
-        $this->security = $security;
-        $this->resourceMetadataFactory = $resourceMetadataFactory;
-        $this->module = $module;
-    }
-
-    public static function getSubscribedEvents()
-    {
-        return [
-            KernelEvents::REQUEST => ['moduleSecurity']
-        ];
-    }
-
-    /**
-     * On every request to api, we need to control if the organization have access to the resource thanks to
-     * it's products/options.
-     * @param RequestEvent $event
-     * @throws \ApiPlatform\Core\Exception\ResourceClassNotFoundException
-     */
-    public function moduleSecurity(RequestEvent $event): void
-    {
-        if(!$this->isApiPath($event->getRequest()->getPathInfo())){
-            return;
-        }
-
-        if (!$attributes = RequestAttributesExtractor::extractAttributes($event->getRequest())) {
-            throw new AccessDeniedHttpException(sprintf('Missing elements inside you\'re request'));
-        }
-        if (!$resourceMetadata = $this->resourceMetadataFactory->create($attributes['resource_class'])) {
-            throw new AccessDeniedHttpException(sprintf('Missing resource class'));
-        }
-
-        $module = $this->module->getModuleByResourceName($resourceMetadata->getShortName());
-
-        //Check if there is a module for this entity : eq configuration problem
-        if (null === $module) {
-            throw new AccessDeniedHttpException(sprintf('There no module for the entity (%s) !', $resourceMetadata->getShortName()));
-        }
-
-        //Security problem
-        if (!$this->security->isGranted('HAVING_MODULE', $module)) {
-            throw new AccessDeniedHttpException(sprintf('You don\'t have access to this module'));
-        }
-    }
-
-    /**
-     * Test if the path is an API Path
-     * @param string $path
-     * @return bool
-     */
-    private function isApiPath(string $path): bool
-    {
-        $pattern = "/(\/api\/)/i";
-        return preg_match($pattern, $path); // Outputs 1
-    }
-}

+ 8 - 1
src/Repository/Access/AccessRepository.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 
 namespace App\Repository\Access;
 
@@ -14,7 +15,7 @@ use Symfony\Component\HttpFoundation\RequestStack;
  * @method Access[]    findAll()
  * @method Access[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
  */
-class AccessRepository extends ServiceEntityRepository implements UserLoaderInterface
+final class AccessRepository extends ServiceEntityRepository implements UserLoaderInterface
 {
     const ACCESS_NAME_HEADER = 'X-AccessId';
 
@@ -26,6 +27,12 @@ class AccessRepository extends ServiceEntityRepository implements UserLoaderInte
         $this->requestStack = $requestStack;
     }
 
+    /**
+     * Méthode permettant de fournir un userProvider custom (voir config provider : access_provider)
+     * @param string $username
+     * @return mixed|\Symfony\Component\Security\Core\User\UserInterface|null
+     * @throws \Doctrine\ORM\NonUniqueResultException
+     */
     public function loadUserByUsername(string $username)
     {
         $entityManager = $this->getEntityManager();

+ 2 - 1
src/Repository/Access/OrganizationFunctionRepository.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 
 namespace App\Repository\Access;
 
@@ -12,7 +13,7 @@ use Doctrine\Persistence\ManagerRegistry;
  * @method OrganizationFunction[]    findAll()
  * @method OrganizationFunction[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
  */
-class OrganizationFunctionRepository extends ServiceEntityRepository
+final class OrganizationFunctionRepository extends ServiceEntityRepository
 {
     public function __construct(ManagerRegistry $registry)
     {

+ 51 - 0
src/Repository/Network/NetworkOrganizationRepository.php

@@ -0,0 +1,51 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Repository\Network;
+
+use App\Entity\Network\NetworkOrganization;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @method NetworkOrganization|null find($id, $lockMode = null, $lockVersion = null)
+ * @method NetworkOrganization|null findOneBy(array $criteria, array $orderBy = null)
+ * @method NetworkOrganization[]    findAll()
+ * @method NetworkOrganization[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+final class NetworkOrganizationRepository extends ServiceEntityRepository
+{
+    public function __construct(ManagerRegistry $registry)
+    {
+        parent::__construct($registry, NetworkOrganization::class);
+    }
+
+    // /**
+    //  * @return NetworkOrganization[] Returns an array of NetworkOrganization objects
+    //  */
+    /*
+    public function findByExampleField($value)
+    {
+        return $this->createQueryBuilder('n')
+            ->andWhere('n.exampleField = :val')
+            ->setParameter('val', $value)
+            ->orderBy('n.id', 'ASC')
+            ->setMaxResults(10)
+            ->getQuery()
+            ->getResult()
+        ;
+    }
+    */
+
+    /*
+    public function findOneBySomeField($value): ?NetworkOrganization
+    {
+        return $this->createQueryBuilder('n')
+            ->andWhere('n.exampleField = :val')
+            ->setParameter('val', $value)
+            ->getQuery()
+            ->getOneOrNullResult()
+        ;
+    }
+    */
+}

+ 51 - 0
src/Repository/Network/NetworkRepository.php

@@ -0,0 +1,51 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Repository\Network;
+
+use App\Entity\Network\Network;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @method Network|null find($id, $lockMode = null, $lockVersion = null)
+ * @method Network|null findOneBy(array $criteria, array $orderBy = null)
+ * @method Network[]    findAll()
+ * @method Network[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+final class NetworkRepository extends ServiceEntityRepository
+{
+    public function __construct(ManagerRegistry $registry)
+    {
+        parent::__construct($registry, Network::class);
+    }
+
+    // /**
+    //  * @return Network[] Returns an array of Network objects
+    //  */
+    /*
+    public function findByExampleField($value)
+    {
+        return $this->createQueryBuilder('n')
+            ->andWhere('n.exampleField = :val')
+            ->setParameter('val', $value)
+            ->orderBy('n.id', 'ASC')
+            ->setMaxResults(10)
+            ->getQuery()
+            ->getResult()
+        ;
+    }
+    */
+
+    /*
+    public function findOneBySomeField($value): ?Network
+    {
+        return $this->createQueryBuilder('n')
+            ->andWhere('n.exampleField = :val')
+            ->setParameter('val', $value)
+            ->getQuery()
+            ->getOneOrNullResult()
+        ;
+    }
+    */
+}

+ 43 - 26
src/Repository/Organization/OrganizationRepository.php

@@ -1,9 +1,12 @@
 <?php
+declare(strict_types=1);
 
 namespace App\Repository\Organization;
 
 use App\Entity\Organization\Organization;
+use App\Enum\Organization\PrincipalTypeEnum;
 use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\ORM\Query\ResultSetMapping;
 use Doctrine\Persistence\ManagerRegistry;
 
 /**
@@ -19,32 +22,46 @@ class OrganizationRepository extends ServiceEntityRepository
         parent::__construct($registry, Organization::class);
     }
 
-    // /**
-    //  * @return Organization[] Returns an array of Organization objects
-    //  */
-    /*
-    public function findByExampleField($value)
-    {
-        return $this->createQueryBuilder('o')
-            ->andWhere('o.exampleField = :val')
-            ->setParameter('val', $value)
-            ->orderBy('o.id', 'ASC')
-            ->setMaxResults(10)
-            ->getQuery()
-            ->getResult()
-        ;
-    }
-    */
+    /**
+     * Vérifie si l'organisation est un dernier parent : possède des enfants mais ces enfants ne possèdent pas d'enfant
+     * @param Organization $organization
+     * @return bool
+     */
+    public function isLastParent(Organization $organization): bool {
 
-    /*
-    public function findOneBySomeField($value): ?Organization
-    {
-        return $this->createQueryBuilder('o')
-            ->andWhere('o.exampleField = :val')
-            ->setParameter('val', $value)
-            ->getQuery()
-            ->getOneOrNullResult()
-        ;
+        $sql = sprintf("
+        SELECT 
+            IF( (SELECT o.id 
+                    FROM Organization as o 
+                    WHERE o.id=neto.organization_id
+                    AND o.principalType IN('%s','%s','%s','%s','%s','%s')) IS NOT NULL ,0,1) AS is_last_parent
+        FROM
+            NetworkOrganization as neto
+        WHERE
+            neto.parent_id = %d
+            and (neto.endDate is null or neto.endDate = \"0000-00-00\" or neto.endDate > CURDATE())
+        GROUP BY is_last_parent
+        ORDER BY is_last_parent DESC",
+            PrincipalTypeEnum::NATIONAL_FEDERATION(),
+            PrincipalTypeEnum::REGIONAL_FEDERATION(),
+            PrincipalTypeEnum::LOCAL_FEDERATION(),
+            PrincipalTypeEnum::GROUPMENT(),
+            PrincipalTypeEnum::DEPARTEMENTAL_FEDERATION(),
+            PrincipalTypeEnum::DELEGATION(),
+            $organization->getId()
+        );
+
+        $rsm = new ResultSetMapping();
+        $rsm->addScalarResult('is_last_parent', 'is_last_parent', 'integer');
+        $query = $this->getEntityManager()->createNativeQuery($sql, $rsm);
+        $result = $query->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
+
+        foreach ($result as $a_tmp) {
+            if ($a_tmp['is_last_parent']) {
+                return true;
+            }
+        }
+
+        return false;
     }
-    */
 }

+ 2 - 1
src/Repository/Organization/SettingsRepository.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 
 namespace App\Repository\Organization;
 
@@ -12,7 +13,7 @@ use Doctrine\Persistence\ManagerRegistry;
  * @method Settings[]    findAll()
  * @method Settings[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
  */
-class SettingsRepository extends ServiceEntityRepository
+final class SettingsRepository extends ServiceEntityRepository
 {
     public function __construct(ManagerRegistry $registry)
     {

+ 2 - 1
src/Repository/Person/PersonActivityRepository.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 
 namespace App\Repository\Person;
 
@@ -12,7 +13,7 @@ use Doctrine\Persistence\ManagerRegistry;
  * @method PersonActivity[]    findAll()
  * @method PersonActivity[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
  */
-class PersonActivityRepository extends ServiceEntityRepository
+final class PersonActivityRepository extends ServiceEntityRepository
 {
     public function __construct(ManagerRegistry $registry)
     {

+ 2 - 1
src/Repository/Person/PersonRepository.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 
 namespace App\Repository\Person;
 
@@ -15,7 +16,7 @@ use Symfony\Component\Security\Core\User\UserInterface;
  * @method Person[]    findAll()
  * @method Person[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
  */
-class PersonRepository extends ServiceEntityRepository implements PasswordUpgraderInterface
+final class PersonRepository extends ServiceEntityRepository implements PasswordUpgraderInterface
 {
     public function __construct(ManagerRegistry $registry)
     {

+ 32 - 6
src/Security/ModuleVoter.php

@@ -1,21 +1,34 @@
 <?php
+declare(strict_types=1);
+
 namespace App\Security;
 
+use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
 use App\Entity\Access\Access;
 use App\Entity\Organization\Organization;
-use App\Service\Utils\Module;
+use App\Service\Security\Module;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
 use Symfony\Component\Security\Core\Authorization\Voter\Voter;
+use ApiPlatform\Core\Util\RequestAttributesExtractor;
 
+/**
+ * Class ModuleVoter : permet d'assurer que la resource appelée est comprise dans l'un des modules de la structure
+ * @package App\Security
+ */
 class ModuleVoter extends Voter
 {
-    const HAVING_MODULE = 'HAVING_MODULE';
+    private $resourceMetadataFactory;
+
+    const HAVING_MODULE = 'IS_HAVING_MODULE';
 
     private $module;
 
-    public function __construct(Module $module)
+    public function __construct(Module $module, ResourceMetadataFactoryInterface $resourceMetadataFactory)
     {
         $this->module = $module;
+        $this->resourceMetadataFactory = $resourceMetadataFactory;
     }
 
     /**
@@ -30,24 +43,37 @@ class ModuleVoter extends Voter
     }
 
     /**
-     * Control if the organization have the required resource.
      * @param string $attribute
      * @param mixed $subject
      * @param TokenInterface $token
      * @return bool
+     * @throws \ApiPlatform\Core\Exception\ResourceClassNotFoundException
      */
     protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
     {
+        if (!$subject->attributes->get('_api_resource_class') || !$resourceMetadata = $this->resourceMetadataFactory->create($subject->attributes->get('_api_resource_class'))) {
+            throw new AccessDeniedHttpException(sprintf('Missing resource class'));
+        }
+
+        $module = $this->module->getModuleByResourceName($resourceMetadata->getShortName());
+
+        //Check if there is a module for this entity : eq configuration problem
+        if (null === $module) {
+            throw new AccessDeniedHttpException(sprintf('There no module for the entity (%s) !', $resourceMetadata->getShortName()));
+        }
+
         /** @var Access $currentAccess */
         $currentAccess = $token->getUser();
         /** @var Organization $organization */
         $organization = $currentAccess->getOrganization();
 
-        return $this->isOrganizationHaveThisModule($organization, $subject);
+        return $this->isOrganizationHaveThisModule($organization, $module);
     }
 
     /**
-     * is the organization have the required resource ?
+     * Test si l'organisation possède le module parmis les modules possédés via le produit souscrit, les options souscrites
+     * ou les modules possédées via des conditions particulières (isCmf par exemple)
+     *
      * @param Organization $organization
      * @param string $module
      * @return bool

+ 115 - 0
src/Service/Cotisation/Utils.php

@@ -0,0 +1,115 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Service\Cotisation;
+
+use App\Entity\Organization\Organization;
+use App\Repository\Organization\OrganizationRepository;
+use App\Service\Organization\Utils as OrganizationUtils;
+use App\Tests\Service\Cotisation\UtilsTest;
+use App\Service\Network\Utils as NetWorkUtils;
+
+/**
+ * Class Utils : Service rassemblant des fonctions d'interrogation pour gérer des conditions dans les Cotisations
+ * @package App\Service\Cotisation
+ */
+class Utils {
+    /** @var NetWorkUtils  */
+    private $networkUtils;
+    /** @var OrganizationRepository  */
+    private $organizationRepository;
+    /** @var OrganizationUtils  */
+    private $organizationUtils;
+
+    function __construct(
+        NetWorkUtils $networkUtils,
+        OrganizationUtils $organizationUtils,
+        OrganizationRepository $organizationRepository
+    ) {
+        $this->networkUtils = $networkUtils;
+        $this->organizationUtils = $organizationUtils;
+        $this->organizationRepository = $organizationRepository;
+    }
+
+    /**
+     * Test si l'organisation est un dernier parent ET appartient à la CMF.
+     * @param Organization $organization
+     * @return bool
+     * @see UtilsTest::testIsLastParentAndCMF()
+     */
+    public function isLastParentAndCMF(Organization $organization): bool {
+        return $this->organizationRepository->isLastParent($organization) && $this->networkUtils->isCMF($organization);
+    }
+
+    /**
+     * Test si l'organisation est une structure (non manager) ET appartient à la CMF
+     * @param Organization $organization
+     * @return bool
+     */
+    public function isStructureAndCMF(Organization $organization):bool {
+        return $this->organizationUtils->isStructure($organization) && $this->networkUtils->isCMF($organization);
+    }
+
+
+//
+//    /**
+//     * check if the organization is "lastParent" and product is manager and belong to CMF net
+//     * @param Organization $organization
+//     * @return type boolean TRUE if the organization is "lastParent" and product is manager and belong to CMF net
+//     */
+//    public function isLastParentAndManagerCMFAndCMF(Organization $organization) {
+//        $organizationRepository = $this->em->getRepository(Organization::class);
+//
+//        $isLastParent = $organizationRepository->isLastParent($organization->getId());
+//        $isCMFOrganization = ($organization->getId() == OrganizationEnum::CMF);
+//        $productName = $this->tipsUtils->getProductName(TipsProductEnum::OPENTALENT_MANAGER_STANDARD);
+//        $isManager = ($organization->getSettings()->getProduct() == $productName);
+//        $isCMF = $this->networkUtils->isOrganizationBelongToTheNetwork($organization, NetworkEnum::CMF());
+//
+//        return $isLastParent & $isCMFOrganization & $isManager & $isCMF;
+//    }
+//
+//    /**
+//     * check if the organization is OrganizationEnum::CMF
+//     *
+//     * @param Organization $organization
+//     * @return type boolean return TRUE if the organization is OrganizationEnum::CMF
+//     */
+//    public function isCMFAdministration(Organization $organization) {
+//        $organizationRepository = $this->em->getRepository(Organization::class);
+//
+//        $isCMFOrganization = ($organization->getId() == OrganizationEnum::CMF());
+//
+//        return $isCMFOrganization;
+//    }
+//
+//    /**
+//     * Check if the organization product is manager and belong to CMF net
+//     * @param Organization $organization
+//     * @return type boolean TRUE if the organization product is manager and belong to CMF net
+//     */
+//    public function isManagerAndCMF(Organization $organization) {
+//        $productName = $this->tipsUtils->getProductName(TipsProductEnum::OPENTALENT_MANAGER_STANDARD());
+//        $isManager = ($organization->getSettings()->getProduct() == $productName);
+//        $isCMF = $this->networkUtils->isOrganizationBelongToTheNetwork($organization, NetworkEnum::CMF());
+//
+//        return $isManager & $isCMF;
+//    }
+//
+//    /**
+//     * Check if the organization product is manager and is not "lastParent" and belong to CMF net
+//     * @param Organization $organization
+//     * @return type boolean TRUE if the organization product is manager and is not "lastParent" and belong to CMF net
+//     */
+//    public function isManagerAndNotLastParentAndCMF(Organization $organization) {
+//        $organizationRepository = $this->em->getRepository(Organization::class);
+//
+//        $productName = $this->tipsUtils->getProductName(TipsProductEnum::OPENTALENT_MANAGER_STANDARD());
+//        $isManager = ($organization->getSettings()->getProduct() == $productName);
+//        $isLastParent = $organizationRepository->isLastParent($organization->getId());
+//        $isCMF = $this->networkUtils->isOrganizationBelongToTheNetwork($organization, NetworkEnum::CMF());
+//        return $isManager & !$isLastParent & $isCMF;
+//    }
+//
+
+}

+ 48 - 0
src/Service/Network/Utils.php

@@ -0,0 +1,48 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Service\Network;
+
+use App\Entity\Network\NetworkOrganization;
+use App\Entity\Organization\Organization;
+use App\Enum\Network\NetworkEnum;
+use App\Tests\Service\Network\UtilsTest;
+
+/**
+ * Class Utils : service rassemblant des fonctions d'aides pour les questions se rapportant au réseau
+ * @package App\Service\Network
+ */
+class Utils
+{
+    public function __construct()
+    {
+    }
+
+    /**
+     * Test si l'organisation appartient au réseau de la CMF
+     * @param Organization $organization
+     * @return bool TRUE if the organization belong to CMF net
+     * @see UtilsTest::testIsCmf()
+     */
+    public function isCMF(Organization $organization): bool {
+        return $this->isOrganizationBelongToTheNetwork($organization, NetworkEnum::CMF());
+    }
+
+    /**
+     * Test si l'organisation appartient à un réseau
+     * @param Organization $organization
+     * @param NetworkEnum $network  id du réseau
+     * @return boolean
+     * @see UtilsTest::testIsOrganizationBelongToTheNetwork()
+     */
+    public function isOrganizationBelongToTheNetwork(Organization $organization, NetworkEnum $network): bool {
+        $networksOrganizations = $organization->getNetworkOrganizations();
+        /** @var NetworkOrganization $networksOrganization */
+        foreach ($networksOrganizations as $networksOrganization) {
+            if ($networksOrganization->getNetwork()->getId() === $network->getValue()) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

+ 30 - 0
src/Service/Organization/Utils.php

@@ -0,0 +1,30 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Service\Organization;
+
+use App\Entity\Organization\Organization;
+use App\Enum\Organization\SettingsProductEnum;
+use App\Test\Service\Organization\UtilsTest;
+
+/**
+ * Class OrganizationUtils : service rassemblant des fonctions d'aides pour les questions se rapportant à l'organisation
+ * @package App\Service\Resource
+ */
+class Utils
+{
+    public function __construct()
+    {
+    }
+
+    /**
+     * Test si l'organisation est considérée comme une structure == n'a pas un produit manager
+     * @param Organization $organization
+     * @return bool
+     * @see UtilsTest::testIsStructureTest()
+     */
+    public function isStructure(Organization $organization): bool{
+        return $organization->getSettings()->getProduct() !== SettingsProductEnum::MANAGER()
+            && $organization->getSettings()->getProduct() !== SettingsProductEnum::MANAGER_PREMIUM();
+    }
+}

+ 63 - 52
src/Service/Utils/Module.php → src/Service/Security/Module.php

@@ -1,13 +1,20 @@
 <?php
-namespace App\Service\Utils;
+declare(strict_types=1);
+
+namespace App\Service\Security;
 
 use App\Entity\Organization\Organization;
+use App\Service\Utils\Reflection;
+use App\Test\Service\Security\ModuleTest;
 use Doctrine\Common\Cache\ApcuCache;
 use Symfony\Component\Config\FileLocator;
-use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\Yaml\Yaml;
 
+/**
+ * Class Module : classe gérant la récupération de l'ensemble des modules possédées par une organisation
+ * @package App\Service\Security
+ */
 class Module
 {
     const OPENTALENT_CONFIG = __DIR__.'/../../../config/opentalent';
@@ -18,55 +25,18 @@ class Module
     /** @var array */
     private $moduleByConditionsConfig;
 
-    /** @var ContainerInterface */
-    private $container;
+    /** @var Reflection  */
+    private $reflection;
 
-    public function __construct(ContainerInterface $container)
+    public function __construct(Reflection $reflection)
     {
-        $this->container = $container;
+        $this->reflection = $reflection;
         $this->moduleConfig = $this->getModuleConfig();
         $this->moduleByConditionsConfig = $this->getModuleByConditionsConfig();
     }
 
     /**
-     * Parse and return the products.yaml content
-     * @return array
-     */
-    private function getModuleConfig(): array{
-        $configDirectories = [self::OPENTALENT_CONFIG];
-        $fileLocator = new FileLocator($configDirectories);
-        $yamlConfig = $fileLocator->locate('products.yaml', null, false)[0];
-        return Yaml::parseFile($yamlConfig);
-    }
-
-    /**
-     * Parse and return the modulesbyconditions.yaml content
-     * @return array
-     */
-    private function getModuleByConditionsConfig(): array{
-        $configDirectories = [self::OPENTALENT_CONFIG];
-        $fileLocator = new FileLocator($configDirectories);
-        $yamlConfig = $fileLocator->locate('modulesbyconditions.yaml', null, false)[0];
-        return Yaml::parseFile($yamlConfig);
-    }
-
-    /**
-     * Get the module who enabled the access to the resource
-     * @param string $resource
-     * @return int|null|string
-     */
-    public function getModuleByResourceName(string $resource): ?string {
-        $modules = $this->moduleConfig['opentalent']['modules'];
-        foreach ($modules as $module => $data) {
-            if ($data['entities'] && in_array($resource, $data['entities'], true)) {
-                return $module;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Get all the modules for one organization
+     * Récupère tous les modules de l'oganisation
      * @param Organization $organization
      * @return array
      */
@@ -93,9 +63,10 @@ class Module
     }
 
     /**
-     * Get the module inside the organization's settings
+     * Récupère les modules disponibles dans les settings de l'organisation (Sms, Pes, etc)
      * @param Organization $organization
      * @return array
+     * @see ModuleTest::testGetModuleBySettings()
      */
     public function getModuleBySettings(Organization $organization): array{
         $moduleByOptions = [];
@@ -110,20 +81,22 @@ class Module
     }
 
     /**
-     * Get the modules by conditions, thanks to the modulebyconditions.yaml file
+     * Récupère les modules par conditions, grace au fichier modulebyconditions.yaml
      * @param Organization $organization
      * @return array
+     * @see ModuleTest::testGetModulesByConditions()
      */
     public function getModulesByConditions(Organization $organization): array {
         $modulesByConditions = [];
-
+        return $modulesByConditions;
         $modules = $this->moduleByConditionsConfig['opentalent']['modulesbyconditions'];
         foreach ($modules as $moduleName => $module) {
             try{
-                $function = $this->container->get($module["conditions"]["service"]["name"]);
-                $reflection = new \ReflectionClass(get_class($function));
-                $method = $reflection->getMethod($module["conditions"]["service"]["function"]);
-                $response = $method->invokeArgs($function, array($organization));
+                $response = $this->reflection->dynamicInvokeWithArgsServiceMethod(
+                    $module["conditions"]["service"]["name"],
+                    $module["conditions"]["service"]["function"],
+                    array($organization)
+                );
                 if($response) {
                     $modulesByConditions[] = $moduleName;
                 }
@@ -134,9 +107,10 @@ class Module
     }
 
     /**
-     * Get product configuration thanks to the products.yaml file
+     * Récupère les modules disponibles par produit grace au fichier products.yaml
      * @param string $product
      * @return array|null
+     * @see ModuleTest::testGetModulesByProductConfiguration()
      */
     public function getModulesByProductConfiguration(string $product): ?array {
         $product = str_replace('-', '_', $product);
@@ -154,4 +128,41 @@ class Module
 
         return $modules;
     }
+
+    /**
+     * Parse et retourne le contenu du fichier products.yaml
+     * @return array
+     */
+    private function getModuleConfig(): array{
+        $configDirectories = [self::OPENTALENT_CONFIG];
+        $fileLocator = new FileLocator($configDirectories);
+        $yamlConfig = $fileLocator->locate('products.yaml', null, false)[0];
+        return Yaml::parseFile($yamlConfig);
+    }
+
+    /**
+     * Parse et retourne le contenu du fichier modulesbyconditions.yaml
+     * @return array
+     */
+    private function getModuleByConditionsConfig(): array{
+        $configDirectories = [self::OPENTALENT_CONFIG];
+        $fileLocator = new FileLocator($configDirectories);
+        $yamlConfig = $fileLocator->locate('modulesbyconditions.yaml', null, false)[0];
+        return Yaml::parseFile($yamlConfig);
+    }
+
+    /**
+     * Retourne le module possédant la resource passée en paramètre
+     * @param string $resource
+     * @return int|null|string
+     */
+    public function getModuleByResourceName(string $resource): ?string {
+        $modules = $this->moduleConfig['opentalent']['modules'];
+        foreach ($modules as $module => $data) {
+            if ($data['entities'] && in_array($resource, $data['entities'], true)) {
+                return $module;
+            }
+        }
+        return null;
+    }
 }

+ 34 - 0
src/Service/Utils/Reflection.php

@@ -0,0 +1,34 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Service\Utils;
+
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Class Reflection : Gestion des réflection de class
+ * @package App\Service\Utils
+ */
+class Reflection
+{
+    /** @var ContainerInterface */
+    private $container;
+
+    public function __construct(ContainerInterface $container)
+    {
+        $this->container = $container;
+    }
+
+    /**
+     * @param string $serviceName
+     * @param string $method
+     * @param array $parameters
+     * @return mixed
+     */
+    public function dynamicInvokeWithArgsServiceMethod(string $serviceName, string $method, array $parameters = []) {
+        $function = $this->container->get($serviceName);
+        $reflection = \ReflectionClass(get_class($function));
+        $method = $reflection->getMethod($method);
+        return $method->invokeArgs($function, $parameters);
+    }
+}

+ 30 - 0
symfony.lock

@@ -134,6 +134,9 @@
             "config/packages/lexik_jwt_authentication.yaml"
         ]
     },
+    "myclabs/php-enum": {
+        "version": "1.7.7"
+    },
     "namshi/jose": {
         "version": "7.2.3"
     },
@@ -200,6 +203,9 @@
     "symfony/asset": {
         "version": "v5.1.7"
     },
+    "symfony/browser-kit": {
+        "version": "v5.2.1"
+    },
     "symfony/cache": {
         "version": "v5.1.7"
     },
@@ -221,6 +227,9 @@
             "bin/console"
         ]
     },
+    "symfony/css-selector": {
+        "version": "v5.2.1"
+    },
     "symfony/dependency-injection": {
         "version": "v5.1.7"
     },
@@ -230,6 +239,9 @@
     "symfony/doctrine-bridge": {
         "version": "v5.1.7"
     },
+    "symfony/dom-crawler": {
+        "version": "v5.2.1"
+    },
     "symfony/dotenv": {
         "version": "v5.1.7"
     },
@@ -304,6 +316,21 @@
     "symfony/orm-pack": {
         "version": "v2.0.0"
     },
+    "symfony/phpunit-bridge": {
+        "version": "5.1",
+        "recipe": {
+            "repo": "github.com/symfony/recipes",
+            "branch": "master",
+            "version": "5.1",
+            "ref": "cb82a2355ec62fef0e7028ac969fe86fa722feb8"
+        },
+        "files": [
+            ".env.test",
+            "bin/phpunit",
+            "phpunit.xml.dist",
+            "tests/bootstrap.php"
+        ]
+    },
     "symfony/polyfill-intl-grapheme": {
         "version": "v1.18.1"
     },
@@ -381,6 +408,9 @@
     "symfony/string": {
         "version": "v5.1.7"
     },
+    "symfony/test-pack": {
+        "version": "v1.0.7"
+    },
     "symfony/translation-contracts": {
         "version": "v2.3.0"
     },

+ 93 - 0
tests/Service/Cotisation/UtilsTest.php

@@ -0,0 +1,93 @@
+<?php
+
+namespace App\Tests\Service\Cotisation;
+
+use App\Entity\Organization\Organization;
+use App\Repository\Organization\OrganizationRepository;
+use App\Service\Cotisation\Utils;
+use App\Service\Organization\Utils as OrganizationUtils;
+use PHPUnit\Framework\TestCase;
+use \App\Service\Network\Utils as NetworkUtils;
+
+class UtilsTest extends TestCase
+{
+    public function setUp(): void
+    {
+    }
+
+    /**
+     * @see Utils::isLastParentAndCMF()
+     */
+    public function testIsLastParentAndCMF(): void
+    {
+        $organizationMock = $this->getMockBuilder(Organization::class)->getMock();
+        $organizationMock
+            ->method('getId')
+            ->willReturn(1);
+
+        $organizationRepositoryMock =
+            $this
+                ->getMockBuilder(OrganizationRepository::class)
+                ->disableOriginalConstructor()
+                ->getMock();
+        $organizationRepositoryMock
+                ->expects($this->once())
+                ->method('isLastParent')
+                ->with($organizationMock)
+                ->willReturn(true);
+
+        $networkUtilsMock =
+            $this
+                ->getMockBuilder(NetworkUtils::class)
+                ->disableOriginalConstructor()
+                ->getMock();
+        $networkUtilsMock
+                ->expects($this->once())
+                ->method('isCMF')
+                ->with($organizationMock)
+                ->willReturn(true);
+
+        $organizationUtilsMock = $this->getMockBuilder(OrganizationUtils::class)->getMock();
+
+        $utils = new Utils($networkUtilsMock, $organizationUtilsMock, $organizationRepositoryMock);
+        $this->assertTrue($utils->isLastParentAndCMF($organizationMock));
+    }
+
+    /**
+     * @see Utils::isLastParentAndCMF()
+     */
+    public function testIsNotLastParentAndCMF(): void
+    {
+        $organizationMock = $this->getMockBuilder(Organization::class)->getMock();
+        $organizationMock
+            ->method('getId')
+            ->willReturn(1);
+
+        $organizationRepositoryMock =
+            $this
+                ->getMockBuilder(OrganizationRepository::class)
+                ->disableOriginalConstructor()
+                ->getMock();
+        $organizationRepositoryMock
+            ->expects($this->once())
+            ->method('isLastParent')
+            ->with($organizationMock)
+            ->willReturn(false);
+
+        $networkUtilsMock =
+            $this
+                ->getMockBuilder(NetworkUtils::class)
+                ->disableOriginalConstructor()
+                ->getMock();
+        $networkUtilsMock
+            ->expects($this->never())
+            ->method('isCMF')
+            ->with($organizationMock)
+            ->willReturn(true);
+
+        $organizationUtilsMock = $this->getMockBuilder(OrganizationUtils::class)->getMock();
+
+        $utils = new Utils($networkUtilsMock, $organizationUtilsMock, $organizationRepositoryMock);
+        $this->assertFalse($utils->isLastParentAndCMF($organizationMock));
+    }
+}

+ 77 - 0
tests/Service/Network/UtilsTest.php

@@ -0,0 +1,77 @@
+<?php
+namespace App\Tests\Service\Network;
+
+use App\Entity\Network\Network;
+use App\Entity\Network\NetworkOrganization;
+use App\Entity\Organization\Organization;
+use App\Enum\Network\NetworkEnum;
+use Doctrine\Common\Collections\ArrayCollection;
+use PHPUnit\Framework\TestCase;
+use App\Service\Network\Utils;
+
+class UtilsTest extends TestCase
+{
+    /** @var Utils */
+    private $utils;
+
+    private $organizationCmf;
+
+    private $organizationFfec;
+
+    public function setUp():void
+    {
+        $networkCmf = new Network();
+        $networkCmf->setId(3);
+        $networkCmf->setName('CMF');
+        $networkOrganization = new NetworkOrganization();
+        $networkOrganization->setNetwork($networkCmf);
+        $this->organizationCmf = new Organization();
+        $this->organizationCmf->addNetworkOrganization($networkOrganization);
+
+        $networkFfec = new Network();
+        $networkFfec->setId(4);
+        $networkFfec->setName('FFEC');
+        $networkOrganization = new NetworkOrganization();
+        $networkOrganization->setNetwork($networkFfec);
+        $this->organizationFfec = new Organization();
+        $this->organizationFfec->addNetworkOrganization($networkOrganization);
+
+        $this->utils = new Utils();
+    }
+
+    /**
+     * @see Utils::isCMF()
+     */
+    public function testIsCmf():void
+    {
+        $result = $this->utils->isCmf($this->organizationCmf);
+        $this->assertTrue($result);
+    }
+
+    /**
+     * @see Utils::isCMF()
+     */
+    public function testIsNotCmf():void
+    {
+        $result = $this->utils->isCmf($this->organizationFfec);
+        $this->assertFalse($result);
+    }
+
+    /**
+     * @see Utils::isOrganizationBelongToTheNetwork()
+     */
+    public function testIsOrganizationBelongToTheNetwork():void
+    {
+        $result = $this->utils->isOrganizationBelongToTheNetwork($this->organizationCmf, NetworkEnum::CMF());
+        $this->assertTrue($result);
+    }
+
+    /**
+     * @see Utils::isOrganizationBelongToTheNetwork()
+     */
+    public function testIsOrganizationNotBelongToTheNetwork():void
+    {
+        $result = $this->utils->isOrganizationBelongToTheNetwork($this->organizationCmf, NetworkEnum::FFEC());
+        $this->assertFalse($result);
+    }
+}

+ 34 - 0
tests/Service/Organization/UtilsTest.php

@@ -0,0 +1,34 @@
+<?php
+namespace App\Test\Service\Organization;
+
+use App\Entity\Organization\Organization;
+use App\Entity\Organization\Settings;
+use App\Enum\Organization\SettingsProductEnum;
+use App\Service\Organization\Utils as OrganizationUtils;
+use PHPUnit\Framework\TestCase;
+
+class UtilsTest extends TestCase
+{
+    /** @var OrganizationUtils */
+    private $organizationUtils;
+
+    /** @var Organization */
+    private $organization;
+
+    public function setUp():void
+    {
+        $settings = new Settings();
+        $settings->setProduct(SettingsProductEnum::ARTIST_PREMIUM());
+        $this->organization = new Organization();
+        $this->organization->setSettings($settings);
+
+        $this->organizationUtils = new OrganizationUtils();
+    }
+
+    /**
+     * @see OrganizationUtils::isStructure()
+     */
+    public function testIsStructureTest(){
+        $this->assertTrue($this->organizationUtils->isStructure($this->organization));
+    }
+}

+ 70 - 0
tests/Service/Security/ModuleTest.php

@@ -0,0 +1,70 @@
+<?php
+namespace App\Test\Service\Security;
+
+use App\Entity\Organization\Organization;
+use App\Entity\Organization\Settings;
+use App\Service\Utils\Reflection;
+use PHPUnit\Framework\TestCase;
+use App\Service\Security\Module;
+
+class ModuleTest extends TestCase
+{
+    private $reflectionMock;
+
+    public function setUp():void
+    {
+        $this->reflectionMock = $this->getMockBuilder(Reflection::class)->disableOriginalConstructor()->getMock();
+    }
+
+    /**
+     * @see Module::getModuleBySettings()
+     */
+    public function testGetModuleBySettings(){
+
+        $settingsMock = $this->getMockBuilder(Settings::class)->getMock();
+        $settingsMock
+            ->expects($this->once())
+            ->method('getModules')
+            ->willReturn(["Sms" => true]);
+
+        $organizationMock = $this->getMockBuilder(Organization::class)->getMock();
+        $organizationMock
+            ->expects($this->once())
+            ->method('getSettings')
+            ->willReturn($settingsMock);
+
+        $module = new Module($this->reflectionMock);
+        $value = "Sms";
+        // assert function to test whether 'value' is a value of array
+        $this->assertContains($value, $module->getModuleBySettings($organizationMock)) ;
+    }
+
+    /**
+     * @see Module::getModulesByConditions()
+     */
+    public function testGetModulesByConditions()
+    {
+        $organizationMock = $this->getMockBuilder(Organization::class)->getMock();
+        $this->reflectionMock
+            ->method('dynamicInvokeWithArgsServiceMethod')
+            ->with('opentalent.network.utils', 'isCMF', array($organizationMock))
+            ->willReturn(true);
+
+
+        $module = new Module($this->reflectionMock);
+        $value = "Network";
+        // assert function to test whether 'value' is a value of array
+        $this->assertContains($value, $module->getModulesByConditions($organizationMock)) ;
+    }
+
+    /**
+     * @see Module::getModulesByProductConfiguration()
+     */
+    public function testGetModulesByProductConfiguration()
+    {
+        $module = new Module($this->reflectionMock);
+        $value = "MessagesAdvanced";
+        // assert function to test whether 'value' is a value of array
+        $this->assertContains($value, $module->getModulesByProductConfiguration('artist-premium')) ;
+    }
+}

+ 11 - 0
tests/bootstrap.php

@@ -0,0 +1,11 @@
+<?php
+
+use Symfony\Component\Dotenv\Dotenv;
+
+require dirname(__DIR__).'/vendor/autoload.php';
+
+if (file_exists(dirname(__DIR__).'/config/bootstrap.php')) {
+    require dirname(__DIR__).'/config/bootstrap.php';
+} elseif (method_exists(Dotenv::class, 'bootEnv')) {
+    (new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
+}