瀏覽代碼

Merge branch 'feature/v8-4410_reserved_subdomains' into develop

Olivier Massot 2 年之前
父節點
當前提交
6fba70c92d

+ 2 - 2
config/bundles.php

@@ -3,7 +3,7 @@
 return [
     Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
     Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
-    Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'docker' => true, 'staging' => true],
+    Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'docker' => true, 'test' => true, 'staging' => true],
     Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
     Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
     Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
@@ -17,7 +17,7 @@ return [
     Knp\Bundle\SnappyBundle\KnpSnappyBundle::class => ['all' => true],
     Knp\Bundle\GaufretteBundle\KnpGaufretteBundle::class => ['all' => true],
     Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
-    Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'docker' => true, 'staging' => true],
+    Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'docker' => true, 'test' => true, 'staging' => true],
     Symfony\Bundle\MercureBundle\MercureBundle::class => ['all' => true],
     Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
     Nelmio\Alice\Bridge\Symfony\NelmioAliceBundle::class => ['dev' => true, 'staging' => true],

+ 178 - 177
config/opentalent/enum.yaml

@@ -1,177 +1,178 @@
-opentalent:
-  #AccessAndFunction
-    function: 'App\Enum\AccessAndFunction\FunctionEnum'
-    function_activities: 'App\Enum\AccessAndFunction\ActivitiesFunctionEnum'
-    function_administratives: 'App\Enum\AccessAndFunction\AdministrativesFunctionEnum'
-    function_associatives: 'App\Enum\AccessAndFunction\AssociativesFunctionEnum'
-    function_departures_cause: 'App\Enum\AccessAndFunction\DeparturesCauseEnum'
-    function_pedagogics: 'App\Enum\AccessAndFunction\PedagogicsFunctionEnum'
-    function_other: 'App\Enum\AccessAndFunction\OtherFunctionEnum'
-    function_type: 'App\Enum\AccessAndFunction\TypeFunctionEnum'
-    license_type: 'App\Enum\AccessAndFunction\LicenseTypeEnum'
-    license_rate: 'App\Enum\AccessAndFunction\LicenseRateEnum'
-    function_role: 'App\Enum\AccessAndFunction\FunctionalRoleEnum'
-
-  #AccessSocial
-    professional_status: 'App\Enum\AccessSocial\ProfessionalStatusEnum'
-    type_of_contact: 'App\Enum\AccessSocial\TypeOfContractEnum'
-    assisted_contract: 'App\Enum\AccessSocial\AssistedContractEnum'
-    period_unit: 'App\Enum\AccessSocial\PeriodUnitEnum'
-    family_situation: 'App\Enum\AccessSocial\FamilySituationEnum'
-
-  #Core
-    period: 'App\Enum\Core\PeriodEnum'
-    action_status_type: 'App\Enum\Core\ActionStatusTypeEnum'
-    control_type: 'App\Enum\Core\ControlTypeEnum'
-    repair_type: 'App\Enum\Core\RepairTypeEnum'
-    contact_point_type: 'App\Enum\Core\ContactPointTypeEnum'
-    contact_point_type_person: 'App\Enum\Core\ContactPointTypePersonEnum'
-    appreciation: 'App\Enum\Core\AppreciationEnum'
-    semester: 'App\Enum\Core\SemesterEnum'
-    trimester: 'App\Enum\Core\TrimesterEnum'
-    month: 'App\Enum\Core\MonthEnum'
-    notification_type: 'App\Enum\Core\NotificationTypeEnum'
-    tips_priority_level: 'App\Enum\Core\PriorityLevelEnum'
-    tips_type_person: 'App\Enum\Core\TipsTypePersonEnum'
-    tips_network: 'App\Enum\Core\TipsNetworkEnum'
-    tips_product: 'App\Enum\Core\TipsProductEnum'
-    days_enum: 'App\Enum\Core\DaysEnum'
-    timezone: 'App\Enum\Core\TimeZoneEnum'
-    tagtextcolor: 'App\Enum\Core\TagTextColorEnum'
-    tips_legalstatus: 'App\Enum\Core\TipsLegalStatusEnum'
-
-  #Donor
-    donor_displayed_on: 'App\Enum\Donor\DonorDisplayedOnEnum'
-    donor_status: 'App\Enum\Donor\DonorStatusEnum'
-
-  #Network
-    network_leading: 'App\Enum\Network\LeadingCauseEnum'
-    network: 'App\Enum\Network\NetworkEnum'
-
-  #Organization
-    organization_category: 'App\Enum\Organization\CategoryEnum'
-    organization_financial: 'App\Enum\Organization\FinancialEnum'
-    organization_legal: 'App\Enum\Organization\LegalEnum'
-    organization_opca: 'App\Enum\Organization\OpcaEnum'
-    organization_principal_type: 'App\Enum\Organization\PrincipalTypeEnum'
-    organization_school_cat: 'App\Enum\Organization\SchoolCategoryEnum'
-    organization_type_establishment_detail: 'App\Enum\Organization\TypeEstablishmentDetailEnum'
-    organization_type_establishment: 'App\Enum\Organization\TypeEstablishmentEnum'
-    organization_familly_type: 'App\Enum\Organization\FamillyTypeEnum'
-    organization_sub_familly_type: 'App\Enum\Organization\SubFamillyTypeEnum'
-    organization_bulletin_period: 'App\Enum\Organization\BulletinPeriodEnum'
-    organization_bulletin_output: 'App\Enum\Organization\BulletinOutputEnum'
-    organization_bulletin_send_to: 'App\Enum\Organization\SendToBulletinEnum'
-    organization_setting_country: 'App\Enum\Organization\CountryEnum'
-    address_postal_organization: 'App\Enum\Organization\AddressPostalOrganizationTypeEnum'
-
-  #Person
-    person_gender: 'App\Enum\Person\GenderEnum'
-    person_insee: 'App\Enum\Person\InseeEnum'
-    person_medal_type: 'App\Enum\Person\MedalTypeEnum'
-    person_moral_type: 'App\Enum\Person\MoralPersonTypeEnum'
-    medal_type: 'App\Enum\Person\MedalTypeEnum'
-    address_postal_person: 'App\Enum\Person\AddressPostalPersonTypeEnum'
-
-  #Place
-    place_day_of_week: 'App\Enum\Place\DayOfWeekEnum'
-    place_site_status: 'App\Enum\Place\SiteStatusEnum'
-    place_site_type: 'App\Enum\Place\SiteTypeEnum'
-
-  #Product
-    equipment_appreciation: 'App\Enum\Product\AppreciationEnum'
-    equipment_control_type: 'App\Enum\Product\ControlTypeEnum'
-    equipment_loan_type: 'App\Enum\Product\LoanTypeEnum'
-    equipment_category: 'App\Enum\Product\EquipmentCategoryEnum'
-    equipment_detail: 'App\Enum\Product\EquipmentDetailEnum'
-    equipment_family: 'App\Enum\Product\EquipmentFamillyEnum'
-    equipment_group: 'App\Enum\Product\EquipmentGroupEnum'
-    equipment_insurance: 'App\Enum\Product\EquipmentInsuranceEnum'
-    equipment_logistical_platform: 'App\Enum\Product\EquipmentLogisticalPlatformEnum'
-    equipment_status: 'App\Enum\Product\EquipmentStatusEnum'
-    equipment_tone: 'App\Enum\Product\EquipmentToneEnum'
-    equipment_used_for: 'App\Enum\Product\EquipmentUsedForEnum'
-    equipment_repair_type: 'App\Enum\Product\RepairTypeEnum'
-    equipment_band: 'App\Enum\Product\BandEnum'
-    equipment_difficulty: 'App\Enum\Product\DifficultyEnum'
-    equipment_origin: 'App\Enum\Product\OriginMusicScoreEnum'
-    equipment_outcause: 'App\Enum\Product\OutCauseEnum'
-    equipment_checking: 'App\Enum\Product\CheckingEnum'
-    intangible_amount_type: 'App\Enum\Product\IntangibleAmountTypeEnum'
-    equipment_periodicity_control: 'App\Enum\Product\PeriodicityControlEnum'
-
-  #Event
-    event_type: 'App\Enum\Booking\EventTypeEnum'
-    event_visibility: 'App\Enum\Booking\VisibilityEnum'
-    event_type_gender: 'App\Enum\Booking\EventGenderTypeEnum'
-    event_educationalproject_establishment: 'App\Enum\Booking\EducationalProjectEstablishmentEnum'
-    event_educationalproject_specialclass: 'App\Enum\Booking\EducationalProjectSpecialClassEnum'
-    event_educationalproject_educationaldevice: 'App\Enum\Booking\EducationalProjectEducationalDeviceEnum'
-    examen_convocation_status: 'App\Enum\Booking\ExamenConvocationStatusEnum'
-    examen_convocation_presence: 'App\Enum\Booking\ExamenConvocationPresenceEnum'
-    examen_timeline: 'App\Enum\Booking\ExamenTimelineTypeEnum'
-    course_timeline: 'App\Enum\Booking\CourseTimelineTypeEnum'
-    organization_holiday_timeline: 'App\Enum\Booking\OrganizationHolidayTimelineTypeEnum'
-    person_holiday_timeline: 'App\Enum\Booking\PersonHolidayTimelineTypeEnum'
-    event_timeline: 'App\Enum\Booking\EventTimelineTypeEnum'
-    educational_project_timeline: 'App\Enum\Booking\EducationalProjectTimelineTypeEnum'
-    event_participation: 'App\Enum\Booking\ParticipationStatusEnum'
-
-  # File
-    file_visibility: 'App\Enum\Core\FileVisibilityEnum'
-    file_folder: 'App\Enum\Core\FileFolderEnum'
-    file_status: 'App\Enum\Core\FileStatusEnum'
-
-  #education
-    education: 'App\Enum\Education\EducationTypeEnum'
-    education_year: 'App\Enum\Education\YearEnum'
-    education_period: 'App\Enum\Education\PeriodEnum'
-    education_periodicity: 'App\Enum\Education\PeriodicityEnum'
-    advanced_education_notation: 'App\Enum\Education\AdvancedEducationNotationTypeEnum'
-
-    #billing
-    billing_periodicity: 'App\Enum\Billing\PeriodicityEnum'
-    billing_type_periodicity: 'App\Enum\Billing\PeriodicityTypeEnum'
-    billing_pricingline_adhesion: 'App\Enum\Billing\PricingLineAdhesionEnum'
-    billing_pricingline_productrent: 'App\Enum\Billing\PricingLineProductRentEnum'
-    billing_discount_global_tariff_family: 'App\Enum\Billing\DiscountGlobalTariffFamilyEnum'
-    billing_pricingline_invoice_line: 'App\Enum\Billing\PricingLineInvoiceLineEnum'
-    billing_payment_choice: 'App\Enum\Billing\PaymentChoiceEnum'
-    billing_bank: 'App\Enum\Billing\BankEnum'
-    billing_periodicity_payment: 'App\Enum\Billing\PeriodicityPaymentEnum'
-    billing_rent_reduction_type: 'App\Enum\Billing\ReductionTypeEnum'
-    billing_rent_year: 'App\Enum\Billing\RentYearEnum'
-    billing_family_reduction_type: 'App\Enum\Billing\FamilyReductionTypeEnum'
-    billing_payment_state: 'App\Enum\Billing\PaymentStateEnum'
-    billing_period: 'App\Enum\Billing\PeriodEnum'
-    billing_adhesion_choice: 'App\Enum\Billing\AdhesionChoiceEnum'
-    billing_order_adult_type_choice: 'App\Enum\Billing\OrderAdultTypeEnum'
-    billing_adult_condition_type_choice: 'App\Enum\Billing\AdultConditionTypeEnum'
-    billing_payment_type_choice: 'App\Enum\Billing\PaymentTypeEnum'
-    billing_type: 'App\Enum\Billing\BillingTypeEnum'
-
-  #message
-    message_status: 'App\Enum\Message\MessageStatusEnum'
-    report_message_satus: 'App\Enum\Message\ReportMessageSatusEnum'
-    message_sender: 'App\Enum\Message\SenderEnum'
-    message_sender_only_access: 'App\Enum\Message\SenderOnlyAccessEnum'
-    message_send_to: 'App\Enum\Message\SendToEnum'
-
-  #rules
-    default_rules: 'App\Enum\Rulerz\RulesEnum'
-    manager_rules: 'App\Enum\Rulerz\RulesManagerEnum'
-
-  #commission
-    commission_member_function: 'App\Enum\Person\CommissionMemberFunctionEnum'
-    commission_member_cause_output: 'App\Enum\Person\CauseOutputEnum'
-
-  #Cotisation
-    cotisation_function_enum_choices: 'App\Enum\Cotisation\CotisationFunctionEnum'
-    type_of_practices_enum: 'App\Enum\Cotisation\TypeOfPracticeEnum'
-    category_type_of_practices_enum: 'App\Enum\Cotisation\CategoryTypeOfPracticeEnum'
-
-  #OnlineRegistration
-    onlineregistration_registration_status: 'App\Enum\OnlineRegistration\RegistrationStatus'
-    onlineregistration_wish_registration: 'App\Enum\OnlineRegistration\WishRegistration'
-    onlineregistration_file_type: 'App\Enum\OnlineRegistration\FileTypeEnum'
-    onlineregistration_origin_education_student_wish: 'App\Enum\OnlineRegistration\EducationStudentWishOriginEnum'
+parameters:
+    opentalent.enum:
+        #AccessAndFunction
+          function: 'App\Enum\AccessAndFunction\FunctionEnum'
+          function_activities: 'App\Enum\AccessAndFunction\ActivitiesFunctionEnum'
+          function_administratives: 'App\Enum\AccessAndFunction\AdministrativesFunctionEnum'
+          function_associatives: 'App\Enum\AccessAndFunction\AssociativesFunctionEnum'
+          function_departures_cause: 'App\Enum\AccessAndFunction\DeparturesCauseEnum'
+          function_pedagogics: 'App\Enum\AccessAndFunction\PedagogicsFunctionEnum'
+          function_other: 'App\Enum\AccessAndFunction\OtherFunctionEnum'
+          function_type: 'App\Enum\AccessAndFunction\TypeFunctionEnum'
+          license_type: 'App\Enum\AccessAndFunction\LicenseTypeEnum'
+          license_rate: 'App\Enum\AccessAndFunction\LicenseRateEnum'
+          function_role: 'App\Enum\AccessAndFunction\FunctionalRoleEnum'
+
+        #AccessSocial
+          professional_status: 'App\Enum\AccessSocial\ProfessionalStatusEnum'
+          type_of_contact: 'App\Enum\AccessSocial\TypeOfContractEnum'
+          assisted_contract: 'App\Enum\AccessSocial\AssistedContractEnum'
+          period_unit: 'App\Enum\AccessSocial\PeriodUnitEnum'
+          family_situation: 'App\Enum\AccessSocial\FamilySituationEnum'
+
+        #Core
+          period: 'App\Enum\Core\PeriodEnum'
+          action_status_type: 'App\Enum\Core\ActionStatusTypeEnum'
+          control_type: 'App\Enum\Core\ControlTypeEnum'
+          repair_type: 'App\Enum\Core\RepairTypeEnum'
+          contact_point_type: 'App\Enum\Core\ContactPointTypeEnum'
+          contact_point_type_person: 'App\Enum\Core\ContactPointTypePersonEnum'
+          appreciation: 'App\Enum\Core\AppreciationEnum'
+          semester: 'App\Enum\Core\SemesterEnum'
+          trimester: 'App\Enum\Core\TrimesterEnum'
+          month: 'App\Enum\Core\MonthEnum'
+          notification_type: 'App\Enum\Core\NotificationTypeEnum'
+          tips_priority_level: 'App\Enum\Core\PriorityLevelEnum'
+          tips_type_person: 'App\Enum\Core\TipsTypePersonEnum'
+          tips_network: 'App\Enum\Core\TipsNetworkEnum'
+          tips_product: 'App\Enum\Core\TipsProductEnum'
+          days_enum: 'App\Enum\Core\DaysEnum'
+          timezone: 'App\Enum\Core\TimeZoneEnum'
+          tagtextcolor: 'App\Enum\Core\TagTextColorEnum'
+          tips_legalstatus: 'App\Enum\Core\TipsLegalStatusEnum'
+
+        #Donor
+          donor_displayed_on: 'App\Enum\Donor\DonorDisplayedOnEnum'
+          donor_status: 'App\Enum\Donor\DonorStatusEnum'
+
+        #Network
+          network_leading: 'App\Enum\Network\LeadingCauseEnum'
+          network: 'App\Enum\Network\NetworkEnum'
+
+        #Organization
+          organization_category: 'App\Enum\Organization\CategoryEnum'
+          organization_financial: 'App\Enum\Organization\FinancialEnum'
+          organization_legal: 'App\Enum\Organization\LegalEnum'
+          organization_opca: 'App\Enum\Organization\OpcaEnum'
+          organization_principal_type: 'App\Enum\Organization\PrincipalTypeEnum'
+          organization_school_cat: 'App\Enum\Organization\SchoolCategoryEnum'
+          organization_type_establishment_detail: 'App\Enum\Organization\TypeEstablishmentDetailEnum'
+          organization_type_establishment: 'App\Enum\Organization\TypeEstablishmentEnum'
+          organization_familly_type: 'App\Enum\Organization\FamillyTypeEnum'
+          organization_sub_familly_type: 'App\Enum\Organization\SubFamillyTypeEnum'
+          organization_bulletin_period: 'App\Enum\Organization\BulletinPeriodEnum'
+          organization_bulletin_output: 'App\Enum\Organization\BulletinOutputEnum'
+          organization_bulletin_send_to: 'App\Enum\Organization\SendToBulletinEnum'
+          organization_setting_country: 'App\Enum\Organization\CountryEnum'
+          address_postal_organization: 'App\Enum\Organization\AddressPostalOrganizationTypeEnum'
+
+        #Person
+          person_gender: 'App\Enum\Person\GenderEnum'
+          person_insee: 'App\Enum\Person\InseeEnum'
+          person_medal_type: 'App\Enum\Person\MedalTypeEnum'
+          person_moral_type: 'App\Enum\Person\MoralPersonTypeEnum'
+          medal_type: 'App\Enum\Person\MedalTypeEnum'
+          address_postal_person: 'App\Enum\Person\AddressPostalPersonTypeEnum'
+
+        #Place
+          place_day_of_week: 'App\Enum\Place\DayOfWeekEnum'
+          place_site_status: 'App\Enum\Place\SiteStatusEnum'
+          place_site_type: 'App\Enum\Place\SiteTypeEnum'
+
+        #Product
+          equipment_appreciation: 'App\Enum\Product\AppreciationEnum'
+          equipment_control_type: 'App\Enum\Product\ControlTypeEnum'
+          equipment_loan_type: 'App\Enum\Product\LoanTypeEnum'
+          equipment_category: 'App\Enum\Product\EquipmentCategoryEnum'
+          equipment_detail: 'App\Enum\Product\EquipmentDetailEnum'
+          equipment_family: 'App\Enum\Product\EquipmentFamillyEnum'
+          equipment_group: 'App\Enum\Product\EquipmentGroupEnum'
+          equipment_insurance: 'App\Enum\Product\EquipmentInsuranceEnum'
+          equipment_logistical_platform: 'App\Enum\Product\EquipmentLogisticalPlatformEnum'
+          equipment_status: 'App\Enum\Product\EquipmentStatusEnum'
+          equipment_tone: 'App\Enum\Product\EquipmentToneEnum'
+          equipment_used_for: 'App\Enum\Product\EquipmentUsedForEnum'
+          equipment_repair_type: 'App\Enum\Product\RepairTypeEnum'
+          equipment_band: 'App\Enum\Product\BandEnum'
+          equipment_difficulty: 'App\Enum\Product\DifficultyEnum'
+          equipment_origin: 'App\Enum\Product\OriginMusicScoreEnum'
+          equipment_outcause: 'App\Enum\Product\OutCauseEnum'
+          equipment_checking: 'App\Enum\Product\CheckingEnum'
+          intangible_amount_type: 'App\Enum\Product\IntangibleAmountTypeEnum'
+          equipment_periodicity_control: 'App\Enum\Product\PeriodicityControlEnum'
+
+        #Event
+          event_type: 'App\Enum\Booking\EventTypeEnum'
+          event_visibility: 'App\Enum\Booking\VisibilityEnum'
+          event_type_gender: 'App\Enum\Booking\EventGenderTypeEnum'
+          event_educationalproject_establishment: 'App\Enum\Booking\EducationalProjectEstablishmentEnum'
+          event_educationalproject_specialclass: 'App\Enum\Booking\EducationalProjectSpecialClassEnum'
+          event_educationalproject_educationaldevice: 'App\Enum\Booking\EducationalProjectEducationalDeviceEnum'
+          examen_convocation_status: 'App\Enum\Booking\ExamenConvocationStatusEnum'
+          examen_convocation_presence: 'App\Enum\Booking\ExamenConvocationPresenceEnum'
+          examen_timeline: 'App\Enum\Booking\ExamenTimelineTypeEnum'
+          course_timeline: 'App\Enum\Booking\CourseTimelineTypeEnum'
+          organization_holiday_timeline: 'App\Enum\Booking\OrganizationHolidayTimelineTypeEnum'
+          person_holiday_timeline: 'App\Enum\Booking\PersonHolidayTimelineTypeEnum'
+          event_timeline: 'App\Enum\Booking\EventTimelineTypeEnum'
+          educational_project_timeline: 'App\Enum\Booking\EducationalProjectTimelineTypeEnum'
+          event_participation: 'App\Enum\Booking\ParticipationStatusEnum'
+
+        # File
+          file_visibility: 'App\Enum\Core\FileVisibilityEnum'
+          file_folder: 'App\Enum\Core\FileFolderEnum'
+          file_status: 'App\Enum\Core\FileStatusEnum'
+
+        #education
+          education: 'App\Enum\Education\EducationTypeEnum'
+          education_year: 'App\Enum\Education\YearEnum'
+          education_period: 'App\Enum\Education\PeriodEnum'
+          education_periodicity: 'App\Enum\Education\PeriodicityEnum'
+          advanced_education_notation: 'App\Enum\Education\AdvancedEducationNotationTypeEnum'
+
+          #billing
+          billing_periodicity: 'App\Enum\Billing\PeriodicityEnum'
+          billing_type_periodicity: 'App\Enum\Billing\PeriodicityTypeEnum'
+          billing_pricingline_adhesion: 'App\Enum\Billing\PricingLineAdhesionEnum'
+          billing_pricingline_productrent: 'App\Enum\Billing\PricingLineProductRentEnum'
+          billing_discount_global_tariff_family: 'App\Enum\Billing\DiscountGlobalTariffFamilyEnum'
+          billing_pricingline_invoice_line: 'App\Enum\Billing\PricingLineInvoiceLineEnum'
+          billing_payment_choice: 'App\Enum\Billing\PaymentChoiceEnum'
+          billing_bank: 'App\Enum\Billing\BankEnum'
+          billing_periodicity_payment: 'App\Enum\Billing\PeriodicityPaymentEnum'
+          billing_rent_reduction_type: 'App\Enum\Billing\ReductionTypeEnum'
+          billing_rent_year: 'App\Enum\Billing\RentYearEnum'
+          billing_family_reduction_type: 'App\Enum\Billing\FamilyReductionTypeEnum'
+          billing_payment_state: 'App\Enum\Billing\PaymentStateEnum'
+          billing_period: 'App\Enum\Billing\PeriodEnum'
+          billing_adhesion_choice: 'App\Enum\Billing\AdhesionChoiceEnum'
+          billing_order_adult_type_choice: 'App\Enum\Billing\OrderAdultTypeEnum'
+          billing_adult_condition_type_choice: 'App\Enum\Billing\AdultConditionTypeEnum'
+          billing_payment_type_choice: 'App\Enum\Billing\PaymentTypeEnum'
+          billing_type: 'App\Enum\Billing\BillingTypeEnum'
+
+        #message
+          message_status: 'App\Enum\Message\MessageStatusEnum'
+          report_message_satus: 'App\Enum\Message\ReportMessageSatusEnum'
+          message_sender: 'App\Enum\Message\SenderEnum'
+          message_sender_only_access: 'App\Enum\Message\SenderOnlyAccessEnum'
+          message_send_to: 'App\Enum\Message\SendToEnum'
+
+        #rules
+          default_rules: 'App\Enum\Rulerz\RulesEnum'
+          manager_rules: 'App\Enum\Rulerz\RulesManagerEnum'
+
+        #commission
+          commission_member_function: 'App\Enum\Person\CommissionMemberFunctionEnum'
+          commission_member_cause_output: 'App\Enum\Person\CauseOutputEnum'
+
+        #Cotisation
+          cotisation_function_enum_choices: 'App\Enum\Cotisation\CotisationFunctionEnum'
+          type_of_practices_enum: 'App\Enum\Cotisation\TypeOfPracticeEnum'
+          category_type_of_practices_enum: 'App\Enum\Cotisation\CategoryTypeOfPracticeEnum'
+
+        #OnlineRegistration
+          onlineregistration_registration_status: 'App\Enum\OnlineRegistration\RegistrationStatus'
+          onlineregistration_wish_registration: 'App\Enum\OnlineRegistration\WishRegistration'
+          onlineregistration_file_type: 'App\Enum\OnlineRegistration\FileTypeEnum'
+          onlineregistration_origin_education_student_wish: 'App\Enum\OnlineRegistration\EducationStudentWishOriginEnum'

