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
package/plugin.json
CHANGED
|
@@ -1,72 +1,65 @@
|
|
|
1
|
-
<div class="acp-page-container
|
|
1
|
+
<div class="acp-page-container">
|
|
2
2
|
<h1>Equipment Calendar</h1>
|
|
3
3
|
|
|
4
|
-
<
|
|
5
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
</
|
|
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
|
-
|
|
39
|
-
<
|
|
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
|
-
|
|
44
|
-
<
|
|
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
|
-
|
|
53
|
-
<
|
|
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
|
-
|
|
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
|
-
<
|
|
71
|
-
|
|
72
|
-
|
|
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="{
|
|
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
|
|