nodebb-plugin-onekite-calendar 2.0.67 → 2.0.68

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/api.js CHANGED
@@ -768,6 +768,7 @@ api.getCapabilities = async function (req, res) {
768
768
  canDeleteSpecial: false,
769
769
  canCreateOuting: false,
770
770
  canCreateReservation: false,
771
+ specialEventCategoryCid: 0,
771
772
  });
772
773
  }
773
774
  const [canMod, canSpecialC, canSpecialD, canOuting, canRes] = await Promise.all([
@@ -783,6 +784,7 @@ api.getCapabilities = async function (req, res) {
783
784
  canDeleteSpecial: canSpecialD,
784
785
  canCreateOuting: canOuting,
785
786
  canCreateReservation: canRes,
787
+ specialEventCategoryCid: parseInt(settings && settings.specialEventCategoryId, 10) || 0,
786
788
  });
787
789
  };
788
790
 
@@ -815,6 +817,7 @@ api.createSpecialEvent = async function (req, res) {
815
817
  const notes = String((req.body && req.body.notes) || '').trim();
816
818
  const lat = String((req.body && req.body.lat) || '').trim();
817
819
  const lon = String((req.body && req.body.lon) || '').trim();
820
+ const content = String((req.body && req.body.content) || '').trim();
818
821
 
819
822
  const u = await user.getUserFields(req.uid, ['username']);
820
823
  const eid = crypto.randomUUID();
@@ -827,6 +830,7 @@ api.createSpecialEvent = async function (req, res) {
827
830
  notes,
828
831
  lat,
829
832
  lon,
833
+ content,
830
834
  uid: String(req.uid),
831
835
  username: u && u.username ? String(u.username) : '',
832
836
  createdAt: String(Date.now()),
@@ -841,7 +845,8 @@ api.createSpecialEvent = async function (req, res) {
841
845
 
842
846
  // Real-time refresh for all viewers
843
847
  realtime.emitCalendarUpdated({ kind: 'specialEvent', action: 'created', eid: ev.eid });
844
- res.json({ ok: true, eid });
848
+ const categoryCid = parseInt(settings && settings.specialEventCategoryId, 10) || 0;
849
+ res.json({ ok: true, eid, categoryCid });
845
850
  };
846
851
 
847
852
  api.deleteSpecialEvent = async function (req, res) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-onekite-calendar",
3
- "version": "2.0.67",
3
+ "version": "2.0.68",
4
4
  "description": "FullCalendar-based equipment reservation workflow with admin approval & HelloAsso payment for NodeBB",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
package/public/admin.js CHANGED
@@ -615,6 +615,32 @@ define('admin/plugins/calendar-onekite', ['alerts', 'bootbox'], function (alerts
615
615
  const s = await loadSettings();
616
616
  fillForm(form, s || {});
617
617
 
618
+ // Populate special event category selector
619
+ const catSelect = document.getElementById('onekite-special-category-select');
620
+ if (catSelect) {
621
+ try {
622
+ const cats = await fetchJson('/api/categories');
623
+ const list = cats && (cats.categories || cats.categoryList || cats.data) || [];
624
+ function flatCats(arr) {
625
+ const out = [];
626
+ for (const c of (arr || [])) {
627
+ if (!c || !c.cid) continue;
628
+ out.push(c);
629
+ if (c.children && c.children.length) out.push(...flatCats(c.children));
630
+ }
631
+ return out;
632
+ }
633
+ for (const c of flatCats(list)) {
634
+ const opt = document.createElement('option');
635
+ opt.value = String(c.cid);
636
+ opt.textContent = String(c.name || c.cid);
637
+ catSelect.appendChild(opt);
638
+ }
639
+ // Re-apply saved value (fillForm ran before options were added)
640
+ if (s && s.specialEventCategoryId) catSelect.value = String(s.specialEventCategoryId);
641
+ } catch (e) { /* non-blocking */ }
642
+ }
643
+
618
644
  // Ensure default creator group prefix appears in the ACP field
619
645
  const y = new Date().getFullYear();
620
646
  const defaultGroup = `onekite-ffvl-${y}`;
package/public/client.js CHANGED
@@ -339,6 +339,12 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
339
339
  <label class="form-label">Notes (facultatif)</label>
340
340
  <textarea class="form-control" id="onekite-se-notes" rows="3" placeholder="..."></textarea>
341
341
  </div>
342
+ ${(kind !== 'outing' && opts && opts.withContent) ? `
343
+ <div class="mt-3">
344
+ <label class="form-label">Message (facultatif)</label>
345
+ <textarea class="form-control" id="onekite-se-content" rows="4" placeholder="Corps du sujet qui sera publié dans le forum (brouillon)..."></textarea>
346
+ </div>
347
+ ` : ''}
342
348
  `;
343
349
 
344
350
  return await new Promise((resolve) => {
@@ -392,8 +398,11 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
392
398
  const notes = (document.getElementById('onekite-se-notes')?.value || '').trim();
393
399
  const lat = (document.getElementById('onekite-se-lat')?.value || '').trim();
394
400
  const lon = (document.getElementById('onekite-se-lon')?.value || '').trim();
401
+ const content = (kind !== 'outing' && opts && opts.withContent)
402
+ ? (document.getElementById('onekite-se-content')?.value || '').trim()
403
+ : '';
395
404
  resolved = true;
396
- resolve({ title, start: startVal, end: endVal, address, notes, lat, lon });
405
+ resolve({ title, start: startVal, end: endVal, address, notes, lat, lon, content });
397
406
  return true;
398
407
  },
399
408
  },
@@ -1225,6 +1234,7 @@ function toDatetimeLocalValue(date) {
1225
1234
  const canDeleteSpecial = !!caps.canDeleteSpecial;
1226
1235
  const canCreateOuting = !!caps.canCreateOuting;
1227
1236
  const canCreateReservation = !!caps.canCreateReservation;
1237
+ const specialEventCategoryCid = parseInt(caps.specialEventCategoryCid, 10) || 0;
1228
1238
 
1229
1239
  // Creation chooser: Location / Prévision de sortie / Évènement (si autorisé).
1230
1240
 
@@ -1415,15 +1425,23 @@ function toDatetimeLocalValue(date) {
1415
1425
  },
1416
1426
  onCreateSpecial: async (sel) => {
1417
1427
  try {
1418
- const payload = await openSpecialEventDialog(sel);
1428
+ const payload = await openSpecialEventDialog(sel, { withContent: specialEventCategoryCid > 0 });
1419
1429
  if (!payload) return;
1420
- await fetchJson('/api/v3/plugins/calendar-onekite/special-events', {
1430
+ const resp = await fetchJson('/api/v3/plugins/calendar-onekite/special-events', {
1421
1431
  method: 'POST',
1422
1432
  body: JSON.stringify(payload),
1423
1433
  });
1424
1434
  showAlert('success', 'Évènement créé.');
1425
1435
  invalidateEventsCache();
1426
1436
  scheduleRefetch(calendar);
1437
+ const cid = (resp && resp.categoryCid) ? parseInt(resp.categoryCid, 10) : specialEventCategoryCid;
1438
+ if (payload.content && cid > 0) {
1439
+ try {
1440
+ require(['composer'], (composer) => {
1441
+ composer.newTopic({ cid, title: payload.title || 'Évènement', body: payload.content });
1442
+ });
1443
+ } catch (e) {}
1444
+ }
1427
1445
  } catch (e) {
1428
1446
  handleCreateError(e);
1429
1447
  } finally {
@@ -1495,15 +1513,23 @@ function toDatetimeLocalValue(date) {
1495
1513
  },
1496
1514
  onCreateSpecial: async (sel) => {
1497
1515
  try {
1498
- const payload = await openSpecialEventDialog(sel);
1516
+ const payload = await openSpecialEventDialog(sel, { withContent: specialEventCategoryCid > 0 });
1499
1517
  if (!payload) return;
1500
- await fetchJson('/api/v3/plugins/calendar-onekite/special-events', {
1518
+ const resp = await fetchJson('/api/v3/plugins/calendar-onekite/special-events', {
1501
1519
  method: 'POST',
1502
1520
  body: JSON.stringify(payload),
1503
1521
  });
1504
1522
  showAlert('success', 'Évènement créé.');
1505
1523
  invalidateEventsCache();
1506
1524
  scheduleRefetch(calendar);
1525
+ const cid = (resp && resp.categoryCid) ? parseInt(resp.categoryCid, 10) : specialEventCategoryCid;
1526
+ if (payload.content && cid > 0) {
1527
+ try {
1528
+ require(['composer'], (composer) => {
1529
+ composer.newTopic({ cid, title: payload.title || 'Évènement', body: payload.content });
1530
+ });
1531
+ } catch (e) {}
1532
+ }
1507
1533
  } catch (e) {
1508
1534
  const msg = (e && e.payload && (e.payload.message || e.payload.error || e.payload.msg)) ? String(e.payload.message || e.payload.error || e.payload.msg) : '';
1509
1535
  showAlert('error', msg || 'Erreur lors de la création.');
@@ -161,11 +161,13 @@
161
161
  <h4>Évènements (autre couleur)</h4>
162
162
  <div class="form-text mb-3">Permet de créer des évènements horaires (début/fin) avec adresse (Leaflet) et notes.</div>
163
163
 
164
- <h4 class="mt-3">Discord</h4>
164
+ <h4 class="mt-3">Publication forum</h4>
165
165
  <div class="mb-3">
166
- <label class="form-label">Webhook URL Évènements</label>
167
- <input class="form-control" name="discordWebhookUrlEvents" placeholder="https://discord.com/api/webhooks/...">
168
- <div class="form-text">Canal Discord dédié aux notifications d'évènements (création / annulation).</div>
166
+ <label class="form-label">Catégorie de publication des évènements</label>
167
+ <select class="form-select" name="specialEventCategoryId" id="onekite-special-category-select">
168
+ <option value="">— Désactivé —</option>
169
+ </select>
170
+ <div class="form-text">Si une catégorie est sélectionnée, un champ "Message" apparaît dans la modale de création. À la validation, le compositeur NodeBB s'ouvre pré-rempli pour que vous puissiez relire et publier.</div>
169
171
  </div>
170
172
 
171
173
  <div class="mb-3">