+ 2 - 2
config/opentalent/modulesbyconditions.yaml

@@ -1,5 +1,5 @@
-opentalent:
-    modulesbyconditions:
+parameters:
+    opentalent.modulesbyconditions:
         CotisationCall:
             roles:
                 - ROLE_COTISATION

+ 3 - 3
config/opentalent/products.yaml

@@ -1,5 +1,5 @@
-opentalent:
-    modules:
+parameters:
+  opentalent.modules:
       Core:
         entities:
           - AccessProfile
@@ -267,7 +267,7 @@ opentalent:
         entities:
           - DolibarrAccount
 
-    products:
+  opentalent.products:
       artist:
         modules:
           - Core

+ 55 - 0
config/opentalent/subdomains.yaml

@@ -0,0 +1,55 @@
+parameters:
+  opentalent.subdomains:
+    # Liste des sous-domaines réservés (sous forme de RegEx, sans les caractères de début et de fin de ligne '^' et '$')
+    # @see https://ressources.opentalent.fr/display/SPEC/Nom+de+sous+domaines+reserves+pour+2IOS
+    reserved:
+      - opentalent
+      - 2ios
+      - 2iopenservice
+      - app
+      - my
+      - api
+      - ap2i
+      - local
+      - logs?
+      - stats
+      - preprod\d*
+      - test\d*
+      - admin
+      - frames
+      - git
+      - v\d+
+      - myadmin
+      - mailcatcher
+      - mail
+      - gitlab
+      - metabase
+      - dolibarr
+      - prod
+      - production
+      - assistance
+      - ressources
+      - support
+      - statistiques.*
+      - drive
+      - cloud
+      - www
+      - ww\d*
+      - agenda
+      - store
+      - boutique
+      - annuaire
+      - opentalent
+      - 2iopenservice
+      - typo3
+      - actus?
+      - actualites?
+      - news
+      - annonces?
+      - mobile
+      - membres
+      - mercure
+      - kibana
+      - phpmyadmin
+      - elasticsearch
+      - es

