nodebb-plugin-onekite-calendar 2.0.56 → 2.0.58
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 +47 -0
- package/library.js +2 -0
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/public/client.js +66 -6
package/lib/api.js
CHANGED
|
@@ -996,6 +996,29 @@ api.joinSpecialEvent = async function (req, res) {
|
|
|
996
996
|
});
|
|
997
997
|
};
|
|
998
998
|
|
|
999
|
+
api.leaveSpecialEvent = async function (req, res) {
|
|
1000
|
+
const settings = await getSettings();
|
|
1001
|
+
const uid = req.uid;
|
|
1002
|
+
if (!uid) return res.status(401).json({ error: 'not-logged-in' });
|
|
1003
|
+
const ok = await canCreateSpecial(uid, settings);
|
|
1004
|
+
if (!ok) return res.status(403).json({ error: 'not-allowed' });
|
|
1005
|
+
|
|
1006
|
+
const eid = String(req.params.eid || '').replace(/^special:/, '').trim();
|
|
1007
|
+
if (!eid) return res.status(400).json({ error: 'bad-id' });
|
|
1008
|
+
|
|
1009
|
+
const ev = await dbLayer.getSpecialEvent(eid);
|
|
1010
|
+
if (!ev) return res.status(404).json({ error: 'not-found' });
|
|
1011
|
+
|
|
1012
|
+
const list = normalizeUidList(ev.participants);
|
|
1013
|
+
const sUid = String(uid);
|
|
1014
|
+
const next = list.filter((x) => String(x) !== sUid);
|
|
1015
|
+
ev.participants = JSON.stringify(next);
|
|
1016
|
+
await dbLayer.saveSpecialEvent(ev);
|
|
1017
|
+
|
|
1018
|
+
realtime.emitCalendarUpdated({ kind: 'specialEvent', action: 'participants', eid });
|
|
1019
|
+
return res.json({ ok: true, participants: next, participantsUsernames: await usernamesByUids(next) });
|
|
1020
|
+
};
|
|
1021
|
+
|
|
999
1022
|
api.getCapabilities = async function (req, res) {
|
|
1000
1023
|
const settings = await getSettings();
|
|
1001
1024
|
const uid = req.uid || 0;
|
|
@@ -1163,6 +1186,30 @@ api.joinOuting = async function (req, res) {
|
|
|
1163
1186
|
return res.json({ ok: true, participants: list, participantsUsernames: await usernamesByUids(list) });
|
|
1164
1187
|
};
|
|
1165
1188
|
|
|
1189
|
+
api.leaveOuting = async function (req, res) {
|
|
1190
|
+
const settings = await getSettings();
|
|
1191
|
+
const uid = req.uid;
|
|
1192
|
+
if (!uid) return res.status(401).json({ error: 'not-logged-in' });
|
|
1193
|
+
// Outings share the same rights as reservations/locations.
|
|
1194
|
+
const ok = await canRequest(uid, settings, Date.now());
|
|
1195
|
+
if (!ok) return res.status(403).json({ error: 'not-allowed' });
|
|
1196
|
+
|
|
1197
|
+
const oid = String(req.params.oid || '').replace(/^outing:/, '').trim();
|
|
1198
|
+
if (!oid) return res.status(400).json({ error: 'bad-id' });
|
|
1199
|
+
|
|
1200
|
+
const o = await dbLayer.getOuting(oid);
|
|
1201
|
+
if (!o) return res.status(404).json({ error: 'not-found' });
|
|
1202
|
+
|
|
1203
|
+
const list = normalizeUidList(o.participants);
|
|
1204
|
+
const sUid = String(uid);
|
|
1205
|
+
const next = list.filter((x) => String(x) !== sUid);
|
|
1206
|
+
o.participants = JSON.stringify(next);
|
|
1207
|
+
await dbLayer.saveOuting(o);
|
|
1208
|
+
|
|
1209
|
+
realtime.emitCalendarUpdated({ kind: 'outing', action: 'participants', oid });
|
|
1210
|
+
return res.json({ ok: true, participants: next, participantsUsernames: await usernamesByUids(next) });
|
|
1211
|
+
};
|
|
1212
|
+
|
|
1166
1213
|
api.createOuting = async function (req, res) {
|
|
1167
1214
|
const settings = await getSettings();
|
|
1168
1215
|
if (!req.uid) return res.status(401).json({ error: 'not-logged-in' });
|
package/library.js
CHANGED
|
@@ -84,6 +84,7 @@ Plugin.init = async function (params) {
|
|
|
84
84
|
router.delete('/api/v3/plugins/calendar-onekite/special-events/:eid', ...publicExpose, api.deleteSpecialEvent);
|
|
85
85
|
// Participants (self-join) for special events
|
|
86
86
|
router.post('/api/v3/plugins/calendar-onekite/special-events/:eid/participants', ...publicExpose, api.joinSpecialEvent);
|
|
87
|
+
router.delete('/api/v3/plugins/calendar-onekite/special-events/:eid/participants', ...publicExpose, api.leaveSpecialEvent);
|
|
87
88
|
|
|
88
89
|
// Outings (prévisions de sortie)
|
|
89
90
|
router.post('/api/v3/plugins/calendar-onekite/outings', ...publicExpose, api.createOuting);
|
|
@@ -91,6 +92,7 @@ Plugin.init = async function (params) {
|
|
|
91
92
|
router.delete('/api/v3/plugins/calendar-onekite/outings/:oid', ...publicExpose, api.deleteOuting);
|
|
92
93
|
// Participants (self-join) for outings
|
|
93
94
|
router.post('/api/v3/plugins/calendar-onekite/outings/:oid/participants', ...publicExpose, api.joinOuting);
|
|
95
|
+
router.delete('/api/v3/plugins/calendar-onekite/outings/:oid/participants', ...publicExpose, api.leaveOuting);
|
|
94
96
|
|
|
95
97
|
// Calendar export (ICS)
|
|
96
98
|
// Note: reservations are protected by a signature in the querystring.
|
package/package.json
CHANGED
package/plugin.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1675,10 +1675,14 @@ function toDatetimeLocalValue(date) {
|
|
|
1675
1675
|
const hasCoords = Number.isFinite(lat) && Number.isFinite(lon);
|
|
1676
1676
|
const notes = String(p.notes || '').trim();
|
|
1677
1677
|
const participants = Array.isArray(p.participantsUsernames) ? p.participantsUsernames : [];
|
|
1678
|
+
const eidPlain = escapeHtml(String(p.eid || '').replace(/^special:/, ''));
|
|
1678
1679
|
const joinBtn = (p.canJoin && !p.isParticipant)
|
|
1679
|
-
? `<a href="#" class="onekite-join-special ms-2" data-eid="${
|
|
1680
|
+
? `<a href="#" class="onekite-join-special ms-2" data-eid="${eidPlain}" title="S'ajouter"><i class="fa fa-plus"></i></a>`
|
|
1680
1681
|
: '';
|
|
1681
|
-
const
|
|
1682
|
+
const leaveBtn = (p.canJoin && p.isParticipant)
|
|
1683
|
+
? `<a href="#" class="onekite-leave-special ms-2" data-eid="${eidPlain}" title="Se retirer"><i class="fa fa-minus"></i></a>`
|
|
1684
|
+
: '';
|
|
1685
|
+
const participantsHtml = `<div class="mb-2" id="onekite-participants-special"><strong>Participants</strong>${joinBtn}${leaveBtn}<br>` +
|
|
1682
1686
|
(participants.length
|
|
1683
1687
|
? participants.map((name) => {
|
|
1684
1688
|
const u = String(name || '').trim();
|
|
@@ -1755,12 +1759,38 @@ function toDatetimeLocalValue(date) {
|
|
|
1755
1759
|
return `<a class="onekite-user-link me-2" href="${window.location.origin}/user/${encodeURIComponent(u)}">${escapeHtml(u)}</a>`;
|
|
1756
1760
|
}).filter(Boolean).join('')
|
|
1757
1761
|
: `<span class="text-muted">Aucun</span>`;
|
|
1758
|
-
box.html(`<strong>Participants</strong><br>${links}`);
|
|
1762
|
+
box.html(`<strong>Participants</strong><a href="#" class="onekite-leave-special ms-2" data-eid="${escapeHtml(eid)}" title="Se retirer"><i class="fa fa-minus"></i></a><br>${links}`);
|
|
1759
1763
|
}
|
|
1760
1764
|
} catch (e3) {
|
|
1761
1765
|
showAlert('error', "Impossible de s'ajouter.");
|
|
1762
1766
|
}
|
|
1763
1767
|
});
|
|
1768
|
+
|
|
1769
|
+
dlg.find('.onekite-leave-special').off('click').on('click', async (e2) => {
|
|
1770
|
+
e2.preventDefault();
|
|
1771
|
+
const btn = e2.currentTarget;
|
|
1772
|
+
if (!btn) return;
|
|
1773
|
+
try {
|
|
1774
|
+
btn.classList.add('disabled');
|
|
1775
|
+
const eid = String(btn.getAttribute('data-eid') || '').trim();
|
|
1776
|
+
if (!eid) return;
|
|
1777
|
+
const r = await fetchJson(`/api/v3/plugins/calendar-onekite/special-events/${encodeURIComponent(eid)}/participants`, { method: 'DELETE' });
|
|
1778
|
+
const names = Array.isArray(r && r.participantsUsernames) ? r.participantsUsernames : [];
|
|
1779
|
+
const box = dlg.find('#onekite-participants-special');
|
|
1780
|
+
if (box && box.length) {
|
|
1781
|
+
const links = names.length
|
|
1782
|
+
? names.map((name) => {
|
|
1783
|
+
const u = String(name || '').trim();
|
|
1784
|
+
if (!u) return '';
|
|
1785
|
+
return `<a class="onekite-user-link me-2" href="${window.location.origin}/user/${encodeURIComponent(u)}">${escapeHtml(u)}</a>`;
|
|
1786
|
+
}).filter(Boolean).join('')
|
|
1787
|
+
: `<span class="text-muted">Aucun</span>`;
|
|
1788
|
+
box.html(`<strong>Participants</strong><a href="#" class="onekite-join-special ms-2" data-eid="${escapeHtml(eid)}" title="S'ajouter"><i class="fa fa-plus"></i></a><br>${links}`);
|
|
1789
|
+
}
|
|
1790
|
+
} catch (e3) {
|
|
1791
|
+
showAlert('error', "Impossible de se retirer.");
|
|
1792
|
+
}
|
|
1793
|
+
});
|
|
1764
1794
|
});
|
|
1765
1795
|
} catch (e) {}
|
|
1766
1796
|
try {
|
|
@@ -1783,10 +1813,14 @@ function toDatetimeLocalValue(date) {
|
|
|
1783
1813
|
const hasCoords = Number.isFinite(lat) && Number.isFinite(lon);
|
|
1784
1814
|
const notes = String(p.notes || '').trim();
|
|
1785
1815
|
const participants = Array.isArray(p.participantsUsernames) ? p.participantsUsernames : [];
|
|
1816
|
+
const oidPlain = escapeHtml(String(p.oid || '').replace(/^outing:/, ''));
|
|
1786
1817
|
const joinBtn = (p.canJoin && !p.isParticipant)
|
|
1787
|
-
? `<a href="#" class="onekite-join-outing ms-2" data-oid="${
|
|
1818
|
+
? `<a href="#" class="onekite-join-outing ms-2" data-oid="${oidPlain}" title="S'ajouter"><i class="fa fa-plus"></i></a>`
|
|
1788
1819
|
: '';
|
|
1789
|
-
const
|
|
1820
|
+
const leaveBtn = (p.canJoin && p.isParticipant)
|
|
1821
|
+
? `<a href="#" class="onekite-leave-outing ms-2" data-oid="${oidPlain}" title="Se retirer"><i class="fa fa-minus"></i></a>`
|
|
1822
|
+
: '';
|
|
1823
|
+
const participantsHtml = `<div class="mb-2" id="onekite-participants-outing"><strong>Participants</strong>${joinBtn}${leaveBtn}<br>` +
|
|
1790
1824
|
(participants.length
|
|
1791
1825
|
? participants.map((name) => {
|
|
1792
1826
|
const u = String(name || '').trim();
|
|
@@ -1863,12 +1897,38 @@ function toDatetimeLocalValue(date) {
|
|
|
1863
1897
|
return `<a class="onekite-user-link me-2" href="${window.location.origin}/user/${encodeURIComponent(u)}">${escapeHtml(u)}</a>`;
|
|
1864
1898
|
}).filter(Boolean).join('')
|
|
1865
1899
|
: `<span class="text-muted">Aucun</span>`;
|
|
1866
|
-
box.html(`<strong>Participants</strong><br>${links}`);
|
|
1900
|
+
box.html(`<strong>Participants</strong><a href="#" class="onekite-leave-outing ms-2" data-oid="${escapeHtml(oid)}" title="Se retirer"><i class="fa fa-minus"></i></a><br>${links}`);
|
|
1867
1901
|
}
|
|
1868
1902
|
} catch (e3) {
|
|
1869
1903
|
showAlert('error', "Impossible de s'ajouter.");
|
|
1870
1904
|
}
|
|
1871
1905
|
});
|
|
1906
|
+
|
|
1907
|
+
dlg.find('.onekite-leave-outing').off('click').on('click', async (e2) => {
|
|
1908
|
+
e2.preventDefault();
|
|
1909
|
+
const btn = e2.currentTarget;
|
|
1910
|
+
if (!btn) return;
|
|
1911
|
+
try {
|
|
1912
|
+
btn.classList.add('disabled');
|
|
1913
|
+
const oid = String(btn.getAttribute('data-oid') || '').trim();
|
|
1914
|
+
if (!oid) return;
|
|
1915
|
+
const r = await fetchJson(`/api/v3/plugins/calendar-onekite/outings/${encodeURIComponent(oid)}/participants`, { method: 'DELETE' });
|
|
1916
|
+
const names = Array.isArray(r && r.participantsUsernames) ? r.participantsUsernames : [];
|
|
1917
|
+
const box = dlg.find('#onekite-participants-outing');
|
|
1918
|
+
if (box && box.length) {
|
|
1919
|
+
const links = names.length
|
|
1920
|
+
? names.map((name) => {
|
|
1921
|
+
const u = String(name || '').trim();
|
|
1922
|
+
if (!u) return '';
|
|
1923
|
+
return `<a class="onekite-user-link me-2" href="${window.location.origin}/user/${encodeURIComponent(u)}">${escapeHtml(u)}</a>`;
|
|
1924
|
+
}).filter(Boolean).join('')
|
|
1925
|
+
: `<span class="text-muted">Aucun</span>`;
|
|
1926
|
+
box.html(`<strong>Participants</strong><a href="#" class="onekite-join-outing ms-2" data-oid="${escapeHtml(oid)}" title="S'ajouter"><i class="fa fa-plus"></i></a><br>${links}`);
|
|
1927
|
+
}
|
|
1928
|
+
} catch (e3) {
|
|
1929
|
+
showAlert('error', "Impossible de se retirer.");
|
|
1930
|
+
}
|
|
1931
|
+
});
|
|
1872
1932
|
});
|
|
1873
1933
|
} catch (e) {}
|
|
1874
1934
|
try {
|