Parcourir la source

tests applicatifs

Maha Bouchiba il y a 1 an
Parent
commit
db79afe579
50 fichiers modifiés avec 2354 ajouts et 419 suppressions
  1. 0 2
      composer.json
  2. 5 5
      config/opentalent/products.yaml
  3. 1 0
      config/packages/security.yaml
  4. 31 0
      migrations/Version20240117143228.php
  5. 31 0
      migrations/Version20240117143535.php
  6. 31 0
      migrations/Version20240117143719.php
  7. 81 81
      old/Entity/Place/Room.php
  8. 2 2
      phpunit.xml.dist
  9. 0 1
      src/Entity/Core/ContactPoint.php
  10. 16 7
      src/Entity/Education/Cycle.php
  11. 1 0
      src/Entity/Education/CycleByEducation.php
  12. 5 4
      src/Entity/Education/Education.php
  13. 4 2
      src/Entity/Education/EducationTiming.php
  14. 12 10
      src/Entity/Organization/Parameters.php
  15. 15 11
      src/Entity/Organization/Subdomain.php
  16. 51 51
      src/Entity/Place/Room.php
  17. 1 1
      src/Enum/Education/AdvancedEducationNotationTypeEnum.php
  18. 8 0
      src/Enum/EnumMethodsTrait.php
  19. 7 4
      src/Enum/Organization/BulletinCriteriaSortEnum.php
  20. 1 1
      src/Enum/Organization/SettingsProductEnum.php
  21. 23 22
      src/Service/Security/Module.php
  22. 6 0
      src/Service/Typo3/SubdomainService.php
  23. 7 2
      src/State/Processor/EntityProcessor.php
  24. 11 3
      src/State/Processor/Organization/ParametersProcessor.php
  25. 1 1
      src/State/Processor/Organization/SubdomainProcessor.php
  26. 21 0
      src/State/Provider/Parameters/SubdomainCollection.php
  27. 52 0
      src/State/Provider/Parameters/SubdomainProvider.php
  28. 218 0
      tests/Application/CycleTest.php
  29. 194 0
      tests/Application/EducationTimingsTest.php
  30. 284 0
      tests/Application/ParametersTest.php
  31. 0 90
      tests/Application/Person/PersonTest.php
  32. 225 0
      tests/Application/PersonTest.php
  33. 26 0
      tests/Application/PublicEventsTest.php
  34. 251 0
      tests/Application/ResidenceAreaTest.php
  35. 234 0
      tests/Application/SubdomainTest.php
  36. 31 21
      tests/ApplicationOld/OtWebTestCase.php
  37. 90 0
      tests/ApplicationOld/Person/PersonTest.php
  38. 2 0
      tests/ApplicationOld/Public/PublicEventsTest.php
  39. 0 0
      tests/ApplicationOld/Public/PublicStructuresTest.php
  40. 34 0
      tests/ApplicationOld/ResidenceAreaTest.php
  41. 167 64
      tests/Fixture/OrganizationFixtures.php
  42. 0 16
      tests/Fixture/readme.md
  43. 0 0
      tests/FixturesOld/Factory/Access/AccessFactory.php
  44. 0 0
      tests/FixturesOld/Factory/Organization/OrganizationFactory.php
  45. 0 0
      tests/FixturesOld/Factory/Organization/SettingsFactory.php
  46. 0 0
      tests/FixturesOld/Factory/Person/PersonFactory.php
  47. 111 0
      tests/FixturesOld/OrganizationFixtures.php
  48. 0 0
      tests/FixturesOld/PersonFixtures.php
  49. 34 0
      tests/FixturesOld/readme.md
  50. 29 18
      tests/Unit/Service/Security/ModuleTest.php

+ 0 - 2
composer.json