+ 1 - 1
config/packages/hautelook_alice.yaml

@@ -2,4 +2,4 @@ when@dev: &dev
     hautelook_alice:
         fixtures_path: fixtures
 
-when@test: *dev
+when@staging: *dev

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

@@ -1,8 +0,0 @@
-# override in api/config/packages/test/security.yaml for test env
-# improve the test suite speed
-security:
-  password_hashers:
-    App\Entity\Person\Person:
-      algorithm: md5
-      encode_as_base64: false
-      iterations: 0

+ 4 - 0
config/services.yaml

@@ -1,3 +1,7 @@
+# config/services.yaml
+imports:
+    - { resource: opentalent/* }
+
 # Put parameters here that don't need to change on each machine where the app is deployed
 # https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
 parameters:

+ 14 - 0
public/.htaccess

@@ -0,0 +1,14 @@
+<IfModule mod_rewrite.c>
+    Options -MultiViews
+    RewriteEngine On
+    RewriteCond %{SERVER_PORT} 80
+    RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
+    RewriteCond %{REQUEST_FILENAME} !-f
+    RewriteRule ^(.*)$ index.php [QSA,L]
+</IfModule>
+
+<IfModule !mod_rewrite.c>
+    <IfModule mod_alias.c>
+        RedirectMatch 302 ^/$ /index.php/
+    </IfModule>
+</IfModule>

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

@@ -6,6 +6,8 @@ namespace App\Entity\Access;
 use ApiPlatform\Metadata\ApiResource;
 use ApiPlatform\Doctrine\Orm\Filter\BooleanFilter;
 use ApiPlatform\Metadata\ApiFilter;
+use ApiPlatform\Metadata\Get;
+use ApiPlatform\Metadata\Put;
 use App\Entity\AccessWish\AccessWish;
 use App\Entity\Billing\AccessBilling;
 use App\Entity\Billing\AccessFictionalIntangible;
@@ -65,7 +67,12 @@ use Symfony\Component\Serializer\Annotation\Groups;
  * Fais le lien entre une Person et une Organization
  * @see : config/api_platform/Access/access.yaml
  */
-#[ApiResource]
+#[ApiResource(
+    operations: [
+        new Get(security: 'object.getId() == user.getId()'),
+        new Put(security: 'object.getId() == user.getId()'),
+    ]
+)]
 //#[Auditable]
 #[ORM\Entity(repositoryClass: AccessRepository::class)]
 #[ApiFilter(filterClass: BooleanFilter::class, properties: ['person.isPhysical'])]

