nodebb-plugin-equipment-calendar 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/library.js
CHANGED
|
@@ -60,20 +60,23 @@ function parseLocationMap(locationMapJson) {
|
|
|
60
60
|
|
|
61
61
|
let haTokenCache = null; // { accessToken, refreshToken, expMs }
|
|
62
62
|
|
|
63
|
-
async function getHelloAssoAccessToken(settings) {
|
|
63
|
+
async function getHelloAssoAccessToken(settings, opts = {}) {
|
|
64
64
|
const now = Date.now();
|
|
65
|
-
if (haTokenCache && haTokenCache.accessToken && haTokenCache.expMs && now < haTokenCache.expMs - 30_000) {
|
|
65
|
+
if (!opts.force && haTokenCache && haTokenCache.accessToken && haTokenCache.expMs && now < haTokenCache.expMs - 30_000) {
|
|
66
66
|
return haTokenCache.accessToken;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
const tokenKey = 'equipmentCalendar:ha:token';
|
|
70
|
+
if (opts.clearStored) {
|
|
71
|
+
try { await db.delete(tokenKey); } catch (e) {}
|
|
72
|
+
}
|
|
70
73
|
let stored = null;
|
|
71
74
|
try {
|
|
72
75
|
stored = await db.getObject(tokenKey);
|
|
73
76
|
} catch (e) {}
|
|
74
77
|
|
|
75
78
|
// If refresh token exists and not expired locally, try refresh flow first
|
|
76
|
-
const canRefresh = stored && stored.refresh_token;
|
|
79
|
+
const canRefresh = !opts.force && stored && stored.refresh_token;
|
|
77
80
|
const useRefresh = canRefresh && stored.refresh_expires_at && now < parseInt(stored.refresh_expires_at, 10);
|
|
78
81
|
|
|
79
82
|
const formBody = new URLSearchParams();
|
|
@@ -158,7 +161,11 @@ async function createHelloAssoCheckoutIntent(settings, bookingId, reservations)
|
|
|
158
161
|
},
|
|
159
162
|
};
|
|
160
163
|
|
|
161
|
-
const token =
|
|
164
|
+
const token = const force = String(req.query.force || '') === '1';
|
|
165
|
+
const clear = String(req.query.clear || '') === '1';
|
|
166
|
+
// force=1 skips in-memory cache and refresh_token; clear=1 wipes stored refresh token
|
|
167
|
+
haTokenCache = null;
|
|
168
|
+
await getHelloAssoAccessToken(settings, { force, clearStored: clear });
|
|
162
169
|
const url = `https://api.helloasso.com/v5/organizations/${encodeURIComponent(org)}/checkout-intents`;
|
|
163
170
|
const resp = await fetchFn(url, {
|
|
164
171
|
method: 'POST',
|
|
@@ -179,7 +186,11 @@ async function createHelloAssoCheckoutIntent(settings, bookingId, reservations)
|
|
|
179
186
|
|
|
180
187
|
async function fetchHelloAssoCheckoutIntent(settings, checkoutIntentId) {
|
|
181
188
|
const org = String(settings.ha_organizationSlug || '').trim();
|
|
182
|
-
const token =
|
|
189
|
+
const token = const force = String(req.query.force || '') === '1';
|
|
190
|
+
const clear = String(req.query.clear || '') === '1';
|
|
191
|
+
// force=1 skips in-memory cache and refresh_token; clear=1 wipes stored refresh token
|
|
192
|
+
haTokenCache = null;
|
|
193
|
+
await getHelloAssoAccessToken(settings, { force, clearStored: clear });
|
|
183
194
|
const url = `https://api.helloasso.com/v5/organizations/${encodeURIComponent(org)}/checkout-intents/${encodeURIComponent(checkoutIntentId)}`;
|
|
184
195
|
const resp = await fetchFn(url, { headers: { authorization: `Bearer ${token}`, accept: 'application/json' } });
|
|
185
196
|
if (!resp.ok) {
|
|
@@ -219,7 +230,11 @@ async function fetchHelloAssoItems(settings) {
|
|
|
219
230
|
} catch (e) {}
|
|
220
231
|
}
|
|
221
232
|
|
|
222
|
-
const token =
|
|
233
|
+
const token = const force = String(req.query.force || '') === '1';
|
|
234
|
+
const clear = String(req.query.clear || '') === '1';
|
|
235
|
+
// force=1 skips in-memory cache and refresh_token; clear=1 wipes stored refresh token
|
|
236
|
+
haTokenCache = null;
|
|
237
|
+
await getHelloAssoAccessToken(settings, { force, clearStored: clear });
|
|
223
238
|
const url = `https://api.helloasso.com/v5/organizations/${encodeURIComponent(org)}/forms/${encodeURIComponent(formType)}/${encodeURIComponent(formSlug)}/items`;
|
|
224
239
|
const resp = await fetchFn(url, { headers: { authorization: `Bearer ${token}` } });
|
|
225
240
|
if (!resp.ok) {
|
|
@@ -796,10 +811,19 @@ async function handleHelloAssoTest(req, res) {
|
|
|
796
811
|
let count = 0;
|
|
797
812
|
|
|
798
813
|
try {
|
|
799
|
-
|
|
814
|
+
const force = String(req.query.force || '') === '1';
|
|
815
|
+
const clear = String(req.query.clear || '') === '1';
|
|
816
|
+
// force=1 skips in-memory cache and refresh_token; clear=1 wipes stored refresh token
|
|
817
|
+
haTokenCache = null;
|
|
818
|
+
await getHelloAssoAccessToken(settings, { force, clearStored: clear });
|
|
800
819
|
const items = await fetchHelloAssoItems(settings);
|
|
801
820
|
const list = Array.isArray(items) ? items : (Array.isArray(items.data) ? items.data : []);
|
|
802
821
|
count = list.length;
|
|
822
|
+
const sampleItems = list.slice(0, 10).map(it => ({
|
|
823
|
+
id: String(it.id || it.itemId || it.reference || it.slug || it.name || '').trim(),
|
|
824
|
+
name: String(it.name || it.label || it.title || '').trim(),
|
|
825
|
+
rawName: String(it.name || it.label || it.title || it.id || '').trim(),
|
|
826
|
+
}));
|
|
803
827
|
ok = true;
|
|
804
828
|
message = `OK: token valide. Items récupérés: ${count}.`;
|
|
805
829
|
} catch (e) {
|
|
@@ -813,6 +837,8 @@ async function handleHelloAssoTest(req, res) {
|
|
|
813
837
|
message,
|
|
814
838
|
count,
|
|
815
839
|
settings,
|
|
840
|
+
sampleItems,
|
|
841
|
+
hasSampleItems: sampleItems && sampleItems.length > 0,
|
|
816
842
|
});
|
|
817
843
|
}
|
|
818
844
|
|
|
@@ -1368,6 +1394,10 @@ async function handleAdminSave(req, res) {
|
|
|
1368
1394
|
approverGroup: String(req.body.approverGroup || DEFAULT_SETTINGS.approverGroup),
|
|
1369
1395
|
notifyGroup: String(req.body.notifyGroup || DEFAULT_SETTINGS.notifyGroup),
|
|
1370
1396
|
itemsJson: String(req.body.itemsJson || DEFAULT_SETTINGS.itemsJson),
|
|
1397
|
+
itemsSource: String(req.body.itemsSource || DEFAULT_SETTINGS.itemsSource),
|
|
1398
|
+
ha_itemsFormType: String(req.body.ha_itemsFormType || DEFAULT_SETTINGS.ha_itemsFormType),
|
|
1399
|
+
ha_itemsFormSlug: String(req.body.ha_itemsFormSlug || DEFAULT_SETTINGS.ha_itemsFormSlug),
|
|
1400
|
+
ha_locationMapJson: String(req.body.ha_locationMapJson || DEFAULT_SETTINGS.ha_locationMapJson),
|
|
1371
1401
|
ha_clientId: String(req.body.ha_clientId || ''),
|
|
1372
1402
|
ha_clientSecret: String(req.body.ha_clientSecret || ''),
|
|
1373
1403
|
ha_organizationSlug: String(req.body.ha_organizationSlug || ''),
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
</div>
|
|
10
10
|
|
|
11
11
|
<div class="card card-body mt-3">
|
|
12
|
+
<div class="d-flex flex-wrap gap-2 mb-2">
|
|
13
|
+
<a class="btn btn-outline-primary" href="/admin/plugins/equipment-calendar/helloasso-test">Test (cache OK)</a>
|
|
14
|
+
<a class="btn btn-outline-primary" href="/admin/plugins/equipment-calendar/helloasso-test?force=1">Test (forcer nouveau token)</a>
|
|
15
|
+
<a class="btn btn-outline-danger" href="/admin/plugins/equipment-calendar/helloasso-test?force=1&clear=1" onclick="return confirm('Supprimer le token stocké et retester ?');">Vider token + retester</a>
|
|
16
|
+
</div>
|
|
12
17
|
{{{ if ok }}}
|
|
13
18
|
<div class="alert alert-success">{message}</div>
|
|
14
19
|
{{{ else }}}
|
|
@@ -18,5 +23,32 @@
|
|
|
18
23
|
<div class="small text-muted">
|
|
19
24
|
Form: <code>{settings.ha_itemsFormType}</code> / <code>{settings.ha_itemsFormSlug}</code> — Orga: <code>{settings.ha_organizationSlug}</code>
|
|
20
25
|
</div>
|
|
26
|
+
{{{ if hasSampleItems }}}
|
|
27
|
+
<div class="card card-body mt-3">
|
|
28
|
+
<div class="d-flex flex-wrap gap-2 mb-2">
|
|
29
|
+
<a class="btn btn-outline-primary" href="/admin/plugins/equipment-calendar/helloasso-test">Test (cache OK)</a>
|
|
30
|
+
<a class="btn btn-outline-primary" href="/admin/plugins/equipment-calendar/helloasso-test?force=1">Test (forcer nouveau token)</a>
|
|
31
|
+
<a class="btn btn-outline-danger" href="/admin/plugins/equipment-calendar/helloasso-test?force=1&clear=1" onclick="return confirm('Supprimer le token stocké et retester ?');">Vider token + retester</a>
|
|
32
|
+
</div>
|
|
33
|
+
<h5 class="mb-2">Aperçu (10 premiers articles)</h5>
|
|
34
|
+
<div class="table-responsive">
|
|
35
|
+
<table class="table table-striped align-middle">
|
|
36
|
+
<thead>
|
|
37
|
+
<tr>
|
|
38
|
+
<th>ID</th>
|
|
39
|
+
<th>Nom</th>
|
|
40
|
+
</tr>
|
|
41
|
+
</thead>
|
|
42
|
+
<tbody>
|
|
43
|
+
{{{ each sampleItems }}}
|
|
44
|
+
<tr>
|
|
45
|
+
<td><code>{sampleItems.id}</code></td>
|
|
46
|
+
<td>{sampleItems.rawName}</td>
|
|
47
|
+
</tr>
|
|
48
|
+
{{{ end }}}
|
|
49
|
+
</tbody>
|
|
50
|
+
</table>
|
|
51
|
+
</div>
|
|
21
52
|
</div>
|
|
53
|
+
{{{ end }}}
|
|
22
54
|
</div>
|