Skip to content

Commit a942ade

Browse files
committed
Add crowd compatibility
1 parent 0202802 commit a942ade

11 files changed

Lines changed: 106 additions & 25 deletions

File tree

.github/workflows/php-sandbox.yml

Lines changed: 1 addition & 1 deletion
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:

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/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: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ private function aggregateEventStreams(array $streams, array $cacheData, bool $t
8787
$stream->organization_slug,
8888
$stream->form_slug,
8989
$streamCache['amount'],
90-
$streamCache['continuation_token']
90+
$streamCache['continuation_token'],
91+
$stream->form_type ?? 'Donation'
9192
);
9293

9394
$streamCache['amount'] = $result['amount'];
@@ -145,6 +146,7 @@ private function fetchStreamDonationData(string $streamGuid): array
145146
$charityStream->form_slug,
146147
$cacheData['amount'],
147148
$cacheData['continuation_token'],
149+
$charityStream->form_type ?? 'Donation',
148150
);
149151

150152
if ($cacheData['continuation_token'] !== $result['continuation_token']
@@ -234,6 +236,7 @@ private function fetchStreamCardData(string $streamGuid): array
234236
$charityStream->form_slug,
235237
$cacheData['amount'],
236238
$cacheData['continuation_token'],
239+
$charityStream->form_type ?? 'Donation',
237240
);
238241

239242
$newDonors = count($result['donations'] ?? []);
@@ -377,6 +380,7 @@ public function widgetAlert(Request $request, Response $response, array $args):
377380
$charityStream->form_slug,
378381
0,
379382
$cacheData['continuation_token'],
383+
$charityStream->form_type ?? 'Donation',
380384
);
381385

382386
if ($cacheData['continuation_token'] !== $result['continuation_token']) {
@@ -442,7 +446,8 @@ public function widgetAlertFetch(Request $request, Response $response, array $ar
442446
$charityStream->organization_slug,
443447
$charityStream->form_slug,
444448
0,
445-
$cacheData['continuation_token']
449+
$cacheData['continuation_token'],
450+
$charityStream->form_type ?? 'Donation'
446451
);
447452

448453
if ($cacheData['continuation_token'] !== $result['continuation_token']) {

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: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -363,31 +363,43 @@ 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

375376
$response = $this->httpRequest('GET', "{$this->apiUrl}/organizations/{$organizationSlug}/forms", [
376377
'query' => [
377-
'formTypes' => 'Donation',
378+
'formTypes' => implode(',', $formTypes),
378379
'pageSize' => 50,
379380
],
380381
'headers' => [
381382
'Authorization' => 'Bearer ' . $tokenData->access_token,
382383
'accept' => 'application/json',
383384
],
384-
], "la récupération des formulaires de don pour {$organizationSlug}");
385+
], "la récupération des formulaires pour {$organizationSlug}");
385386

386387
$data = $this->decodeJsonResponse($response);
387388

388389
return $data['data'] ?? [];
389390
}
390391

