nodebb-plugin-onekite-calendar 2.0.47 → 2.0.49
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 +21 -3
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/public/client.js +25 -8
package/lib/api.js
CHANGED
|
@@ -924,7 +924,9 @@ api.getCapabilities = async function (req, res) {
|
|
|
924
924
|
canModerate: canMod,
|
|
925
925
|
canCreateSpecial: uid ? await canCreateSpecial(uid, settings) : false,
|
|
926
926
|
canDeleteSpecial: uid ? await canDeleteSpecial(uid, settings) : false,
|
|
927
|
+
// Outings share the same rights as reservations/locations.
|
|
927
928
|
canCreateOuting: uid ? await canRequest(uid, settings, Date.now()) : false,
|
|
929
|
+
canCreateReservation: uid ? await canRequest(uid, settings, Date.now()) : false,
|
|
928
930
|
});
|
|
929
931
|
};
|
|
930
932
|
|
|
@@ -1050,8 +1052,18 @@ api.createOuting = async function (req, res) {
|
|
|
1050
1052
|
if (!req.uid) return res.status(401).json({ error: 'not-logged-in' });
|
|
1051
1053
|
|
|
1052
1054
|
const startTs = toTs(req.body && req.body.start);
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
+
// Permissions for outings must match reservations/locations rights.
|
|
1056
|
+
// We intentionally base the "auto" yearly group on the *current* year,
|
|
1057
|
+
// not on the outing date, so members can plan future outings without
|
|
1058
|
+
// requiring next-year group membership.
|
|
1059
|
+
const ok = await canRequest(req.uid, settings, Date.now());
|
|
1060
|
+
if (!ok) {
|
|
1061
|
+
return res.status(403).json({
|
|
1062
|
+
error: 'not-allowed',
|
|
1063
|
+
code: 'NOT_MEMBER',
|
|
1064
|
+
message: 'Vous devez être adhérent Onekite',
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1055
1067
|
|
|
1056
1068
|
const title = String((req.body && req.body.title) || '').trim() || 'Sortie';
|
|
1057
1069
|
const endTs = toTs(req.body && req.body.end);
|
|
@@ -1182,7 +1194,13 @@ api.createReservation = async function (req, res) {
|
|
|
1182
1194
|
const settings = await meta.settings.get('calendar-onekite');
|
|
1183
1195
|
const startPreview = toTs(req.body.start);
|
|
1184
1196
|
const ok = await canRequest(uid, settings, startPreview);
|
|
1185
|
-
if (!ok)
|
|
1197
|
+
if (!ok) {
|
|
1198
|
+
return res.status(403).json({
|
|
1199
|
+
error: 'not-allowed',
|
|
1200
|
+
code: 'NOT_MEMBER',
|
|
1201
|
+
message: 'Vous devez être adhérent Onekite',
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1186
1204
|
|
|
1187
1205
|
const isValidator = await canValidate(uid, settings);
|
|
1188
1206
|
|
package/package.json
CHANGED
package/plugin.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1203,6 +1203,8 @@ function toDatetimeLocalValue(date) {
|
|
|
1203
1203
|
const caps = await loadCapabilities().catch(() => ({}));
|
|
1204
1204
|
const canCreateSpecial = !!caps.canCreateSpecial;
|
|
1205
1205
|
const canDeleteSpecial = !!caps.canDeleteSpecial;
|
|
1206
|
+
const canCreateOuting = !!caps.canCreateOuting;
|
|
1207
|
+
const canCreateReservation = !!caps.canCreateReservation;
|
|
1206
1208
|
|
|
1207
1209
|
// Creation chooser: Location / Prévision de sortie / Évènement (si autorisé).
|
|
1208
1210
|
|
|
@@ -1281,6 +1283,17 @@ function toDatetimeLocalValue(date) {
|
|
|
1281
1283
|
if (isDialogOpen) return;
|
|
1282
1284
|
if (!lockAction('create', 900)) return;
|
|
1283
1285
|
|
|
1286
|
+
// If the user is not an Onekite member (or not logged in), do not open
|
|
1287
|
+
// the creation chooser at all. This avoids a confusing "not-allowed"
|
|
1288
|
+
// error after the user fills the form.
|
|
1289
|
+
try {
|
|
1290
|
+
if (!canCreateReservation && !canCreateOuting && !canCreateSpecial) {
|
|
1291
|
+
showAlert('error', 'Vous devez être adhérent Onekite');
|
|
1292
|
+
try { calendar.unselect(); } catch (e) {}
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1295
|
+
} catch (e) {}
|
|
1296
|
+
|
|
1284
1297
|
// Business rule: nothing can be created in the past.
|
|
1285
1298
|
try {
|
|
1286
1299
|
const startDateCheck = toLocalYmd(info.start);
|
|
@@ -1325,7 +1338,7 @@ function toDatetimeLocalValue(date) {
|
|
|
1325
1338
|
// Buttons order matters for UX: put "Annuler" at bottom-right (last).
|
|
1326
1339
|
const buttons = {};
|
|
1327
1340
|
|
|
1328
|
-
buttons.location = {
|
|
1341
|
+
if (canCreateReservation) buttons.location = {
|
|
1329
1342
|
label: 'Location',
|
|
1330
1343
|
className: 'btn-onekite-location',
|
|
1331
1344
|
callback: async () => {
|
|
@@ -1364,7 +1377,7 @@ function toDatetimeLocalValue(date) {
|
|
|
1364
1377
|
},
|
|
1365
1378
|
};
|
|
1366
1379
|
|
|
1367
|
-
buttons.outing = {
|
|
1380
|
+
if (canCreateOuting) buttons.outing = {
|
|
1368
1381
|
label: 'Prévision de sortie',
|
|
1369
1382
|
className: 'btn-onekite-outing',
|
|
1370
1383
|
callback: async () => {
|
|
@@ -1494,12 +1507,13 @@ function toDatetimeLocalValue(date) {
|
|
|
1494
1507
|
}
|
|
1495
1508
|
} catch (e) {}
|
|
1496
1509
|
|
|
1497
|
-
// IMPORTANT: align "special"
|
|
1510
|
+
// IMPORTANT: align "special" events and "outings" display exactly like
|
|
1511
|
+
// reservation icons.
|
|
1498
1512
|
// We inject the clock + time range directly into the event title so FC
|
|
1499
1513
|
// doesn't reserve a separate time column (which creates a leading gap).
|
|
1500
1514
|
const mapped = (Array.isArray(data) ? data : []).map((ev) => {
|
|
1501
1515
|
try {
|
|
1502
|
-
if (ev && ev.extendedProps && ev.extendedProps.type === 'special' && ev.start && ev.end) {
|
|
1516
|
+
if (ev && ev.extendedProps && (ev.extendedProps.type === 'special' || ev.extendedProps.type === 'outing') && ev.start && ev.end) {
|
|
1503
1517
|
// Force the same visual layout as reservations in month view
|
|
1504
1518
|
// (avoid the "dot" layout which introduces a leading gap).
|
|
1505
1519
|
ev.display = 'block';
|
|
@@ -1525,15 +1539,18 @@ function toDatetimeLocalValue(date) {
|
|
|
1525
1539
|
}
|
|
1526
1540
|
},
|
|
1527
1541
|
eventDidMount: function (arg) {
|
|
1528
|
-
// Keep special event colors consistent
|
|
1542
|
+
// Keep special event + outing colors consistent even if a theme overrides
|
|
1543
|
+
// FullCalendar defaults.
|
|
1529
1544
|
try {
|
|
1530
1545
|
const ev = arg && arg.event;
|
|
1531
1546
|
if (!ev) return;
|
|
1532
|
-
|
|
1547
|
+
const t = ev.extendedProps && ev.extendedProps.type;
|
|
1548
|
+
if (t === 'special' || t === 'outing') {
|
|
1533
1549
|
const el2 = arg.el;
|
|
1534
1550
|
if (el2 && el2.style) {
|
|
1535
|
-
|
|
1536
|
-
el2.style.
|
|
1551
|
+
const bg = (t === 'outing') ? '#2980b9' : '#8e44ad';
|
|
1552
|
+
el2.style.backgroundColor = bg;
|
|
1553
|
+
el2.style.borderColor = bg;
|
|
1537
1554
|
el2.style.color = '#ffffff';
|
|
1538
1555
|
}
|
|
1539
1556
|
}
|