nodebb-plugin-equipment-calendar 0.2.8 → 0.3.0

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
@@ -311,8 +311,9 @@ plugin.init = async function (params) {
311
311
 
312
312
  // Admin (ACP) routes
313
313
  if (mid && mid.admin) {
314
- router.get('/admin/plugins/equipment-calendar', mid.admin.buildHeader, renderAdminPage);
315
- router.get('/api/admin/plugins/equipment-calendar', renderAdminPage);
314
+ router.get('/admin/plugins/equipment-calendar', middleware.applyCSRF, mid.admin.buildHeader, renderAdminPage);
315
+ router.get('/api/admin/plugins/equipment-calendar', middleware.applyCSRF, renderAdminPage);
316
+ router.post('/admin/plugins/equipment-calendar/save', middleware.applyCSRF, handleAdminSave);
316
317
  }
317
318
 
318
319
  // Convenience alias (optional): /calendar -> /equipment/calendar
@@ -392,8 +393,8 @@ plugin.addAdminNavigation = async function (header) {
392
393
  // --- Admin page routes (ACP) ---
393
394
  plugin.addAdminRoutes = async function (params) {
394
395
  const { router, middleware: mid } = params;
395
- router.get('/admin/plugins/equipment-calendar', mid.admin.buildHeader, renderAdminPage);
396
- router.get('/api/admin/plugins/equipment-calendar', renderAdminPage);
396
+ router.get('/admin/plugins/equipment-calendar', middleware.applyCSRF, mid.admin.buildHeader, renderAdminPage);
397
+ router.get('/api/admin/plugins/equipment-calendar', middleware.applyCSRF, renderAdminPage);
397
398
  };
398
399
 
399
400
  async function renderAdminPage(req, res) {
@@ -487,7 +488,6 @@ async function renderCalendarPage(req, res) {
487
488
  eventsB64: Buffer.from(JSON.stringify(events), 'utf8').toString('base64'),
488
489
  blocksB64: Buffer.from(JSON.stringify(blocks), 'utf8').toString('base64'),
489
490
  itemsB64: Buffer.from(JSON.stringify(items.map(i => ({ id: i.id, name: i.name, location: i.location }))), 'utf8').toString('base64'),
490
- csrf: req.csrfToken,
491
491
  });
492
492
  }
493
493
 
@@ -537,7 +537,6 @@ async function renderApprovalsPage(req, res) {
537
537
  title: 'Validation des réservations',
538
538
  rows,
539
539
  hasRows: Array.isArray(rows) && rows.length > 0,
540
- csrf: req.csrfToken,
541
540
  });
542
541
  }
543
542
 
@@ -684,4 +683,35 @@ async function handleRejectReservation(req, res) {
684
683
  }
685
684
  }
686
685
 
686
+
687
+ async function handleAdminSave(req, res) {
688
+ try {
689
+ // Simple admin check (avoid relying on client-side require/settings)
690
+ const isAdmin = req.uid ? await groups.isMember(req.uid, 'administrators') : false;
691
+ if (!isAdmin) {
692
+ return helpers.notAllowed(req, res);
693
+ }
694
+
695
+ const values = {
696
+ creatorGroups: String(req.body.creatorGroups || DEFAULT_SETTINGS.creatorGroups),
697
+ approverGroup: String(req.body.approverGroup || DEFAULT_SETTINGS.approverGroup),
698
+ notifyGroup: String(req.body.notifyGroup || DEFAULT_SETTINGS.notifyGroup),
699
+ itemsJson: String(req.body.itemsJson || DEFAULT_SETTINGS.itemsJson),
700
+ ha_clientId: String(req.body.ha_clientId || ''),
701
+ ha_clientSecret: String(req.body.ha_clientSecret || ''),
702
+ ha_organizationSlug: String(req.body.ha_organizationSlug || ''),
703
+ ha_returnUrl: String(req.body.ha_returnUrl || ''),
704
+ ha_webhookSecret: String(req.body.ha_webhookSecret || ''),
705
+ defaultView: String(req.body.defaultView || DEFAULT_SETTINGS.defaultView),
706
+ timezone: String(req.body.timezone || DEFAULT_SETTINGS.timezone),
707
+ showRequesterToAll: (req.body.showRequesterToAll === '1' || req.body.showRequesterToAll === 'on') ? '1' : '0',
708
+ };
709
+
710
+ await meta.settings.set(SETTINGS_KEY, values);
711
+ return res.redirect('/admin/plugins/equipment-calendar');
712
+ } catch (e) {
713
+ return res.status(500).send(e.message || 'error');
714
+ }
715
+ }
716
+
687
717
  module.exports = plugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-equipment-calendar",