392+
/**
393+
* Récupère la liste des formulaires de don d'une organisation.
394+
*
395+
* @param string $organizationSlug
396+
* @return array
397+
*/
398+
public function getDonationForms(string $organizationSlug): array
399+
{
400+
return $this->getOrganizationForms($organizationSlug, ['Donation']);
401+
}
402+
391403
/**
392404
* Configure le domaine du client API pour une organisation donnée en utilisant un token d'accès valide.
393405
*
@@ -480,16 +492,18 @@ public function exchangeAuthorizationCode(string $code, string $redirectUri, str
480492
* @param [type] $continuationToken
481493
* @return array
482494
*/
483-
private function getDonationFormOrders(string $organizationSlug, string $donationSlug, string $accessToken, ?string $continuationToken = null): array
495+
private function getDonationFormOrders(string $organizationSlug, string $donationSlug, string $accessToken, ?string $continuationToken = null, string $formType = 'Donation'): array
484496
{
485497
$query = ['withDetails' => 'true', 'sortOrder' => 'asc', 'pageSize' => 100];
486498
if ($continuationToken) {
487499
$query['continuationToken'] = $continuationToken;
488500
}
489501

502+
$formTypePath = $formType ?: 'Donation';
503+
490504
$response = $this->httpRequest(
491505
'GET',
492-
"{$this->apiUrl}/organizations/{$organizationSlug}/forms/donation/{$donationSlug}/orders",
506+
"{$this->apiUrl}/organizations/{$organizationSlug}/forms/{$formTypePath}/{$donationSlug}/orders",
493507
[
494508
'query' => $query,
495509
'headers' => [
@@ -512,7 +526,7 @@ private function getDonationFormOrders(string $organizationSlug, string $donatio
512526
* @param [type] $continuationToken
513527
* @return array
514528
*/
515-
public function getAllOrders(string $organizationSlug, string $formSlug, int $currentAmount = 0, ?string $continuationToken = null): array
529+
public function getAllOrders(string $organizationSlug, string $formSlug, int $currentAmount = 0, ?string $continuationToken = null, string $formType = 'Donation'): array
516530
{
517531
$previousToken = '';
518532
$donations = [];
@@ -539,7 +553,8 @@ public function getAllOrders(string $organizationSlug, string $formSlug, int $cu
539553
$organizationSlug,
540554
$formSlug,
541555
$organizationAccessToken->access_token,
542-
$continuationToken
556+
$continuationToken,
557+
$formType
543558
);
544559

545560
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

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,17 @@
4646
if (toastEl) { new bootstrap.Toast(toastEl).show(); }
4747
});
4848
49+
/* ── Mise à jour du préfixe formulaire mode manuel ── */
50+
function updateManualFormPrefix() {
51+
var formType = document.getElementById('form_type').value;
52+
var prefix = document.getElementById('manual_form_prefix');
53+
if (formType === 'CrowdFunding') {
54+
prefix.textContent = '…/collectes/';
55+
} else {
56+
prefix.textContent = '…/formulaires/don/';
57+
}
58+
}
59+
4960
/* ── Sélection du mode (cartes cliquables) ── */
5061
function selectStreamMode(mode) {
5162
var isAsso = (mode === 'asso');
@@ -114,20 +125,40 @@
114125
115126
var formSelect = document.getElementById('asso_form_slug');
116127
formSelect.innerHTML = '<option value="">— Sélectionner un formulaire —</option>';
128+
129+
var formTypeLabels = {
130+
'Donation': '🎁 Don',
131+
'CrowdFunding': '🚀 Crowdfunding'
132+
};
133+
117134
forms.forEach(function(form) {
118135
var slug = form.slug || form.formSlug || '';
119136
var label = form.privateTitle || form.title || slug;
137+
var formType = form.formType || 'Donation';
138+
var typeLabel = formTypeLabels[formType] || formType;
120139
var opt = document.createElement('option');
121140
opt.value = slug;
122-
opt.textContent = label;
141+
opt.textContent = '[' + typeLabel + '] ' + label;
123142
opt.dataset.title = label;
143+
opt.dataset.formType = formType;
124144
formSelect.appendChild(opt);
125145
});
126146
127147
formSelect.addEventListener('change', function() {
128148
var titleInput = document.getElementById('asso_title');
149+
var formTypeInput = document.getElementById('asso_form_type');
150+
var formTypeHint = document.getElementById('asso_form_type_hint');
129151
var selectedOpt = this.options[this.selectedIndex];
130152
titleInput.value = selectedOpt && selectedOpt.dataset.title ? selectedOpt.dataset.title : '';
153+
var selectedFormType = selectedOpt && selectedOpt.dataset.formType ? selectedOpt.dataset.formType : 'Donation';
154+
formTypeInput.value = selectedFormType;
155+
if (selectedFormType === 'CrowdFunding') {
156+
formTypeHint.textContent = 'Type : Crowdfunding';
157+
} else if (selectedFormType === 'Donation') {
158+
formTypeHint.textContent = 'Type : Formulaire de don';
159+
} else {
160+
formTypeHint.textContent = '';
161+
}
131162
});
132163
133164
setStepActive(2);

0 commit comments

Comments
 (0)