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 = await getHelloAssoAccessToken(settings);
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 = await getHelloAssoAccessToken(settings);
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 = await getHelloAssoAccessToken(settings);
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
- await getHelloAssoAccessToken(settings);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-equipment-calendar",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Equipment reservation calendar for NodeBB (FullCalendar, approvals, HelloAsso payments)",
5
5
  "main": "library.js",
6
6
  "scripts": {
package/plugin.json CHANGED
@@ -26,6 +26,6 @@
26
26
  "scripts": [
27
27
  "public/js/client.js"
28
28
  ],
29
- "version": "0.4.4",
29
+ "version": "0.4.7",
30
30
  "minver": "4.7.1"
31
31
  }
@@ -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>