@@ -133,8 +133,6 @@
   },
   "scripts": {
     "auto-scripts": {
-      "ot:setup:env": "symfony-cmd",
-      "secrets:decrypt-to-local --force": "symfony-cmd",
       "cache:clear": "symfony-cmd",
       "assets:install %PUBLIC_DIR%": "symfony-cmd"
     },

+ 5 - 5
config/opentalent/products.yaml

@@ -289,14 +289,14 @@ parameters:
           - Statistic
           - Dolibarr
 
-      artist_premium:
+      artist-premium:
         extend: artist
         modules:
           - MessagesAdvanced
           - TaggAdvanced
 
       school:
-        extend: artist_premium
+        extend: artist-premium
         modules:
           - PedagogicsAdministation
           - PedagogicsSeizure
@@ -308,7 +308,7 @@ parameters:
           - BillingAdministration
           - TemplateMessages
 
-      school_premium:
+      school-premium:
         extend: school
         modules: ~
 
@@ -316,7 +316,7 @@ parameters:
         extend: artist-premium
         modules: ~
 
-      manager_premium:
+      manager-premium:
         extend: manager
         modules:
-          - CorePremium
+          - CorePremium

+ 1 - 0
config/packages/security.yaml

@@ -8,6 +8,7 @@ security:
         BASE_ROLE_ADMINISTRATION_CORE: &BASE_ROLE_ADMINISTRATION_CORE
             - ROLE_MEMBER_CORE
             - ROLE_ORGANIZATION
+            - ROLE_ORGANIZATION_VIEW
 
         ROLE_ADMIN:
             - ROLE_CORE-CRUD

+ 31 - 0
migrations/Version20240117143228.php

@@ -0,0 +1,31 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\Migrations\AbstractMigration;
+
+/**
+ * Auto-generated Migration: Please modify to your needs!
+ */
+final class Version20240117143228 extends AbstractMigration
+{
+    public function getDescription(): string
+    {
+        return '';
+    }
+
+    public function up(Schema $schema): void
+    {
+        // this up() migration is auto-generated, please modify it to your needs
+
+    }
+
+    public function down(Schema $schema): void
+    {
+        // this down() migration is auto-generated, please modify it to your needs
+
+    }
+}

+ 31 - 0
migrations/Version20240117143535.php

@@ -0,0 +1,31 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\Migrations\AbstractMigration;
+
+/**
+ * Auto-generated Migration: Please modify to your needs!
+ */
+final class Version20240117143535 extends AbstractMigration
+{
+    public function getDescription(): string
+    {
+        return '';
+    }
+
+    public function up(Schema $schema): void
+    {
+        // this up() migration is auto-generated, please modify it to your needs
+
+    }
+
+    public function down(Schema $schema): void
+    {
+        // this down() migration is auto-generated, please modify it to your needs
+
+    }
+}

+ 31 - 0
migrations/Version20240117143719.php

@@ -0,0 +1,31 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\Migrations\AbstractMigration;
+
+/**
+ * Auto-generated Migration: Please modify to your needs!
+ */
+final class Version20240117143719 extends AbstractMigration
+{
+    public function getDescription(): string
+    {
+        return '';
+    }
+
+    public function up(Schema $schema): void
+    {
+        // this up() migration is auto-generated, please modify it to your needs
+
+    }
+
+    public function down(Schema $schema): void
+    {
+        // this down() migration is auto-generated, please modify it to your needs
+
+    }
+}

+ 81 - 81
old/Entity/Place/Room.php

@@ -87,22 +87,22 @@ class Room implements ContactInterface
     #[ORM\JoinColumn(name: 'openinghoursspecification_id', referencedColumnName: 'id', unique: true)]
     #[Groups(['room_openinghoursspecification'])]
     private $openingHoursSpecification;
-    /**
-     * @var ArrayCollection<ContactPoint>
-     */
-    #[ORM\ManyToMany(targetEntity: 'AppBundle\Entity\Core\ContactPoint')]
-    #[Groups(['room_contactpoint'])]
-    private $contactpoint;
-    /**
-     * @var ArrayCollection<Equipment>
-     */
-    #[Assert\Valid]
-    #[ORM\ManyToMany(targetEntity: 'AppBundle\Entity\Product\Equipment', cascade: ['persist'])]
-    #[ORM\JoinTable(joinColumns: [], inverseJoinColumns: [])]
-    #[ORM\JoinColumn(name: 'room_id', referencedColumnName: 'id')]
-    #[ORM\JoinColumn(name: 'equipment_id', referencedColumnName: 'id', unique: true)]
-    #[Groups(['room_equipment'])]
-    private $equipments;
+    // /**
+    //  * @var ArrayCollection<ContactPoint>
+    //  */
+    // #[ORM\ManyToMany(targetEntity: 'AppBundle\Entity\Core\ContactPoint')]
+    // #[Groups(['room_contactpoint'])]
+    // // private $contactpoint;
+    // /**
+    //  * @var ArrayCollection<Equipment>
+    //  */
+    // #[Assert\Valid]
+    // #[ORM\ManyToMany(targetEntity: 'AppBundle\Entity\Product\Equipment', cascade: ['persist'])]
+    // #[ORM\JoinTable(joinColumns: [], inverseJoinColumns: [])]
+    // #[ORM\JoinColumn(name: 'room_id', referencedColumnName: 'id')]
+    // #[ORM\JoinColumn(name: 'equipment_id', referencedColumnName: 'id', unique: true)]
+    // #[Groups(['room_equipment'])]
+    // private $equipments;
     /**
      * @var ArrayCollection<RoomControl>
      */
@@ -165,8 +165,8 @@ class Room implements ContactInterface
     public function __construct()
     {
         $this->openingHoursSpecification = new ArrayCollection();
-        $this->contactpoint = new ArrayCollection();
-        $this->equipments = new ArrayCollection();
+        // $this->contactpoint = new ArrayCollection();
+        // $this->equipments = new ArrayCollection();
         $this->repairs = new ArrayCollection();
         $this->controls = new ArrayCollection();
         $this->courses = new ArrayCollection();
@@ -364,40 +364,40 @@ class Room implements ContactInterface
     {
         return $this->openingHoursSpecification;
     }
-    /**
-     * Adds contactpoint.
-     *
-     * @param ContactPoint $contactpoint
-     *
-     * @return $this
-     */
-    public function addContactpoint(ContactPoint $contactpoint)
-    {
-        $this->contactpoint[] = $contactpoint;
+    // /**
+    //  * Adds contactpoint.
+    //  *
+    //  * @param ContactPoint $contactpoint
+    //  *
+    //  * @return $this
+    //  */
+    // public function addContactpoint(ContactPoint $contactpoint)
+    // {
+    //     $this->contactpoint[] = $contactpoint;
 
-        return $this;
-    }
-    /**
-     * Removes contactpoint.
-     *
-     * @param ContactPoint $contactpoint
-     *
-     * @return $this
-     */
-    public function removeContactpoint(ContactPoint $contactpoint)
-    {
-        $this->contactpoint->removeElement($contactpoint);
-        return $this;
-    }
-    /**
-     * Gets contactpoint.
-     *
-     * @return ArrayCollection<ContactPoint>
-     */
-    public function getContactpoint()
-    {
-        return $this->contactpoint;
-    }
+    //     return $this;
+    // }
+    // /**
+    //  * Removes contactpoint.
+    //  *
+    //  * @param ContactPoint $contactpoint
+    //  *
+    //  * @return $this
+    //  */
+    // public function removeContactpoint(ContactPoint $contactpoint)
+    // {
+    //     $this->contactpoint->removeElement($contactpoint);
+    //     return $this;
+    // }
+    // /**
+    //  * Gets contactpoint.
+    //  *
+    //  * @return ArrayCollection<ContactPoint>
+    //  */
+    // public function getContactpoint()
+    // {
+    //     return $this->contactpoint;
+    // }
     /**
      * Adds control.
      *
@@ -468,37 +468,37 @@ class Room implements ContactInterface
     {
         return $this->repairs;
     }
-    /**
-     * Add equipment
-     *
-     * @param \AppBundle\Entity\Product\Equipment $equipment
-     *
-     * @return Room
-     */
-    public function addEquipment(\AppBundle\Entity\Product\Equipment $equipment)
-    {
-        $this->equipments[] = $equipment;
+    // /**
+    //  * Add equipment
+    //  *
+    //  * @param \AppBundle\Entity\Product\Equipment $equipment
+    //  *
+    //  * @return Room
+    //  */
+    // public function addEquipment(\AppBundle\Entity\Product\Equipment $equipment)
+    // {
+    //     $this->equipments[] = $equipment;
 
-        return $this;
-    }
-    /**
-     * Remove equipment
-     *
-     * @param \AppBundle\Entity\Product\Equipment $equipment
-     */
-    public function removeEquipment(\AppBundle\Entity\Product\Equipment $equipment)
-    {
-        $this->equipments->removeElement($equipment);
-    }
-    /**
-     * Get equipments
-     *
-     * @return \Doctrine\Common\Collections\Collection
-     */
-    public function getEquipments()
-    {
-        return $this->equipments;
-    }
+    //     return $this;
+    // }
+    // /**
+    //  * Remove equipment
+    //  *
+    //  * @param \AppBundle\Entity\Product\Equipment $equipment
+    //  */
+    // public function removeEquipment(\AppBundle\Entity\Product\Equipment $equipment)
+    // {
+    //     $this->equipments->removeElement($equipment);
+    // }
+    // /**
+    //  * Get equipments
+    //  *
+    //  * @return \Doctrine\Common\Collections\Collection
+    //  */
+    // public function getEquipments()
+    // {
+    //     return $this->equipments;
+    // }
     /**
      * Add course
      *

+ 2 - 2
phpunit.xml.dist

@@ -6,7 +6,7 @@
         backupGlobals="false"
         colors="true"
         bootstrap="tests/bootstrap.php"
-        defaultTestSuite="unit"
+        defaultTestSuite="application"
 >
   <coverage includeUncoveredFiles="true">
     <include>
@@ -18,7 +18,7 @@
     </report>
   </coverage>
   <php>
-    <ini name="error_reporting" value="-1"/>
+    <ini name="error_reporting" value="E_ALL &amp; ~E_DEPRECATED &amp; ~E_USER_DEPRECATED"/>
     <server name="APP_ENV" value="staging" force="true"/>
     <server name="SHELL_VERBOSITY" value="-1"/>
     <server name="SYMFONY_PHPUNIT_REMOVE" value=""/>

+ 0 - 1
src/Entity/Core/ContactPoint.php

@@ -87,7 +87,6 @@ class ContactPoint
     #[ORM\InverseJoinColumn(name: 'place_id', referencedColumnName: 'id')]
     private Collection $place;
 
-    #[Pure]
     public function __construct()
     {
         $this->organization = new ArrayCollection();

+ 16 - 7
src/Entity/Education/Cycle.php

@@ -3,19 +3,20 @@ declare (strict_types=1);
 
 namespace App\Entity\Education;
 
-use ApiPlatform\Metadata\GetCollection;
-use ApiPlatform\Metadata\Put;
 use ApiPlatform\Metadata\Get;
-use ApiPlatform\Metadata\ApiResource;
+use ApiPlatform\Metadata\Put;
+use Doctrine\ORM\Mapping as ORM;
 use App\Enum\Education\CycleEnum;
-use App\Repository\Education\CycleRepository;
+use ApiPlatform\Metadata\ApiResource;
+use ApiPlatform\Metadata\GetCollection;
 use App\Entity\Organization\Organization;
 
 //use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
+use Doctrine\Common\Collections\Collection;
+use App\Repository\Education\CycleRepository;
 use Doctrine\Common\Collections\ArrayCollection;
-use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Serializer\Annotation\Groups;
 use Symfony\Component\Validator\Constraints as Assert;
-use Doctrine\Common\Collections\Collection;
 
 /**
  * Enum des cycles éducatifs, utilisés par les EducationCurriculum
@@ -25,6 +26,7 @@ use Doctrine\Common\Collections\Collection;
  *   * @see App\Doctrine\Education\CurrentCycleExtension
  */
 #[ApiResource(
+  normalizationContext: ['groups' => ['cycle_read']],
     operations: [
         new Get(
             security: 'is_granted(\'ROLE_ORGANIZATION_VIEW\') and object.getOrganization().getId() == user.getOrganization().getId()'
@@ -45,22 +47,29 @@ class Cycle
     #[ORM\Id]
     #[ORM\Column]
     #[ORM\GeneratedValue]
+    #[Groups(["cycle_read"])]
     private ?int $id = null;
 
     #[ORM\ManyToOne(inversedBy: 'cycles')]
     #[ORM\JoinColumn(nullable: false)]
+    #[Groups(["cycle_read"])]
     private Organization $organization;
 
-    #[ORM\Column(nullable: true)]
+    // sans l'ajout des " " autour de order, la requête SQL générée est invalide
+    #[ORM\Column(name:"`order`", nullable: true)]
+    #[Groups(["cycle_read"])]
     private ?int $order = null;
 
     #[ORM\Column(length: 255)]
+    #[Groups(["cycle_read"])]
     private string $label;
 
     #[ORM\Column(length: 50, enumType: CycleEnum::class)]
+    #[Groups(["cycle_read"])]
     private CycleEnum $cycleEnum;
 
     #[ORM\Column(options: ['default' => false])]
+    #[Groups(["cycle_read"])]
     private bool $isSystem = false;
 
     #[ORM\OneToMany(mappedBy: 'cycle', targetEntity: CycleByEducation::class, orphanRemoval: true)]

+ 1 - 0
src/Entity/Education/CycleByEducation.php

@@ -5,6 +5,7 @@ namespace App\Entity\Education;
 
 //use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
 use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Serializer\Annotation\Groups;
 
 /**
  * Classe ... qui ...

+ 5 - 4
src/Entity/Education/Education.php

@@ -3,16 +3,17 @@ declare (strict_types=1);
 
 namespace App\Entity\Education;
 
+use App\Entity\Core\Tagg;
 use ApiPlatform\Metadata\Get;
-use ApiPlatform\Metadata\ApiResource;
 use App\Entity\Booking\Course;
 use App\Entity\Booking\Examen;
-use App\Entity\Core\Tagg;
+use Doctrine\ORM\Mapping as ORM;
 
 //use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
-use Doctrine\Common\Collections\ArrayCollection;
+use ApiPlatform\Metadata\ApiResource;
 use Doctrine\Common\Collections\Collection;
-use Doctrine\ORM\Mapping as ORM;
+use Doctrine\Common\Collections\ArrayCollection;
+use Symfony\Component\Serializer\Annotation\MaxDepth;
 
 /**
  * Classe ... qui ...

+ 4 - 2
src/Entity/Education/EducationTiming.php

@@ -34,12 +34,14 @@ use Doctrine\Common\Collections\Collection;
             security: 'object.getOrganization().getId() == user.getOrganization().getId()'
         ),
         new Delete(
-            security: 'object.getOrganization().getId() == user.getOrganization().getId()'
+            security: 'object.getOrganization().getId() == user.getOrganization().getId()',
         ),
         new GetCollection(
             security: 'is_granted(\'ROLE_ORGANIZATION_VIEW\')'
         ),
-        new Post()
+        new Post(
+            security: 'is_granted(\'ROLE_ORGANIZATION\')'
+        )
     ],
     security: 'is_granted(\'ROLE_ORGANIZATION\')'
 )]

+ 12 - 10
src/Entity/Organization/Parameters.php

@@ -4,27 +4,28 @@ declare (strict_types=1);
 
 namespace App\Entity\Organization;
 
-use ApiPlatform\Metadata\Put;
+use App\Entity\Core\File;
+use JetBrains\PhpStorm\Pure;
 use ApiPlatform\Metadata\Get;
-use ApiPlatform\Metadata\ApiResource;
+use ApiPlatform\Metadata\Put;
 use App\Entity\Access\Access;
-use App\Entity\Core\File;
 use App\Enum\Core\FileTypeEnum;
 use App\Enum\Core\TimeZoneEnum;
-use App\Enum\Education\AdvancedEducationNotationTypeEnum;
+use Doctrine\ORM\Mapping as ORM;
+use ApiPlatform\Metadata\ApiResource;
 use App\Enum\Education\PeriodicityEnum;
+use Doctrine\Common\Collections\Collection;
 use App\Enum\Organization\BulletinOutputEnum;
 use App\Enum\Organization\BulletinPeriodEnum;
 use App\Enum\Organization\SendToBulletinEnum;
-use App\Repository\Organization\ParametersRepository;
-use App\State\Processor\Organization\ParametersProcessor;
 
 //use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
 use Doctrine\Common\Collections\ArrayCollection;
-use Doctrine\Common\Collections\Collection;
-use Doctrine\ORM\Mapping as ORM;
-use JetBrains\PhpStorm\Pure;
+use App\Enum\Organization\BulletinCriteriaSortEnum;
+use App\Repository\Organization\ParametersRepository;
 use Symfony\Component\Validator\Constraints as Assert;
+use App\Enum\Education\AdvancedEducationNotationTypeEnum;
+use App\State\Processor\Organization\ParametersProcessor;
 use App\Validator\Organization\Parameters as OpentalentAssert;
 
 #[ApiResource(
@@ -132,7 +133,7 @@ class Parameters
     private ?SendToBulletinEnum $bulletinReceiver = SendToBulletinEnum::STUDENTS_AND_THEIR_GUARDIANS;
 
     #[ORM\Column(length: 255, nullable: false, options: ['default' => 'BY_CRITERIA_INSERT'])]
-    #[Assert\Choice(callback: ['\\App\\Enum\\Organization\\BulletinCriteriaSortEnum', 'toArray'], message: 'invalid-bulletin-criteria-sort')]
+    #[Assert\Choice(callback: '\\App\\Enum\\Organization\\BulletinCriteriaSortEnum::toArray', message: 'invalid-bulletin-criteria-sort')]
     private string $bulletinCriteriaSort = "BY_CRITERIA_INSERT";
 
     #[ORM\Column(length: 255, nullable: true)]
@@ -158,6 +159,7 @@ class Parameters
     private ?PeriodicityEnum $educationPeriodicity = null;
 
     #[ORM\Column(length: 255, nullable: true, enumType: AdvancedEducationNotationTypeEnum::class, options: ['default' => AdvancedEducationNotationTypeEnum::BY_EDUCATION])]
+    #[Assert\Choice(callback: '\\App\\Enum\\Education\\AdvancedEducationNotationTypeEnum::toArray', message: 'invalid-advanced-education-notation-type')]
     private ?AdvancedEducationNotationTypeEnum $advancedEducationNotationType = null;
 
     #[ORM\Column(options: ['default' => false])]

+ 15 - 11
src/Entity/Organization/Subdomain.php

@@ -3,22 +3,23 @@ declare (strict_types=1);
 
 namespace App\Entity\Organization;
 
-use ApiPlatform\Metadata\Post;
-use ApiPlatform\Metadata\GetCollection;
-use ApiPlatform\Metadata\Put;
 use ApiPlatform\Metadata\Get;
-use ApiPlatform\Metadata\ApiResource;
-use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
+use ApiPlatform\Metadata\Put;
+use ApiPlatform\Metadata\Post;
+use Doctrine\ORM\Mapping as ORM;
 use ApiPlatform\Metadata\ApiFilter;
+use ApiPlatform\Metadata\ApiProperty;
+use ApiPlatform\Metadata\ApiResource;
+use ApiPlatform\Metadata\GetCollection;
 use App\Attribute\OrganizationDefaultValue;
+use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
+use ApiPlatform\Metadata\Delete;
+use Symfony\Component\Serializer\Annotation\Groups;
 use App\Repository\Organization\SubdomainRepository;
+use App\State\Provider\Parameters\SubdomainProvider;
+use Symfony\Component\Validator\Constraints as Assert;
 use App\State\Processor\Organization\SubdomainProcessor;
-
-//use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
-use Doctrine\ORM\Mapping as ORM;
 use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
-use Symfony\Component\Serializer\Annotation\Groups;
-use Symfony\Component\Validator\Constraints as Assert;
 
 /**
  * Sous-domaine enregistré par une organisation
@@ -34,7 +35,8 @@ use Symfony\Component\Validator\Constraints as Assert;
         new Put(
             security: 'is_granted("ROLE_ORGANIZATION") and object.getOrganization().getId() == user.getOrganization().getId()'
         ),
-        new GetCollection(),
+        new GetCollection(
+        ),
         new Post(
             security: 'is_granted("ROLE_ORGANIZATION")'
         )
@@ -51,6 +53,7 @@ class Subdomain
     #[ORM\Id]
     #[ORM\Column]
     #[ORM\GeneratedValue]
+    #[ApiProperty(identifier: true)]
     private ?int $id = null;
 
     #[ORM\ManyToOne(inversedBy: 'subdomains')]
@@ -128,4 +131,5 @@ class Subdomain
     {
         $this->active = $active;
     }
+    
 }

+ 51 - 51
src/Entity/Place/Room.php

@@ -33,13 +33,13 @@ class Room
     #[ORM\ManyToOne(targetEntity: Place::class, inversedBy: 'rooms')]
     private Place $place;
 
-    #[ORM\ManyToMany(targetEntity: ContactPoint::class)]
-    private Collection $contactpoint;
+    // #[ORM\ManyToMany(targetEntity: ContactPoint::class)]
+    // private Collection $contactpoint;
 
-    #[ORM\ManyToMany(targetEntity: Equipment::class, cascade: ['persist'])]
-    #[ORM\JoinColumn(name: 'room_id', referencedColumnName: 'id')]
-    #[ORM\InverseJoinColumn(name: 'equipment_id', referencedColumnName: 'id', unique: true)]
-    private Collection $equipments;
+    // #[ORM\ManyToMany(targetEntity: Equipment::class, cascade: ['persist'])]
+    // #[ORM\JoinColumn(name: 'room_id', referencedColumnName: 'id')]
+    // #[ORM\InverseJoinColumn(name: 'equipment_id', referencedColumnName: 'id', unique: true)]
+    // private Collection $equipments;
 
     #[ORM\OneToMany(mappedBy: 'room', targetEntity: RoomControl::class, cascade: ['persist'], orphanRemoval: true)]
     #[ORM\JoinColumn(nullable: false)]
@@ -69,8 +69,8 @@ class Room
 
     public function __construct()
     {
-        $this->contactpoint = new ArrayCollection();
-        $this->equipments = new ArrayCollection();
+        // $this->contactpoint = new ArrayCollection();
+        // $this->equipments = new ArrayCollection();
         $this->controls = new ArrayCollection();
         $this->repairs = new ArrayCollection();
         $this->courses = new ArrayCollection();
@@ -97,49 +97,49 @@ class Room
         return $this;
     }
 
-    /**
-     * @return Collection<int, ContactPoint>
-     */
-    public function getContactpoint(): Collection
-    {
-        return $this->contactpoint;
-    }
-
-    public function addContactpoint(ContactPoint $contactpoint): self
-    {
-        if (!$this->contactpoint->contains($contactpoint)) {
-            $this->contactpoint[] = $contactpoint;
-        }
-        return $this;
-    }
-
-    public function removeContactpoint(ContactPoint $contactpoint): self
-    {
-        $this->contactpoint->removeElement($contactpoint);
-        return $this;
-    }
-
-    /**
-     * @return Collection<int, Equipment>
-     */
-    public function getEquipments(): Collection
-    {
-        return $this->equipments;
-    }
-
-    public function addEquipment(Equipment $equipment): self
-    {
-        if (!$this->equipments->contains($equipment)) {
-            $this->equipments[] = $equipment;
-        }
-        return $this;
-    }
-
-    public function removeEquipment(Equipment $equipment): self
-    {
-        $this->equipments->removeElement($equipment);
-        return $this;
-    }
+    // /**
+    //  * @return Collection<int, ContactPoint>
+    //  */
+    // public function getContactpoint(): Collection
+    // {
+    //     return $this->contactpoint;
+    // }
+
+    // public function addContactpoint(ContactPoint $contactpoint): self
+    // {
+    //     if (!$this->contactpoint->contains($contactpoint)) {
+    //         $this->contactpoint[] = $contactpoint;
+    //     }
+    //     return $this;
+    // }
+
+    // public function removeContactpoint(ContactPoint $contactpoint): self
+    // {
+    //     $this->contactpoint->removeElement($contactpoint);
+    //     return $this;
+    // }
+
+    // /**
+    //  * @return Collection<int, Equipment>
+    //  */
+    // public function getEquipments(): Collection
+    // {
+    //     return $this->equipments;
+    // }
+
+    // public function addEquipment(Equipment $equipment): self
+    // {
+    //     if (!$this->equipments->contains($equipment)) {
+    //         $this->equipments[] = $equipment;
+    //     }
+    //     return $this;
+    // }
+
+    // public function removeEquipment(Equipment $equipment): self
+    // {
+    //     $this->equipments->removeElement($equipment);
+    //     return $this;
+    // }
 
     /**
      * @return Collection<int, RoomControl>

+ 1 - 1
src/Enum/Education/AdvancedEducationNotationTypeEnum.php

@@ -8,7 +8,7 @@ use App\Enum\EnumMethodsTrait;
 /**
  * Type possible sur lesquels les grilles péda doivent se baser
  */
-enum AdvancedEducationNotationTypeEnum: string
+enum AdvancedEducationNotationTypeEnum : string
 {
     use EnumMethodsTrait;
 

+ 8 - 0
src/Enum/EnumMethodsTrait.php

@@ -28,4 +28,12 @@ trait EnumMethodsTrait{
     {
         return array_combine(self::values(), self::names());
     }
+
+    /**
+     * @return bool >
+     */
+    public static function isValid(string|int $value): bool
+    {
+        return in_array($value, self::values(), true);
+    }
 }

+ 7 - 4
src/Enum/Organization/BulletinCriteriaSortEnum.php

@@ -1,15 +1,18 @@
 <?php
+
 declare(strict_types=1);
 
 namespace App\Enum\Organization;
 
-use MyCLabs\Enum\Enum;
+use App\Enum\EnumMethodsTrait;
 
 /**
  * Type de tri des critères des bulletins
  */
-class BulletinCriteriaSortEnum extends Enum
+enum BulletinCriteriaSortEnum: string
 {
-    private const ALPHANUM = 'ALPHANUM';
-    private const BY_CRITERIA_INSERT = 'BY_CRITERIA_INSERT';
+    use EnumMethodsTrait;
+
+    case ALPHANUM = 'ALPHANUM';
+    case BY_CRITERIA_INSERT = 'BY_CRITERIA_INSERT';
 }

+ 1 - 1
src/Enum/Organization/SettingsProductEnum.php

@@ -18,4 +18,4 @@ enum SettingsProductEnum: string
     case SCHOOL_PREMIUM = 'school-premium';
     case MANAGER = 'manager';
     case MANAGER_PREMIUM = 'manager-premium';
-}
+}

+ 23 - 22
src/Service/Security/Module.php

@@ -1,14 +1,15 @@
 <?php
+
 declare(strict_types=1);
 
 namespace App\Service\Security;
 
 use App\Entity\Organization\Organization;
-use App\Enum\Organization\SettingsProductEnum;
 use App\Service\Utils\Reflection;
 use Doctrine\Common\Cache\ApcuCache;
-use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
+use App\Enum\Organization\SettingsProductEnum;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
 
 /**
  * Class Module : classe gérant la récupération de l'ensemble des modules possédées par une organisation
@@ -29,11 +30,11 @@ class Module
      */
     public function getOrganizationModules(Organization $organization): array
     {
-//        $cacheDriver = new ApcuCache();
-//        //If the modules are all ready available inside the APCu cache
-//        if($cacheDriver->contains('organization_modules_' . $organization->getId())){
-//            return $cacheDriver->fetch('organization_modules_' . $organization->getId());
-//        }
+        //        $cacheDriver = new ApcuCache();
+        //        //If the modules are all ready available inside the APCu cache
+        //        if($cacheDriver->contains('organization_modules_' . $organization->getId())){
+        //            return $cacheDriver->fetch('organization_modules_' . $organization->getId());
+        //        }
 
         // Get modules from the organization settings
         $modulesBySettings = $this->getModuleBySettings($organization);
@@ -58,8 +59,8 @@ class Module
 
         $organizationModules = array_merge_recursive($modulesForProduct, $modulesBySettings, $modulesByConditions);
 
-//        //Keep the modules inside the APCu cache
-//        $cacheDriver->save('organization_modules_' . $organization->getId(), $organizationModules, '86400');
+        //        //Keep the modules inside the APCu cache
+        //        $cacheDriver->save('organization_modules_' . $organization->getId(), $organizationModules, '86400');
 
         return $organizationModules;
     }
@@ -74,10 +75,11 @@ class Module
     {
         $moduleByOptions = [];
         $modulesOptions = $organization->getSettings()->getModules();
-        if(!empty($modulesOptions)){
-            foreach($modulesOptions as $moduleOptionName => $moduleOptionValue){
-                if($moduleOptionValue)
+        if(!empty($modulesOptions)) {
+            foreach($modulesOptions as $moduleOptionName => $moduleOptionValue) {
+                if($moduleOptionValue) {
                     $moduleByOptions[] = $moduleOptionName;
+                }
             }
         }
         return $moduleByOptions;
@@ -106,7 +108,7 @@ class Module
                 if ($response) {
                     $modulesByConditions[] = $moduleName;
                 }
-            } catch (\Exception $exception){
+            } catch (\Exception $exception) {
                 throw new \LogicException(
                     $exception->getMessage(),
                     400,
@@ -118,20 +120,19 @@ class Module
     }
 
     /**
-     * Récupère les modules disponibles par produit grace au fichier products.yaml
-     * @param SettingsProductEnum $product
-     * @return list<string>|null
-     * @see ModuleTest::testGetModulesByProductConfiguration()
-     */
+ * Récupère les modules disponibles par produit grace au fichier products.yaml
+ * @param SettingsProductEnum $product
+ * @return list<string>|null
+ * @see ModuleTest::testGetModulesByProductConfiguration()
+ */
     public function getModulesByProductConfiguration(SettingsProductEnum $product): ?array
     {
-        $product = str_replace('-', '_', $product->value);
         $opentalentProducts = $this->parameterBag->get('opentalent.products');
 
-        if (!array_key_exists($product, $opentalentProducts)) {
-            throw new AccessDeniedHttpException(sprintf('The product %s does not exist !', $product));
+        if (!array_key_exists($product->value, $opentalentProducts)) {
+            throw new AccessDeniedHttpException(sprintf('The product %s does not exist !', $product->value));
         }
-        $productConfig = $opentalentProducts[$product];
+        $productConfig = $opentalentProducts[$product->value];
         $modules = $productConfig['modules'] ?? [];
 
         if (array_key_exists('extend', $productConfig)) {

+ 6 - 0
src/Service/Typo3/SubdomainService.php

@@ -38,6 +38,12 @@ class SubdomainService
         private readonly ParameterBagInterface $parameterBag
     ) {}
 
+    // récupérer le subdomain
+    public function getSubdomain(string $subdomainValue): ?Subdomain
+    {
+        return $this->subdomainRepository->findOneBy(['subdomain' => $subdomainValue]);
+    }
+
     /**
      * Is the organization allowed to register a new subdomain
      *

+ 7 - 2
src/State/Processor/EntityProcessor.php

@@ -2,14 +2,15 @@
 
 namespace App\State\Processor;
 
+use RuntimeException;
+use ApiPlatform\Metadata\Put;
 use ApiPlatform\Metadata\Delete;
 use ApiPlatform\Metadata\Operation;
 use ApiPlatform\State\ProcessorInterface;
-use Symfony\Component\HttpFoundation\Response;
 use App\Service\OnChange\OnChangeContext;
 use App\Service\OnChange\OnChangeDefault;
 use App\Service\OnChange\OnChangeInterface;
-use RuntimeException;
+use Symfony\Component\HttpFoundation\Response;
 use Symfony\Contracts\Service\Attribute\Required;
 
 /**
@@ -46,6 +47,10 @@ class EntityProcessor implements ProcessorInterface
             throw new RuntimeException('not supported', Response::HTTP_METHOD_NOT_ALLOWED);
         }
 
+        if($operation instanceof Put){
+          throw new RuntimeException('not supported', Response::HTTP_METHOD_NOT_ALLOWED);
+        }
+
         $onChangeContext = new OnChangeContext($context);
 
         $this->onChange->validate($data, $onChangeContext);

+ 11 - 3
src/State/Processor/Organization/ParametersProcessor.php

@@ -1,11 +1,20 @@
 <?php
+
 declare(strict_types=1);
 
 namespace App\State\Processor\Organization;
 
+use RuntimeException;
+use JetBrains\PhpStorm\Pure;
+use ApiPlatform\Metadata\Put;
+use ApiPlatform\Metadata\Operation;
+use App\Enum\Education\PeriodicityEnum;
 use App\State\Processor\EntityProcessor;
+use Symfony\Component\HttpFoundation\Response;
+use App\Enum\Organization\BulletinCriteriaSortEnum;
+use App\Enum\Education\AdvancedEducationNotationTypeEnum;
 use App\Service\OnChange\Organization\OnParametersChange;
-use JetBrains\PhpStorm\Pure;
+use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
 
 /**
  * Classe ParametersProcessor qui est un custom dataPersister gérant la resource Parameters
@@ -15,8 +24,7 @@ class ParametersProcessor extends EntityProcessor
     #[Pure]
     public function __construct(
         OnParametersChange $onChange
-    )
-    {
+    ) {
         parent::__construct($onChange);
     }
 }

+ 1 - 1
src/State/Processor/Organization/SubdomainProcessor.php

@@ -37,7 +37,7 @@ class SubdomainProcessor implements ProcessorInterface
      */
     public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []) {
         if($operation instanceof Delete){
-            throw new \RuntimeException('not supported', Response::HTTP_METHOD_NOT_ALLOWED);
+            throw new \RuntimeException('Mehod Delete not supported', Response::HTTP_METHOD_NOT_ALLOWED);
         }
 
         /** @var Access $access */

+ 21 - 0
src/State/Provider/Parameters/SubdomainCollection.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace App\State\Provider\Parameters;
+
+use App\Entity\Organization\Subdomain;
+
+
+class SubdomainCollection
+{
+    private array $subdomains = [];
+
+    public function addSubdomain(Subdomain $subdomain): void
+    {
+        $this->subdomains[] = $subdomain;
+    }
+
+    public function getSubdomains(): array
+    {
+        return $this->subdomains;
+    }
+}

+ 52 - 0
src/State/Provider/Parameters/SubdomainProvider.php

@@ -0,0 +1,52 @@
+<?php
+
+namespace App\State\Provider\Parameters;
+
+use RuntimeException;
+use ApiPlatform\Metadata\Get;
+use ApiPlatform\Metadata\Operation;
+use App\Entity\Organization\Subdomain;
+use ApiPlatform\Metadata\GetCollection;
+use App\Service\Typo3\SubdomainService;
+use ApiPlatform\State\ProviderInterface;
+use App\Service\Access\AdminAccessUtils;
+use Doctrine\ORM\EntityManagerInterface;
+use Symfony\Bundle\SecurityBundle\Security;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Serializer\SerializerInterface;
+
+class SubdomainProvider implements ProviderInterface
+{
+    public function __construct(
+        private Security $security,
+        private EntityManagerInterface $entityManager,
+        private SubdomainService $subdomainService,
+        private SerializerInterface $serializer
+    ) {}
+
+    public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?object
+    {
+        if ($operation instanceof GetCollection) {
+            $access = $this->security->getUser();
+            $organization = $access->getOrganization();
+
+            $subdomains = $this->entityManager->getRepository(Subdomain::class)->findBy(['organization' => $organization]);
+
+            $subdomainCollection = new SubdomainCollection();
+            foreach ($subdomains as $subdomain) {
+                $subdomainCollection->addSubdomain($subdomain);
+            }
+
+            return $subdomainCollection;
+        } elseif ($operation instanceof Get) {
+            $id = $uriVariables['id'] ?? null;
+            if ($id === null) {
+                throw new RuntimeException('No identifier provided for Subdomain entity.');
+            }
+            return $this->entityManager->getRepository(Subdomain::class)->find($id);
+        }
+        throw new RuntimeException('Unsupported operation for SubdomainProvider.');
+    }
+
+
+}

+ 218 - 0
tests/Application/CycleTest.php

@@ -0,0 +1,218 @@
+<?php
+
+namespace App\Tests\Application;
+
+use Zenstruck\Foundry\Proxy;
+use App\Entity\Access\Access;
+use Doctrine\ORM\EntityManagerInterface;
+use ApiPlatform\Symfony\Bundle\Test\Client;
+use Symfony\Component\HttpFoundation\Request;
+use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
+use Symfony\Contracts\HttpClient\ResponseInterface;
+
+class CycleTest extends ApiTestCase
+{
+    protected Access | Proxy | null $user = null;
+    private $securityToken;
+    protected Client $client;
+    private EntityManagerInterface $em;
+
+    protected function setUp(): void
+    {
+        self::bootKernel();
+        $this->em = self::getContainer()->get(EntityManagerInterface::class);
+        $this->client = static::createClient();
+    }
+
+    // public function testCycleCollection()
+    // {
+    //     $this->loginAs($this->user);
+
+    //     $this->assertResponseIsSuccessful();
+
+    //     $this->get('/api/cycles');
+
+    //     $this->assertResponseStatusCodeSame(200);
+
+    // }
+
+    //test get by id 
+    
+    // public function testGetACycle()
+    // {
+    //     $this->loginAs($this->user);
+
+    //     $this->assertResponseIsSuccessful();
+
+    //     $this->get('/api/cycles/36548');
+
+    //     $this->assertResponseStatusCodeSame(200);
+
+    //     $this->assertJsonContains([
+    //         'label' => 'Cycle 1'
+    //     ]);
+    // }
+
+    // public function testPutCycle()
+    // {
+    //     $this->loginAs($this->user);
+
+    //     $this->assertResponseIsSuccessful();
+
+    //     $this->put('/api/cycles/36548', [
+    //       'label' => 'new label'
+    //   ]);
+
+    //     $this->assertResponseStatusCodeSame(200);
+
+    //     $this->assertJsonContains([
+    //         'label' => 'new label'
+    //     ]);
+    // }
+
+
+
+    public function loginAs()
+    {
+        // on récupère l'access qui a l'id 641003 dans l'entity manager
+        $access = $this->em->getRepository(Access::class)->find(642459);
+        $person =  $access->getPerson();
+
+        $response = $this->post(
+            '/login_check',
+            ['username' => $person->getUsername(), 'password' => $person->getPassword()]
+        );
+
+        $content = $response->getContent();
+
+        $this->securityToken = json_decode($content)->token;
+        $this->user = $access;
+    }
+
+    /**
+     * Send a GET request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function get(string $route, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_GET,
+            $route,
+            null,
+            $headers
+        );
+    }
+    /**
+     * Send a POST request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function post(string $route, array $data, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_POST,
+            $route,
+            $data,
+            $headers
+        );
+    }
+
+
+
+    /**
+     * Send a requests, parse the hydra response and return an object or a Collection
+     *
+     * @param string $method
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function request(string $method, string $route, array | null $data = null, array $headers = []): ResponseInterface
+    {
+        if ($this->user) {
+            $headers = array_merge(
+                ['x-accessid' => $this->user->getId(), 'authorization' => 'BEARER ' . $this->securityToken],
+                $headers
+            );
+        }
+
+        $parameters = ['headers' => $headers];
+        if ($data) {
+            $parameters['json'] = $data;
+        }
+
+        return $this->client->request(
+            $method,
+            $route,
+            $parameters
+        );
+    }
+
+    /**
+     * Send a PUT request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function put(string $route, array $data, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_PUT,
+            $route,
+            $data,
+            $headers
+        );
+    }
+
+    /**
+     * Send a DELETE request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function delete(string $route, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_DELETE,
+            $route,
+            null,
+            $headers
+        );
+    }
+
+    /**
+     * Assert that the response has the expected status code and is well formated
+     *
+     * @param string $resourceClass
+     * @param int $expectedStatus
+     * @return void
+     */
+    protected function validateCollectionSchema(string $resourceClass, int $expectedStatus = 200): void
+    {
+        $this->assertResponseStatusCodeSame($expectedStatus);
+
+        if ($expectedStatus == 200) {
+            $this->assertResponseIsSuccessful();
+        }
+
+        // Asserts that the returned content type is JSON-LD (the default)
+        $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
+
+        // Asserts that the returned JSON is validated by the JSON Schema generated for this resource by API Platform
+        // >>> Issue with the json typed PublicStructure::addresses properties
+        // $this->assertMatchesResourceCollectionJsonSchema($resourceClass);
+    }
+
+
+
+}

+ 194 - 0
tests/Application/EducationTimingsTest.php

@@ -0,0 +1,194 @@
+<?php
+
+namespace App\Tests\Application;
+
+use Zenstruck\Foundry\Proxy;
+use App\Entity\Access\Access;
+use Doctrine\ORM\EntityManagerInterface;
+use ApiPlatform\Symfony\Bundle\Test\Client;
+use Symfony\Component\HttpFoundation\Request;
+use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
+use Symfony\Contracts\HttpClient\ResponseInterface;
+
+class ResidenceAreaTest extends ApiTestCase
+{
+    protected Access | Proxy | null $user = null;
+    private $securityToken;
+    protected Client $client;
+    private EntityManagerInterface $em;
+
+    protected function setUp(): void
+    {
+        self::bootKernel();
+        $this->em = self::getContainer()->get(EntityManagerInterface::class);
+        $this->client = static::createClient();
+    }
+
+
+    public function testGetCollectionEducationTiming(): void
+    {
+        $this->loginAs($this->user);
+  
+
+        $this->assertResponseIsSuccessful();
+
+        $this->get('/api/residence_areas');
+
+        $this->assertResponseStatusCodeSame(200);
+
+        $this->assertJsonContains([
+            '@context' => '/api/contexts/ResidenceArea',
+            '@id' => '/api/residence_areas',
+            '@type' => 'hydra:Collection',
+            'hydra:totalItems' => 5,
+            'hydra:member' => [
+                ["label" => "label"]
+            ],
+        ]);
+    }
+
+    public function loginAs()
+    {
+        // on récupère l'access qui a l'id 641003 dans l'entity manager
+        $access = $this->em->getRepository(Access::class)->find(642459);
+        $person =  $access->getPerson();
+
+        $response = $this->post(
+            '/login_check',
+            ['username' => $person->getUsername(), 'password' => $person->getPassword()]
+        );
+
+        $content = $response->getContent();
+
+        $this->securityToken = json_decode($content)->token;
+        $this->user = $access;
+
+    }
+
+    /**
+     * Send a GET request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function get(string $route, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_GET,
+            $route,
+            null,
+            $headers
+        );
+    }
+    /**
+     * Send a POST request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function post(string $route, array $data, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_POST,
+            $route,
+            $data,
+            $headers
+        );
+    }
+
+
+
+    /**
+     * Send a requests, parse the hydra response and return an object or a Collection
+     *
+     * @param string $method
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function request(string $method, string $route, array | null $data = null, array $headers = []): ResponseInterface
+    {
+        if ($this->user) {
+            $headers = array_merge(
+                ['x-accessid' => $this->user->getId(), 'authorization' => 'BEARER ' . $this->securityToken],
+                $headers
+            );
+        }
+
+        $parameters = ['headers' => $headers];
+        if ($data) {
+            $parameters['json'] = $data;
+        }
+
+        return $this->client->request(
+            $method,
+            $route,
+            $parameters
+        );
+    }
+
+    /**
+     * Send a PUT request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function put(string $route, array $data, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_PUT,
+            $route,
+            $data,
+            $headers
+        );
+    }
+
+    /**
+     * Send a DELETE request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function delete(string $route, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_DELETE,
+            $route,
+            null,
+            $headers
+        );
+    }
+
+    /**
+     * Assert that the response has the expected status code and is well formated
+     *
+     * @param string $resourceClass
+     * @param int $expectedStatus
+     * @return void
+     */
+    protected function validateCollectionSchema(string $resourceClass, int $expectedStatus = 200): void
+    {
+        $this->assertResponseStatusCodeSame($expectedStatus);
+
+        if ($expectedStatus == 200) {
+            $this->assertResponseIsSuccessful();
+        }
+
+        // Asserts that the returned content type is JSON-LD (the default)
+        $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
+
+        // Asserts that the returned JSON is validated by the JSON Schema generated for this resource by API Platform
+        // >>> Issue with the json typed PublicStructure::addresses properties
+        // $this->assertMatchesResourceCollectionJsonSchema($resourceClass);
+    }
+
+
+
+}

+ 284 - 0
tests/Application/ParametersTest.php

@@ -0,0 +1,284 @@
+<?php
+
+namespace App\Tests\Application;
+
+use Zenstruck\Foundry\Proxy;
+use App\Entity\Access\Access;
+use Doctrine\ORM\EntityManagerInterface;
+use ApiPlatform\Symfony\Bundle\Test\Client;
+use Symfony\Component\HttpFoundation\Request;
+use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
+use Symfony\Contracts\HttpClient\ResponseInterface;
+
+class ParametersTest extends ApiTestCase
+{
+    protected Access | Proxy | null $user = null;
+    private $securityToken;
+    protected Client $client;
+    private EntityManagerInterface $em;
+
+    protected function setUp(): void
+    {
+        self::bootKernel();
+        $this->em = self::getContainer()->get(EntityManagerInterface::class);
+        $this->client = static::createClient();
+    }
+
+
+    // public function testGetParameters(): void
+    // {
+    //     $this->loginAs($this->user);
+
+    //     $this->assertResponseIsSuccessful();
+
+    //     $this->get('/api/parameters/6262');
+
+    //     $this->assertResponseStatusCodeSame(200);
+
+    //     $this->assertJsonContains([
+    //         '@context' => '/api/contexts/Parameters',
+    //         '@id' => '/api/parameters/6262',
+    //         '@type' => 'Parameters',
+    //         'id' => 6262,
+    //         'organization' => '/api/organizations/616013',
+    //         'financialDate' => '2024-01-23T00:00:00+00:00',
+    //         'musicalDate' => '2024-01-23T00:00:00+00:00',
+    //         'startCourseDate' => '2024-01-23T00:00:00+00:00',
+    //         'endCourseDate' => '2024-01-23T00:00:00+00:00',
+    //         'average' => 20,
+    //         'editCriteriaNotationByAdminOnly'=> true,
+    //         'smsSenderName' => 'MySender',
+    //         'logoDonorsMove' => false,
+    //         'subDomain' => 'subdomain',
+    //         'website' => 'https://www.example.com',
+    //         'otherWebsite' => 'https://www.otherwebsite.com',
+    //         'customDomain' => 'https://www.customdomain.com',
+    //         'desactivateOpentalentSiteWeb' => false,
+    //         'bulletinPeriod' => 'SomePeriod',
+    //         'bulletinWithTeacher' => false,
+    //         'bulletinPrintAddress' => false,
+    //         'bulletinSignatureDirector' => true,
+    //         'bulletinDisplayLevelAcquired' => true,
+    //         'bulletinShowEducationWithoutEvaluation' => false,
+    //         'bulletinViewTestResults' => false,
+    //         'bulletinShowAbsences' => false,
+    //         'bulletinShowAverages' => true,
+    //         'bulletinOutput' => 'SomeOutput',
+    //         'bulletinEditWithoutEvaluation' => true,
+    //         'bulletinReceiver' => 'STUDENTS_AND_THEIR_GUARDIANS',
+    //         'bulletinCriteriaSort' => 'BY_CRITERIA_INSERT',
+    //         'usernameSMS' => 'username',
+    //         'passwordSMS' => 'password',
+    //         'showAdherentList' => true,
+    //         'studentsAreAdherents' => false,
+    //         'timezone' => 'Europe/Paris',
+    //         'educationPeriodicity' => 'ANNUAL',
+    //         'advancedEducationNotationType' => 'BY_EDUCATION',
+    //         'sendAttendanceEmail' => false,
+    //         'sendAttendanceSms' => false,
+    //         'generateAttendanceReport' => true,
+    //         'consultPedagogicResult' => true,
+    //         'consultTeacherListing' => true,
+    //         'periodValidation' => true,
+    //         'notifyAdministrationAbsence' => false,
+    //     ]);
+    // }
+
+    // public function testBadPutBulletinCriteriasort()
+    // {
+    //     $this->loginAs($this->user);
+
+    //     $this->put('/api/parameters/6262', [
+    //         'bulletinCriteriaSort' => 'BAD_CRITERIA_SORT'
+    //     ]);
+
+    //     $this->assertResponseStatusCodeSame(400);
+    // }
+
+    public function testBadadvancedEducationNotationType()
+    {
+        $this->loginAs($this->user);
+
+        $this->put('/api/parameters/6262', [
+            'bulletinCriteriaSort' => 'bad_advancedEducation'
+        ]);
+
+        $this->assertResponseStatusCodeSame(400);
+    }
+
+    // public function testDeleteParameters()
+    // {
+    //     $this->loginAs($this->user);
+
+    //     $this->delete('/api/parameters/6262');
+
+    //     $this->assertResponseStatusCodeSame(405);
+    // }
+
+    // public function testBadTimeZone()
+    // {
+    //     $this->loginAs($this->user);
+
+    //     $this->put('/api/parameters/6262', [
+    //         'timezone' => 'bad_timezone'
+    //     ]);
+
+    //     $this->assertResponseStatusCodeSame(500);
+    // }
+
+    // public function testBadPeridicity()
+    // {
+    //     $this->loginAs($this->user);
+
+    //     $this->put('/api/parameters/6262', [
+    //         'educationPeriodicity' => 'bad_periodicity'
+    //     ]);
+
+    //     $this->assertResponseStatusCodeSame(500);
+    // }
+
+
+    public function loginAs()
+    {
+        // on récupère l'access qui a l'id 641003 dans l'entity manager
+        $access = $this->em->getRepository(Access::class)->find(642459);
+        $person =  $access->getPerson();
+
+        $response = $this->post(
+            '/login_check',
+            ['username' => $person->getUsername(), 'password' => $person->getPassword()]
+        );
+
+        $content = $response->getContent();
+
+        $this->securityToken = json_decode($content)->token;
+        $this->user = $access;
+    }
+
+    /**
+     * Send a GET request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function get(string $route, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_GET,
+            $route,
+            null,
+            $headers
+        );
+    }
+    /**
+     * Send a POST request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function post(string $route, array $data, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_POST,
+            $route,
+            $data,
+            $headers
+        );
+    }
+
+
+
+    /**
+     * Send a requests, parse the hydra response and return an object or a Collection
+     *
+     * @param string $method
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function request(string $method, string $route, array | null $data = null, array $headers = []): ResponseInterface
+    {
+        if ($this->user) {
+            $headers = array_merge(
+                ['x-accessid' => $this->user->getId(), 'authorization' => 'BEARER ' . $this->securityToken],
+                $headers
+            );
+        }
+
+        $parameters = ['headers' => $headers];
+        if ($data) {
+            $parameters['json'] = $data;
+        }
+
+        return $this->client->request(
+            $method,
+            $route,
+            $parameters
+        );
+    }
+
+    /**
+     * Send a PUT request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function put(string $route, array $data, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_PUT,
+            $route,
+            $data,
+            $headers
+        );
+    }
+
+    /**
+     * Send a DELETE request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function delete(string $route, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_DELETE,
+            $route,
+            null,
+            $headers
+        );
+    }
+
+    /**
+     * Assert that the response has the expected status code and is well formated
+     *
+     * @param string $resourceClass
+     * @param int $expectedStatus
+     * @return void
+     */
+    protected function validateCollectionSchema(string $resourceClass, int $expectedStatus = 200): void
+    {
+        $this->assertResponseStatusCodeSame($expectedStatus);
+
+        if ($expectedStatus == 200) {
+            $this->assertResponseIsSuccessful();
+        }
+
+        // Asserts that the returned content type is JSON-LD (the default)
+        $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
+
+        // Asserts that the returned JSON is validated by the JSON Schema generated for this resource by API Platform
+        // >>> Issue with the json typed PublicStructure::addresses properties
+        // $this->assertMatchesResourceCollectionJsonSchema($resourceClass);
+    }
+
+
+
+}

+ 0 - 90
tests/Application/Person/PersonTest.php

@@ -1,90 +0,0 @@
-<?php
-namespace App\Tests\Application\Person;
-
-use App\Entity\Person\Person;
-use App\Entity\Access\Access;
-use App\Entity\Organization\Organization;
-use App\Entity\Organization\Settings;
-use App\Entity\Public\PublicEvent;
-use App\Enum\Organization\PrincipalTypeEnum;
-use App\Enum\Organization\SettingsProductEnum;
-use App\Tests\Application\OtWebTestCase;
-use App\Tests\Fixture\Factory\Access\AccessFactory;
-use App\Tests\Fixture\Factory\Organization\OrganizationFactory;
-use App\Tests\Fixture\Factory\Organization\SettingsFactory;
-use App\Tests\Fixture\Factory\Person\PersonFactory;
-use App\Tests\Fixture\PersonFixtures;
-use Zenstruck\Foundry\Factory;
-use Zenstruck\Foundry\Proxy;
-use App\Enum\Organization\LegalEnum;
-
-class PersonTest extends OtWebTestCase
-{
-    public function testPersonGet(): void
-    {
-        $this->loginAs($this->user);
-
-        $this->get('/api/people/' . $this->user->getPerson()->getId());
-
-        $this->validateCollectionSchema(Person::class);
-
-        $this->assertJsonContains([
-            '@context' => '/api/contexts/Person',
-            '@id' => '/api/people/' . $this->user->getPerson()->getId(),
-            '@type' => 'Person',
-            'username' => 'username'
-        ]);
-    }
-
-    public function testPersonGetHasNoRole(): void {
-
-        // User has not the required role
-        $this->user->setRoles([]);
-        $this->user->save();
-
-        $this->loginAs($this->user);
-
-        $this->get('/api/people/' . $this->user->getPerson()->getId());
-
-        $this->validateCollectionSchema(Person::class, 403);
-
-        $this->assertJsonContains([
-            "hydra:description" => "Access Denied."
-        ]);
-    }
-
-    public function testPersonGetCollection(): void {
-        $this->loginAs($this->user);
-
-        $this->get('/api/peoples');
-
-        $this->assertResponseStatusCodeSame(404);
-    }
-
-    public function testPersonPut(): void {
-        $this->loginAs($this->user);
-
-        $this->put('/api/people/' . $this->user->getPerson()->getId(), []);
-
-        // Expects : 405 Method Not Allowed
-        $this->assertResponseStatusCodeSame(405);
-    }
-
-    public function testPersonPost(): void {
-        $this->loginAs($this->user);
-
-        $this->post('/api/people/' . $this->user->getPerson()->getId(), []);
-
-        // Expects : 405 Method Not Allowed
-        $this->assertResponseStatusCodeSame(405);
-    }
-
-    public function testPersonDelete(): void {
-        $this->loginAs($this->user);
-
-        $this->delete('/api/people/' . $this->user->getPerson()->getId());
-
-        // Expects : 405 Method Not Allowed
-        $this->assertResponseStatusCodeSame(405);
-    }
-}

+ 225 - 0
tests/Application/PersonTest.php

@@ -0,0 +1,225 @@
+<?php
+
+namespace App\Tests\Application;
+
+use Zenstruck\Foundry\Proxy;
+use App\Entity\Access\Access;
+use Doctrine\ORM\EntityManager;
+use AppBundle\Entity\Person\Person;
+use Doctrine\ORM\EntityManagerInterface;
+use ApiPlatform\Symfony\Bundle\Test\Client;
+use Symfony\Component\HttpFoundation\Request;
+use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
+use Symfony\Contracts\HttpClient\ResponseInterface;
+
+class PersonTest extends ApiTestCase
+{
+    protected Access | Proxy | null $user = null;
+    private $securityToken;
+    protected Client $client;
+    private EntityManagerInterface $em;
+
+    protected function setUp(): void
+    {
+        self::bootKernel();
+        $this->em = self::getContainer()->get(EntityManagerInterface::class);
+        $this->client = static::createClient();
+    }
+
+    public function testPerson(): void
+    {
+        $this->loginAs($this->user);
+
+
+        $this->assertResponseIsSuccessful();
+
+    }
+
+
+
+    public function testPersonGetCollection(): void
+    {
+        $this->loginAs($this->user);
+
+        $this->get('/api/peoples');
+
+        $this->assertResponseStatusCodeSame(404);
+    }
+
+    public function testPersonPut(): void
+    {
+        $this->loginAs($this->user);
+
+        $this->put('/api/people/' . $this->user->getPerson()->getId(), []);
+
+        // Expects : 405 Method Not Allowed
+        $this->assertResponseStatusCodeSame(405);
+    }
+
+
+
+    public function testPersonPost(): void
+    {
+        $this->loginAs($this->user);
+
+        $this->post('/api/people/' . $this->user->getPerson()->getId(), []);
+
+        // Expects : 405 Method Not Allowed
+        $this->assertResponseStatusCodeSame(405);
+    }
+
+    public function testPersonDelete(): void
+    {
+        $this->loginAs($this->user);
+
+        $this->delete('/api/people/' . $this->user->getPerson()->getId());
+
+        // Expects : 405 Method Not Allowed
+        $this->assertResponseStatusCodeSame(405);
+    }
+
+
+
+    /**
+     * Assert that the response has the expected status code and is well formated
+     *
+     * @param string $resourceClass
+     * @param int $expectedStatus
+     * @return void
+     */
+    protected function validateCollectionSchema(string $resourceClass, int $expectedStatus = 200): void
+    {
+        $this->assertResponseStatusCodeSame($expectedStatus);
+
+        if ($expectedStatus == 200) {
+            $this->assertResponseIsSuccessful();
+        }
+
+        // Asserts that the returned content type is JSON-LD (the default)
+        $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
+
+        // Asserts that the returned JSON is validated by the JSON Schema generated for this resource by API Platform
+        // >>> Issue with the json typed PublicStructure::addresses properties
+        // $this->assertMatchesResourceCollectionJsonSchema($resourceClass);
+    }
+
+    public function loginAs()
+    {
+        // on récupère l'access qui a l'id 641003 dans l'entity manager
+        $access = $this->em->getRepository(Access::class)->find(642459);
+        $person =  $access->getPerson();
+
+        $response = $this->post(
+            '/login_check',
+            ['username' => $person->getUsername(), 'password' => $person->getPassword()]
+        );
+
+        $content = $response->getContent();
+
+        $this->securityToken = json_decode($content)->token;
+        $this->user = $access;
+    }
+
+    /**
+     * Send a GET request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function get(string $route, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_GET,
+            $route,
+            null,
+            $headers
+        );
+    }
+    /**
+     * Send a POST request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function post(string $route, array $data, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_POST,
+            $route,
+            $data,
+            $headers
+        );
+    }
+
+
+
+    /**
+     * Send a requests, parse the hydra response and return an object or a Collection
+     *
+     * @param string $method
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function request(string $method, string $route, array | null $data = null, array $headers = []): ResponseInterface
+    {
+        if ($this->user) {
+            $headers = array_merge(
+                ['x-accessid' => $this->user->getId(), 'authorization' => 'BEARER ' . $this->securityToken],
+                $headers
+            );
+        }
+
+        $parameters = ['headers' => $headers];
+        if ($data) {
+            $parameters['json'] = $data;
+        }
+
+        return $this->client->request(
+            $method,
+            $route,
+            $parameters
+        );
+    }
+
+    /**
+     * Send a PUT request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function put(string $route, array $data, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_PUT,
+            $route,
+            $data,
+            $headers
+        );
+    }
+
+    /**
+     * Send a DELETE request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function delete(string $route, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_DELETE,
+            $route,
+            null,
+            $headers
+        );
+    }
+
+
+}

+ 26 - 0
tests/Application/PublicEventsTest.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace App\Tests\Application;
+use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
+
+class PublicEventsTest extends ApiTestCase
+{
+
+    public function testEvents(): void
+    {
+      // on fait un get sur /api/public/events
+      $response = static::createClient()->request('GET', '/api/public/events');
+      // on vérifie que le code de retour est 200
+      $this->assertResponseIsSuccessful();
+      // on vérifie que le json contient bien les données attendues
+      $this->assertJsonContains([
+          '@context' => '/api/contexts/PublicEvent',
+          '@id' => '/api/public/events',
+          '@type' => 'hydra:Collection',
+          'hydra:totalItems' => 1,
+          'hydra:member' => [
+              ["name" => "My Event"]
+          ],
+      ]);
+    }
+}

+ 251 - 0
tests/Application/ResidenceAreaTest.php

@@ -0,0 +1,251 @@
+<?php
+
+namespace App\Tests\Application;
+
+use Zenstruck\Foundry\Proxy;
+use App\Entity\Access\Access;
+use Doctrine\ORM\EntityManagerInterface;
+use ApiPlatform\Symfony\Bundle\Test\Client;
+use Symfony\Component\HttpFoundation\Request;
+use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
+use Symfony\Contracts\HttpClient\ResponseInterface;
+
+class ResidenceAreaTest extends ApiTestCase
+{
+    protected Access | Proxy | null $user = null;
+    private $securityToken;
+    protected Client $client;
+    private EntityManagerInterface $em;
+
+    protected function setUp(): void
+    {
+        self::bootKernel();
+        $this->em = self::getContainer()->get(EntityManagerInterface::class);
+        $this->client = static::createClient();
+    }
+
+
+    // public function testGetResidenceArea(): void
+    // {
+    //     $this->loginAs($this->user);
+  
+
+    //     $this->assertResponseIsSuccessful();
+
+    //     $this->get('/api/residence_areas');
+
+    //     $this->assertResponseStatusCodeSame(200);
+
+    //     $this->assertJsonContains([
+    //         '@context' => '/api/contexts/ResidenceArea',
+    //         '@id' => '/api/residence_areas',
+    //         '@type' => 'hydra:Collection',
+    //         'hydra:totalItems' => 5,
+    //         'hydra:member' => [
+    //             ["label" => "label"]
+    //         ],
+    //     ]);
+    // }
+
+
+
+    // public function testPostResidenceArea()
+    // {
+    //     $this->loginAs($this->user);
+
+    //     $this->post('/api/residence_areas', [
+    //         'label' => 'toto',
+    //         'billingSetting' => '/api/billing_settings/6070'
+    //     ]);
+
+    //     $this->assertResponseStatusCodeSame(201);
+
+    //     $this->assertJsonContains([
+    //         '@context' => '/api/contexts/ResidenceArea',
+    //         '@type' => 'ResidenceArea',
+    //         'label' => 'toto',
+    //         'billingSetting' => '/api/billing_settings/6070'
+    //     ]);
+
+    // }
+
+    // public function testPutResidenceArea()
+    // {
+    //     $this->loginAs($this->user);
+
+    //     $this->put('/api/residence_areas/752', [
+    //         'label' => 'tata',
+    //         'billingSetting' => '/api/billing_settings/6070'
+    //     ]);
+
+    //     $this->assertResponseStatusCodeSame(200);
+
+    //     $this->assertJsonContains([
+    //         '@context' => '/api/contexts/ResidenceArea',
+    //         '@type' => 'ResidenceArea',
+    //         'label' => 'tata',
+    //         'billingSetting' => '/api/billing_settings/6070'
+    //     ]);
+
+    // }
+
+    public function testDeleteResidenceArea()
+    {
+        $this->loginAs($this->user);
+
+        $this->delete('/api/residence_areas/752');
+
+        $this->assertResponseStatusCodeSame(204);
+
+    }
+
+
+
+
+
+
+    public function loginAs()
+    {
+        // on récupère l'access qui a l'id 641003 dans l'entity manager
+        $access = $this->em->getRepository(Access::class)->find(642459);
+        $person =  $access->getPerson();
+
+        $response = $this->post(
+            '/login_check',
+            ['username' => $person->getUsername(), 'password' => $person->getPassword()]
+        );
+
+        $content = $response->getContent();
+
+        $this->securityToken = json_decode($content)->token;
+        $this->user = $access;
+
+    }
+
+    /**
+     * Send a GET request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function get(string $route, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_GET,
+            $route,
+            null,
+            $headers
+        );
+    }
+    /**
+     * Send a POST request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function post(string $route, array $data, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_POST,
+            $route,
+            $data,
+            $headers
+        );
+    }
+
+
+
+    /**
+     * Send a requests, parse the hydra response and return an object or a Collection
+     *
+     * @param string $method
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function request(string $method, string $route, array | null $data = null, array $headers = []): ResponseInterface
+    {
+        if ($this->user) {
+            $headers = array_merge(
+                ['x-accessid' => $this->user->getId(), 'authorization' => 'BEARER ' . $this->securityToken],
+                $headers
+            );
+        }
+
+        $parameters = ['headers' => $headers];
+        if ($data) {
+            $parameters['json'] = $data;
+        }
+
+        return $this->client->request(
+            $method,
+            $route,
+            $parameters
+        );
+    }
+
+    /**
+     * Send a PUT request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function put(string $route, array $data, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_PUT,
+            $route,
+            $data,
+            $headers
+        );
+    }
+
+    /**
+     * Send a DELETE request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function delete(string $route, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_DELETE,
+            $route,
+            null,
+            $headers
+        );
+    }
+
+    /**
+     * Assert that the response has the expected status code and is well formated
+     *
+     * @param string $resourceClass
+     * @param int $expectedStatus
+     * @return void
+     */
+    protected function validateCollectionSchema(string $resourceClass, int $expectedStatus = 200): void
+    {
+        $this->assertResponseStatusCodeSame($expectedStatus);
+
+        if ($expectedStatus == 200) {
+            $this->assertResponseIsSuccessful();
+        }
+
+        // Asserts that the returned content type is JSON-LD (the default)
+        $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
+
+        // Asserts that the returned JSON is validated by the JSON Schema generated for this resource by API Platform
+        // >>> Issue with the json typed PublicStructure::addresses properties
+        // $this->assertMatchesResourceCollectionJsonSchema($resourceClass);
+    }
+
+
+
+}

+ 234 - 0
tests/Application/SubdomainTest.php

@@ -0,0 +1,234 @@
+<?php
+
+namespace App\Tests\Application;
+
+use Zenstruck\Foundry\Proxy;
+use App\Entity\Access\Access;
+use Doctrine\ORM\EntityManagerInterface;
+use ApiPlatform\Symfony\Bundle\Test\Client;
+use Symfony\Component\HttpFoundation\Request;
+use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
+use Symfony\Contracts\HttpClient\ResponseInterface;
+
+class SubdomainTest extends ApiTestCase
+{
+    protected Access | Proxy | null $user = null;
+    private $securityToken;
+    protected Client $client;
+    private EntityManagerInterface $em;
+
+    protected function setUp(): void
+    {
+        self::bootKernel();
+        $this->em = self::getContainer()->get(EntityManagerInterface::class);
+        $this->client = static::createClient();
+    }
+
+
+    // public function testGetCollectionSubdomain(): void
+    // {
+    //     $this->loginAs($this->user);
+  
+
+    //     $this->assertResponseIsSuccessful();
+
+    //     $this->get('/api/subdomains');
+
+    //     $this->assertResponseStatusCodeSame(200);
+
+    //     $this->assertJsonContains([
+    //         '@context' => '/api/contexts/Subdomain',
+    //         '@id' => '/api/subdomains',
+    //         '@type' => 'hydra:Collection',
+    //         'hydra:totalItems' => 1,
+    //         'hydra:member' => [
+    //             ["subdomain" => "subdomain"]
+    //         ],
+    //     ]);
+    // }
+
+    // public function testPutSubdomain(): void
+    // {
+    //     $this->loginAs($this->user);
+
+    //     $this->assertResponseIsSuccessful();
+
+    //     $this->put('/api/subdomains/6622', [
+    //         'json' => [
+    //           'organization' => '/api/organizations/642459',
+    //             'subdomain' => 'toto',
+    //             'active' => true,
+    //         ],
+    //     ]);
+
+    //     $this->assertResponseStatusCodeSame(200);
+
+    //     $this->assertJsonContains([
+    //         '@context' => '/api/contexts/Subdomain',
+    //         '@id' => '/api/subdomains/6622',
+    //         '@type' => 'Subdomain',
+    //         'subdomain' => 'subdomain',
+    //         'active' => true,
+    //         'organization' => '/api/organizations/616013',
+    //     ]);
+    // }
+
+    public function testDeleteSubdomain(): void
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->delete('/api/subdomains/6622');
+
+        // méthode non supporté
+        $this->assertResponseStatusCodeSame(405);
+    }
+
+    // tester en ayant perdu le role admin admin_core
+
+    public function loginAs()
+    {
+        // on récupère l'access qui a l'id 641003 dans l'entity manager
+        $access = $this->em->getRepository(Access::class)->find(642459);
+        $person =  $access->getPerson();
+
+        $response = $this->post(
+            '/login_check',
+            ['username' => $person->getUsername(), 'password' => $person->getPassword()]
+        );
+
+        $content = $response->getContent();
+
+        $this->securityToken = json_decode($content)->token;
+        $this->user = $access;
+
+    }
+
+    /**
+     * Send a GET request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function get(string $route, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_GET,
+            $route,
+            null,
+            $headers
+        );
+    }
+    /**
+     * Send a POST request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function post(string $route, array $data, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_POST,
+            $route,
+            $data,
+            $headers
+        );
+    }
+
+
+
+    /**
+     * Send a requests, parse the hydra response and return an object or a Collection
+     *
+     * @param string $method
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function request(string $method, string $route, array | null $data = null, array $headers = []): ResponseInterface
+    {
+        if ($this->user) {
+            $headers = array_merge(
+                ['x-accessid' => $this->user->getId(), 'authorization' => 'BEARER ' . $this->securityToken],
+                $headers
+            );
+        }
+
+        $parameters = ['headers' => $headers];
+        if ($data) {
+            $parameters['json'] = $data;
+        }
+
+        return $this->client->request(
+            $method,
+            $route,
+            $parameters
+        );
+    }
+
+    /**
+     * Send a PUT request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function put(string $route, array $data, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_PUT,
+            $route,
+            $data,
+            $headers
+        );
+    }
+
+    /**
+     * Send a DELETE request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $headers
+     * @return ResponseInterface
+     */
+    protected function delete(string $route, array $headers = []): ResponseInterface
+    {
+        return $this->request(
+            Request::METHOD_DELETE,
+            $route,
+            null,
+            $headers
+        );
+    }
+
+    /**
+     * Assert that the response has the expected status code and is well formated
+     *
+     * @param string $resourceClass
+     * @param int $expectedStatus
+     * @return void
+     */
+    protected function validateCollectionSchema(string $resourceClass, int $expectedStatus = 200): void
+    {
+        $this->assertResponseStatusCodeSame($expectedStatus);
+
+        if ($expectedStatus == 200) {
+            $this->assertResponseIsSuccessful();
+        }
+
+        // Asserts that the returned content type is JSON-LD (the default)
+        $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
+
+        // Asserts that the returned JSON is validated by the JSON Schema generated for this resource by API Platform
+        // >>> Issue with the json typed PublicStructure::addresses properties
+        // $this->assertMatchesResourceCollectionJsonSchema($resourceClass);
+    }
+
+
+
+}

+ 31 - 21
tests/Application/OtWebTestCase.php → tests/ApplicationOld/OtWebTestCase.php

@@ -38,7 +38,8 @@ abstract class OtWebTestCase extends ApiTestCase
      * @return void
      * @throws \Exception
      */
-    public function setup(): void {
+    public function setup(): void
+    {
 
         // Boot le kernel symfony et récupère l'entity manager
         // @see https://symfony.com/doc/current/testing.html#retrieving-services-in-the-test
@@ -63,7 +64,8 @@ abstract class OtWebTestCase extends ApiTestCase
      * @return void
      * @throws \Doctrine\DBAL\Exception
      */
-    private function purgeDb() {
+    private function purgeDb()
+    {
         if (!preg_match('/.*test.*/', $this->em->getConnection()->getDatabase())) {
             throw new \RuntimeException("The DB name shall contain 'test' in its name to be purge");
         }
@@ -82,29 +84,30 @@ abstract class OtWebTestCase extends ApiTestCase
      *
      * @return void
      */
-    protected function loadFixture(): void {
+    protected function loadFixture(): void
+    {
         $person = PersonFactory::createOne(
             [
-                'username' => 'username',
-                'password' => 'password'
-            ]
+            'username' => 'username',
+            'password' => 'password'
+      ]
         );
 
         $organization = OrganizationFactory::createOne([
-            'legalStatus' => LegalEnum::ASSOCIATION_LAW_1901()->getValue(),
-            'principalType' => PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY()->getValue(),
-            'name' => 'My Organization'
+          'legalStatus' => LegalEnum::ASSOCIATION_LAW_1901()->getValue(),
+          'principalType' => PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY()->getValue(),
+          'name' => 'My Organization'
         ]);
 
         SettingsFactory::createOne([
-            'product' => SettingsProductEnum::ARTIST(),
-            'organization' => $organization
+          'product' => SettingsProductEnum::ARTIST(),
+          'organization' => $organization
         ]);
 
         $this->user = AccessFactory::createOne([
-            'person' => $person,
-            'organization' => $organization,
-            'roles' => ['ROLE_USERS_VIEW']
+          'person' => $person,
+          'organization' => $organization,
+          'roles' => ['ROLE_USERS_VIEW']
         ]);
     }
 
@@ -117,7 +120,8 @@ abstract class OtWebTestCase extends ApiTestCase
      * @param array<mixed> $headers
      * @return ResponseInterface
      */
-    protected function request(string $method, string $route, array | null $data = null, array $headers = []): ResponseInterface {
+    protected function request(string $method, string $route, array | null $data = null, array $headers = []): ResponseInterface
+    {
         if ($this->user) {
             $headers = array_merge(
                 ['x-accessid' => $this->user->getId(), 'authorization' => 'BEARER ' . $this->securityToken],
@@ -144,7 +148,8 @@ abstract class OtWebTestCase extends ApiTestCase
      * @param array<mixed> $headers
      * @return ResponseInterface
      */
-    protected function get(string $route, array $headers = []): ResponseInterface {
+    protected function get(string $route, array $headers = []): ResponseInterface
+    {
         return $this->request(
             Request::METHOD_GET,
             $route,
@@ -161,7 +166,8 @@ abstract class OtWebTestCase extends ApiTestCase
      * @param array<mixed> $headers
      * @return ResponseInterface
      */
-    protected function put(string $route, array $data, array $headers = []): ResponseInterface {
+    protected function put(string $route, array $data, array $headers = []): ResponseInterface
+    {
         return $this->request(
             Request::METHOD_PUT,
             $route,
@@ -178,7 +184,8 @@ abstract class OtWebTestCase extends ApiTestCase
      * @param array<mixed> $headers
      * @return ResponseInterface
      */
-    protected function post(string $route, array $data, array $headers = []): ResponseInterface {
+    protected function post(string $route, array $data, array $headers = []): ResponseInterface
+    {
         return $this->request(
             Request::METHOD_POST,
             $route,
@@ -194,7 +201,8 @@ abstract class OtWebTestCase extends ApiTestCase
      * @param array<mixed> $headers
      * @return ResponseInterface
      */
-    protected function delete(string $route, array $headers = []): ResponseInterface {
+    protected function delete(string $route, array $headers = []): ResponseInterface
+    {
         return $this->request(
             Request::METHOD_DELETE,
             $route,
@@ -213,7 +221,8 @@ abstract class OtWebTestCase extends ApiTestCase
      * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
      * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
      */
-    protected function loginAs(Proxy | Access $access): void {
+    protected function loginAs(Proxy | Access $access): void
+    {
         $person = $access->getPerson();
 
         $response = $this->post(
@@ -233,7 +242,8 @@ abstract class OtWebTestCase extends ApiTestCase
      * @param int $expectedStatus
      * @return void
      */
-    protected function validateCollectionSchema(string $resourceClass, int $expectedStatus = 200): void {
+    protected function validateCollectionSchema(string $resourceClass, int $expectedStatus = 200): void
+    {
         $this->assertResponseStatusCodeSame($expectedStatus);
 
         if ($expectedStatus == 200) {

+ 90 - 0
tests/ApplicationOld/Person/PersonTest.php

@@ -0,0 +1,90 @@
+<?php
+namespace App\Tests\Application\Person;
+
+use App\Entity\Person\Person;
+use App\Entity\Access\Access;
+use App\Entity\Organization\Organization;
+use App\Entity\Organization\Settings;
+use App\Entity\Public\PublicEvent;
+use App\Enum\Organization\PrincipalTypeEnum;
+use App\Enum\Organization\SettingsProductEnum;
+use App\Tests\Application\OtWebTestCase;
+use App\Tests\Fixture\Factory\Access\AccessFactory;
+use App\Tests\Fixture\Factory\Organization\OrganizationFactory;
+use App\Tests\Fixture\Factory\Organization\SettingsFactory;
+use App\Tests\Fixture\Factory\Person\PersonFactory;
+use App\Tests\Fixture\PersonFixtures;
+use Zenstruck\Foundry\Factory;
+use Zenstruck\Foundry\Proxy;
+use App\Enum\Organization\LegalEnum;
+
+class PersonTest extends OtWebTestCase
+{
+    public function testPersonGet(): void
+    {
+        $this->loginAs($this->user);
+
+        $this->get('/api/people/' . $this->user->getPerson()->getId());
+
+        $this->validateCollectionSchema(Person::class);
+
+        $this->assertJsonContains([
+            '@context' => '/api/contexts/Person',
+            '@id' => '/api/people/' . $this->user->getPerson()->getId(),
+            '@type' => 'Person',
+            'username' => 'username'
+        ]);
+    }
+
+    // public function testPersonGetHasNoRole(): void {
+
+    //     // User has not the required role
+    //     $this->user->setRoles([]);
+    //     $this->user->save();
+
+    //     $this->loginAs($this->user);
+
+    //     $this->get('/api/people/' . $this->user->getPerson()->getId());
+
+    //     $this->validateCollectionSchema(Person::class, 403);
+
+    //     $this->assertJsonContains([
+    //         "hydra:description" => "Access Denied."
+    //     ]);
+    // }
+
+    // public function testPersonGetCollection(): void {
+    //     $this->loginAs($this->user);
+
+    //     $this->get('/api/peoples');
+
+    //     $this->assertResponseStatusCodeSame(404);
+    // }
+
+    // public function testPersonPut(): void {
+    //     $this->loginAs($this->user);
+
+    //     $this->put('/api/people/' . $this->user->getPerson()->getId(), []);
+
+    //     // Expects : 405 Method Not Allowed
+    //     $this->assertResponseStatusCodeSame(405);
+    // }
+
+    // public function testPersonPost(): void {
+    //     $this->loginAs($this->user);
+
+    //     $this->post('/api/people/' . $this->user->getPerson()->getId(), []);
+
+    //     // Expects : 405 Method Not Allowed
+    //     $this->assertResponseStatusCodeSame(405);
+    // }
+
+    // public function testPersonDelete(): void {
+    //     $this->loginAs($this->user);
+
+    //     $this->delete('/api/people/' . $this->user->getPerson()->getId());
+
+    //     // Expects : 405 Method Not Allowed
+    //     $this->assertResponseStatusCodeSame(405);
+    // }
+}

+ 2 - 0
tests/Application/Public/PublicEventsTest.php → tests/ApplicationOld/Public/PublicEventsTest.php

@@ -24,3 +24,5 @@ class PublicEventsTest extends OtWebTestCase
         ]);
     }
 }
+
+

+ 0 - 0
tests/Application/Public/PublicStructuresTest.php → tests/ApplicationOld/Public/PublicStructuresTest.php


+ 34 - 0
tests/ApplicationOld/ResidenceAreaTest.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Tests\Application;
+
+use App\Entity\Billing\ResidenceArea;
+use App\Tests\Application\OtWebTestCase;
+
+class ResidenceAreaTest extends OtWebTestCase
+{
+    public function testGetResidenceAreas(): void
+    {
+      $this->loginAs($this->user);
+        // $this->client->request('GET', '/api/residence_areas');
+
+        // $this->assertResponseIsSuccessful();
+        // $this->assertMatchesResourceCollectionJsonSchema(ResidenceArea::class);
+        if($this->user->getPerson()) {
+          $this->get('/api/residence_areas');
+
+          $this->validateCollectionSchema(ResidenceArea::class);
+
+          $this->assertJsonContains([
+              '@context' => '/api/contexts/ResidenceArea',
+              '@id' => '/api/residence_areas',
+              '@type' => 'hydra:Collection',
+              'hydra:totalItems' => 1,
+              'hydra:member' => [
+                  ["label" => "My Residence Area"]
+              ],
+          ]);
+        }
+    }
+
+}

+ 167 - 64
tests/Fixture/OrganizationFixtures.php

@@ -2,94 +2,188 @@
 
 namespace App\Tests\Fixture;
 
+use DateTime;
+use App\Service\Utils\Uuid;
+use App\Entity\Access\Access;
 use App\Entity\Booking\Event;
-use App\Entity\Core\ContactPoint;
+use App\Entity\Person\Person;
+use App\Entity\Education\Cycle;
 use App\Entity\Network\Network;
-use App\Entity\Network\NetworkOrganization;
-use App\Entity\Organization\Organization;
-use App\Entity\Organization\Parameters;
+use App\Entity\Core\ContactPoint;
+use App\Entity\Education\Education;
 use App\Enum\Booking\VisibilityEnum;
-use App\Enum\Core\ContactPointTypeEnum;
 use App\Enum\Organization\LegalEnum;
-use App\Enum\Organization\PrincipalTypeEnum;
-use Doctrine\Bundle\FixturesBundle\Fixture;
+use App\Entity\Billing\AccessBilling;
+use App\Entity\Billing\ResidenceArea;
+use App\Entity\Organization\Settings;
+use App\Entity\Billing\BillingSetting;
+use App\Entity\Organization\Subdomain;
+use App\Entity\Organization\Parameters;
+use App\Enum\Core\ContactPointTypeEnum;
 use Doctrine\Persistence\ObjectManager;
+use Doctrine\ORM\EntityManagerInterface;
+use App\Entity\Education\EducationTiming;
+use App\Entity\Organization\Organization;
+use App\Entity\Education\CycleByEducation;
+use App\Entity\Education\EducationStudent;
+use App\Entity\Network\NetworkOrganization;
+use Doctrine\Bundle\FixturesBundle\Fixture;
+use App\Enum\Organization\PrincipalTypeEnum;
+use App\Entity\Education\EducationCurriculum;
+use Doctrine\Common\DataFixtures\Purger\ORMPurger;
+use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
 use Symfony\Component\Serializer\Context\SerializerContextBuilder;
-use App\Service\Utils\Uuid;
 
-class OrganizationFixtures extends Fixture
+class OrganizationFixtures extends Fixture implements FixtureGroupInterface
 {
+    protected EntityManagerInterface $em;
+
+    public static function getGroups(): array
+    {
+        return ['poc'];
+    }
+
+    /**
+     * Delete all DB records before populating fixtures.
+     *
+     * @return void
+     * @throws \Doctrine\DBAL\Exception
+     */
+    private function purgeDb()
+    {
+        if (!preg_match('/.*test.*/', $this->em->getConnection()->getDatabase())) {
+            throw new \RuntimeException("The DB name shall contain 'test' in its name to be purge");
+        }
+
+        $this->em->getConnection()->exec('SET FOREIGN_KEY_CHECKS = 0;');
+        $purger = new ORMPurger($this->em);
+        $purger->setPurgeMode(ORMPurger::PURGE_MODE_DELETE);
+        $purger->purge();
+        $this->em->getConnection()->exec('SET FOREIGN_KEY_CHECKS = 1;');
+    }
     public function load(ObjectManager $em): void
     {
+        // purge DB
+        $this->em = $em;
+        $this->purgeDb();
+
+        // create an organization with a network, legal status accesses, Param , name, id and settings
         $network = new Network();
         $network->setName('NET');
         $em->persist($network);
 
-        // Create the root organization (opentalent)
-        $parameters0 = new Parameters();
-        $em->persist($parameters0);
+
 
         $contactPoint0 = new ContactPoint();
         $contactPoint0->setContactType(ContactPointTypeEnum::PRINCIPAL()->getValue());
         $em->persist($contactPoint0);
 
+        // Create the root organization (opentalent)
         $root = new Organization();
         $root->setName('Root');
         $root->setLegalStatus(LegalEnum::COMMERCIAL_SOCIETY()->getValue());
         $root->setPrincipalType(PrincipalTypeEnum::NATIONAL_FEDERATION()->getValue());
-        $root->setParameters($parameters0);
         $root->addContactPoint($contactPoint0);
-        $em->persist($root);
 
-        $networkOrganisation0 = new NetworkOrganization();
-        $networkOrganisation0->setOrganization($root);
-        $networkOrganisation0->setNetwork($network);
-        $em->persist($networkOrganisation0);
-
-
-        // Create a federation organization
-        $parameters1 = new Parameters();
-        $em->persist($parameters1);
-
-        $contactPoint1 = new ContactPoint();
-        $contactPoint1->setContactType(ContactPointTypeEnum::PRINCIPAL()->getValue());
-        $em->persist($contactPoint1);
-
-        $fede = new Organization();
-        $fede->setName('Fede 1');
-        $fede->setLegalStatus(LegalEnum::ASSOCIATION_LAW_1901()->getValue());
-        $fede->setPrincipalType(PrincipalTypeEnum::NATIONAL_FEDERATION()->getValue());
-        $fede->setParameters($parameters1);
-        $fede->addContactPoint($contactPoint1);
-        $em->persist($fede);
-
-        $networkOrganisation1 = new NetworkOrganization();
-        $networkOrganisation1->setOrganization($fede);
-        $networkOrganisation1->setNetwork($network);
-        $networkOrganisation1->setParent($root);
-        $em->persist($networkOrganisation1);
-
-        // Create a simple organization
-        $parameters2 = new Parameters();
-        $em->persist($parameters2);
-
-        $contactPoint2 = new ContactPoint();
-        $contactPoint2->setContactType(ContactPointTypeEnum::PRINCIPAL()->getValue());
-        $em->persist($contactPoint2);
-
-        $organization = new Organization();
-        $organization->setName('Organization 2');
-        $organization->setLegalStatus(LegalEnum::ASSOCIATION_LAW_1901()->getValue());
-        $organization->setPrincipalType(PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY()->getValue());
-        $organization->setParameters($parameters2);
-        $organization->addContactPoint($contactPoint2);
-        $em->persist($organization);
-
-        $networkOrganisation2 = new NetworkOrganization();
-        $networkOrganisation2->setOrganization($organization);
-        $networkOrganisation2->setNetwork($network);
-        $networkOrganisation2->setParent($fede);
-        $em->persist($networkOrganisation2);
+
+        // subdomain fixtures
+        $subdomain = new Subdomain();
+        $subdomain->setOrganization($root);
+        $subdomain->setSubdomain('subdomain');
+        $subdomain->setActive(true);
+
+        $parameters = new Parameters();
+        $parameters->setFinancialDate(new DateTime());
+        $parameters->setMusicalDate(new DateTime());
+        $parameters->setStartCourseDate(new DateTime());
+        $parameters->setEndCourseDate(new DateTime());
+        $parameters->setAverage(20);
+        $parameters->setEditCriteriaNotationByAdminOnly(true);
+        $parameters->setSmsSenderName('MySender');
+        $parameters->setLogoDonorsMove(false);
+        $parameters->setSubDomain('subdomain');
+        $parameters->setWebsite('https://www.example.com');
+        $parameters->setOtherWebsite('https://www.otherwebsite.com');
+        $parameters->setCustomDomain('https://www.customdomain.com');
+        $parameters->setDesactivateOpentalentSiteWeb(false);
+        $parameters->setBulletinPeriod('SomePeriod');
+        $parameters->setBulletinWithTeacher(false);
+        $parameters->setBulletinPrintAddress(false);
+        $parameters->setBulletinSignatureDirector(true);
+        $parameters->setBulletinDisplayLevelAcquired(true);
+        $parameters->setBulletinShowEducationWithoutEvaluation(false);
+        $parameters->setBulletinViewTestResults(false);
+        $parameters->setBulletinShowAbsences(false);
+        $parameters->setBulletinShowAverages(true);
+        $parameters->setBulletinOutput('SomeOutput');
+        $parameters->setBulletinEditWithoutEvaluation(true);
+        $parameters->setBulletinReceiver('STUDENTS_AND_THEIR_GUARDIANS');
+        $parameters->setBulletinCriteriaSort('BY_CRITERIA_INSERT');
+        $parameters->setUsernameSMS('username');
+        $parameters->setPasswordSMS('password');
+        $parameters->setShowAdherentList(true);
+        $parameters->setStudentsAreAdherents(false);
+        $parameters->setTimezone('Europe/Paris');
+        $parameters->setEducationPeriodicity('ANNUAL');
+        $parameters->setAdvancedEducationNotationType('BY_EDUCATION');
+        $parameters->setSendAttendanceEmail(false);
+        $parameters->setSendAttendanceSms(false);
+        $parameters->setGenerateAttendanceReport(true);
+        $parameters->setConsultPedagogicResult(true);
+        $parameters->setConsultTeacherListing(true);
+        $parameters->setPeriodValidation(true);
+        $parameters->setNotifyAdministrationAbsence(false);
+        $root->setParameters($parameters);
+
+
+        $settings = new Settings();
+        $settings->setProduct('school');
+        $settings->setModules(['BillingAdministration']);
+        $root->setSettings($settings);
+
+        //create acesses with orga
+        $access = new Access();
+        $access->setOrganization($root);
+        $access->setRoles(["ROLE_ADMIN","ROLE_ADMIN_CORE","ROLE_SUPER_ADMIN"]);
+
+        $teacherAccess = new Access();
+        $teacherAccess->setOrganization($root);
+        $teacherAccess->setRoles(["ROLE_TEACHER"]);
+
+        // create a person :
+        $person = new Person();
+        $person->addAccess($access);
+        $person->setUsername('username');
+        $person->setPassword('password');
+
+
+        // create BillingSetting with an organization
+        $billingSetting = new BillingSetting();
+        $billingSetting->setOrganization($root);
+        $em->persist($billingSetting);
+
+
+
+        $residenceArea = new ResidenceArea();
+        $residenceArea->setLabel('label');
+        $residenceArea->setBillingSetting($billingSetting);
+
+        //create an AccessBilling with an access
+        $accessBilling = new AccessBilling();
+        $accessBilling->setAccess($access);
+        $accessBilling->setResidenceArea($residenceArea);
+
+        $education = new Education();
+        $educationCurriculum = new EducationCurriculum();
+        $cycleByEducation = new CycleByEducation();
+
+
+        $cycle = new Cycle();
+        $cycle->setOrganization($root);
+        $cycle->setLabel('cycle');
+        $cycle->setCycleEnum('CYCLE_1');
+        $cycle->setIsSystem(false);
+        $cycle->addCycleByEducation($cycleByEducation);
 
 
         // Booking
@@ -98,13 +192,22 @@ class OrganizationFixtures extends Fixture
         $end = $now->add(new \DateInterval('P1M1D'));
 
         $event = new Event();
-        $event->setOrganization($organization);
+        $event->setOrganization($root);
         $event->setName('My Event');
         $event->setDatetimeStart($start);
         $event->setDatetimeEnd($end);
         $event->setVisibility(VisibilityEnum::PUBLIC_VISIBILITY());
         $event->setUuid(Uuid::uuid());
+
+        $em->persist($root);
         $em->persist($event);
+        $em->persist($person);
+        $em->persist($access);
+        $em->persist($accessBilling);
+        $em->persist($billingSetting);
+        $em->persist($residenceArea);
+        $em->persist($subdomain);
+        $em->persist($parameters);
 
         $em->flush();
     }

+ 0 - 16
tests/Fixture/readme.md

@@ -1,16 +0,0 @@
-# Générer la DB de test et charger les fixtures
-
-Pour regénérer le SQL de création de la DB de test :
-
-    mysqldump --user=root --password=mysql660 --host=localhost --port=3306 --default-character-set=utf8 --single-transaction=TRUE --no-data --skip-triggers "opentalent" --column-statistics=0 > opentalent_test.sql
-
-    mysql --user=root --password=mysql660 --host=127.0.0.1 --port=3306 -D opentalent_test < opentalent_test.sql
-
-Il peut être nécessaire de regénérer les vues :
-
-    bin/console --env=staging doctrine:schema:update
-
-
-Pour recharger les fixtures :
-
-    bin/console --env=staging doctrine:fixtures:load

+ 0 - 0
tests/Fixture/Factory/Access/AccessFactory.php → tests/FixturesOld/Factory/Access/AccessFactory.php


+ 0 - 0
tests/Fixture/Factory/Organization/OrganizationFactory.php → tests/FixturesOld/Factory/Organization/OrganizationFactory.php


+ 0 - 0
tests/Fixture/Factory/Organization/SettingsFactory.php → tests/FixturesOld/Factory/Organization/SettingsFactory.php


+ 0 - 0
tests/Fixture/Factory/Person/PersonFactory.php → tests/FixturesOld/Factory/Person/PersonFactory.php


+ 111 - 0
tests/FixturesOld/OrganizationFixtures.php

@@ -0,0 +1,111 @@
+<?php
+
+namespace App\Tests\Fixture;
+
+use App\Entity\Booking\Event;
+use App\Entity\Core\ContactPoint;
+use App\Entity\Network\Network;
+use App\Entity\Network\NetworkOrganization;
+use App\Entity\Organization\Organization;
+use App\Entity\Organization\Parameters;
+use App\Enum\Booking\VisibilityEnum;
+use App\Enum\Core\ContactPointTypeEnum;
+use App\Enum\Organization\LegalEnum;
+use App\Enum\Organization\PrincipalTypeEnum;
+use Doctrine\Bundle\FixturesBundle\Fixture;
+use Doctrine\Persistence\ObjectManager;
+use Symfony\Component\Serializer\Context\SerializerContextBuilder;
+use App\Service\Utils\Uuid;
+
+class OrganizationFixtures extends Fixture
+{
+    public function load(ObjectManager $em): void
+    {
+        $network = new Network();
+        $network->setName('NET');
+        $em->persist($network);
+
+        // Create the root organization (opentalent)
+        $parameters0 = new Parameters();
+        $em->persist($parameters0);
+
+        $contactPoint0 = new ContactPoint();
+        $contactPoint0->setContactType(ContactPointTypeEnum::PRINCIPAL()->getValue());
+        $em->persist($contactPoint0);
+
+        $root = new Organization();
+        $root->setName('Root');
+        $root->setLegalStatus(LegalEnum::COMMERCIAL_SOCIETY()->getValue());
+        $root->setPrincipalType(PrincipalTypeEnum::NATIONAL_FEDERATION()->getValue());
+        $root->setParameters($parameters0);
+        $root->addContactPoint($contactPoint0);
+        $em->persist($root);
+
+        $networkOrganisation0 = new NetworkOrganization();
+        $networkOrganisation0->setOrganization($root);
+        $networkOrganisation0->setNetwork($network);
+        $em->persist($networkOrganisation0);
+
+
+        // Create a federation organization
+        $parameters1 = new Parameters();
+        $em->persist($parameters1);
+
+        $contactPoint1 = new ContactPoint();
+        $contactPoint1->setContactType(ContactPointTypeEnum::PRINCIPAL()->getValue());
+        $em->persist($contactPoint1);
+
+        $fede = new Organization();
+        $fede->setName('Fede 1');
+        $fede->setLegalStatus(LegalEnum::ASSOCIATION_LAW_1901()->getValue());
+        $fede->setPrincipalType(PrincipalTypeEnum::NATIONAL_FEDERATION()->getValue());
+        $fede->setParameters($parameters1);
+        $fede->addContactPoint($contactPoint1);
+        $em->persist($fede);
+
+        $networkOrganisation1 = new NetworkOrganization();
+        $networkOrganisation1->setOrganization($fede);
+        $networkOrganisation1->setNetwork($network);
+        $networkOrganisation1->setParent($root);
+        $em->persist($networkOrganisation1);
+
+        // Create a simple organization
+        $parameters2 = new Parameters();
+        $em->persist($parameters2);
+
+        $contactPoint2 = new ContactPoint();
+        $contactPoint2->setContactType(ContactPointTypeEnum::PRINCIPAL()->getValue());
+        $em->persist($contactPoint2);
+
+        $organization = new Organization();
+        $organization->setName('Organization 2');
+        $organization->setLegalStatus(LegalEnum::ASSOCIATION_LAW_1901()->getValue());
+        $organization->setPrincipalType(PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY()->getValue());
+        $organization->setParameters($parameters2);
+        $organization->addContactPoint($contactPoint2);
+        $em->persist($organization);
+
+        $networkOrganisation2 = new NetworkOrganization();
+        $networkOrganisation2->setOrganization($organization);
+        $networkOrganisation2->setNetwork($network);
+        $networkOrganisation2->setParent($fede);
+        $em->persist($networkOrganisation2);
+
+
+        // Booking
+        $now = new \DateTime('now');
+        $start = $now->add(new \DateInterval('P1M'));
+        $end = $now->add(new \DateInterval('P1M1D'));
+
+        $event = new Event();
+        $event->setOrganization($organization);
+        $event->setName('My Event');
+        $event->setDatetimeStart($start);
+        $event->setDatetimeEnd($end);
+        $event->setVisibility(VisibilityEnum::PUBLIC_VISIBILITY());
+        $event->setUuid(Uuid::uuid());
+        $em->persist($event);
+
+        $em->flush();
+    }
+}

+ 0 - 0
tests/Fixture/PersonFixtures.php → tests/FixturesOld/PersonFixtures.php


+ 34 - 0
tests/FixturesOld/readme.md

@@ -0,0 +1,34 @@
+# Générer la DB de test et charger les fixtures
+
+Pour regénérer le SQL de création de la DB de test :
+
+mysql --user=root --password=mysql660 --host=127.0.0.1 --port=3306
+DROP DATABASE opentalent_test;
+EXIT;
+
+Dans le docker mariaDb :
+
+    mysqldump --user=root --password=mysql660 --host=localhost --port=3306 --default-character-set=utf8 --single-transaction=TRUE --no-data --skip-triggers "opentalent" > opentalent_test.sql
+
+    Attention il faut créer la table manuellement avant
+
+    mysql --user=root --password=mysql660 --host=127.0.0.1 --port=3306
+
+    CREATE DATABASE opentalent_test;
+     EXIT;
+
+    mysql --user=root --password=mysql660 --host=127.0.0.1 --port=3306 -D opentalent_test < opentalent_test.sql
+
+Il peut être nécessaire de regénérer les vues dans ap2I :
+
+    bin/console --env=staging doctrine:schema:update
+
+Pour recharger les fixtures :
+
+bin/console --env=staging doctrine:fixtures:load
+
+php bin/phpunit tests/ApplicationPoc/PublicEventsTest
+php bin/phpunit --filter PublicEventsTest
+
+php bin/phpunit --filter ResidenceAreaTest
+

+ 29 - 18
tests/Unit/Service/Security/ModuleTest.php

@@ -4,21 +4,25 @@ namespace App\Tests\Unit\Service\Security;
 
 use App\Entity\Organization\Organization;
 use App\Entity\Organization\Settings;
-use App\Enum\Organization\SettingsProductEnum;
 use App\Service\Cotisation\Utils as CotisationUtils;
 use App\Service\Security\Module;
+use App\Service\Utils\Reflection;
 use App\Service\Utils\ConfigUtils;
+use App\Entity\Organization\Settings;
 use App\Service\Utils\Parser\YamlParser;
-use App\Service\Utils\Reflection;
-use Hoa\Iterator\Mock;
+use App\Entity\Organization\Organization;
 use PHPUnit\Framework\MockObject\MockObject;
-use PHPUnit\Framework\TestCase;
-use PHPUnit\Util\Test;
-use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
+use App\Enum\Organization\SettingsProductEnum;
+use App\Service\Cotisation\Utils as CotisationUtils;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
 
-class TestableModule extends Module {
-    public function getModuleByConditionsConfig(): array { return parent::getModuleByConditionsConfig(); }
+class TestableModule extends Module
+{
+    public function getModuleByConditionsConfig(): array
+    {
+        return parent::getModuleByConditionsConfig();
+    }
 }
 
 class ModuleTest extends TestCase
@@ -26,13 +30,14 @@ class ModuleTest extends TestCase
     private MockObject | Reflection $reflection;
     private MockObject | ParameterBagInterface $parameterBag;
 
-    public function setUp():void
+    public function setUp(): void
     {
         $this->reflection = $this->getMockBuilder(Reflection::class)->disableOriginalConstructor()->getMock();
         $this->parameterBag = $this->getMockBuilder(ParameterBagInterface::class)->disableOriginalConstructor()->getMock();
     }
 
-    public function getMockForMethod(string $methodName): MockObject | TestableModule {
+    public function getMockForMethod(string $methodName): MockObject | TestableModule
+    {
         return $this->getMockBuilder(TestableModule::class)
             ->setConstructorArgs([$this->reflection, $this->parameterBag])
             ->setMethodsExcept([$methodName])
@@ -150,8 +155,11 @@ class ModuleTest extends TestCase
     }
 
     /**
-     * @see Module::getModulesByProductConfiguration()
-     */
+ * @see Module::getModulesByProductConfiguration()
+ */
+    /**
+ * @see Module::getModulesByProductConfiguration()
+ */
     public function testGetModulesByProductConfigurationExtend(): void
     {
         $module = $this->getMockForMethod('getModulesByProductConfiguration');
@@ -159,7 +167,7 @@ class ModuleTest extends TestCase
         $this->parameterBag->method('get')->with('opentalent.products')->willReturn(
             [
                 'artist' => ['modules' => ['foo']],
-                'artist_premium' => ['extend' => 'artist', 'modules' => ['bar']]
+                'artist-premium' => ['extend' => 'artist', 'modules' => ['bar']]
             ]
         );
 
@@ -169,9 +177,10 @@ class ModuleTest extends TestCase
         ) ;
     }
 
+
     /**
-     * @see Module::getModulesByProductConfiguration()
-     */
+ * @see Module::getModulesByProductConfiguration()
+ */
     public function testGetModulesByProductConfigurationAccessDenied(): void
     {
         $module = $this->getMockBuilder(TestableModule::class);
@@ -183,7 +192,7 @@ class ModuleTest extends TestCase
         );
 
         $this->expectException(AccessDeniedHttpException::class);
-        $this->expectExceptionMessage('The product artist_premium does not exist !');
+        $this->expectExceptionMessage('The product artist-premium does not exist !');
 
         $module->getModulesByProductConfiguration(SettingsProductEnum::ARTIST_PREMIUM);
     }
@@ -191,7 +200,8 @@ class ModuleTest extends TestCase
     /**
      * @see Module::getModuleByResourceName()
      */
-    public function testGetModuleByResourceName(): void {
+    public function testGetModuleByResourceName(): void
+    {
         $module = $this->getMockForMethod('getModuleByResourceName');
 
         $this->parameterBag->method('get')->with('opentalent.modules')->willReturn(
@@ -204,7 +214,8 @@ class ModuleTest extends TestCase
     /**
      * @see Module::getModuleByResourceName()
      */
-    public function testGetModuleByResourceNameNotFound(): void {
+    public function testGetModuleByResourceNameNotFound(): void
+    {
         $module = $this->getMockForMethod('getModuleByResourceName');
 
         $this->parameterBag->method('get')->with('opentalent.modules')->willReturn(