+ 2 - 0
src/Entity/Message/Mail.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Entity\Message;
 
+use ApiPlatform\Metadata\ApiResource;
 use App\Entity\Access\Access;
 use App\Entity\Core\File;
 use App\Entity\Core\Tagg;
@@ -18,6 +19,7 @@ use Ramsey\Uuid\Uuid;
  *
  * Classe ... qui ...
  */
+#[ApiResource(operations: [])]
 //#[Auditable]
 #[ORM\Table(name: 'Message')]
 #[ORM\Entity]

+ 2 - 0
src/Enum/Utils/EnvironnementVarEnum.php

@@ -6,6 +6,8 @@ namespace App\Enum\Utils;
 use MyCLabs\Enum\Enum;
 
 /**
+ * Liste des variables d'environnement qu'il est possible de requêter via le service Utils/Environnement
+ *
  * @method static APP_ENV()
  */
 class EnvironnementVarEnum extends Enum

+ 8 - 61
src/Service/Security/Module.php

@@ -4,10 +4,9 @@ declare(strict_types=1);
 namespace App\Service\Security;
 
 use App\Entity\Organization\Organization;
-use App\Service\Utils\Parser;
 use App\Service\Utils\Reflection;
 use Doctrine\Common\Cache\ApcuCache;
-use Symfony\Component\Config\FileLocator;
+use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 
 /**
@@ -16,21 +15,10 @@ use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  */
 class Module
 {
-    /**
-     * @var mixed[]|null $moduleConfig
-     */
-    private array | null $moduleConfig = null;
-
-    /**
-     * @var mixed[]|null $moduleByConditionsConfig
-     */
-    private array | null $moduleByConditionsConfig = null;
-
     public function __construct(
         readonly private Reflection $reflection,
-        readonly private Parser $parser,
-        readonly private string $opentalentConfig)
-    {}
+        readonly private ParameterBagInterface $parameterBag
+    ) {}
 
     /**
      * @todo activer le cache après que la fin de la migration.
@@ -89,7 +77,7 @@ class Module
     public function getModulesByConditions(Organization $organization): array
     {
         $modulesByConditions = [];
-        $modules = $this->getModuleByConditionsConfig()['opentalent']['modulesbyconditions'];
+        $modules = $this->parameterBag->get('opentalent.modulesbyconditions');
         foreach ($modules as $moduleName => $module) {
             try{
                 $response = $this->reflection->dynamicInvokeServiceWithArgsAndMethod(
@@ -116,11 +104,12 @@ class Module
     public function getModulesByProductConfiguration(string $product): ?array
     {
         $product = str_replace('-', '_', $product);
+        $opentalentProducts = $this->parameterBag->get('opentalent.products');
 
-        if (!array_key_exists($product, $this->getModuleConfig()['opentalent']['products'])) {
+        if (!array_key_exists($product, $opentalentProducts)) {
             throw new AccessDeniedHttpException(sprintf('The product %s does not exist !', $product));
         }
-        $productConfig = $this->getModuleConfig()['opentalent']['products'][$product];
+        $productConfig = $opentalentProducts[$product];
         $modules = $productConfig['modules'] ?? [];
 
         if (array_key_exists('extend', $productConfig)) {
@@ -131,48 +120,6 @@ class Module
         return $modules;
     }
 
-    /**
-     * @return mixed[]
-     * @throws \Exception
-     */
-    protected function getModuleConfig(): array {
-        if ($this->moduleConfig === null) {
-            $this->moduleConfig = $this->loadModuleConfig();
-        }
-        return $this->moduleConfig;
-    }
-
-    /**
-     * Parse et retourne le contenu du fichier products.yaml
-     * @return mixed
-     * @throws \Exception
-     */
-    protected function loadModuleConfig(): mixed
-    {
-        return $this->parser->yamlParser($this->opentalentConfig, 'products.yaml');
-    }
-
-    /**
-     * @return mixed[]
-     * @throws \Exception
-     */
-    protected function getModuleByConditionsConfig(): array {
-        if ($this->moduleByConditionsConfig === null) {
-            $this->moduleByConditionsConfig = $this->loadModuleByConditionsConfig();
-        }
-        return $this->moduleByConditionsConfig;
-    }
-
-    /**
-     * Parse et retourne le contenu du fichier modulesbyconditions.yaml
-     * @return mixed
-     * @throws \Exception
-     */
-    protected function loadModuleByConditionsConfig(): mixed
-    {
-        return $this->parser->yamlParser($this->opentalentConfig, 'modulesbyconditions.yaml');
-    }
-
     /**
      * Retourne le module possédant la resource passée en paramètre
      * @param string $resource
@@ -180,7 +127,7 @@ class Module
      */
     public function getModuleByResourceName(string $resource): int|string|null
     {
-        $modules = $this->getModuleConfig()['opentalent']['modules'];
+        $modules = $this->parameterBag->get('opentalent.modules');
         foreach ($modules as $module => $data) {
             if ($data['entities'] && in_array($resource, $data['entities'], true)) {
                 return $module;

+ 27 - 1
src/Service/Typo3/SubdomainService.php

@@ -15,6 +15,7 @@ use Doctrine\ORM\EntityManagerInterface;
 use Symfony\Bundle\SecurityBundle\Security;
 use Symfony\Component\Console\Exception\InvalidArgumentException;
 use Symfony\Component\Messenger\MessageBusInterface;
+use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
 
 /**
  * Service de gestion des sous-domaines des utilisateurs
@@ -33,7 +34,8 @@ class SubdomainService
         private readonly MessageBusInterface $messageBus,
         private readonly OrganizationUtils $organizationUtils,
         private readonly BindFileService $bindFileService,
-        private readonly AccessRepository $accessRepository
+        private readonly AccessRepository $accessRepository,
+        private readonly ParameterBagInterface $parameterBag
     ) {}
 
     /**
@@ -61,6 +63,26 @@ class SubdomainService
         return (bool)preg_match(self::RX_VALIDATE_SUBDOMAIN, $subdomainValue);
     }
 
+    /**
+     * Is the subdomain a reserved one
+     * @see https://ressources.opentalent.fr/display/SPEC/Nom+de+sous+domaines+reserves+pour+2IOS
+     *
+     * @param string $subdomainValue
+     * @return bool
+     * @throws \Exception
+     */
+    public function isReservedSubdomain(string $subdomainValue): bool {
+        $reservedSubdomains = $this->parameterBag->get('opentalent.subdomains')['reserved'];
+        $subRegexes = array_map(
+            function (string $s) { return '(\b' . trim($s, '^$/\s') . '\b)'; },
+            $reservedSubdomains
+        );
+
+        $regex = '/^' . strtolower(implode("|", $subRegexes)) . '$/';
+
+        return preg_match($regex, $subdomainValue) !== 0;
+    }
+
     /**
      * Register a new subdomain for the organization
      * Is $activate is true, makes this new subdomain the active one too.
@@ -84,6 +106,10 @@ class SubdomainService
             throw new \RuntimeException("This organization can not register new subdomains");
         }
 
+        if ($this->isReservedSubdomain($subdomainValue)) {
+            throw new \RuntimeException('This subdomain is not available');
+        }
+
         // Vérifie que le sous-domaine n'est pas déjà utilisé
         if ($this->subdomainRepository->findBy(['subdomain' => $subdomainValue])) {
             throw new \RuntimeException('This subdomain is already registered');

+ 3 - 3
src/Service/Utils/Environnement.php

@@ -11,10 +11,10 @@ use RuntimeException;
  */
 class Environnement
 {
-    public function get(string $name): string{
-        if(in_array($name, EnvironnementVarEnum::toArray(), true)){
+    public function get(string $name): string {
+        if(in_array($name, EnvironnementVarEnum::toArray(), true)) {
             return $_ENV[$name];
         }
         throw new RuntimeException(sprintf('Undefined environment variable : %s', $name), 500);
     }
-}
+}

+ 0 - 29
src/Service/Utils/Parser.php

@@ -1,29 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace App\Service\Utils;
-
-use Symfony\Component\Config\FileLocator;
-use Symfony\Component\Yaml\Yaml;
-
-/**
- * Class Parser : méthodes d'aide pour la gestion de parsing de fichier.
- * @package App\Service\Utils
- */
-class Parser
-{
-    /**
-     * Parse le fichier yaml passé en paramètre et renvoie un tableau PHP
-     * @param string $directory
-     * @param string $yamlFile
-     * @return mixed
-     * @see ParserTest::testYamlParser()
-     */
-    public function yamlParser(string $directory, string $yamlFile): mixed
-    {
-        $configDirectories = [$directory];
-        $fileLocator = new FileLocator($configDirectories);
-        $yamlConfig = $fileLocator->locate($yamlFile, null, false)[0];
-        return Yaml::parseFile($yamlConfig);
-    }
-}

+ 25 - 0
src/Service/Utils/Parser/ParserInterface.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace App\Service\Utils\Parser;
+
+/**
+ * Interface d'un service de parsing de fichiers
+ */
+interface ParserInterface
+{
+    /**
+     * Parse une chaine de caractères au format donné
+     *
+     * @param string $content
+     * @return mixed
+     */
+    public function parse(string $content): mixed;
+
+    /**
+     * Parse le contenu d'un fichier au format donné
+     *
+     * @param string $path
+     * @return mixed
+     */
+    public function parseFile(string $path): mixed;
+}

+ 36 - 0
src/Service/Utils/Parser/YamlParser.php

@@ -0,0 +1,36 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Service\Utils\Parser;
+
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\Yaml\Yaml;
+
+/**
+ * Class Parser : méthodes d'aide pour la gestion de parsing de fichier.
+ * @package App\Service\Utils
+ */
+class YamlParser implements ParserInterface
+{
+    /**
+     * Parse la chaine de caractères au format Yaml donné et renvoie un tableau PHP
+     *
+     * @param string $content
+     * @return mixed
+     */
+    public function parse(string $content): mixed {
+        return Yaml::parse($content);
+    }
+
+    /**
+     * Parse le fichier yaml passé en paramètre et renvoie un tableau PHP
+     *
+     * @param string $path Chemin d'accès du fichier à parser
+     * @return mixed
+     * @see ParserTest::testYamlParser()
+     */
+    public function parseFile(string $path): mixed
+    {
+        return Yaml::parseFile($path);
+    }
+}

+ 13 - 0
src/Service/Utils/Path.php

@@ -4,6 +4,7 @@ declare(strict_types=1);
 namespace App\Service\Utils;
 
 use RuntimeException;
+use Symfony\Component\Config\FileLocator;
 
 /**
  * Various methods to manipulate file paths
@@ -66,4 +67,16 @@ class Path
         }
         return $content;
     }
+
+    /**
+     * Locate a file in the given directories and return its absolute path
+     *
+     * @param array<string> $directories
+     * @param string $filename
+     * @return string
+     */
+    public static function locate(array $directories, string $filename): string {
+        $fileLocator = new FileLocator($directories);
+        return $fileLocator->locate($filename, null, false)[0];
+    }
 }

+ 1 - 1
src/State/Provider/Dolibarr/DolibarrAccountProvider.php

@@ -34,6 +34,6 @@ final class DolibarrAccountProvider implements ProviderInterface
             throw new RuntimeException('not supported', 500);
         }
 
-        return $this->dolibarrAccountCreator->getDolibarrAccount($uriVariables['id']);
+        return $this->dolibarrAccountCreator->getDolibarrAccount($uriVariables['organizationId']);
     }
 }

