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 CHANGED
@@ -19,12 +19,33 @@ function formatFR(tsOrIso) {
19
19
  }
20
20
 
21
21
  async function sendEmail(template, toEmail, subject, data) {
22
- if (!toEmail) return;
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),
@@ -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
- if (!toEmail) return;
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
- if (typeof emailer.send === 'function') {
48
- if (emailer.send.length >= 4) {
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
- // We register both v3 and legacy (/api/...) endpoints as a compatibility fallback.
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
- ['/api/v3/plugins/calendar-onekite/events', '/api/plugins/calendar-onekite/events'].forEach((p) => {
60
- router.get(p, ...publicExpose, api.getEvents);
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', '/api/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.99",
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": "^3.0.0 || ^4.0.0"
12
+ "compatibility": "^4.0.0"
13
13
  }
14
- }
14
+ }
package/plugin.json CHANGED
@@ -31,5 +31,5 @@
31
31
  "acpScripts": [
32
32
  "public/admin.js"
33
33
  ],
34
- "version": "1.0.47"
35
- }
34
+ "version": "1.0.48"
35
+ }
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
- try {
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)) ? 'Erreur vous devez être adhérent Onekite' : 'Erreur lors de la création de la demande.'));
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
+ });