nodebb-plugin-equipment-calendar 9.0.13 → 9.0.15
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 +2 -85
- package/package.json +1 -1
- package/plugin.json +1 -1
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);
|
|
@@ -736,13 +672,8 @@ plugin.init = async function (params) {
|
|
|
736
672
|
// Admin (ACP) routes
|
|
737
673
|
if (mid && mid.admin) {
|
|
738
674
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
} catch (e) {
|
|
742
|
-
winston.error('[equipment-calendar] admin save error', e);
|
|
743
|
-
return res.redirect(nconf.get('relative_path') + '/admin/plugins/equipment-calendar?error=1');
|
|
744
|
-
}
|
|
745
|
-
});
|
|
675
|
+
|
|
676
|
+
|
|
746
677
|
|
|
747
678
|
router.get('/admin/plugins/equipment-calendar', middleware.applyCSRF, mid.admin.buildHeader, renderAdminPage);
|
|
748
679
|
router.get('/admin/plugins/equipment-calendar/reservations', middleware.applyCSRF, mid.admin.buildHeader, renderAdminReservationsPage);
|
|
@@ -759,7 +690,6 @@ router.get('/admin/plugins/equipment-calendar', middleware.applyCSRF, mid.admin.
|
|
|
759
690
|
// Convenience alias (optional): /calendar -> /equipment/calendar
|
|
760
691
|
router.get('/calendar', (req, res) => res.redirect('/equipment/calendar'));
|
|
761
692
|
|
|
762
|
-
|
|
763
693
|
// To verify webhook signature we need raw body; add a rawBody collector for this route only
|
|
764
694
|
router.post('/equipment/webhook/helloasso',
|
|
765
695
|
require.main.require('body-parser').text({ type: '*/*' }),
|
|
@@ -870,7 +800,6 @@ plugin.addAdminRoutes = async function (params) {
|
|
|
870
800
|
router.get('/api/admin/plugins/equipment-calendar', middleware.applyCSRF, renderAdminPage);
|
|
871
801
|
};
|
|
872
802
|
|
|
873
|
-
|
|
874
803
|
async function renderAdminReservationsPage(req, res) {
|
|
875
804
|
if (!(await ensureIsAdmin(req, res))) return;
|
|
876
805
|
|
|
@@ -995,7 +924,6 @@ async function handleAdminDelete(req, res) {
|
|
|
995
924
|
return res.redirect('/admin/plugins/equipment-calendar/reservations?updated=1');
|
|
996
925
|
}
|
|
997
926
|
|
|
998
|
-
|
|
999
927
|
async function handleHelloAssoTest(req, res) {
|
|
1000
928
|
const isAdmin = req.uid ? await groups.isMember(req.uid, 'administrators') : false;
|
|
1001
929
|
if (!isAdmin) return helpers.notAllowed(req, res);
|
|
@@ -1196,11 +1124,8 @@ async function renderCalendarPage(req, res) {
|
|
|
1196
1124
|
});
|
|
1197
1125
|
}
|
|
1198
1126
|
|
|
1199
|
-
|
|
1200
1127
|
// --- Approvals page ---
|
|
1201
1128
|
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
1129
|
async function notifyApprovers(reservations, settings) {
|
|
1205
1130
|
const groupName = (settings.notifyGroup || settings.approverGroup || 'administrators').trim();
|
|
1206
1131
|
if (!groupName) return;
|
|
@@ -1431,8 +1356,6 @@ async function handleCreateReservation(req, res) {
|
|
|
1431
1356
|
}
|
|
1432
1357
|
}
|
|
1433
1358
|
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
1359
|
async function handleApproveReservation(req, res) {
|
|
1437
1360
|
try {
|
|
1438
1361
|
const settings = await getSettings();
|
|
@@ -1512,9 +1435,6 @@ async function handleRejectReservation(req, res) {
|
|
|
1512
1435
|
}
|
|
1513
1436
|
}
|
|
1514
1437
|
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
1438
|
async function ensureIsAdmin(req, res) {
|
|
1519
1439
|
const isAdmin = req.uid ? await groups.isMember(req.uid, 'administrators') : false;
|
|
1520
1440
|
if (!isAdmin) {
|
|
@@ -1593,8 +1513,6 @@ async function handleAdminPurge(req, res) {
|
|
|
1593
1513
|
}
|
|
1594
1514
|
}
|
|
1595
1515
|
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
1516
|
let paymentTimeoutInterval = null;
|
|
1599
1517
|
|
|
1600
1518
|
function startPaymentTimeoutScheduler() {
|
|
@@ -1646,7 +1564,6 @@ function startPaymentTimeoutScheduler() {
|
|
|
1646
1564
|
|
|
1647
1565
|
module.exports = plugin;
|
|
1648
1566
|
|
|
1649
|
-
|
|
1650
1567
|
async function handleGetReservation(req, res) {
|
|
1651
1568
|
if (!req.uid) return res.status(403).json({ error: 'not-logged-in' });
|
|
1652
1569
|
const rid = String(req.params.id || '');
|
package/package.json
CHANGED