Sfoglia il codice sorgente

Implements HelloAsso event forms retrieval

Adds functionality to retrieve HelloAsso event forms, replacing the previous organization form retrieval.
It introduces a new `EventForm` API resource and provider, and refactors the HelloAsso service to fetch and map event form data from the HelloAsso API, including fetching a form by event ID.
The changes also include updating the product configuration, adding HelloAsso slug and URL to the Event entity to link event with helloasso form.
Olivier Massot 11 mesi fa
parent
commit
f804d9d0e2

+ 1 - 1
config/opentalent/products.yaml

@@ -38,7 +38,7 @@ parameters:
           - ConnectionRequest
           - ConnectionRequest
           - UnlinkRequest
           - UnlinkRequest
           - HelloAssoProfile
           - HelloAssoProfile
-          - OrganizationForm
+          - EventForm
         roles:
         roles:
           - ROLE_IMPORT
           - ROLE_IMPORT
           - ROLE_TAGG
           - ROLE_TAGG

+ 44 - 13
src/ApiResources/HelloAsso/EventForm.php

@@ -8,68 +8,99 @@ use ApiPlatform\Metadata\ApiProperty;
 use ApiPlatform\Metadata\ApiResource;
 use ApiPlatform\Metadata\ApiResource;
 use ApiPlatform\Metadata\Get;
 use ApiPlatform\Metadata\Get;
 use ApiPlatform\Metadata\GetCollection;
 use ApiPlatform\Metadata\GetCollection;
+use ApiPlatform\Metadata\Link;
 use App\State\Provider\HelloAsso\AuthUrlProvider;
 use App\State\Provider\HelloAsso\AuthUrlProvider;
 use App\State\Provider\HelloAsso\HelloAssoProfileProvider;
 use App\State\Provider\HelloAsso\HelloAssoProfileProvider;
-use App\State\Provider\HelloAsso\OrganizationFormProvider;
+use App\State\Provider\HelloAsso\EventFormProvider;
 
 
 /**
 /**
  * Retourne les formulaires d'une organisation.
  * Retourne les formulaires d'une organisation.
  */
  */
 #[ApiResource(
 #[ApiResource(
     operations: [
     operations: [
+        new GetCollection(
+            uriTemplate: '/helloasso/forms',
+        ),
         new Get(
         new Get(
-            uriTemplate: '/helloasso/form/{eventId}',
+            uriTemplate: '/helloasso/form/{slug}',
+        ),
+        new Get(
+            uriTemplate: '/helloasso/form/by-event/{eventId}',
+            uriVariables: [
+                'eventId' => new Link(
+                    fromProperty: 'eventId',
+                    identifiers: ['eventId']
+                )
+            ]
         )
         )
     ],
     ],
-    provider: OrganizationFormProvider::class,
+    provider: EventFormProvider::class,
     security: 'is_granted("ROLE_ORGANIZATION")'
     security: 'is_granted("ROLE_ORGANIZATION")'
 )]
 )]