3
- "version": "0.2.8",
3
+ "version": "0.3.0",
4
4
  "description": "Equipment reservation calendar for NodeBB (FullCalendar, approvals, HelloAsso payments)",
5
5
  "main": "library.js",
6
6
  "scripts": {
package/plugin.json CHANGED
@@ -26,7 +26,6 @@
26
26
  "scripts": [
27
27
  "public/js/client.js"
28
28
  ],
29
- "acpScripts": [
30
- "public/js/admin.js"
31
- ]
29
+ "version": "0.2.2",
30
+ "minver": "4.7.1"
32
31
  }
@@ -1,72 +1,65 @@
1
- <div class="acp-page-container equipment-calendar-settings">
1
+ <div class="acp-page-container">
2
2
  <h1>Equipment Calendar</h1>
3
3
 
4
- <div class="alert alert-warning">
5
- Le champ "Matériel" doit être un JSON valide (array). Exemple :
6
- <pre class="mb-0">[
7
- { "id": "cam1", "name": "Caméra A", "priceCents": 5000, "location": "Stock A", "active": true },
8
- { "id": "light1", "name": "Projecteur", "priceCents": 2000, "location": "Stock B", "active": true }
9
- ]</pre>
10
- </div>
11
-
12
- <div class="row">
13
- <div class="col-lg-8">
14
- <div class="card card-body mb-3">
15
- <h5>Permissions</h5>
16
-
17
- <div class="mb-3">
18
- <label class="form-label">Groupes autorisés à créer (CSV)</label>
19
- <input class="form-control" data-key="creatorGroups" placeholder="registered-users,staff">
20
- </div>
4
+ <form method="post" action="/admin/plugins/equipment-calendar/save" class="mb-3">
5
+ <input type="hidden" name="_csrf" value="{config.csrf_token}">
21
6
 
22
- <div class="mb-3">
23
- <label class="form-label">Groupe validateur</label>
24
- <input class="form-control" data-key="approverGroup" placeholder="administrators">
25
- </div>
26
-
27
- <div class="mb-3">
28
- <label class="form-label">Groupe notifié (emails/notifs)</label>
29
- <input class="form-control" data-key="notifyGroup" placeholder="administrators">
30
- </div>
7
+ <div class="alert alert-warning">
8
+ Le champ "Matériel" doit être un JSON valide (array). Exemple :
9
+ <pre class="mb-0">[
10
+ { "id": "cam1", "name": "Caméra A", "priceCents": 50, "location": "Stock A", "active": true },
11
+ { "id": "light1", "name": "Projecteur", "priceCents": 20, "location": "Stock B", "active": true }
12
+ ]</pre>
13
+ <div class="mt-2">Note : <strong>priceCents est en euros</strong> dans ce plugin (ex: 50 = 50€).</div>
14
+ </div>
31
15
 
32
- <div class="form-check">
33
- <input class="form-check-input" type="checkbox" data-key="showRequesterToAll" id="showRequesterToAll">
34
- <label class="form-check-label" for="showRequesterToAll">Afficher le demandeur à tout le monde</label>
35
- </div>
16
+ <div class="card card-body mb-3">
17
+ <h5>Permissions</h5>
18
+ <div class="mb-3">
19
+ <label class="form-label">Groupes autorisés à créer (CSV)</label>
20
+ <input name="creatorGroups" class="form-control" value="{settings.creatorGroups}">
36
21
  </div>
37
-
38
- <div class="card card-body mb-3">
39
- <h5>Matériel</h5>
40
- <textarea class="form-control" rows="10" data-key="itemsJson"></textarea>
22
+ <div class="mb-3">
23
+ <label class="form-label">Groupe validateur</label>
24
+ <input name="approverGroup" class="form-control" value="{settings.approverGroup}">
41
25
  </div>
