|
@@ -6,12 +6,14 @@ 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\Entity\HelloAsso\HelloAsso;
|
|
use App\Entity\HelloAsso\HelloAsso;
|
|
|
use App\Entity\Organization\Organization;
|
|
use App\Entity\Organization\Organization;
|
|
|
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;
|
|
|
use App\Service\Utils\UrlBuilder;
|
|
use App\Service\Utils\UrlBuilder;
|
|
|
|
|
+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;
|
|
@@ -23,7 +25,7 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
|
|
|
* @see doc/helloasso.md
|
|
* @see doc/helloasso.md
|
|
|
* @see https://dev.helloasso.com/docs/mire-authorisation
|
|
* @see https://dev.helloasso.com/docs/mire-authorisation
|
|
|
*/
|
|
*/
|
|
|
-class ConnectionService extends ApiRequestService
|
|
|
|
|
|
|
+class HelloAssoService extends ApiRequestService
|
|
|
{
|
|
{
|
|
|
public function __construct(
|
|
public function __construct(
|
|
|
HttpClientInterface $client,
|
|
HttpClientInterface $client,
|
|
@@ -193,6 +195,58 @@ class ConnectionService 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');
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!$helloAssoEntity->getOrganizationSlug() || !$helloAssoEntity->getToken()) {
|
|
|
|
|
+ throw new \RuntimeException('HelloAsso entity incomplete');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $helloAssoEntity = $this->refreshTokenIfNeeded($helloAssoEntity);
|
|
|
|
|
+
|
|
|
|
|
+ $response = $this->get(
|
|
|
|
|
+ UrlBuilder::concat(
|
|
|
|
|
+ $this->helloAssoApiBaseUrl,
|
|
|
|
|
+ ['/v5/organizations', $helloAssoEntity->getOrganizationSlug(), '/forms']
|
|
|
|
|
+ ),
|
|
|
|
|
+ [],
|
|
|
|
|
+ ['headers' =>
|
|
|
|
|
+ [
|
|
|
|
|
+ 'accept' => 'application/json',
|
|
|
|
|
+ 'authorization' => 'Bearer '.$helloAssoEntity->getToken(),
|
|
|
|
|
+ ]
|
|
|
|
|
+ ]
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if ($response->getStatusCode() !== 200) {
|
|
|
|
|
+ throw new HttpException(500, 'Failed to fetch access token: '.$response->getContent(false));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $data = json_decode($response->getContent(), true, 512, JSON_THROW_ON_ERROR)['data'];
|
|
|
|
|
+
|
|
|
|
|
+ $forms = [];
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($data as $formData) {
|
|
|
|
|
+ $form = new OrganizationForm();
|
|
|
|
|
+ $form->setSlug($formData['formSlug']);
|
|
|
|
|
+ $form->setTitle($formData['title']);
|
|
|
|
|
+ $form->setUrl($formData['url']);
|
|
|
|
|
+
|
|
|
|
|
+ $forms[] = $form;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return $forms;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 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
|
|
|
*
|
|
*
|
|
@@ -285,4 +339,47 @@ class ConnectionService extends ApiRequestService
|
|
|
throw new HttpException(500, 'Failed to update domain: '.$response->getContent());
|
|
throw new HttpException(500, 'Failed to update domain: '.$response->getContent());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ protected function refreshTokenIfNeeded(HelloAsso $helloAssoEntity): HelloAsso {
|
|
|
|
|
+ if (!$helloAssoEntity->getRefreshToken() || !$helloAssoEntity->getRefreshTokenCreatedAt()) {
|
|
|
|
|
+ throw new \RuntimeException('HelloAsso entity incomplete');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Les tokens ont une durée de validité de 30min, on les rafraichit passé 25min.
|
|
|
|
|
+ $needsRefreshing = $helloAssoEntity->getRefreshTokenCreatedAt()->add(new \DateInterval('PT25M')) < DatesUtils::new();
|
|
|
|
|
+ if (!$needsRefreshing) {
|
|
|
|
|
+ return $helloAssoEntity;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $body = [
|
|
|
|
|
+ 'grant_type' => 'refresh_token',
|
|
|
|
|
+ 'refresh_token' => $helloAssoEntity->getRefreshToken(),
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ $response = $this->client->request('POST',
|
|
|
|
|
+ UrlBuilder::concat($this->helloAssoApiBaseUrl, ['/oauth2/token']),
|
|
|
|
|
+ [
|
|
|
|
|
+ 'headers' => [
|
|
|
|
|
+ 'Content-Type' => 'application/x-www-form-urlencoded',
|
|
|
|
|
+ ],
|
|
|
|
|
+ 'body' => $body,
|
|
|
|
|
+ ]
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if ($response->getStatusCode() !== 200) {
|
|
|
|
|
+ throw new HttpException(500, 'Failed to refresh access token: '.$response->getContent(false));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $data = json_decode($response->getContent(), true, 512, JSON_THROW_ON_ERROR);
|
|
|
|
|
+
|
|
|
|
|
+ $helloAssoEntity->setToken($data['access_token']);
|
|
|
|
|
+ $helloAssoEntity->setTokenCreatedAt(DatesUtils::new());
|
|
|
|
|
+ $helloAssoEntity->setRefreshToken($data['refresh_token']);
|
|
|
|
|
+ $helloAssoEntity->setRefreshTokenCreatedAt(DatesUtils::new());
|
|
|
|
|
+
|
|
|
|
|
+ $this->entityManager->persist($helloAssoEntity);
|
|
|
|
|
+ $this->entityManager->flush();
|
|
|
|
|
+
|
|
|
|
|
+ return $helloAssoEntity;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|