+ 6 - 6
src/State/Provider/Enum/EnumProvider.php

@@ -7,10 +7,11 @@ use ApiPlatform\Metadata\GetCollection;
 use ApiPlatform\Metadata\Operation;
 use ApiPlatform\State\ProviderInterface;
 use App\ApiResources\Enum\Enum;
-use App\Service\Utils\Parser;
+use App\Service\Utils\Parser\YamlParser;
 use App\Service\Utils\Reflection;
 use Exception;
 use RuntimeException;
+use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
 /**
@@ -20,9 +21,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 final class EnumProvider implements ProviderInterface
 {
     public function __construct(
-        private Parser $parser,
-        private string $opentalentConfig,
-        private Reflection $reflection
+        private Reflection $reflection,
+        private readonly ParameterBagInterface $parameterBag
     )
     { }
 
@@ -39,7 +39,7 @@ final class EnumProvider implements ProviderInterface
         }
 
         $id = $uriVariables['id'];
-        $enums = $this->parser->yamlParser($this->opentalentConfig, 'enum.yaml');
+        $enums = $this->parameterBag->get('opentalent.enum');
         $enumClass = $enums['opentalent'][$id];
 
         if(!$enumClass) {
@@ -60,4 +60,4 @@ final class EnumProvider implements ProviderInterface
         $enumResponse->setItems($items);
         return $enumResponse;
     }
-}
+}

+ 1 - 1
src/State/Provider/Mobyt/MobytUserStatusProvider.php

@@ -35,6 +35,6 @@ final class MobytUserStatusProvider implements ProviderInterface
             throw new RuntimeException('not supported', 500);
         }
 
-        return $this->mobytUserStatusCreator->getUserStatus((int) $uriVariables['id']);
+        return $this->mobytUserStatusCreator->getUserStatus((int) $uriVariables['organizationId']);
     }
 }

+ 51 - 158
tests/Unit/Service/Security/ModuleTest.php

@@ -6,30 +6,36 @@ use App\Entity\Organization\Organization;
 use App\Entity\Organization\Settings;
 use App\Service\Cotisation\Utils as CotisationUtils;
 use App\Service\Security\Module;
-use App\Service\Utils\Parser;
+use App\Service\Utils\ConfigUtils;
+use App\Service\Utils\Parser\YamlParser;
 use App\Service\Utils\Reflection;
+use Hoa\Iterator\Mock;
 use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
+use PHPUnit\Util\Test;
+use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 
 class TestableModule extends Module {
-    public function loadModuleConfig(): array { return parent::loadModuleConfig(); }
-    public function getModuleConfig(): array { return parent::getModuleConfig(); }
-    public function loadModuleByConditionsConfig(): array { return parent::loadModuleByConditionsConfig(); }
     public function getModuleByConditionsConfig(): array { return parent::getModuleByConditionsConfig(); }
 }
 
 class ModuleTest extends TestCase
 {
-    private const OPENTALENT_CONFIG = __DIR__.'/../../../config/opentalent';
-
     private MockObject | Reflection $reflection;
-    private MockObject | Parser $parser;
+    private MockObject | ParameterBagInterface $parameterBag;
 
     public function setUp():void
     {
         $this->reflection = $this->getMockBuilder(Reflection::class)->disableOriginalConstructor()->getMock();
-        $this->parser = $this->getMockBuilder(Parser::class)->disableOriginalConstructor()->getMock();
+        $this->parameterBag = $this->getMockBuilder(ParameterBagInterface::class)->disableOriginalConstructor()->getMock();
+    }
+
+    public function getMockForMethod(string $methodName): MockObject | TestableModule {
+        return $this->getMockBuilder(TestableModule::class)
+            ->setConstructorArgs([$this->reflection, $this->parameterBag])
+            ->setMethodsExcept([$methodName])
+            ->getMock();
     }
 
     /**
@@ -37,10 +43,7 @@ class ModuleTest extends TestCase
      */
     public function testGetOrganizationModules(): void
     {
-        $module = $this->getMockBuilder(Module::class)
-            ->setConstructorArgs([$this->reflection, $this->parser, self::OPENTALENT_CONFIG])
-            ->setMethodsExcept(['getOrganizationModules'])
-            ->getMock();
+        $module = $this->getMockForMethod('getOrganizationModules');
 
         $module->expects(self::once())->method('getModuleBySettings')->willReturn(['Sms']);
         $module->expects(self::once())->method('getModulesByConditions')->willReturn(['CotisationCall']);
@@ -64,10 +67,7 @@ class ModuleTest extends TestCase
      */
     public function testGetModuleBySettings(): void
     {
-        $module = $this->getMockBuilder(TestableModule::class)
-            ->setConstructorArgs([$this->reflection, $this->parser, self::OPENTALENT_CONFIG])
-            ->setMethodsExcept(['getModuleBySettings'])
-            ->getMock();
+        $module = $this->getMockForMethod('getModuleBySettings');
 
         $settings = $this->getMockBuilder(Settings::class)->getMock();
         $settings
@@ -89,25 +89,18 @@ class ModuleTest extends TestCase
      */
     public function testGetModulesByConditions(): void
     {
-        $module = $this->getMockBuilder(TestableModule::class)
-            ->setConstructorArgs([$this->reflection, $this->parser, self::OPENTALENT_CONFIG])
-            ->setMethodsExcept(['getModulesByConditions'])
-            ->getMock();
-
-        $module->method('getModuleByConditionsConfig')->willReturn(
-            ['opentalent' =>
-                ['modulesbyconditions' =>
-                    ['CotisationCall' => [
-                        'roles' => ['ROLE_COTISATION'],
-                        'conditions' => [
-                            'service' => [
-                                'name' => CotisationUtils::class,
-                                'function' => 'isLastParentAndCMF'
-                            ]
-                        ]
-                    ]]
+        $module = $this->getMockForMethod('getModulesByConditions');
+
+        $this->parameterBag->method('get')->with('opentalent.modulesbyconditions')->willReturn(
+            ['CotisationCall' => [
+                'roles' => ['ROLE_COTISATION'],
+                'conditions' => [
+                    'service' => [
+                        'name' => CotisationUtils::class,
+                        'function' => 'isLastParentAndCMF'
+                    ]
                 ]
-            ]
+            ]]
         );
 
         $organization = $this->getMockBuilder(Organization::class)->getMock();
@@ -124,17 +117,10 @@ class ModuleTest extends TestCase
      */
     public function testGetModulesByConditionsLogicError(): void
     {
-        $module = $this->getMockBuilder(TestableModule::class)
-            ->setConstructorArgs([$this->reflection, $this->parser, self::OPENTALENT_CONFIG])
-            ->setMethodsExcept(['getModulesByConditions'])
-            ->getMock();
+        $module = $this->getMockForMethod('getModulesByConditions');
 
-        $module->method('getModuleByConditionsConfig')->willReturn(
-            ['opentalent' =>
-                ['modulesbyconditions' =>
-                    ['CotisationCall' => []]
-                ]
-            ]
+        $this->parameterBag->method('get')->with('opentalent.modulesbyconditions')->willReturn(
+            ['CotisationCall' => []]
         );
 
         $organization = $this->getMockBuilder(Organization::class)->getMock();
@@ -153,12 +139,11 @@ class ModuleTest extends TestCase
      */
     public function testGetModulesByProductConfiguration(): void
     {
-        $module = $this->getMockBuilder(TestableModule::class)
-            ->setConstructorArgs([$this->reflection, $this->parser, self::OPENTALENT_CONFIG])
-            ->setMethodsExcept(['getModulesByProductConfiguration'])
-            ->getMock();
+        $module = $this->getMockForMethod('getModulesByProductConfiguration');
 
-        $module->method('getModuleConfig')->willReturn(['opentalent' => ['products' => ['artist' => ['modules' => ['foo']]]]]);
+        $this->parameterBag->method('get')->with('opentalent.products')->willReturn(
+            ['artist' => ['modules' => ['foo']]]
+        );
 
         $this->assertEquals(['foo'], $module->getModulesByProductConfiguration('artist')) ;
     }
@@ -168,19 +153,12 @@ class ModuleTest extends TestCase
      */
     public function testGetModulesByProductConfigurationExtend(): void
     {
-        $module = $this->getMockBuilder(TestableModule::class)
-            ->setConstructorArgs([$this->reflection, $this->parser, self::OPENTALENT_CONFIG])
-            ->setMethodsExcept(['getModulesByProductConfiguration'])
-            ->getMock();
+        $module = $this->getMockForMethod('getModulesByProductConfiguration');
 
-        $module->method('getModuleConfig')->willReturn(
-            ['opentalent' =>
-                ['products' =>
-                    [
-                        'artist' => ['modules' => ['foo']],
-                        'artist_premium' => ['extend' => 'artist', 'modules' => ['bar']]
-                    ]
-                ]
+        $this->parameterBag->method('get')->with('opentalent.products')->willReturn(
+            [
+                'artist' => ['modules' => ['foo']],
+                'artist_premium' => ['extend' => 'artist', 'modules' => ['bar']]
             ]
         );
 
@@ -195,12 +173,13 @@ class ModuleTest extends TestCase
      */
     public function testGetModulesByProductConfigurationAccessDenied(): void
     {
-        $module = $this->getMockBuilder(TestableModule::class)
-            ->setConstructorArgs([$this->reflection, $this->parser, self::OPENTALENT_CONFIG])
-            ->setMethodsExcept(['getModulesByProductConfiguration'])
-            ->getMock();
+        $module = $this->getMockBuilder(TestableModule::class);
 
-        $module->method('getModuleConfig')->willReturn(['opentalent' => ['products' => ['artist' => ['modules' => ['foo']]]]]);
+        $module = $this->getMockForMethod('getModulesByProductConfiguration');
+
+        $this->parameterBag->method('get')->with('opentalent.products')->willReturn(
+            ['artist' => ['modules' => ['foo']]]
+        );
 
         $this->expectException(AccessDeniedHttpException::class);
         $this->expectExceptionMessage('The product artist_premium does not exist !');
@@ -208,93 +187,14 @@ class ModuleTest extends TestCase
         $module->getModulesByProductConfiguration('artist-premium');
     }
 
-    /**
-     * @see Module::getModuleConfig()
-     */
-    public function testGetModuleConfig(): void {
-        $module = $this->getMockBuilder(TestableModule::class)
-            ->setConstructorArgs([$this->reflection, $this->parser, self::OPENTALENT_CONFIG])
-            ->setMethodsExcept(['getModuleConfig'])
-            ->getMock();
-
-        $module->expects(self::once())->method('loadModuleConfig')->willReturn(['foo']);
-
-        $this->assertEquals(['foo'], $module->getModuleConfig());
-        $this->assertEquals(['foo'], $module->getModuleConfig());
-    }
-
-    /**
-     * @see Module::loadModuleConfig()
-     */
-    public function testLoadModuleConfig(): void {
-        $module = $this->getMockBuilder(TestableModule::class)
-            ->setConstructorArgs([$this->reflection, $this->parser, self::OPENTALENT_CONFIG])
-            ->setMethodsExcept(['loadModuleConfig'])
-            ->getMock();
-
-        $this->parser
-            ->expects(self::once())
-            ->method('yamlParser')
-            ->with(self::OPENTALENT_CONFIG, 'products.yaml')
-            ->willReturn(['foo']);
-
-        $this->assertEquals(
-            ['foo'],
-            $module->loadModuleConfig()
-        );
-    }
-
-    /**
-     * @see Module::getModuleByConditionsConfig()
-     */
-    public function testGetModuleByConditionsConfig(): void {
-        $module = $this->getMockBuilder(TestableModule::class)
-            ->setConstructorArgs([$this->reflection, $this->parser, self::OPENTALENT_CONFIG])
-            ->setMethodsExcept(['getModuleByConditionsConfig'])
-            ->getMock();
-
-        $module->expects(self::once())->method('loadModuleByConditionsConfig')->willReturn(['foo']);
-
-        $this->assertEquals(['foo'], $module->getModuleByConditionsConfig());
-        $this->assertEquals(['foo'], $module->getModuleByConditionsConfig());
-    }
-
-    /**
-     * @see Module::loadModuleByConditionsConfig()
-     */
-    public function testLoadModuleByConditionsConfig(): void {
-        $module = $this->getMockBuilder(TestableModule::class)
-            ->setConstructorArgs([$this->reflection, $this->parser, self::OPENTALENT_CONFIG])
-            ->setMethodsExcept(['loadModuleByConditionsConfig'])
-            ->getMock();
-
-        $this->parser->expects(self::once())
-            ->method('yamlParser')
-            ->with(self::OPENTALENT_CONFIG, 'modulesbyconditions.yaml')
-            ->willReturn(['foo']);
-
-        $this->assertEquals(
-            ['foo'],
-            $module->loadModuleByConditionsConfig()
-        );
-    }
-
     /**
      * @see Module::getModuleByResourceName()
      */
     public function testGetModuleByResourceName(): void {
-        $module = $this->getMockBuilder(TestableModule::class)
-            ->setConstructorArgs([$this->reflection, $this->parser, self::OPENTALENT_CONFIG])
-            ->setMethodsExcept(['getModuleByResourceName'])
-            ->getMock();
-
+        $module = $this->getMockForMethod('getModuleByResourceName');
 
-        $module->method('getModuleConfig')->willReturn(
-            ['opentalent' =>
-                ['modules' =>
-                    ['Core' => ['entities' => ['foo', 'bar']]]
-                ]
-            ]
+        $this->parameterBag->method('get')->with('opentalent.modules')->willReturn(
+            ['Core' => ['entities' => ['foo', 'bar']]]
         );
 
         $this->assertEquals('Core', $module->getModuleByResourceName('foo'));
@@ -304,17 +204,10 @@ class ModuleTest extends TestCase
      * @see Module::getModuleByResourceName()
      */
     public function testGetModuleByResourceNameNotFound(): void {
-        $module = $this->getMockBuilder(TestableModule::class)
-            ->setConstructorArgs([$this->reflection, $this->parser, self::OPENTALENT_CONFIG])
-            ->setMethodsExcept(['getModuleByResourceName'])
-            ->getMock();
+        $module = $this->getMockForMethod('getModuleByResourceName');
 
-        $module->method('getModuleConfig')->willReturn(
-            ['opentalent' =>
-                ['modules' =>
-                    ['Core' => ['entities' => ['bar']]]
-                ]
-            ]
+        $this->parameterBag->method('get')->with('opentalent.modules')->willReturn(
+            ['Core' => ['entities' => ['bar']]]
         );
 
         $this->assertNull($module->getModuleByResourceName('foo'));

+ 60 - 7
tests/Unit/Service/Typo3/SubdomainServiceTest.php

@@ -15,10 +15,12 @@ use App\Service\Mailer\Model\SubdomainChangeModel;
 use App\Service\Organization\Utils as OrganizationUtils;
 use App\Service\Typo3\BindFileService;
 use App\Service\Typo3\SubdomainService;
+use App\Service\Utils\ConfigUtils;
 use Doctrine\Common\Collections\ArrayCollection;
 use Doctrine\ORM\EntityManagerInterface;
 use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
+use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
 use Symfony\Component\Messenger\Envelope;
 use Symfony\Component\Messenger\MessageBusInterface;
 
@@ -46,12 +48,13 @@ class TestableSubdomainService extends SubdomainService {
 }
 class SubdomainServiceTest extends TestCase
 {
-    private SubdomainRepository $subdomainRepository;
-    private OrganizationUtils $organizationUtils;
-    private BindFileService $bindFileService;
-    private MessageBusInterface $messageBus;
-    private EntityManagerInterface $entityManager;
-    private AccessRepository $accessRepository;
+    private MockObject | SubdomainRepository $subdomainRepository;
+    private MockObject | OrganizationUtils $organizationUtils;
+    private MockObject | BindFileService $bindFileService;
+    private MockObject | MessageBusInterface $messageBus;
+    private MockObject | EntityManagerInterface $entityManager;
+    private MockObject | AccessRepository $accessRepository;
+    private MockObject | ParameterBagInterface $parameterBag;
 
     public function setUp():void
     {
@@ -61,6 +64,7 @@ class SubdomainServiceTest extends TestCase
         $this->organizationUtils = $this->getMockBuilder(OrganizationUtils::class)->disableOriginalConstructor()->getMock();
         $this->bindFileService = $this->getMockBuilder(BindFileService::class)->disableOriginalConstructor()->getMock();
         $this->accessRepository = $this->getMockBuilder(AccessRepository::class)->disableOriginalConstructor()->getMock();
+        $this->parameterBag = $this->getMockBuilder(ParameterBagInterface::class)->disableOriginalConstructor()->getMock();
     }
 
     private function makeSubdomainServiceMockFor(string $methodName): MockObject | TestableSubdomainService {
@@ -71,7 +75,8 @@ class SubdomainServiceTest extends TestCase
                 $this->messageBus,
                 $this->organizationUtils,
                 $this->bindFileService,
-                $this->accessRepository
+                $this->accessRepository,
+                $this->parameterBag
             ])
             ->setMethodsExcept([$methodName])
             ->getMock();
@@ -120,6 +125,27 @@ class SubdomainServiceTest extends TestCase
         $this->assertFalse($subdomainService->isValidSubdomain(str_repeat('abcdef', 20)));
     }
 
+    public function testIsReservedSubdomain(): void {
+        $subdomainService = $this->makeSubdomainServiceMockFor('isReservedSubdomain');
+
+        $this->parameterBag
+            ->method('get')
+            ->with('opentalent.subdomains')
+            ->willReturn([
+                'reserved' => [
+                    'abcd',
+                    'abc\d+'
+                ]
+            ]);
+
+        $this->assertTrue($subdomainService->isReservedSubdomain('abcd'));
+        $this->assertTrue($subdomainService->isReservedSubdomain('abc123'));
+
+        $this->assertFalse($subdomainService->isReservedSubdomain('abcde'));
+        $this->assertFalse($subdomainService->isReservedSubdomain('abc'));
+        $this->assertFalse($subdomainService->isReservedSubdomain('foo'));
+    }
+
     public function testAddNewSubdomain(): void {
         $subdomainService = $this->makeSubdomainServiceMockFor('addNewSubdomain');
 
@@ -127,6 +153,7 @@ class SubdomainServiceTest extends TestCase
 
         $subdomainService->expects(self::once())->method('isValidSubdomain')->with('sub')->willReturn(True);
         $subdomainService->expects(self::once())->method('canRegisterNewSubdomain')->with($organization)->willReturn(True);
+        $subdomainService->expects(self::once())->method('isReservedSubdomain')->with('sub')->willReturn(false);
         $this->subdomainRepository->expects(self::once())->method('findBy')->with(['subdomain' => 'sub'])->willReturn(0);
 
         $this->entityManager->expects(self::once())->method('persist');
@@ -152,6 +179,7 @@ class SubdomainServiceTest extends TestCase
 
         $subdomainService->expects(self::once())->method('isValidSubdomain')->with('_sub')->willReturn(False);
         $subdomainService->expects(self::never())->method('canRegisterNewSubdomain')->with($organization)->willReturn(True);
+        $subdomainService->expects(self::never())->method('isReservedSubdomain')->with($organization)->willReturn(false);
         $this->subdomainRepository->expects(self::never())->method('findBy')->with(['subdomain' => '_sub'])->willReturn(0);
 
         $this->entityManager->expects(self::never())->method('persist');
@@ -173,6 +201,7 @@ class SubdomainServiceTest extends TestCase
 
         $subdomainService->expects(self::once())->method('isValidSubdomain')->with('_sub')->willReturn(true);
         $subdomainService->expects(self::once())->method('canRegisterNewSubdomain')->with($organization)->willReturn(false);
+        $subdomainService->expects(self::never())->method('isReservedSubdomain')->with($organization)->willReturn(false);
         $this->subdomainRepository->expects(self::never())->method('findBy')->with(['subdomain' => '_sub'])->willReturn(0);
 
         $this->entityManager->expects(self::never())->method('persist');
@@ -186,6 +215,28 @@ class SubdomainServiceTest extends TestCase
         $subdomainService->addNewSubdomain($organization, '_sub');
     }
 
+    public function testAddNewSubdomainIsReserved(): void
+    {
+        $subdomainService = $this->makeSubdomainServiceMockFor('addNewSubdomain');
+
+        $organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
+
+        $subdomainService->expects(self::once())->method('isValidSubdomain')->with('_sub')->willReturn(true);
+        $subdomainService->expects(self::once())->method('canRegisterNewSubdomain')->with($organization)->willReturn(true);
+        $subdomainService->expects(self::once())->method('isReservedSubdomain')->with('_sub')->willReturn(true);
+        $this->subdomainRepository->expects(self::never())->method('findBy')->with(['subdomain' => '_sub'])->willReturn(0);
+
+        $this->entityManager->expects(self::never())->method('persist');
+        $this->entityManager->expects(self::never())->method('flush');
+        $this->bindFileService->expects(self::never())->method('registerSubdomain')->with('_sub');
+        $subdomainService->expects(self::never())->method('activateSubdomain');
+
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionMessage('This subdomain is not available');
+
+        $subdomainService->addNewSubdomain($organization, '_sub');
+    }
+
     public function testAddNewSubdomainExisting(): void
     {
         $subdomainService = $this->makeSubdomainServiceMockFor('addNewSubdomain');
@@ -194,6 +245,7 @@ class SubdomainServiceTest extends TestCase
 
         $subdomainService->expects(self::once())->method('isValidSubdomain')->with('sub')->willReturn(true);
         $subdomainService->expects(self::once())->method('canRegisterNewSubdomain')->with($organization)->willReturn(true);
+        $subdomainService->expects(self::once())->method('isReservedSubdomain')->with('sub')->willReturn(false);
         $this->subdomainRepository->expects(self::once())->method('findBy')->with(['subdomain' => 'sub'])->willReturn(1);
 
         $this->entityManager->expects(self::never())->method('persist');
@@ -215,6 +267,7 @@ class SubdomainServiceTest extends TestCase
 
         $subdomainService->expects(self::once())->method('isValidSubdomain')->with('sub')->willReturn(true);
         $subdomainService->expects(self::once())->method('canRegisterNewSubdomain')->with($organization)->willReturn(true);
+        $subdomainService->expects(self::once())->method('isReservedSubdomain')->with('sub')->willReturn(false);
         $this->subdomainRepository->expects(self::once())->method('findBy')->with(['subdomain' => 'sub'])->willReturn(0);
 
         $subdomainService->expects(self::once())->method('activateSubdomain');

+ 12 - 0
tests/Unit/Service/Utils/ArrayUtilsTest.php

@@ -81,4 +81,16 @@ class ArrayUtilsTest extends TestCase
             )
         );
     }
+
+    public function testGetAndCast(): void {
+        $this->assertEquals(
+            123,
+            ArrayUtils::getAndCast(['a' => '123'], 'a', 'int')
+        );
+
+        $this->assertEquals(
+            null,
+            ArrayUtils::getAndCast(['b' => '123'], 'a', 'int')
+        );
+    }
 }

+ 31 - 0
tests/Unit/Service/Utils/EnvironnementTest.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace App\Tests\Unit\Service\Utils;
+
+use App\Enum\Utils\EnvironnementVarEnum;
+use App\Service\Utils\Environnement;
+use PHPUnit\Framework\TestCase;
+use RuntimeException;
+
+class EnvironnementTest extends TestCase
+{
+    public function testGet(): void {
+        $environnement = new Environnement();
+
+        $_ENV[EnvironnementVarEnum::APP_ENV()->getValue()] = 'foo';
+
+        $this->assertEquals(
+            'foo',
+            $environnement->get(EnvironnementVarEnum::APP_ENV()->getValue())
+        );
+    }
+
+    public function testGetInvalid(): void {
+        $environnement = new Environnement();
+
+        $this->expectException(RuntimeException::class);
+        $this->expectExceptionMessage('Undefined environment variable : invalid');
+
+        $environnement->get('invalid');
+    }
+}

+ 43 - 0
tests/Unit/Service/Utils/Parser/YamlParserTest.php

@@ -0,0 +1,43 @@
+<?php
+namespace App\Tests\Unit\Service\Utils\Parser;
+
+use App\Service\Utils\Parser\YamlParser;
+use PHPUnit\Framework\TestCase;
+
+class YamlParserTest extends TestCase
+{
+    public const FIXTURES = __DIR__.'/fixtures';
+
+    /**
+     * @see YamlParser::yamlParser()
+     */
+    public function testParse():void
+    {
+        $parser = new YamlParser();
+        $parsingArray = $parser->parse("
+opentalent:
+    modulesbyconditions:
+        CotisationCall:
+            roles:
+                - ROLE_COTISATION
+            conditions:
+                service:
+                    name: opentalent.cotisation.utils
+                    function: isLastParentAndCMF");
+        $this->assertIsArray($parsingArray);
+        $this->assertIsArray($parsingArray['opentalent']);
+        $this->assertEquals('ROLE_COTISATION', $parsingArray['opentalent']['modulesbyconditions']['CotisationCall']['roles'][0]);
+    }
+
+    /**
+     * @see YamlParser::yamlParser()
+     */
+    public function testParseFile():void
+    {
+        $parser = new YamlParser();
+        $parsingArray = $parser->parseFile(self::FIXTURES . '/fixture.yaml');
+        $this->assertIsArray($parsingArray);
+        $this->assertIsArray($parsingArray['opentalent']);
+        $this->assertEquals('ROLE_COTISATION', $parsingArray['opentalent']['modulesbyconditions']['CotisationCall']['roles'][0]);
+    }
+}

+ 0 - 0
tests/Unit/Service/Utils/fixtures/fixture.yaml → tests/Unit/Service/Utils/Parser/fixtures/fixture.yaml


+ 0 - 22
tests/Unit/Service/Utils/ParserTest.php

@@ -1,22 +0,0 @@
-<?php
-namespace App\Tests\Unit\Service\Utils;
-
-use App\Service\Utils\Parser;
-use PHPUnit\Framework\TestCase;
-
-class ParserTest extends TestCase
-{
-    public const FIXTURES = __DIR__.'/fixtures';
-
-    /**
-     * @see Parser::yamlParser()
-     */
-    public function testYamlParser():void
-    {
-        $parser = new Parser();
-        $parsingArray = $parser->yamlParser(self::FIXTURES, 'fixture.yaml');
-        $this->assertIsArray($parsingArray);
-        $this->assertIsArray($parsingArray['opentalent']);
-        $this->assertEquals('ROLE_COTISATION', $parsingArray['opentalent']['modulesbyconditions']['CotisationCall']['roles'][0]);
-    }
-}