nodebb-plugin-calendar-onekite 11.1.7 → 11.1.8

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
@@ -5,27 +5,44 @@ const api = require('./lib/api');
5
5
  const admin = require('./lib/admin');
6
6
  const scheduler = require('./lib/scheduler');
7
7
 
8
+ const routeHelpers = require.main.require('./src/routes/helpers');
9
+
8
10
  const Plugin = {};
9
11
 
10
12
  Plugin.init = async function (params) {
11
- const { router } = params;
12
-
13
- // Page routes
14
- router.get('/calendar', params.middleware.buildHeader, controllers.renderCalendar);
15
- router.get('/api/calendar-onekite/events', api.getEvents);
16
- router.get('/api/calendar-onekite/items', api.getItems);
17
- router.post('/api/calendar-onekite/reservations', params.middleware.authenticate, api.createReservation);
18
-
19
- // Admin ACP routes
20
- router.get('/admin/plugins/calendar-onekite', params.middleware.admin.buildHeader, admin.renderAdmin);
21
- router.get('/api/admin/plugins/calendar-onekite', params.middleware.admin.authenticate, admin.getSettings);
22
- router.post('/api/admin/plugins/calendar-onekite', params.middleware.admin.authenticate, admin.saveSettings);
23
- router.get('/api/admin/plugins/calendar-onekite/pending', params.middleware.admin.authenticate, admin.listPending);
24
- router.put('/api/admin/plugins/calendar-onekite/reservations/:rid/approve', params.middleware.admin.authenticate, admin.approveReservation);
25
- router.put('/api/admin/plugins/calendar-onekite/reservations/:rid/refuse', params.middleware.admin.authenticate, admin.refuseReservation);
26
- router.post('/api/admin/plugins/calendar-onekite/purge', params.middleware.admin.authenticate, admin.purgeByYear);
27
-
28
- // Background cleanup for expired "pending" reservations
13
+ const { router, middleware } = params;
14
+
15
+ // Public page
16
+ routeHelpers.setupPageRoute(router, '/calendar', [
17
+ middleware.exposeUid,
18
+ middleware.buildHeader,
19
+ ], controllers.renderCalendar);
20
+
21
+ // ACP page
22
+ routeHelpers.setupAdminPageRoute(router, '/admin/plugins/calendar-onekite', [], admin.renderAdmin);
23
+
24
+ // API routes (NodeBB will mount these under /api/v3)
25
+ routeHelpers.setupApiRoute(router, 'get', '/plugins/calendar-onekite/events', [middleware.exposeUid], api.getEvents);
26
+ routeHelpers.setupApiRoute(router, 'get', '/plugins/calendar-onekite/items', [middleware.exposeUid], api.getItems);
27
+ routeHelpers.setupApiRoute(router, 'post', '/plugins/calendar-onekite/reservations', [
28
+ middleware.exposeUid,
29
+ middleware.ensureLoggedIn,
30
+ ], api.createReservation);
31
+
32
+ // Admin API routes (also under /api/v3/admin/...)
33
+ const adminMiddlewares = [
34
+ middleware.exposeUid,
35
+ middleware.ensureLoggedIn,
36
+ middleware.admin.checkPrivileges,
37
+ ];
38
+
39
+ routeHelpers.setupApiRoute(router, 'get', '/admin/plugins/calendar-onekite/settings', adminMiddlewares, admin.getSettings);
40
+ routeHelpers.setupApiRoute(router, 'put', '/admin/plugins/calendar-onekite/settings', adminMiddlewares, admin.saveSettings);
41
+ routeHelpers.setupApiRoute(router, 'get', '/admin/plugins/calendar-onekite/pending', adminMiddlewares, admin.listPending);
42
+ routeHelpers.setupApiRoute(router, 'put', '/admin/plugins/calendar-onekite/reservations/:rid/approve', adminMiddlewares, admin.approveReservation);
43
+ routeHelpers.setupApiRoute(router, 'put', '/admin/plugins/calendar-onekite/reservations/:rid/refuse', adminMiddlewares, admin.refuseReservation);
44
+ routeHelpers.setupApiRoute(router, 'post', '/admin/plugins/calendar-onekite/purge', adminMiddlewares, admin.purgeByYear);
45
+
29
46
  scheduler.start();
30
47
  };