42
-
43
- <div class="card card-body mb-3">
44
- <h5>HelloAsso</h5>
45
- <div class="mb-3"><label class="form-label">Client ID</label><input class="form-control" data-key="ha_clientId"></div>
46
- <div class="mb-3"><label class="form-label">Client Secret</label><input class="form-control" data-key="ha_clientSecret"></div>
47
- <div class="mb-3"><label class="form-label">Organization Slug</label><input class="form-control" data-key="ha_organizationSlug"></div>
48
- <div class="mb-3"><label class="form-label">Return URL</label><input class="form-control" data-key="ha_returnUrl"></div>
49
- <div class="mb-3"><label class="form-label">Webhook Secret (HMAC SHA256)</label><input class="form-control" data-key="ha_webhookSecret"></div>
26
+ <div class="mb-3">
27
+ <label class="form-label">Groupe notifié (emails/notifs)</label>
28
+ <input name="notifyGroup" class="form-control" value="{settings.notifyGroup}">
50
29
  </div>
51
-
52
- <div class="card card-body mb-3">
53
- <h5>Calendrier</h5>
54
- <div class="mb-3">
55
- <label class="form-label">Vue par défaut</label>
56
- <select class="form-select" data-key="defaultView">
57
- <option value="dayGridMonth">Mois</option>
58
- <option value="timeGridWeek">Semaine</option>
59
- <option value="timeGridDay">Jour</option>
60
- </select>
61
- </div>
62
- <div class="mb-3"><label class="form-label">Timezone</label><input class="form-control" data-key="timezone"></div>
30
+ <div class="form-check">
31
+ <input class="form-check-input" type="checkbox" name="showRequesterToAll" id="showRequesterToAll" {{{ if view_showRequesterToAll }}}checked{{{ end }}}>
32
+ <label class="form-check-label" for="showRequesterToAll">Afficher le demandeur à tout le monde</label>
63
33
  </div>
34
+ </div>
64
35
 
65
- <button id="save" class="btn btn-primary">Sauvegarder</button>
36
+ <div class="card card-body mb-3">
37
+ <h5>Matériel</h5>
38
+ <textarea name="itemsJson" class="form-control" rows="10">{settings.itemsJson}</textarea>
39
+ </div>
40
+
41
+ <div class="card card-body mb-3">
42
+ <h5>HelloAsso</h5>
43
+ <div class="mb-3"><label class="form-label">Client ID</label><input name="ha_clientId" class="form-control" value="{settings.ha_clientId}"></div>
44
+ <div class="mb-3"><label class="form-label">Client Secret</label><input name="ha_clientSecret" class="form-control" value="{settings.ha_clientSecret}"></div>
45
+ <div class="mb-3"><label class="form-label">Organization Slug</label><input name="ha_organizationSlug" class="form-control" value="{settings.ha_organizationSlug}"></div>
46
+ <div class="mb-3"><label class="form-label">Return URL</label><input name="ha_returnUrl" class="form-control" value="{settings.ha_returnUrl}"></div>
47
+ <div class="mb-3"><label class="form-label">Webhook Secret (HMAC SHA256)</label><input name="ha_webhookSecret" class="form-control" value="{settings.ha_webhookSecret}"></div>
66
48
  </div>
67
- </div>
68
- </div>
69
49
 
70
- <script>
71
- require(['admin/plugins/equipment-calendar'], function (m) { m.init(); });
72
- </script>
50
+ <div class="card card-body mb-3">
51
+ <h5>Calendrier</h5>
52
+ <div class="mb-3">
53
+ <label class="form-label">Vue par défaut</label>
54
+ <select name="defaultView" class="form-select">
55
+ <option value="dayGridMonth" {{{ if view_dayGridMonth }}}selected{{{ end }}}>Mois</option>
56
+ <option value="timeGridWeek" {{{ if view_timeGridWeek }}}selected{{{ end }}}>Semaine</option>
57
+ <option value="timeGridDay" {{{ if view_timeGridDay }}}selected{{{ end }}}>Jour</option>
58
+ </select>
59
+ </div>
60
+ <div class="mb-3"><label class="form-label">Timezone</label><input name="timezone" class="form-control" value="{settings.timezone}"></div>
61
+ </div>
62
+
63
+ <button class="btn btn-primary" type="submit">Sauvegarder</button>
64
+ </form>
65
+ </div>
@@ -24,7 +24,7 @@
24
24
  <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
25
25
  </div>
26
26
  <div class="modal-body">
27
- <input type="hidden" name="_csrf" value="{csrf}">
27
+ <input type="hidden" name="_csrf" value="{config.csrf_token}">
28
28
  <input type="hidden" name="start" value="">
29
29
  <input type="hidden" name="end" value="">
30
30