-class OrganizationForm
+class EventForm
 {
 {
     /**
     /**
      * Slug du formulaire
      * Slug du formulaire
      */
      */
-    private string $slug;
+    #[ApiProperty(identifier: true)]
+    private ?string $slug = null;
+
+    /**
+     * Id de l'Event auquel le formulaire est associé
+     * @var int | null
+     */
+    private ?int $eventId = null;
 
 
     /**
     /**
      * Titre du formulaire
      * Titre du formulaire
      * @var bool
      * @var bool
      */
      */
-    private string $title;
+    private ?string $title = null;
 
 
     /**
     /**
      * Url du formulaire
      * Url du formulaire
      */
      */
-    private string $widgetUrl;
+    private ?string $widgetUrl = null;
 
 
-    public function getSlug(): string
+    public function getSlug(): ?string
     {
     {
         return $this->slug;
         return $this->slug;
     }
     }
 
 
-    public function setSlug(string $slug): self
+    public function setSlug(?string $slug): self
     {
     {
         $this->slug = $slug;
         $this->slug = $slug;
         return $this;
         return $this;
     }
     }
 
 
-    public function getTitle(): string
+    public function getEventId(): ?int
+    {
+        return $this->eventId;
+    }
+
+    public function setEventId(?int $eventId): self
+    {
+        $this->eventId = $eventId;
+        return $this;
+    }
+
+    public function getTitle(): ?string
     {
     {
         return $this->title;
         return $this->title;
     }
     }
 
 
-    public function setTitle(string $title): self
+    public function setTitle(?string $title): self
     {
     {
         $this->title = $title;
         $this->title = $title;
         return $this;
         return $this;
     }
     }
 
 
-    public function getWidgetUrl(): string
+    public function getWidgetUrl(): ?string
     {
     {
         return $this->widgetUrl;
         return $this->widgetUrl;
     }
     }
 
 
-    public function setWidgetUrl(string $widgetUrl): self
+    public function setWidgetUrl(?string $widgetUrl): self
     {
     {
         $this->widgetUrl = $widgetUrl;
         $this->widgetUrl = $widgetUrl;
         return $this;
         return $this;

+ 28 - 0
src/Entity/Booking/Event.php

@@ -117,6 +117,12 @@ class Event extends AbstractBooking
     #[Assert\Positive]
     #[Assert\Positive]
     protected ?float $priceMaxi = null;
     protected ?float $priceMaxi = null;
 
 
+    #[ORM\Column(length: 255, nullable: true)]
+    private ?string $helloAssoSlug = null;
+
+    #[ORM\Column(length: 255, nullable: true)]
+    private ?string $helloAssoPublicUrl = null;
+
     public function __construct()
     public function __construct()
     {
     {
         $this->eventRecur = new ArrayCollection();
         $this->eventRecur = new ArrayCollection();
@@ -474,4 +480,26 @@ class Event extends AbstractBooking
         $this->priceMaxi = $priceMaxi;
         $this->priceMaxi = $priceMaxi;
         return $this;
         return $this;
     }
     }
+
+    public function getHelloAssoSlug(): ?string
+    {
+        return $this->helloAssoSlug;
+    }
+
+    public function setHelloAssoSlug(?string $helloAssoSlug): self
+    {
+        $this->helloAssoSlug = $helloAssoSlug;
+        return $this;
+    }
+
+    public function getHelloAssoPublicUrl(): ?string
+    {
+        return $this->helloAssoPublicUrl;
+    }
+
+    public function setHelloAssoPublicUrl(?string $helloAssoPublicUrl): self
+    {
+        $this->helloAssoPublicUrl = $helloAssoPublicUrl;
+        return $this;
+    }
 }
 }

+ 102 - 30
src/Service/HelloAsso/HelloAssoService.php

@@ -6,9 +6,12 @@ namespace App\Service\HelloAsso;
 
 
 use App\ApiResources\HelloAsso\AuthUrl;
 use App\ApiResources\HelloAsso\AuthUrl;
 use App\ApiResources\HelloAsso\HelloAssoProfile;
 use App\ApiResources\HelloAsso\HelloAssoProfile;
-use App\ApiResources\HelloAsso\OrganizationForm;
+use App\ApiResources\HelloAsso\EventForm;
+use App\Entity\Booking\Event;
 use App\Entity\HelloAsso\HelloAsso;
 use App\Entity\HelloAsso\HelloAsso;
 use App\Entity\Organization\Organization;
 use App\Entity\Organization\Organization;
+use App\Repository\Booking\EventRepository;
+use App\Repository\Organization\OrganizationRepository;
 use App\Service\Rest\ApiRequestService;
 use App\Service\Rest\ApiRequestService;
 use App\Service\Security\OAuthPkceGenerator;
 use App\Service\Security\OAuthPkceGenerator;
 use App\Service\Utils\DatesUtils;
 use App\Service\Utils\DatesUtils;
@@ -17,7 +20,9 @@ use Doctrine\Common\Collections\Collection;
 use Doctrine\ORM\EntityManagerInterface;
 use Doctrine\ORM\EntityManagerInterface;
 use Psr\Log\LoggerInterface;
 use Psr\Log\LoggerInterface;
 use Symfony\Component\HttpKernel\Exception\HttpException;
 use Symfony\Component\HttpKernel\Exception\HttpException;
+use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
 use Symfony\Contracts\HttpClient\HttpClientInterface;
 use Symfony\Contracts\HttpClient\HttpClientInterface;
+use Symfony\Contracts\HttpClient\ResponseInterface;
 
 
 /**
 /**
  * Service de connexion à HelloAsso.
  * Service de connexion à HelloAsso.
@@ -29,6 +34,8 @@ class HelloAssoService extends ApiRequestService
 {
 {
     public function __construct(
     public function __construct(
         HttpClientInterface $client,
         HttpClientInterface $client,
+        private readonly OrganizationRepository $organizationRepository,
+        private readonly EventRepository $eventRepository,
         private readonly string $baseUrl,
         private readonly string $baseUrl,
         private readonly string $publicAppBaseUrl,
         private readonly string $publicAppBaseUrl,
         private readonly string $helloAssoApiBaseUrl,
         private readonly string $helloAssoApiBaseUrl,
@@ -66,7 +73,7 @@ class HelloAssoService extends ApiRequestService
      */
      */
     public function getAuthUrl(int $organizationId): AuthUrl
     public function getAuthUrl(int $organizationId): AuthUrl
     {
     {
-        $organization = $this->entityManager->getRepository(Organization::class)->find($organizationId);
+        $organization = $this->organizationRepository->find($organizationId);
 
 
         if (!$organization) {
         if (!$organization) {
             throw new \RuntimeException('Organization not found');
             throw new \RuntimeException('Organization not found');
@@ -114,7 +121,7 @@ class HelloAssoService extends ApiRequestService
      */
      */
     public function connect(int $organizationId, string $authorizationCode): HelloAsso
     public function connect(int $organizationId, string $authorizationCode): HelloAsso
     {
     {
-        $organization = $this->entityManager->getRepository(Organization::class)->find($organizationId);
+        $organization = $this->organizationRepository->find($organizationId);
         if (!$organization) {
         if (!$organization) {
             throw new \RuntimeException('Organization not found');
             throw new \RuntimeException('Organization not found');
         }
         }
@@ -154,7 +161,7 @@ class HelloAssoService extends ApiRequestService
      */
      */
     public function makeHelloAssoProfile(int $organizationId): HelloAssoProfile
     public function makeHelloAssoProfile(int $organizationId): HelloAssoProfile
     {
     {
-        $organization = $this->entityManager->getRepository(Organization::class)->find($organizationId);
+        $organization = $this->organizationRepository->find($organizationId);
         if (!$organization) {
         if (!$organization) {
             throw new \RuntimeException('Organization not found');
             throw new \RuntimeException('Organization not found');
         }
         }
@@ -175,7 +182,7 @@ class HelloAssoService extends ApiRequestService
 
 
     public function unlinkHelloAssoAccount(int $organizationId): void
     public function unlinkHelloAssoAccount(int $organizationId): void
     {
     {
-        $organization = $this->entityManager->getRepository(Organization::class)->find($organizationId);
+        $organization = $this->organizationRepository->find($organizationId);
         if (!$organization) {
         if (!$organization) {
             throw new \RuntimeException('Organization not found');
             throw new \RuntimeException('Organization not found');
         }
         }
@@ -195,28 +202,20 @@ class HelloAssoService extends ApiRequestService
         $this->entityManager->flush();
         $this->entityManager->flush();
     }
     }
 
 
-    public function getHelloAssoForms(int $organizationId): array
-    {
-        $organization = $this->entityManager->getRepository(Organization::class)->find($organizationId);
-        if (!$organization) {
-            throw new \RuntimeException('Organization not found');
-        }
-
-        $helloAssoEntity = $organization->getHelloAsso();
-        if (!$helloAssoEntity) {
-            throw new \RuntimeException('HelloAsso entity not found');
-        }
+    public function getResource(HelloAsso $helloAssoEntity, array $routeParts): array {
         if (!$helloAssoEntity->getOrganizationSlug() || !$helloAssoEntity->getToken()) {
         if (!$helloAssoEntity->getOrganizationSlug() || !$helloAssoEntity->getToken()) {
             throw new \RuntimeException('HelloAsso entity incomplete');
             throw new \RuntimeException('HelloAsso entity incomplete');
         }
         }
 
 
         $helloAssoEntity = $this->refreshTokenIfNeeded($helloAssoEntity);
         $helloAssoEntity = $this->refreshTokenIfNeeded($helloAssoEntity);
 
 
+        $url = UrlBuilder::concat(
+            $this->helloAssoApiBaseUrl,
+            array_merge(['/v5'], $routeParts),
+        );
+
         $response = $this->get(
         $response = $this->get(
-            UrlBuilder::concat(
-                $this->helloAssoApiBaseUrl,
-                ['/v5/organizations', $helloAssoEntity->getOrganizationSlug(), '/forms']
-            ),
+            $url,
             [],
             [],
             ['headers' =>
             ['headers' =>
                 [
                 [
@@ -227,25 +226,98 @@ class HelloAssoService extends ApiRequestService
         );
         );
 
 
         if ($response->getStatusCode() !== 200) {
         if ($response->getStatusCode() !== 200) {
-            throw new HttpException(500, 'Failed to fetch access token: '.$response->getContent(false));
+            throw new HttpException(
+                500,
+                'Failed to fetch resource: ['.$response->getStatusCode().'] '.$response->getContent(false)
+            );
         }
         }
 
 
-        $data = json_decode($response->getContent(), true, 512, JSON_THROW_ON_ERROR)['data'];
+        return json_decode($response->getContent(), true, 512, JSON_THROW_ON_ERROR);
+    }
 
 
-        $forms = [];
+    public function getHelloAssoEventForms(int $organizationId): array
+    {
+        $helloAssoEntity = $this->getHelloAssoEntityFor($organizationId);
+
+        $data = $this->getResource(
+            $helloAssoEntity,
+            ['organizations', $helloAssoEntity->getOrganizationSlug(), 'forms']
+        );
 
 
-        foreach ($data as $formData) {
-            $form = new OrganizationForm();
-            $form->setSlug($formData['formSlug']);
-            $form->setTitle($formData['title']);
-            $form->setUrl($formData['url']);
+        $forms = [];
 
 
-            $forms[] = $form;
+        foreach ($data['data'] as $formData) {
+            $forms[] = $this->makeHelloAssoEventForm($formData);
         }
         }
 
 
         return $forms;
         return $forms;
     }
     }
 
 
+    public function getHelloAssoEventForm(int $organizationId, string $formSlug): EventForm
+    {
+        $helloAssoEntity = $this->getHelloAssoEntityFor($organizationId);
+
+        if (!$helloAssoEntity->getOrganizationSlug() || !$helloAssoEntity->getToken()) {
+            throw new \RuntimeException('HelloAsso entity incomplete');
+        }
+
+        $formType = 'Event';
+
+        $data = $this->getResource(
+            $helloAssoEntity,
+            ['organizations', $helloAssoEntity->getOrganizationSlug(), 'forms', $formType, $formSlug, 'public']
+        );
+
+        return $this->makeHelloAssoEventForm($data);
+    }
+
+    public function getHelloAssoEventFormByEventId(int $organizationId, int $eventId): EventForm
+    {
+        $helloAssoEntity = $this->getHelloAssoEntityFor($organizationId);
+
+        if (!$helloAssoEntity->getOrganizationSlug() || !$helloAssoEntity->getToken()) {
+            throw new \RuntimeException('HelloAsso entity incomplete');
+        }
+
+        $event = $this->eventRepository->find($eventId);
+        if (!$event) {
+            throw new \RuntimeException('Event not found');
+        }
+
+        $helloAssoFormSlug = $event->getHelloAssoSlug();
+        if (!$helloAssoFormSlug) {
+            throw new \RuntimeException('HelloAsso form slug not found');
+        }
+
+        return $this->getHelloAssoEventForm($organizationId, $helloAssoFormSlug);
+    }
+
+    protected function getHelloAssoEntityFor(int $organizationId): HelloAsso
+    {
+        $organization = $this->organizationRepository->find($organizationId);
+        if (!$organization) {
+            throw new \RuntimeException('Organization not found');
+        }
+        $helloAssoEntity = $organization->getHelloAsso();
+        if (!$helloAssoEntity) {
+            throw new \RuntimeException('HelloAsso entity not found');
+        }
+        return $helloAssoEntity;
+    }
+
+    /**
+     * Construit un objet EventForm à partir des données retournées par l'api HelloAsso.
+     * @param array $formData
+     * @return EventForm
+     */
+    protected function makeHelloAssoEventForm(array $formData): EventForm {
+        $form = new EventForm();
+        $form->setSlug($formData['formSlug']);
+        $form->setTitle($formData['title']);
+        $form->setWidgetUrl($formData['widgetFullUrl']);
+
+        return $form;
+    }
 
 
     /**
     /**
      * Génère l'URL de rappel pour les callbacks suite à l'authentification HelloAsso
      * Génère l'URL de rappel pour les callbacks suite à l'authentification HelloAsso
@@ -351,7 +423,7 @@ class HelloAssoService extends ApiRequestService
             return $helloAssoEntity;
             return $helloAssoEntity;
         }
         }
 
 
-        return $this->refreshToken($helloAssoEntity);
+        return $this->refreshTokens($helloAssoEntity);
     }
     }
 
 
     public function refreshTokens(HelloAsso $helloAssoEntity): HelloAsso {
     public function refreshTokens(HelloAsso $helloAssoEntity): HelloAsso {

+ 5 - 3
src/State/Provider/HelloAsso/EventFormProvider.php

@@ -19,7 +19,7 @@ use Symfony\Component\HttpFoundation\Response;
 /**
 /**
  * Provider pour la ressource HelloAssoProfile.
  * Provider pour la ressource HelloAssoProfile.
  */
  */
-final class OrganizationFormProvider implements ProviderInterface
+final class EventFormProvider implements ProviderInterface
 {
 {
     public function __construct(
     public function __construct(
         private HelloAssoService $helloAssoService,
         private HelloAssoService $helloAssoService,
@@ -41,11 +41,13 @@ final class OrganizationFormProvider implements ProviderInterface
         $organizationId = $access->getOrganization()->getId();
         $organizationId = $access->getOrganization()->getId();
 
 
         if ($operation instanceof GetCollection) {
         if ($operation instanceof GetCollection) {
-            $forms = $this->helloAssoService->getHelloAssoForms($organizationId);
+            $forms = $this->helloAssoService->getHelloAssoEventForms($organizationId);
 
 
             return new ArrayCollection($forms);
             return new ArrayCollection($forms);
+        } else if (isset($uriVariables['eventId'])) {
+            return $this->helloAssoService->getHelloAssoEventFormByEventId($organizationId, $uriVariables['eventId']);
         } else {
         } else {
-            $form = $this->helloAssoService->getHelloAssoEventForm($organizationId, $uriVariables['id']);
+            return $this->helloAssoService->getHelloAssoEventForm($organizationId, $uriVariables['slug']);
         }
         }
     }
     }
 }
 }