nodebb-plugin-equipment-calendar 9.0.13 → 9.0.14

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
@@ -28,7 +28,6 @@ function generateId() {
28
28
  }
29
29
  }
30
30
 
31
-
32
31
  function normalizeItemIds(itemIdsRaw) {
33
32
  if (!itemIdsRaw) return [];
34
33
  if (Array.isArray(itemIdsRaw)) {
@@ -45,7 +44,6 @@ function normalizeItemIds(itemIdsRaw) {
45
44
  }
46
45
  }
47
46
 
48
-
49
47
  function parseDateInput(v) {
50
48
  if (v === null || v === undefined) return null;
51
49
  if (typeof v === 'number' || (typeof v === 'string' && v.trim() && /^\d+$/.test(v.trim()))) {
@@ -71,7 +69,6 @@ function parseDateInput(v) {
71
69
  }
72
70
  }
73
71
 
74
-
75
72
  function tzOffsetMs(date, timeZone) {
76
73
  const asTz = new Date(date.toLocaleString('en-US', { timeZone }));
77
74
  return asTz.getTime() - date.getTime();
@@ -100,8 +97,6 @@ function addDaysIso(iso, days) {
100
97
  return dt.getUTCFullYear() + '-' + pad(dt.getUTCMonth() + 1) + '-' + pad(dt.getUTCDate());
101
98
  }
102
99
 
103
-
104
-
105
100
  function formatDateTimeFR(ms) {
106
101
  const n = Number(ms || 0);
107
102
  if (!n) return '';
@@ -124,8 +119,6 @@ function formatDateTimeFR(ms) {
124
119
  }
125
120
  }
126
121
 
127
-
128
-
129
122
  const axios = require('axios');
130
123
  const { DateTime } = require('luxon');
131
124
  const { v4: uuidv4 } = require('uuid');
@@ -190,53 +183,6 @@ async function setSettings(payload) {
190
183
  Object.keys(payload || {}).forEach((k) => {
191
184
  sets[k] = JSON.stringify(payload[k]);
192
185
  });
193
- await meta.settings.set('equipmentCalendar', sets);
194
- }
195
- function parseLocationMap(locationMapJson) {
196
- try {
197
- const obj = JSON.parse(locationMapJson || '{}');
198
- return (obj && typeof obj === 'object') ? obj : {};
199
- } catch (e) {
200
- return {};
201
- }
202
- }
203
-
204
- let haTokenCache = null; // { accessToken, refreshToken, expMs }
205
-
206
- async function getHelloAssoAccessToken(settings, opts = {}) {
207
- const now = Date.now();
208
- if (!opts.force && haTokenCache && haTokenCache.accessToken && haTokenCache.expMs && now < haTokenCache.expMs - 30_000) {
209
- return haTokenCache.accessToken;
210
- }
211
-
212
- const tokenKey = 'equipmentCalendar:ha:token';
213
- if (opts.clearStored) {
214
- try { await db.delete(tokenKey); } catch (e) {}
215
- }
216
- let stored = null;
217
- try {
218
- stored = await db.getObject(tokenKey);
219
- } catch (e) {}
220
-
221
- // If refresh token exists and not expired locally, try refresh flow first
222
- const canRefresh = !opts.force && stored && stored.refresh_token;
223
- const useRefresh = canRefresh && stored.refresh_expires_at && now < parseInt(stored.refresh_expires_at, 10);
224
-
225
- const formBody = new URLSearchParams();
226
- if (useRefresh) {
227
- formBody.set('grant_type', 'refresh_token');
228
- formBody.set('refresh_token', stored.refresh_token);
229
- } else {
230
- formBody.set('grant_type', 'client_credentials');
231
- formBody.set('client_id', String(settings.ha_clientId || ''));
232
- formBody.set('client_secret', String(settings.ha_clientSecret || ''));
233
- }
234
-
235
- const resp = await fetchFn('https://api.helloasso.com/oauth2/token', {
236
- method: 'POST',
237
- headers: { 'content-type': 'application/x-www-form-urlencoded' },
238
- body: formBody.toString(),
239
- });
240
186
  if (!resp.ok) {
241
187
  const t = await resp.text();
242
188
  throw new Error(`HelloAsso token error: ${resp.status} ${t}`);
@@ -263,7 +209,6 @@ async function getHelloAssoAccessToken(settings, opts = {}) {
263
209
  return accessToken;
264
210
  }
265
211
 
266
-
267
212
  async function createHelloAssoCheckoutIntent(settings, bookingId, reservations) {
268
213
  const org = String(settings.ha_organizationSlug || '').trim();
269
214
  if (!org) throw new Error('HelloAsso organization slug missing');
@@ -350,7 +295,6 @@ function isCheckoutPaid(checkout) {
350
295
  return false;
351
296
  }
352
297
 
353
-
354
298
  async function fetchHelloAssoItems(settings) {
355
299
  const org = String(settings.ha_organizationSlug || '').trim();
356
300
  const formType = String(settings.ha_itemsFormType || '').trim();
@@ -424,8 +368,6 @@ async function fetchHelloAssoItems(settings) {
424
368
  return out;
425
369
  }
426
370
 
427
-
428
-
429
371
  async function getActiveItems() {
430
372
  const settings = await getSettings();
431
373
  const rawItems = await fetchHelloAssoItems(settings);
@@ -438,7 +380,6 @@ async function getActiveItems() {
438
380
  return items;
439
381
  }
440
382
 
441
-
442
383
  // --- Data layer ---
443
384
  // Keys:
444
385
  // item hash: equipmentCalendar:items (stored in settings as JSON)
@@ -455,9 +396,6 @@ function statusBlocksItem(status) {
455
396
  return (s === 'pending' || s === 'approved' || s === 'payment_pending' || s === 'paid');
456
397
  }
457
398
 
458
-
459
-
460
-
461
399
  async function saveBooking(booking) {
462
400
  const bid = booking.bookingId;
463
401
  await db.setObject(`equipmentCalendar:booking:${bid}`, booking);
@@ -490,7 +428,6 @@ async function getReservation(rid) {
490
428
  return await db.getObject(resKey(id));
491
429
  }
492
430
 
493
-
494
431
  async function setReservationStatus(rid, status) {
495
432
  const r = await getReservation(rid);
496
433
  if (!r) throw new Error('not_found');
@@ -509,7 +446,6 @@ async function deleteReservation(rid) {
509
446
  await db.delete(resKey(rid));
510
447
  }
511
448
 
512
-
513
449
  function normalizeReservation(obj) {
514
450
  const startMs = Number(obj.startMs);
515
451
  const endMs = Number(obj.endMs);
@@ -759,7 +695,6 @@ router.get('/admin/plugins/equipment-calendar', middleware.applyCSRF, mid.admin.
759
695
  // Convenience alias (optional): /calendar -> /equipment/calendar
760
696
  router.get('/calendar', (req, res) => res.redirect('/equipment/calendar'));
761
697
 
762
-
763
698
  // To verify webhook signature we need raw body; add a rawBody collector for this route only
764
699
  router.post('/equipment/webhook/helloasso',
765
700
  require.main.require('body-parser').text({ type: '*/*' }),
@@ -870,7 +805,6 @@ plugin.addAdminRoutes = async function (params) {
870
805
  router.get('/api/admin/plugins/equipment-calendar', middleware.applyCSRF, renderAdminPage);
871
806
  };
872
807
 
873
-
874
808
  async function renderAdminReservationsPage(req, res) {
875
809
  if (!(await ensureIsAdmin(req, res))) return;
876
810
 
@@ -995,7 +929,6 @@ async function handleAdminDelete(req, res) {
995
929
  return res.redirect('/admin/plugins/equipment-calendar/reservations?updated=1');
996
930
  }
997
931
 
998
-
999
932
  async function handleHelloAssoTest(req, res) {
1000
933
  const isAdmin = req.uid ? await groups.isMember(req.uid, 'administrators') : false;
1001
934
  if (!isAdmin) return helpers.notAllowed(req, res);
@@ -1196,11 +1129,8 @@ async function renderCalendarPage(req, res) {
1196
1129
  });
1197
1130
  }
1198
1131
 
1199
-
1200
1132
  // --- Approvals page ---
1201
1133
 
1202
-
1203
-
1204
1134
  async function notifyApprovers(reservations, settings) {
1205
1135
  const groupName = (settings.notifyGroup || settings.approverGroup || 'administrators').trim();
1206
1136
  if (!groupName) return;
@@ -1431,8 +1361,6 @@ async function handleCreateReservation(req, res) {
1431
1361
  }
1432
1362
  }
1433
1363
 
1434
-
1435
-
1436
1364
  async function handleApproveReservation(req, res) {
1437
1365
  try {
1438
1366
  const settings = await getSettings();
@@ -1512,9 +1440,6 @@ async function handleRejectReservation(req, res) {
1512
1440
  }
1513
1441
  }
1514
1442
 
1515
-
1516
-
1517
-
1518
1443
  async function ensureIsAdmin(req, res) {
1519
1444
  const isAdmin = req.uid ? await groups.isMember(req.uid, 'administrators') : false;
1520
1445
  if (!isAdmin) {
@@ -1593,8 +1518,6 @@ async function handleAdminPurge(req, res) {
1593
1518
  }
1594
1519
  }
1595
1520
 
1596
-
1597
-
1598
1521
  let paymentTimeoutInterval = null;
1599
1522
 
1600
1523
  function startPaymentTimeoutScheduler() {
@@ -1646,7 +1569,6 @@ function startPaymentTimeoutScheduler() {
1646
1569
 
1647
1570
  module.exports = plugin;
1648
1571
 
1649
-
1650
1572
  async function handleGetReservation(req, res) {
1651
1573
  if (!req.uid) return res.status(403).json({ error: 'not-logged-in' });
1652
1574
  const rid = String(req.params.id || '');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-equipment-calendar",
3
- "version": "9.0.13",
3
+ "version": "9.0.14",
4
4
  "description": "Equipment reservation calendar for NodeBB (FullCalendar, approvals, HelloAsso payments)",
5
5
  "main": "library.js",
6
6
  "scripts": {
package/plugin.json CHANGED
@@ -25,7 +25,7 @@
25
25
  "scripts": [
26
26
  "public/js/client.js"
27
27
  ],
28
- "version": "3.0.0-stable5a-acp-official-behavior",
28
+ "version": "3.0.0-stable5b-syntaxfix",
29
29
  "minver": "4.7.1",
30
30
  "acpScripts": [
31
31
  "public/js/admin.js"