nodebb-plugin-onekite-calendar 2.0.10 → 2.0.11

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/CHANGELOG.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Changelog – calendar-onekite
2
2
 
3
+ ## 1.2.18
4
+ - API events + anti double booking : les tests de chevauchement utilisent désormais en priorité startDate/endDate (YYYY-MM-DD) quand disponibles (logique calendaire pure, endDate exclusive). Cela supprime définitivement les faux chevauchements liés aux timestamps/fuseaux/DST, notamment sur mobile et « Durée rapide ».
5
+
3
6
  ## 1.2.17
4
7
  - Modale réservation : la requête de disponibilité initiale utilise aussi des dates calendaires (YYYY-MM-DD) au lieu de startStr/endStr/toISOString(), ce qui corrige le grisé erroné (mobile + durée rapide).
5
8
 
package/lib/api.js CHANGED
@@ -445,8 +445,17 @@ function computeEtag(payload) {
445
445
  }
446
446
 
447
447
  api.getEvents = async function (req, res) {
448
- const startTs = toTs(req.query.start) || 0;
449
- const endTs = toTs(req.query.end) || (Date.now() + 365 * 24 * 3600 * 1000);
448
+ const qStartRaw = (req && req.query && req.query.start !== undefined) ? String(req.query.start).trim() : '';
449
+ const qEndRaw = (req && req.query && req.query.end !== undefined) ? String(req.query.end).trim() : '';
450
+
451
+ // If the client provides date-only strings (YYYY-MM-DD), prefer purely calendar-based
452
+ // overlap checks. This avoids any dependency on server timezone, user timezone, DST,
453
+ // or how JS Date() parses inputs.
454
+ const qStartYmd = (/^\d{4}-\d{2}-\d{2}$/.test(qStartRaw)) ? qStartRaw : null;
455
+ const qEndYmd = (/^\d{4}-\d{2}-\d{2}$/.test(qEndRaw)) ? qEndRaw : null;
456
+
457
+ const startTs = toTs(qStartRaw) || 0;
458
+ const endTs = toTs(qEndRaw) || (Date.now() + 365 * 24 * 3600 * 1000);
450
459
 
451
460
  const settings = await meta.settings.get('calendar-onekite');
452
461
  const canMod = req.uid ? await canValidate(req.uid, settings) : false;
@@ -494,9 +503,19 @@ api.getEvents = async function (req, res) {
494
503
  }
495
504
  // Only show active statuses
496
505
  if (!['pending', 'awaiting_payment', 'paid'].includes(r.status)) continue;
497
- const rStart = parseInt(r.start, 10);
498
- const rEnd = parseInt(r.end, 10);
499
- if (!(rStart < endTs && startTs < rEnd)) continue; // overlap check
506
+ // Overlap check
507
+ // Prefer date-only strings (YYYY-MM-DD) for 100% reliable calendar-day logic.
508
+ const rStartYmd = (r.startDate && /^\d{4}-\d{2}-\d{2}$/.test(String(r.startDate))) ? String(r.startDate) : null;
509
+ const rEndYmd = (r.endDate && /^\d{4}-\d{2}-\d{2}$/.test(String(r.endDate))) ? String(r.endDate) : null;
510
+
511
+ if (qStartYmd && qEndYmd && rStartYmd && rEndYmd) {
512
+ // endDate is EXCLUSIVE (FullCalendar rule): overlap iff aStart < bEnd && bStart < aEnd
513
+ if (!(rStartYmd < qEndYmd && qStartYmd < rEndYmd)) continue;
514
+ } else {
515
+ const rStart = parseInt(r.start, 10);
516
+ const rEnd = parseInt(r.end, 10);
517
+ if (!(rStart < endTs && startTs < rEnd)) continue;
518
+ }
500
519
  const evs = eventsFor(r);
501
520
  for (const ev of evs) {
502
521
  const p = ev.extendedProps || {};
@@ -822,9 +841,16 @@ api.createReservation = async function (req, res) {
822
841
  const existingRows = await dbLayer.getReservations(candidateIds);
823
842
  for (const existing of (existingRows || [])) {
824
843
  if (!existing || !blocking.has(existing.status)) continue;
825
- const exStart = parseInt(existing.start, 10);
826
- const exEnd = parseInt(existing.end, 10);
827
- if (!(exStart < end && start < exEnd)) continue;
844
+ const exStartYmd = (existing.startDate && /^\d{4}-\d{2}-\d{2}$/.test(String(existing.startDate))) ? String(existing.startDate) : null;
845
+ const exEndYmd = (existing.endDate && /^\d{4}-\d{2}-\d{2}$/.test(String(existing.endDate))) ? String(existing.endDate) : null;
846
+ if (startDate && endDate && exStartYmd && exEndYmd) {
847
+ // endDate is EXCLUSIVE: overlap iff aStart < bEnd && bStart < aEnd
848
+ if (!(exStartYmd < endDate && startDate < exEndYmd)) continue;
849
+ } else {
850
+ const exStart = parseInt(existing.start, 10);
851
+ const exEnd = parseInt(existing.end, 10);
852
+ if (!(exStart < end && start < exEnd)) continue;
853
+ }
828
854
  const exItemIds = Array.isArray(existing.itemIds) ? existing.itemIds : (existing.itemId ? [existing.itemId] : []);
829
855
  const shared = exItemIds.filter(x => itemIds.includes(String(x)));
830
856
  if (shared.length) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-onekite-calendar",
3
- "version": "2.0.10",
3
+ "version": "2.0.11",
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/plugin.json CHANGED
@@ -39,5 +39,5 @@
39
39
  "acpScripts": [
40
40
  "public/admin.js"
41
41
  ],
42
- "version": "2.0.10"
42
+ "version": "2.0.11"
43
43
  }