Skip to content

Commit 7959d44

Browse files
authored
Merge pull request #28 from HelloAsso/add-crowd-compatibility
Add crowd compatibility
2 parents 0202802 + 8462cda commit 7959d44

15 files changed

Lines changed: 412 additions & 183 deletions

File tree

.github/workflows/php-sandbox.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Build & deploy sandbox
22

33
on:
44
push:
5-
branches: [ "develop" ]
5+
branches: [ "develop", "add-crowd-compatibility" ]
66
workflow_dispatch:
77

88
permissions:
@@ -69,7 +69,7 @@ jobs:
6969

7070
- name: Tar
7171
run : |
72-
tar czvf artifact.tar.gz migrations public src vendor .env cron.php
72+
tar czv --ignore-failed-read -f artifact.tar.gz migrations public src vendor .env cron.php 2>/dev/null || tar czv -f artifact.tar.gz migrations public src vendor .env cron.php
7373
7474
- name: Upload
7575
run : |

migrations/15-add-form-type.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
ALTER TABLE {prefix}charity_stream ADD COLUMN form_type VARCHAR(50) NOT NULL DEFAULT 'Donation' AFTER form_slug;
2+
3+

src/Assets/js/admin.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ if (cardWidgetForm) {
100100
}
101101
if (goalEl) goalEl.innerHTML = `Objectif : <strong>${goalValue} €</strong>`;
102102
if (pct) pct.textContent = '50%';
103+
104+
const cta = document.getElementById('cardPreviewCta');
105+
if (cta) {
106+
cta.style.color = tagColor;
107+
cta.style.backgroundColor = tagBgColor;
108+
}
103109
}
104110

105111
bindPreviewInputs(

src/Controllers/AdminController.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ public function newStream(Request $request, Response $response): Response
316316
$event = $this->eventRepository->selectByUserAndId($user, $parentEvent);
317317
}
318318

319-
$stream = $this->streamRepository->insert($data['form_slug'], $data['organization_slug'], $data['title'], $event->id ?? null);
319+
$stream = $this->streamRepository->insert($data['form_slug'], $data['organization_slug'], $data['title'], $event->id ?? null, $data['form_type'] ?? 'Donation');
320320
$this->userRepository->insertRight($owner, $stream, null);
321321

322322
if ($event !== null && $parentStyle) {
@@ -376,7 +376,8 @@ public function editStream(Request $request, Response $response, array $args): R
376376
$availableEvents = $this->eventRepository->selectListByUser($user);
377377
}
378378

379-
$donationUrl = $_SERVER['HA_URL'] . '/associations/' . $charityStream->organization_slug . '/formulaires/' . $charityStream->form_slug;
379+
$formTypeUrlSegment = ($charityStream->form_type === 'CrowdFunding') ? 'collectes' : 'formulaires';
380+
$donationUrl = $_SERVER['HA_URL'] . '/associations/' . $charityStream->organization_slug . '/' . $formTypeUrlSegment . '/' . $charityStream->form_slug;
380381
$routeParser = RouteContext::fromRequest($request)->getRouteParser();
381382

382383
$data = [
@@ -552,8 +553,8 @@ public function streamAuthCallback(Request $request, Response $response): Respon
552553
// Stocker / mettre à jour les tokens
553554
$this->apiWrapper->storeOrUpdateToken($tokenData);
554555

555-
// Récupérer les formulaires de don
556-
$forms = $this->apiWrapper->getDonationForms($organizationSlug);
556+
// Récupérer les formulaires de don et de crowdfunding
557+
$forms = $this->apiWrapper->getOrganizationForms($organizationSlug, ['Donation', 'CrowdFunding']);
557558
} catch (Exception $e) {
558559
$response->getBody()->write($this->buildCallbackPage(null, [], $e->getMessage()));
559560
return $response;

src/Controllers/ApiController.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,20 @@ public function new(Request $request, Response $response): Response
2323
$formSlug = $data['form_slug'] ?? null;
2424
$organizationSlug = $data['organization_slug'] ?? null;
2525
$title = $data['title'] ?? null;
26+
$formType = $data['form_type'] ?? 'Donation';
27+
28+
// Valider le form_type
29+
$allowedFormTypes = ['Donation', 'CrowdFunding'];
30+
if (!in_array($formType, $allowedFormTypes)) {
31+
$formType = 'Donation';
32+
}
2633

2734
if (!$ownerEmail || !$formSlug || !$organizationSlug || !$title) {
2835
$response->getBody()->write(json_encode(['error' => 'all fields are mandatory']));
2936
return $response->withStatus(400)->withHeader('Content-Type', 'application/json');
3037
}
3138

32-
$stream = $this->streamRepository->insert($formSlug, $organizationSlug, $title);
39+
$stream = $this->streamRepository->insert($formSlug, $organizationSlug, $title, null, $formType);
3340
$user = $this->userRepository->findOrCreate($ownerEmail);
3441
$this->userRepository->insertRight($user, $stream, null);
3542
$this->userRepository->insertResetToken($user);

src/Controllers/WidgetController.php

Lines changed: 183 additions & 144 deletions
Large diffs are not rendered by default.

src/Models/Stream.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class Stream
1010
public $title;
1111
public $goal;
1212
public $form_slug;
13+
public $form_type = 'Donation';
1314
public $organization_slug;
1415
public $creation_date;
1516
public $last_update;

src/Repositories/StreamRepository.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,19 +109,20 @@ public function selectByUserAndGuid(User $user, string $guid): ?Stream
109109
return $stream ?: null;
110110
}
111111