31
48
 
@@ -38,8 +55,4 @@ Plugin.addAdminNavigation = async function (header) {
38
55
  return header;
39
56
  };
40
57
 
41
- // Keep compatibility with older NodeBB plugin routing hooks
42
- Plugin.addPageRoute = async function (routes) { return routes; };
43
- Plugin.addApiRoute = async function (routes) { return routes; };
44
-
45
58
  module.exports = Plugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-calendar-onekite",
3
- "version": "11.1.7",
3
+ "version": "11.1.8",
4
4
  "description": "FullCalendar-based equipment reservation workflow with HelloAsso payment for NodeBB",
5
5
  "main": "library.js",
6
6
  "scripts": {
package/public/admin.js CHANGED
@@ -105,7 +105,7 @@ define('admin/plugins/calendar-onekite', ['alerts', 'bootbox'], function (alerts
105
105
  const listEl = qs('#calendar-onekite-pending-list');
106
106
  if (!listEl) return;
107
107
  try {
108
- const resp = await http('GET', '/api/admin/plugins/calendar-onekite/pending');
108
+ const resp = await http('GET', '/api/v3/admin/plugins/calendar-onekite/pending');
109
109
  listEl.innerHTML = renderPending(resp.pending || []);
110
110
  } catch (e) {
111
111
  listEl.innerHTML = '<div class="alert alert-danger">Impossible de charger les demandes en attente.</div>';
@@ -125,7 +125,7 @@ define('admin/plugins/calendar-onekite', ['alerts', 'bootbox'], function (alerts
125
125
 
126
126
  if (btn.classList.contains('js-approve')) {
127
127
  try {
128
- await http('PUT', `/api/admin/plugins/calendar-onekite/reservations/${rid}/approve`);
128
+ await http('PUT', `/api/v3/admin/plugins/calendar-onekite/reservations/${rid}/approve`);
129
129
  alertSuccess('Réservation validée, lien de paiement envoyé.');
130
130
  await refreshPending();
131
131
  } catch (e) {
@@ -141,7 +141,7 @@ define('admin/plugins/calendar-onekite', ['alerts', 'bootbox'], function (alerts
141
141
  });
142
142
  });
143
143
  try {
144
- await http('PUT', `/api/admin/plugins/calendar-onekite/reservations/${rid}/refuse`, { note });
144
+ await http('PUT', `/api/v3/admin/plugins/calendar-onekite/reservations/${rid}/refuse`, { note });
145
145
  alertSuccess('Réservation refusée, email envoyé.');
146
146
  await refreshPending();
147
147
  } catch (e) {
@@ -160,7 +160,7 @@ define('admin/plugins/calendar-onekite', ['alerts', 'bootbox'], function (alerts
160
160
  ev.preventDefault();
161
161
  const payload = getFormData();
162
162
  try {
163
- await http('POST', '/api/admin/plugins/calendar-onekite', payload);
163
+ await http('PUT', '/api/v3/admin/plugins/calendar-onekite/settings', payload);
164
164
  if (savedEl) {
165
165
  savedEl.classList.remove('d-none');
166
166
  setTimeout(() => savedEl.classList.add('d-none'), 2000);
@@ -181,7 +181,7 @@ define('admin/plugins/calendar-onekite', ['alerts', 'bootbox'], function (alerts
181
181
  ev.preventDefault();
182
182
  const year = qs('[name="year"]', form)?.value || '';
183
183
  try {
184
- const resp = await http('POST', '/api/admin/plugins/calendar-onekite/purge', { year });
184
+ const resp = await http('POST', '/api/v3/admin/plugins/calendar-onekite/purge', { year });
185
185
  const y = resp?.result?.year;
186
186
  const purged = resp?.result?.purged;
187
187
  if (resultEl) resultEl.innerHTML = `<div class="alert alert-success">Année ${y}: ${purged} réservation(s) supprimée(s).</div>`;
@@ -193,7 +193,7 @@ define('admin/plugins/calendar-onekite', ['alerts', 'bootbox'], function (alerts
193
193
 
194
194
  async function init() {
195
195
  try {
196
- const resp = await http('GET', '/api/admin/plugins/calendar-onekite');
196
+ const resp = await http('GET', '/api/v3/admin/plugins/calendar-onekite/settings');
197
197
  setForm(resp.settings || {});
198
198
  } catch (e) {
199
199
  alertError('Impossible de charger les paramètres.');
package/public/client.js CHANGED
@@ -67,7 +67,7 @@ define('forum/calendar-onekite', ['alerts', 'bootbox'], function (alerts, bootbo
67
67
  },
68
68
  events: async function (info, success, failure) {
69
69
  try {
70
- const resp = await http('GET', `/api/calendar-onekite/events?start=${encodeURIComponent(info.startStr)}&end=${encodeURIComponent(info.endStr)}`);
70
+ const resp = await http('GET', `/api/v3/plugins/calendar-onekite/events?start=${encodeURIComponent(info.startStr)}&end=${encodeURIComponent(info.endStr)}`);
71
71
  success(resp.events || resp);
72
72
  } catch (err) {
73
73
  failure(err);
@@ -107,7 +107,7 @@ define('forum/calendar-onekite', ['alerts', 'bootbox'], function (alerts, bootbo
107
107
  async function openReservationDialog(startStr, endStr) {
108
108
  let itemsResp;
109
109
  try {
110
- itemsResp = await http('GET', '/api/calendar-onekite/items');
110
+ itemsResp = await http('GET', '/api/v3/plugins/calendar-onekite/items');
111
111
  } catch (e) {
112
112
  return bootbox.alert('Impossible de récupérer la liste du matériel (HelloAsso). Vérifiez les paramètres dans l’ACP.');
113
113
  }
@@ -162,7 +162,7 @@ define('forum/calendar-onekite', ['alerts', 'bootbox'], function (alerts, bootbo
162
162
  };
163
163
 
164
164
  try {
165
- await http('POST', '/api/calendar-onekite/reservations', payload);
165
+ await http('POST', '/api/v3/plugins/calendar-onekite/reservations', payload);
166
166
  alertSuccess('Demande envoyée (en attente de validation).');
167
167
  calendar.refetchEvents();
168
168
  } catch (err) {
@@ -1,103 +1,107 @@
1
1
  <div class="acp-page-container">
2
2
  <div class="row">
3
- <div class="col-lg-7">
4
- <h2>Calendar OneKite — Paramètres</h2>
3
+ <div class="col-lg-8">
4
+ <h3 class="mb-3">Calendar OneKite</h3>
5
5
 
6
- <form id="calendar-onekite-settings" class="mb-4">
7
- <div class="mb-3">
8
- <label class="form-label">Groupes autorisés à réserver (noms séparés par des virgules)</label>
9
- <input class="form-control" name="allowedGroups" placeholder="registered-users, membres, ..." />
10
- </div>
6
+ <form id="calendar-onekite-settings">
7
+ <div class="card mb-3">
8
+ <div class="card-header">Accès & workflow</div>
9
+ <div class="card-body">
10
+ <div class="mb-3">
11
+ <label class="form-label">Groupes autorisés à déposer une demande (CSV)</label>
12
+ <input class="form-control" name="allowedGroups" placeholder="registered-users,membres" />
13
+ </div>
11
14
 
12
- <div class="mb-3">
13
- <label class="form-label">Groupes notifiés par email (validation/refus)</label>
14
- <input class="form-control" name="notifyGroups" placeholder="administrators, ..." />
15
- </div>
15
+ <div class="mb-3">
16
+ <label class="form-label">Groupes à notifier par email (CSV)</label>
17
+ <input class="form-control" name="notifyGroups" placeholder="administrators" />
18
+ </div>
16
19
 
17
- <div class="row g-3">
18
- <div class="col-md-6">
19
- <label class="form-label">Durée de blocage d’une demande en attente (minutes)</label>
20
- <input class="form-control" type="number" min="1" name="pendingHoldMinutes" />
21
- <div class="form-text">5 minutes par défaut.</div>
22
- </div>
23
- <div class="col-md-6">
24
- <label class="form-label">Intervalle de purge automatique (secondes)</label>
25
- <input class="form-control" type="number" min="10" name="cleanupIntervalSeconds" />
20
+ <div class="row">
21
+ <div class="col-md-6 mb-3">
22
+ <label class="form-label">Durée de blocage en attente (minutes)</label>
23
+ <input class="form-control" name="pendingHoldMinutes" type="number" min="1" value="5" />
24
+ </div>
25
+ <div class="col-md-6 mb-3">
26
+ <label class="form-label">Fréquence de nettoyage (secondes)</label>
27
+ <input class="form-control" name="cleanupIntervalSeconds" type="number" min="10" value="60" />
28
+ </div>
29
+ </div>
30
+
31
+ <div class="form-check">
32
+ <input class="form-check-input" type="checkbox" name="showUsernamesOnCalendar" id="showUsernamesOnCalendar" />
33
+ <label class="form-check-label" for="showUsernamesOnCalendar">Afficher les usernames sur le calendrier</label>
34
+ </div>
26
35
  </div>
27
36
  </div>
28
37
 
29
- <hr class="my-4"/>
38
+ <div class="card mb-3">
39
+ <div class="card-header">HelloAsso</div>
40
+ <div class="card-body">
41
+ <div class="row">
42
+ <div class="col-md-4 mb-3">
43
+ <label class="form-label">Environnement</label>
44
+ <select class="form-select" name="helloassoEnv">
45
+ <option value="sandbox">Sandbox</option>
46
+ <option value="prod">Production</option>
47
+ </select>
48
+ </div>
49
+ <div class="col-md-4 mb-3">
50
+ <label class="form-label">Client ID</label>
51
+ <input class="form-control" name="helloassoClientId" />
52
+ </div>
53
+ <div class="col-md-4 mb-3">
54
+ <label class="form-label">Client Secret</label>
55
+ <input class="form-control" name="helloassoClientSecret" type="password" />
56
+ </div>
57
+ </div>
30
58
 
31
- <h4>HelloAsso</h4>
32
- <div class="row g-3">
33
- <div class="col-md-4">
34
- <label class="form-label">Environnement</label>
35
- <select class="form-select" name="helloassoEnv">
36
- <option value="sandbox">Sandbox</option>
37
- <option value="prod">Production</option>
38
- </select>
39
- </div>
40
- <div class="col-md-4">
41
- <label class="form-label">Organization slug</label>
42
- <input class="form-control" name="helloassoOrganizationSlug" placeholder="mon-asso" />
43
- </div>
44
- <div class="col-md-4">
45
- <label class="form-label">Form type</label>
46
- <input class="form-control" name="helloassoFormType" placeholder="event" />
47
- </div>
48
- <div class="col-12">
49
- <label class="form-label">Form slug</label>
50
- <input class="form-control" name="helloassoFormSlug" placeholder="location-materiel" />
51
- </div>
52
- <div class="col-md-6">
53
- <label class="form-label">Client ID</label>
54
- <input class="form-control" name="helloassoClientId" />
55
- </div>
56
- <div class="col-md-6">
57
- <label class="form-label">Client Secret</label>
58
- <input class="form-control" name="helloassoClientSecret" />
59
- </div>
60
- <div class="col-12">
61
- <label class="form-label">Return URL (optionnel)</label>
62
- <input class="form-control" name="helloassoReturnUrl" placeholder="https://www.onekite.com/calendar" />
59
+ <div class="row">
60
+ <div class="col-md-4 mb-3">
61
+ <label class="form-label">Organization Slug</label>
62
+ <input class="form-control" name="helloassoOrganizationSlug" />
63
+ </div>
64
+ <div class="col-md-4 mb-3">
65
+ <label class="form-label">Form Type</label>
66
+ <input class="form-control" name="helloassoFormType" placeholder="event, membership, crowdfunding..." />
67
+ </div>
68
+ <div class="col-md-4 mb-3">
69
+ <label class="form-label">Form Slug</label>
70
+ <input class="form-control" name="helloassoFormSlug" />
71
+ </div>
72
+ </div>
73
+
74
+ <div class="mb-3">
75
+ <label class="form-label">Return URL (optionnel)</label>
76
+ <input class="form-control" name="helloassoReturnUrl" placeholder="https://www.onekite.com/calendar" />
77
+ </div>
78
+
79
+ <div class="alert alert-info mb-0">
80
+ Les items du matériel sont récupérés depuis HelloAsso (items du formulaire).
81
+ </div>
63
82
  </div>
64
83
  </div>
65
84
 
66
- <div class="form-check mt-3">
67
- <input class="form-check-input" type="checkbox" name="showUsernamesOnCalendar" id="showUsernamesOnCalendar">
68
- <label class="form-check-label" for="showUsernamesOnCalendar">Afficher les usernames sur le calendrier</label>
69
- </div>
85
+ <button class="btn btn-primary" type="submit">Enregistrer</button>
86
+ <span id="calendar-onekite-saved" class="badge text-bg-success ms-2 d-none">Enregistré</span>
87
+ </form>
70
88
 
71
- <button class="btn btn-primary mt-3" type="submit">
72
- <i class="fa fa-save"></i> Enregistrer
73
- </button>
89
+ <hr class="my-4" />
74
90
 
75
- <span class="ms-3 text-success d-none" id="calendar-onekite-saved">Enregistré ✓</span>
76
- </form>
91
+ <h4>Demandes en attente</h4>
92
+ <div id="calendar-onekite-pending-list" class="mt-3"></div>
93
+ </div>
77
94
 
78
- <h3>Purge</h3>
79
- <form id="calendar-onekite-purge" class="row g-2 align-items-end">
80
- <div class="col-auto">
95
+ <div class="col-lg-4">
96
+ <h4>Purge</h4>
97
+ <form id="calendar-onekite-purge" class="card">
98
+ <div class="card-body">
81
99
  <label class="form-label">Année (YYYY)</label>
82
100
  <input class="form-control" name="year" placeholder="2025" />
83
- </div>
84
- <div class="col-auto">
85
- <button class="btn btn-danger" type="submit"><i class="fa fa-trash"></i> Purger</button>
86
- </div>
87
- <div class="col-12">
88
- <div class="form-text">Supprime toutes les réservations de l’année (ainsi que l’historique).</div>
101
+ <button class="btn btn-danger mt-3" type="submit">Purger</button>
102
+ <div id="calendar-onekite-purge-result" class="mt-3"></div>
89
103
  </div>
90
104
  </form>
91
- <div class="mt-2" id="calendar-onekite-purge-result"></div>
92
- </div>
93
-
94
- <div class="col-lg-5">
95
- <h2>Demandes en attente</h2>
96
- <div class="alert alert-info">
97
- Les demandes en attente expirent automatiquement après la durée définie.
98
- </div>
99
-
100
- <div id="calendar-onekite-pending-list"></div>
101
105
  </div>
102
106
  </div>
103
107
  </div>
@@ -106,8 +110,8 @@
106
110
  (function () {
107
111
  function boot() {
108
112
  if (!window.require) return setTimeout(boot, 50);
109
- window.require(['admin/plugins/calendar-onekite'], function (Admin) {
110
- Admin.init();
113
+ window.require(['admin/plugins/calendar-onekite'], function (mod) {
114
+ mod.init();
111
115
  });
112
116
  }
113
117
  boot();