nodebb-plugin-calendar-onekite 11.1.99 → 11.2.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/lib/admin.js +24 -5
- package/lib/helloassoWebhook.js +22 -12
- package/library.js +11 -38
- package/package.json +3 -3
- package/plugin.json +2 -2
- package/public/admin.js +2 -2
- package/public/client.js +6 -11
package/lib/admin.js
CHANGED
|
@@ -19,12 +19,33 @@ function formatFR(tsOrIso) {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
async function sendEmail(template, toEmail, subject, data) {
|
|
22
|
-
|
|
22
|
+
// Prefer sending by uid (NodeBB core expects uid in various places)
|
|
23
|
+
const uid = data && Number.isInteger(data.uid) ? data.uid : null;
|
|
24
|
+
if (!toEmail && !uid) return;
|
|
23
25
|
|
|
24
26
|
const settings = await meta.settings.get('calendar-onekite').catch(() => ({}));
|
|
25
27
|
const lang = (settings && settings.defaultLang) || (meta && meta.config && meta.config.defaultLang) || 'fr';
|
|
26
28
|
const params = Object.assign({}, data || {}, subject ? { subject } : {});
|
|
27
29
|
|
|
30
|
+
// If we have a uid, use the native uid-based sender first.
|
|
31
|
+
try {
|
|
32
|
+
if (uid && typeof emailer.send === 'function') {
|
|
33
|
+
// NodeBB: send(template, uid, params)
|
|
34
|
+
if (emailer.send.length >= 3) {
|
|
35
|
+
await emailer.send(template, uid, params);
|
|
36
|
+
} else {
|
|
37
|
+
await emailer.send(template, uid, params);
|
|
38
|
+
}
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
} catch (err) {
|
|
42
|
+
console.warn('[calendar-onekite] Failed to send email', {
|
|
43
|
+
template,
|
|
44
|
+
toEmail,
|
|
45
|
+
err: err && err.message ? err.message : String(err),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
28
49
|
try {
|
|
29
50
|
if (typeof emailer.sendToEmail === 'function') {
|
|
30
51
|
// NodeBB: sendToEmail(template, email, language, params)
|
|
@@ -36,10 +57,6 @@ async function sendEmail(template, toEmail, subject, data) {
|
|
|
36
57
|
}
|
|
37
58
|
return;
|
|
38
59
|
}
|
|
39
|
-
if (typeof emailer.send === 'function') {
|
|
40
|
-
// Fallback: send(template, uid, params) - not usable without uid
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
60
|
} catch (err) {
|
|
44
61
|
console.warn('[calendar-onekite] Failed to send email', {
|
|
45
62
|
template,
|
|
@@ -184,6 +201,7 @@ admin.approveReservation = async function (req, res) {
|
|
|
184
201
|
? `https://www.openstreetmap.org/?mlat=${encodeURIComponent(String(latNum))}&mlon=${encodeURIComponent(String(lonNum))}#map=18/${encodeURIComponent(String(latNum))}/${encodeURIComponent(String(lonNum))}`
|
|
185
202
|
: '';
|
|
186
203
|
await sendEmail('calendar-onekite_approved', requester.email, 'Location matériel - Réservation validée', {
|
|
204
|
+
uid: parseInt(r.uid, 10),
|
|
187
205
|
username: requester.username,
|
|
188
206
|
itemName: (Array.isArray(r.itemNames) ? r.itemNames.join(', ') : (r.itemName || '')),
|
|
189
207
|
itemNames: (Array.isArray(r.itemNames) ? r.itemNames : (r.itemName ? [r.itemName] : [])),
|
|
@@ -216,6 +234,7 @@ admin.refuseReservation = async function (req, res) {
|
|
|
216
234
|
const requester = await user.getUserFields(r.uid, ['username', 'email']);
|
|
217
235
|
if (requester && requester.email) {
|
|
218
236
|
await sendEmail('calendar-onekite_refused', requester.email, 'Location matériel - Réservation refusée', {
|
|
237
|
+
uid: parseInt(r.uid, 10),
|
|
219
238
|
username: requester.username,
|
|
220
239
|
itemName: r.itemName,
|
|
221
240
|
start: formatFR(r.start),
|
package/lib/helloassoWebhook.js
CHANGED
|
@@ -24,7 +24,8 @@ const SETTINGS_KEY = 'calendar-onekite';
|
|
|
24
24
|
const PROCESSED_KEY = 'calendar-onekite:helloasso:processedPayments';
|
|
25
25
|
|
|
26
26
|
async function sendEmail(template, toEmail, subject, data) {
|
|
27
|
-
|
|
27
|
+
const uidFromData = data && Number.isInteger(data.uid) ? data.uid : null;
|
|
28
|
+
if (!toEmail && !uidFromData) return;
|
|
28
29
|
try {
|
|
29
30
|
const emailer = require.main.require('./src/emailer');
|
|
30
31
|
// NodeBB core signature is typically:
|
|
@@ -33,6 +34,23 @@ async function sendEmail(template, toEmail, subject, data) {
|
|
|
33
34
|
const language = (meta && meta.config && (meta.config.defaultLang || meta.config.defaultLanguage)) || 'fr';
|
|
34
35
|
const params = Object.assign({}, data || {}, subject ? { subject } : {});
|
|
35
36
|
|
|
37
|
+
// In NodeBB 4.x, various email flows expect a uid to be present.
|
|
38
|
+
// If we have it, always prefer the uid-based sender.
|
|
39
|
+
let uid = uidFromData;
|
|
40
|
+
if (!uid && toEmail && typeof user.getUidByEmail === 'function') {
|
|
41
|
+
try {
|
|
42
|
+
uid = await user.getUidByEmail(toEmail);
|
|
43
|
+
if (uid && typeof uid === 'string') uid = parseInt(uid, 10);
|
|
44
|
+
} catch (e) {
|
|
45
|
+
uid = null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (uid && typeof emailer.send === 'function') {
|
|
49
|
+
// NodeBB: send(template, uid, params)
|
|
50
|
+
await emailer.send(template, uid, params);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
36
54
|
if (typeof emailer.sendToEmail === 'function') {
|
|
37
55
|
// Prefer the canonical signature.
|
|
38
56
|
// If a fork uses a shorter signature, we'll still try passing params as 3rd arg.
|
|
@@ -44,17 +62,8 @@ async function sendEmail(template, toEmail, subject, data) {
|
|
|
44
62
|
return;
|
|
45
63
|
}
|
|
46
64
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
await emailer.send(template, toEmail, language, params);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
if (emailer.send.length === 3) {
|
|
53
|
-
await emailer.send(template, toEmail, params);
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
await emailer.send(template, toEmail, language, params);
|
|
57
|
-
}
|
|
65
|
+
// Do not call emailer.send with an email address (it expects uid). If we reach here,
|
|
66
|
+
// fall back to sendToEmail only.
|
|
58
67
|
} catch (err) {
|
|
59
68
|
// eslint-disable-next-line no-console
|
|
60
69
|
console.warn('[calendar-onekite] Failed to send email (webhook)', { template, toEmail, err: String(err && err.message || err) });
|
|
@@ -345,6 +354,7 @@ async function handler(req, res, next) {
|
|
|
345
354
|
const requester = await user.getUserFields(r.uid, ['username', 'email']);
|
|
346
355
|
if (requester && requester.email) {
|
|
347
356
|
await sendEmail('calendar-onekite_paid', requester.email, 'Location matériel - Paiement reçu', {
|
|
357
|
+
uid: parseInt(r.uid, 10),
|
|
348
358
|
username: requester.username,
|
|
349
359
|
itemName: (Array.isArray(r.itemNames) ? r.itemNames.join(', ') : (r.itemName || '')),
|
|
350
360
|
itemNames: (Array.isArray(r.itemNames) ? r.itemNames : (r.itemName ? [r.itemName] : [])),
|
package/library.js
CHANGED
|
@@ -53,48 +53,21 @@ Plugin.init = async function (params) {
|
|
|
53
53
|
routeHelpers.setupPageRoute(router, '/calendar', mw(), controllers.renderCalendar);
|
|
54
54
|
routeHelpers.setupAdminPageRoute(router, '/admin/plugins/calendar-onekite', mw(), admin.renderAdmin);
|
|
55
55
|
|
|
56
|
-
// Public API (JSON)
|
|
57
|
-
|
|
56
|
+
// Public API (JSON) — NodeBB 4.x only (v3 API)
|
|
57
|
+
router.get('/api/v3/plugins/calendar-onekite/events', ...publicExpose, api.getEvents);
|
|
58
|
+
router.get('/api/v3/plugins/calendar-onekite/items', ...publicExpose, api.getItems);
|
|
59
|
+
router.get('/api/v3/plugins/calendar-onekite/capabilities', ...publicExpose, api.getCapabilities);
|
|
58
60
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
['/api/v3/plugins/calendar-onekite/items', '/api/plugins/calendar-onekite/items'].forEach((p) => {
|
|
64
|
-
router.get(p, ...publicExpose, api.getItems);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
['/api/v3/plugins/calendar-onekite/capabilities', '/api/plugins/calendar-onekite/capabilities'].forEach((p) => {
|
|
68
|
-
router.get(p, ...publicExpose, api.getCapabilities);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
['/api/v3/plugins/calendar-onekite/reservations', '/api/plugins/calendar-onekite/reservations'].forEach((p) => {
|
|
72
|
-
router.post(p, ...publicAuth, api.createReservation);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// Special events (other colour) - created/deleted by configured groups
|
|
76
|
-
['/api/v3/plugins/calendar-onekite/special-events', '/api/plugins/calendar-onekite/special-events'].forEach((p) => {
|
|
77
|
-
router.post(p, ...publicAuth, api.createSpecialEvent);
|
|
78
|
-
});
|
|
79
|
-
['/api/v3/plugins/calendar-onekite/special-events/:eid', '/api/plugins/calendar-onekite/special-events/:eid'].forEach((p) => {
|
|
80
|
-
router.delete(p, ...publicAuth, api.deleteSpecialEvent);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// Validator actions from the calendar popup (requires login + validatorGroups)
|
|
84
|
-
['/api/v3/plugins/calendar-onekite/reservations/:rid/approve', '/api/plugins/calendar-onekite/reservations/:rid/approve'].forEach((p) => {
|
|
85
|
-
router.put(p, ...publicAuth, api.approveReservation);
|
|
86
|
-
});
|
|
87
|
-
['/api/v3/plugins/calendar-onekite/reservations/:rid/refuse', '/api/plugins/calendar-onekite/reservations/:rid/refuse'].forEach((p) => {
|
|
88
|
-
router.put(p, ...publicAuth, api.refuseReservation);
|
|
89
|
-
});
|
|
90
|
-
// Cancellation by requester (or staff): owner can cancel even if not in validator group
|
|
91
|
-
['/api/v3/plugins/calendar-onekite/reservations/:rid/cancel', '/api/plugins/calendar-onekite/reservations/:rid/cancel'].forEach((p) => {
|
|
92
|
-
router.put(p, ...publicAuth, api.cancelReservation);
|
|
93
|
-
});
|
|
61
|
+
router.post('/api/v3/plugins/calendar-onekite/reservations', ...publicExpose, api.createReservation);
|
|
62
|
+
router.put('/api/v3/plugins/calendar-onekite/reservations/:rid/approve', ...publicExpose, api.approveReservation);
|
|
63
|
+
router.put('/api/v3/plugins/calendar-onekite/reservations/:rid/refuse', ...publicExpose, api.refuseReservation);
|
|
64
|
+
router.put('/api/v3/plugins/calendar-onekite/reservations/:rid/cancel', ...publicExpose, api.cancelReservation);
|
|
94
65
|
|
|
66
|
+
router.post('/api/v3/plugins/calendar-onekite/special-events', ...publicExpose, api.createSpecialEvent);
|
|
67
|
+
router.delete('/api/v3/plugins/calendar-onekite/special-events/:eid', ...publicExpose, api.deleteSpecialEvent);
|
|
95
68
|
|
|
96
69
|
// Admin API (JSON)
|
|
97
|
-
const adminBases = ['/api/v3/admin/plugins/calendar-onekite'
|
|
70
|
+
const adminBases = ['/api/v3/admin/plugins/calendar-onekite'];
|
|
98
71
|
|
|
99
72
|
adminBases.forEach((base) => {
|
|
100
73
|
router.get(`${base}/settings`, ...adminMws, admin.getSettings);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodebb-plugin-calendar-onekite",
|
|
3
|
-
"version": "11.1
|
|
3
|
+
"version": "11.2.1",
|
|
4
4
|
"description": "FullCalendar-based equipment reservation workflow with admin approval & HelloAsso payment for NodeBB",
|
|
5
5
|
"main": "library.js",
|
|
6
6
|
"license": "MIT",
|
|
@@ -9,6 +9,6 @@
|
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {},
|
|
11
11
|
"nbbpm": {
|
|
12
|
-
"compatibility": "^
|
|
12
|
+
"compatibility": "^4.0.0"
|
|
13
13
|
}
|
|
14
|
-
}
|
|
14
|
+
}
|
package/plugin.json
CHANGED
package/public/admin.js
CHANGED
|
@@ -426,7 +426,7 @@ define('admin/plugins/calendar-onekite', ['alerts', 'bootbox'], function (alerts
|
|
|
426
426
|
body: JSON.stringify({ year }),
|
|
427
427
|
});
|
|
428
428
|
} catch (e) {
|
|
429
|
-
return await fetchJson('/api/admin/plugins/calendar-onekite/special-events/purge', {
|
|
429
|
+
return await fetchJson('/api/v3/admin/plugins/calendar-onekite/special-events/purge', {
|
|
430
430
|
method: 'POST',
|
|
431
431
|
body: JSON.stringify({ year }),
|
|
432
432
|
});
|
|
@@ -437,7 +437,7 @@ define('admin/plugins/calendar-onekite', ['alerts', 'bootbox'], function (alerts
|
|
|
437
437
|
try {
|
|
438
438
|
return await fetchJson('/api/v3/admin/plugins/calendar-onekite/debug');
|
|
439
439
|
} catch (e) {
|
|
440
|
-
return await fetchJson('/api/admin/plugins/calendar-onekite/debug');
|
|
440
|
+
return await fetchJson('/api/v3/admin/plugins/calendar-onekite/debug');
|
|
441
441
|
}
|
|
442
442
|
}
|
|
443
443
|
|
package/public/client.js
CHANGED
|
@@ -253,11 +253,7 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
async function loadCapabilities() {
|
|
256
|
-
|
|
257
|
-
return await fetchJson('/api/v3/plugins/calendar-onekite/capabilities');
|
|
258
|
-
} catch (e) {
|
|
259
|
-
return await fetchJson('/api/plugins/calendar-onekite/capabilities');
|
|
260
|
-
}
|
|
256
|
+
return await fetchJson('/api/v3/plugins/calendar-onekite/capabilities');
|
|
261
257
|
}
|
|
262
258
|
|
|
263
259
|
// Leaflet (OpenStreetMap) helpers - loaded lazily only when needed.
|
|
@@ -799,7 +795,7 @@ function toDatetimeLocalValue(date) {
|
|
|
799
795
|
method: 'POST',
|
|
800
796
|
body: JSON.stringify(payload),
|
|
801
797
|
}).catch(async () => {
|
|
802
|
-
return await fetchJson('/api/plugins/calendar-onekite/special-events', {
|
|
798
|
+
return await fetchJson('/api/v3/plugins/calendar-onekite/special-events', {
|
|
803
799
|
method: 'POST',
|
|
804
800
|
body: JSON.stringify(payload),
|
|
805
801
|
});
|
|
@@ -853,7 +849,7 @@ function toDatetimeLocalValue(date) {
|
|
|
853
849
|
showAlert('error', 'Impossible : au moins un matériel est déjà réservé ou en attente sur cette période.');
|
|
854
850
|
} else {
|
|
855
851
|
const msg = payload && (payload.message || payload.error || payload.msg) ? String(payload.message || payload.error || payload.msg) : '';
|
|
856
|
-
showAlert('error', msg || ((e && (e.status === 401 || e.status === 403)) ? '
|
|
852
|
+
showAlert('error', msg || ((e && (e.status === 401 || e.status === 403)) ? 'Vous devez être adhérent Onekite' : 'Erreur lors de la création de la demande.'));
|
|
857
853
|
}
|
|
858
854
|
calendar.unselect();
|
|
859
855
|
isDialogOpen = false;
|
|
@@ -882,7 +878,7 @@ function toDatetimeLocalValue(date) {
|
|
|
882
878
|
method: 'POST',
|
|
883
879
|
body: JSON.stringify(payload),
|
|
884
880
|
}).catch(async () => {
|
|
885
|
-
return await fetchJson('/api/plugins/calendar-onekite/special-events', {
|
|
881
|
+
return await fetchJson('/api/v3/plugins/calendar-onekite/special-events', {
|
|
886
882
|
method: 'POST',
|
|
887
883
|
body: JSON.stringify(payload),
|
|
888
884
|
});
|
|
@@ -937,8 +933,7 @@ function toDatetimeLocalValue(date) {
|
|
|
937
933
|
callback: async () => {
|
|
938
934
|
try {
|
|
939
935
|
const eid = String(p.eid || ev.id).replace(/^special:/, '');
|
|
940
|
-
await fetchJson(`/api/v3/plugins/calendar-onekite/special-events/${encodeURIComponent(eid)}`, { method: 'DELETE' })
|
|
941
|
-
.catch(() => fetchJson(`/api/plugins/calendar-onekite/special-events/${encodeURIComponent(eid)}`, { method: 'DELETE' }));
|
|
936
|
+
await fetchJson(`/api/v3/plugins/calendar-onekite/special-events/${encodeURIComponent(eid)}`, { method: 'DELETE' });
|
|
942
937
|
showAlert('success', 'Évènement supprimé.');
|
|
943
938
|
calendar.refetchEvents();
|
|
944
939
|
} catch (e) {
|
|
@@ -1357,4 +1352,4 @@ try {
|
|
|
1357
1352
|
return {
|
|
1358
1353
|
init,
|
|
1359
1354
|
};
|
|
1360
|
-
});
|
|
1355
|
+
});
|