112-
public function insert(string $form_slug, string $organization_slug, string $title, ?int $parent = null): Stream
112+
public function insert(string $form_slug, string $organization_slug, string $title, ?int $parent = null, string $form_type = 'Donation'): Stream
113113
{
114114
$guid = bin2hex(random_bytes(16));
115115

116116
$this->pdo->beginTransaction();
117117

118118
try {
119-
$query = 'INSERT INTO ' . $this->prefix . 'charity_stream (guid, form_slug, organization_slug, title, charity_event_id)
120-
VALUES (:guid, :form_slug, :organization_slug, :title, :charity_event_id)';
119+
$query = 'INSERT INTO ' . $this->prefix . 'charity_stream (guid, form_slug, form_type, organization_slug, title, charity_event_id)
120+
VALUES (:guid, :form_slug, :form_type, :organization_slug, :title, :charity_event_id)';
121121
$stmt = $this->pdo->prepare($query);
122122
$stmt->execute([
123123
':guid' => $guid,
124124
':form_slug' => $form_slug,
125+
':form_type' => $form_type,
125126
':organization_slug' => $organization_slug,
126127
':title' => $title,
127128
':charity_event_id' => $parent
@@ -158,6 +159,7 @@ public function insert(string $form_slug, string $organization_slug, string $tit
158159
$stream->id = $id;
159160
$stream->guid = $guid;
160161
$stream->form_slug = $form_slug;
162+
$stream->form_type = $form_type;
161163
$stream->organization_slug = $organization_slug;
162164
$stream->title = $title;
163165
return $stream;

src/Services/ApiWrapper.php

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -363,31 +363,49 @@ public function generateAuthorizationUrl(?string $organizationSlug, ?string $red
363363
}
364364

365365
/**
366-
* Récupère la liste des formulaires de don d'une organisation.
366+
* Récupère la liste des formulaires d'une organisation pour les types donnés.
367367
*
368368
* @param string $organizationSlug
369+
* @param array $formTypes Liste des types de formulaires à récupérer (ex: ['Donation', 'CrowdFunding'])
369370
* @return array
370371
*/
371-
public function getDonationForms(string $organizationSlug): array
372+
public function getOrganizationForms(string $organizationSlug, array $formTypes = ['Donation', 'CrowdFunding']): array
372373
{
373374
$tokenData = $this->getOrganizationAccessToken($organizationSlug);
374375

375-
$response = $this->httpRequest('GET', "{$this->apiUrl}/organizations/{$organizationSlug}/forms", [
376-
'query' => [
377-
'formTypes' => 'Donation',
378-
'pageSize' => 50,
379-
],
376+
// Construire la query string manuellement car Guzzle sérialise les arrays
377+
// avec des indices PHP (formTypes[0]=...) que l'API HelloAsso ne supporte pas.
378+
// L'API attend : formTypes=Donation&formTypes=CrowdFunding
379+
$queryParts = [];
380+
foreach ($formTypes as $type) {
381+
$queryParts[] = 'formTypes=' . urlencode($type);
382+
}
383+
$queryParts[] = 'pageSize=50';
384+
$queryString = implode('&', $queryParts);
385+
386+
$response = $this->httpRequest('GET', "{$this->apiUrl}/organizations/{$organizationSlug}/forms?{$queryString}", [
380387
'headers' => [
381388
'Authorization' => 'Bearer ' . $tokenData->access_token,
382389
'accept' => 'application/json',
383390
],
384-
], "la récupération des formulaires de don pour {$organizationSlug}");
391+
], "la récupération des formulaires pour {$organizationSlug}");
385392

386393
$data = $this->decodeJsonResponse($response);
387394

388395
return $data['data'] ?? [];
389396
}
390397

398+
/**
399+
* Récupère la liste des formulaires de don d'une organisation.
400+
*
401+
* @param string $organizationSlug
402+
* @return array
403+
*/
404+
public function getDonationForms(string $organizationSlug): array
405+
{
406+
return $this->getOrganizationForms($organizationSlug, ['Donation']);
407+
}
408+
391409
/**
392410
* Configure le domaine du client API pour une organisation donnée en utilisant un token d'accès valide.
393411
*
@@ -480,16 +498,18 @@ public function exchangeAuthorizationCode(string $code, string $redirectUri, str
480498
* @param [type] $continuationToken
481499
* @return array
482500
*/
483-
private function getDonationFormOrders(string $organizationSlug, string $donationSlug, string $accessToken, ?string $continuationToken = null): array
501+
private function getDonationFormOrders(string $organizationSlug, string $donationSlug, string $accessToken, ?string $continuationToken = null, string $formType = 'Donation'): array
484502
{
485503
$query = ['withDetails' => 'true', 'sortOrder' => 'asc', 'pageSize' => 100];
486504
if ($continuationToken) {
487505
$query['continuationToken'] = $continuationToken;
488506
}
489507

508+
$formTypePath = $formType ?: 'Donation';
509+
490510
$response = $this->httpRequest(
491511
'GET',
492-
"{$this->apiUrl}/organizations/{$organizationSlug}/forms/donation/{$donationSlug}/orders",
512+
"{$this->apiUrl}/organizations/{$organizationSlug}/forms/{$formTypePath}/{$donationSlug}/orders",
493513
[
494514
'query' => $query,
495515
'headers' => [
@@ -512,7 +532,7 @@ private function getDonationFormOrders(string $organizationSlug, string $donatio
512532
* @param [type] $continuationToken
513533
* @return array
514534
*/
515-
public function getAllOrders(string $organizationSlug, string $formSlug, int $currentAmount = 0, ?string $continuationToken = null): array
535+
public function getAllOrders(string $organizationSlug, string $formSlug, int $currentAmount = 0, ?string $continuationToken = null, string $formType = 'Donation'): array
516536
{
517537
$previousToken = '';
518538
$donations = [];
@@ -539,7 +559,8 @@ public function getAllOrders(string $organizationSlug, string $formSlug, int $cu
539559
$organizationSlug,
540560
$formSlug,
541561
$organizationAccessToken->access_token,
542-
$continuationToken
562+
$continuationToken,
563+
$formType
543564
);
544565

545566
if (!isset($formOrdersData['data'])) {

src/views/stream/_modal-create-stream.html.twig

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,24 @@
8888
</div>
8989
<div class="mb-3">
9090
<label for="form_id" class="form-label fw-semibold">
91-
<span class="me-1">📋</span> Slug du formulaire de don
91+
<span class="me-1">📋</span> Slug du formulaire
9292
</label>
9393
<div class="input-group">
94-
<span class="input-group-text text-muted small">…/formulaires/don/</span>
94+
<span class="input-group-text text-muted small" id="manual_form_prefix">…/formulaires/don/</span>
9595
<input type="text" class="form-control" id="form_id" name="form_slug"
96-
value="{{ formSlug }}" placeholder="mon-formulaire-de-don" required>
96+
value="{{ formSlug }}" placeholder="mon-formulaire" required>
9797
</div>
9898
<div class="invalid-feedback">Le slug du formulaire est requis.</div>
9999
</div>
100+
<div class="mb-3">
101+
<label for="form_type" class="form-label fw-semibold">
102+
<span class="me-1">📦</span> Type de formulaire
103+
</label>
104+
<select class="form-select" id="form_type" name="form_type" onchange="updateManualFormPrefix()">
105+
<option value="Donation" selected>Formulaire de don</option>
106+
<option value="CrowdFunding">Crowdfunding</option>
107+
</select>
108+
</div>
100109
<div class="mb-4">
101110
<label for="title" class="form-label fw-semibold">
102111
<span class="me-1">🎯</span> Titre du stream
@@ -133,7 +142,7 @@
133142
<div id="stepConnect" class="text-center py-2">
134143
<div class="mb-3 p-4 rounded-3 bg-body-tertiary">
135144
<div class="fs-1 mb-2">🔑</div>
136-
<p class="text-muted mb-0">Connectez votre association HelloAsso pour récupérer automatiquement vos formulaires de don.</p>
145+
<p class="text-muted mb-0">Connectez votre association HelloAsso pour récupérer automatiquement vos formulaires de don et de crowdfunding.</p>
137146
</div>
138147
<button type="button" class="btn btn-primary btn-lg px-5 fw-semibold" id="connectAssoBtn" onclick="connectAsso()">
139148
Connecter mon asso
@@ -191,14 +200,16 @@
191200
{% endif %}
192201

193202
<input type="hidden" id="asso_organization_slug" name="organization_slug">
203+
<input type="hidden" id="asso_form_type" name="form_type" value="Donation">
194204

195205
<div class="mb-3">
196206
<label for="asso_form_slug" class="form-label fw-semibold">
197-
<span class="me-1">📋</span> Formulaire de don
207+
<span class="me-1">📋</span> Formulaire
198208
</label>
199209
<select class="form-select" id="asso_form_slug" name="form_slug" required>
200210
<option value="">— Sélectionner un formulaire —</option>
201211
</select>
212+
<div class="form-text text-muted small" id="asso_form_type_hint"></div>
202213
<div class="invalid-feedback">Veuillez sélectionner un formulaire.</div>
203214
</div>
204215

0 commit comments

Comments
 (0)