nodebb-plugin-onekite-calendar 2.0.70 → 2.0.72
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/admin.js +0 -4
- package/lib/api.js +9 -27
- package/lib/db.js +3 -16
- package/lib/helloassoWebhook.js +0 -3
- package/lib/scheduler.js +1 -4
- package/lib/shared.js +2 -2
- package/library.js +20 -22
- package/package.json +1 -1
- package/public/client.js +10 -3
package/lib/admin.js
CHANGED
package/lib/api.js
CHANGED
|
@@ -361,12 +361,6 @@ function eventsForOuting(o) {
|
|
|
361
361
|
|
|
362
362
|
const api = {};
|
|
363
363
|
|
|
364
|
-
// baseUrl, hmacSecret, signCalendarLink, ymdToCompact, dtToGCalUtc,
|
|
365
|
-
// buildCalendarLinks are imported from shared.js
|
|
366
|
-
function baseUrl() {
|
|
367
|
-
return forumBaseUrl();
|
|
368
|
-
}
|
|
369
|
-
|
|
370
364
|
function computeEtag(payload) {
|
|
371
365
|
// Weak ETag is fine here: it is only used to skip identical JSON payloads.
|
|
372
366
|
const hash = crypto.createHash('sha1').update(JSON.stringify(payload)).digest('hex');
|
|
@@ -773,19 +767,18 @@ api.getCapabilities = async function (req, res) {
|
|
|
773
767
|
specialEventCategoryCid: 0,
|
|
774
768
|
});
|
|
775
769
|
}
|
|
776
|
-
const [canMod, canSpecialC, canSpecialD,
|
|
770
|
+
const [canMod, canSpecialC, canSpecialD, canReq] = await Promise.all([
|
|
777
771
|
canValidate(uid, settings),
|
|
778
772
|
canCreateSpecial(uid, settings),
|
|
779
773
|
canDeleteSpecial(uid, settings),
|
|
780
774
|
canRequest(uid, settings, Date.now()),
|
|
781
|
-
canRequest(uid, settings, Date.now()),
|
|
782
775
|
]);
|
|
783
776
|
res.json({
|
|
784
777
|
canModerate: canMod,
|
|
785
778
|
canCreateSpecial: canSpecialC,
|
|
786
779
|
canDeleteSpecial: canSpecialD,
|
|
787
|
-
canCreateOuting:
|
|
788
|
-
canCreateReservation:
|
|
780
|
+
canCreateOuting: canReq,
|
|
781
|
+
canCreateReservation: canReq,
|
|
789
782
|
specialEventCategoryCid: parseInt(settings && settings.specialEventCategoryId, 10) || 0,
|
|
790
783
|
});
|
|
791
784
|
};
|
|
@@ -1376,7 +1369,7 @@ api.createReservation = async function (req, res) {
|
|
|
1376
1369
|
|
|
1377
1370
|
// Notify groups by email (NodeBB emailer config)
|
|
1378
1371
|
try {
|
|
1379
|
-
const notifyGroups = (settings.notifyGroups
|
|
1372
|
+
const notifyGroups = normalizeAllowedGroups(settings.notifyGroups);
|
|
1380
1373
|
if (notifyGroups.length) {
|
|
1381
1374
|
const requester = await user.getUserFields(uid, ['username', 'email']);
|
|
1382
1375
|
const itemsLabel = (resv.itemNames || []).join(', ');
|
|
@@ -1601,18 +1594,7 @@ api.approveReservation = async function (req, res) {
|
|
|
1601
1594
|
pickupLon: r.pickupLon || '',
|
|
1602
1595
|
mapUrl,
|
|
1603
1596
|
paymentUrl: r.paymentUrl || '',
|
|
1604
|
-
|
|
1605
|
-
type: 'reservation',
|
|
1606
|
-
id: String(r.rid),
|
|
1607
|
-
uid: requesterUid,
|
|
1608
|
-
title: (Array.isArray(r.itemNames) && r.itemNames.length) ? `Location - ${r.itemNames.join(', ')}` : 'Location',
|
|
1609
|
-
details: (Array.isArray(r.itemNames) && r.itemNames.length) ? `Matériel: ${r.itemNames.join(', ')}` : (r.itemName ? `Matériel: ${r.itemName}` : ''),
|
|
1610
|
-
location: r.pickupAddress || '',
|
|
1611
|
-
allDay: true,
|
|
1612
|
-
startYmd: (r.startDate && /^\d{4}-\d{2}-\d{2}$/.test(String(r.startDate))) ? String(r.startDate) : new Date(parseInt(r.start, 10)).toISOString().slice(0, 10),
|
|
1613
|
-
endYmd: (r.endDate && /^\d{4}-\d{2}-\d{2}$/.test(String(r.endDate))) ? String(r.endDate) : new Date(parseInt(r.end, 10)).toISOString().slice(0, 10),
|
|
1614
|
-
})).icsUrl,
|
|
1615
|
-
googleCalUrl: (buildCalendarLinks({
|
|
1597
|
+
...buildCalendarLinks({
|
|
1616
1598
|
type: 'reservation',
|
|
1617
1599
|
id: String(r.rid),
|
|
1618
1600
|
uid: requesterUid,
|
|
@@ -1622,7 +1604,7 @@ api.approveReservation = async function (req, res) {
|
|
|
1622
1604
|
allDay: true,
|
|
1623
1605
|
startYmd: (r.startDate && /^\d{4}-\d{2}-\d{2}$/.test(String(r.startDate))) ? String(r.startDate) : new Date(parseInt(r.start, 10)).toISOString().slice(0, 10),
|
|
1624
1606
|
endYmd: (r.endDate && /^\d{4}-\d{2}-\d{2}$/.test(String(r.endDate))) ? String(r.endDate) : new Date(parseInt(r.end, 10)).toISOString().slice(0, 10),
|
|
1625
|
-
})
|
|
1607
|
+
}),
|
|
1626
1608
|
validatedBy: r.approvedByUsername || '',
|
|
1627
1609
|
validatedByUrl: (r.approvedByUsername ? `https://www.onekite.com/user/${encodeURIComponent(String(r.approvedByUsername))}` : ''),
|
|
1628
1610
|
});
|
|
@@ -1972,7 +1954,7 @@ api.getIcs = async function (req, res) {
|
|
|
1972
1954
|
allDay: true,
|
|
1973
1955
|
startYmd,
|
|
1974
1956
|
endYmd,
|
|
1975
|
-
url: `${
|
|
1957
|
+
url: `${forumBaseUrl()}/calendar`,
|
|
1976
1958
|
});
|
|
1977
1959
|
} else if (type === 'special') {
|
|
1978
1960
|
const ev = await dbLayer.getSpecialEvent(id);
|
|
@@ -1987,7 +1969,7 @@ api.getIcs = async function (req, res) {
|
|
|
1987
1969
|
allDay: false,
|
|
1988
1970
|
start,
|
|
1989
1971
|
end,
|
|
1990
|
-
url: `${
|
|
1972
|
+
url: `${forumBaseUrl()}/calendar`,
|
|
1991
1973
|
});
|
|
1992
1974
|
} else if (type === 'outing') {
|
|
1993
1975
|
const o = await dbLayer.getOuting(id);
|
|
@@ -2002,7 +1984,7 @@ api.getIcs = async function (req, res) {
|
|
|
2002
1984
|
allDay: false,
|
|
2003
1985
|
start,
|
|
2004
1986
|
end,
|
|
2005
|
-
url: `${
|
|
1987
|
+
url: `${forumBaseUrl()}/calendar`,
|
|
2006
1988
|
});
|
|
2007
1989
|
} else {
|
|
2008
1990
|
return res.status(400).send('unknown-type');
|
package/lib/db.js
CHANGED
|
@@ -21,19 +21,6 @@ const KEY_MAINTENANCE_ZSET = 'calendar-onekite:maintenance:itemIds';
|
|
|
21
21
|
const KEY_AUDIT_ZSET = (year) => `calendar-onekite:audit:${year}`;
|
|
22
22
|
const KEY_AUDIT_OBJ = (id) => `calendar-onekite:audit:entry:${id}`;
|
|
23
23
|
|
|
24
|
-
// Helpers
|
|
25
|
-
function reservationKey(rid) {
|
|
26
|
-
return KEY_OBJ(rid);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function specialKey(eid) {
|
|
30
|
-
return KEY_SPECIAL_OBJ(eid);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function outingKey(oid) {
|
|
34
|
-
return KEY_OUTING_OBJ(oid);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
24
|
async function getReservation(rid) {
|
|
38
25
|
return await db.getObject(KEY_OBJ(rid));
|
|
39
26
|
}
|
|
@@ -45,7 +32,7 @@ async function getReservation(rid) {
|
|
|
45
32
|
async function getReservations(rids) {
|
|
46
33
|
const ids = Array.isArray(rids) ? rids.filter(Boolean) : [];
|
|
47
34
|
if (!ids.length) return [];
|
|
48
|
-
const keys = ids.map(
|
|
35
|
+
const keys = ids.map(KEY_OBJ);
|
|
49
36
|
const rows = await db.getObjects(keys);
|
|
50
37
|
// Ensure rid is present even if older objects were missing it.
|
|
51
38
|
return (rows || []).map((row, idx) => {
|
|
@@ -198,7 +185,7 @@ module.exports = {
|
|
|
198
185
|
getSpecialEvents: async (eids) => {
|
|
199
186
|
const ids = Array.isArray(eids) ? eids.filter(Boolean) : [];
|
|
200
187
|
if (!ids.length) return [];
|
|
201
|
-
const keys = ids.map(
|
|
188
|
+
const keys = ids.map(KEY_SPECIAL_OBJ);
|
|
202
189
|
const rows = await db.getObjects(keys);
|
|
203
190
|
return (rows || []).map((row, idx) => {
|
|
204
191
|
if (!row) return null;
|
|
@@ -225,7 +212,7 @@ module.exports = {
|
|
|
225
212
|
getOutings: async (oids) => {
|
|
226
213
|
const ids = Array.isArray(oids) ? oids.filter(Boolean) : [];
|
|
227
214
|
if (!ids.length) return [];
|
|
228
|
-
const keys = ids.map(
|
|
215
|
+
const keys = ids.map(KEY_OUTING_OBJ);
|
|
229
216
|
const rows = await db.getObjects(keys);
|
|
230
217
|
return (rows || []).map((row, idx) => {
|
|
231
218
|
if (!row) return null;
|
package/lib/helloassoWebhook.js
CHANGED
|
@@ -14,9 +14,6 @@ const realtime = require('./realtime');
|
|
|
14
14
|
const shared = require('./shared');
|
|
15
15
|
const { formatFR, forumBaseUrl, sendEmail, buildCalendarLinks, signCalendarLink, ymdToCompact } = shared;
|
|
16
16
|
|
|
17
|
-
function baseUrl() { return forumBaseUrl(); }
|
|
18
|
-
|
|
19
|
-
|
|
20
17
|
function buildReservationCalendarLinks(r) {
|
|
21
18
|
const startYmd = (r.startDate && /^\d{4}-\d{2}-\d{2}$/.test(String(r.startDate)))
|
|
22
19
|
? String(r.startDate)
|
package/lib/scheduler.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const nconf = require.main.require('nconf');
|
|
4
4
|
const db = require.main.require('./src/database');
|
|
5
|
+
const user = require.main.require('./src/user');
|
|
5
6
|
const dbLayer = require('./db');
|
|
6
7
|
const discord = require('./discord');
|
|
7
8
|
const realtime = require('./realtime');
|
|
@@ -109,8 +110,6 @@ async function expirePending(preIds, preReservations) {
|
|
|
109
110
|
const validatorReminderMins = parseInt(getSetting(settings, 'validatorReminderMinutesPending', '0'), 10) || 0;
|
|
110
111
|
const now = Date.now();
|
|
111
112
|
|
|
112
|
-
const user = require.main.require('./src/user');
|
|
113
|
-
|
|
114
113
|
const adminUrl = (() => {
|
|
115
114
|
const base = forumBaseUrl();
|
|
116
115
|
return base ? `${base}/admin/plugins/calendar-onekite` : '/admin/plugins/calendar-onekite';
|
|
@@ -214,8 +213,6 @@ async function processAwaitingPayment(preIds, preReservations) {
|
|
|
214
213
|
const ids = preIds || await dbLayer.listAllReservationIds(5000);
|
|
215
214
|
if (!ids || !ids.length) return;
|
|
216
215
|
|
|
217
|
-
const user = require.main.require('./src/user');
|
|
218
|
-
|
|
219
216
|
const adminUrl = (() => {
|
|
220
217
|
const base = forumBaseUrl();
|
|
221
218
|
return base ? `${base}/admin/plugins/calendar-onekite` : '/admin/plugins/calendar-onekite';
|
package/lib/shared.js
CHANGED
|
@@ -23,8 +23,8 @@ function forumBaseUrl() {
|
|
|
23
23
|
// Try meta.config first (runtime-accurate), then nconf fallback.
|
|
24
24
|
let base = '';
|
|
25
25
|
try {
|
|
26
|
-
base = (meta && meta.config &&
|
|
27
|
-
? String(meta.config.url
|
|
26
|
+
base = (meta && meta.config && meta.config.url)
|
|
27
|
+
? String(meta.config.url)
|
|
28
28
|
: '';
|
|
29
29
|
} catch (_) { /* ignore */ }
|
|
30
30
|
if (!base) {
|
package/library.js
CHANGED
|
@@ -101,28 +101,26 @@ Plugin.init = async function (params) {
|
|
|
101
101
|
router.get('/plugins/calendar-onekite/ics/:type/:id', api.getIcs);
|
|
102
102
|
|
|
103
103
|
// Admin API (JSON)
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
router.post(`${base}/outings/purge`, ...adminMws, admin.purgeOutingsByYear);
|
|
125
|
-
});
|
|
104
|
+
const adminBase = '/api/v3/admin/plugins/calendar-onekite';
|
|
105
|
+
|
|
106
|
+
router.get(`${adminBase}/settings`, ...adminMws, admin.getSettings);
|
|
107
|
+
router.put(`${adminBase}/settings`, ...adminMws, admin.saveSettings);
|
|
108
|
+
|
|
109
|
+
router.get(`${adminBase}/pending`, ...adminMws, admin.listPending);
|
|
110
|
+
router.put(`${adminBase}/reservations/:rid/approve`, ...adminMws, admin.approveReservation);
|
|
111
|
+
router.put(`${adminBase}/reservations/:rid/refuse`, ...adminMws, admin.refuseReservation);
|
|
112
|
+
|
|
113
|
+
router.post(`${adminBase}/purge`, ...adminMws, admin.purgeByYear);
|
|
114
|
+
router.get(`${adminBase}/debug`, ...adminMws, admin.debugHelloAsso);
|
|
115
|
+
// Accounting / exports
|
|
116
|
+
router.get(`${adminBase}/accounting`, ...adminMws, admin.getAccounting);
|
|
117
|
+
router.get(`${adminBase}/accounting.csv`, ...adminMws, admin.exportAccountingCsv);
|
|
118
|
+
router.post(`${adminBase}/accounting/purge`, ...adminMws, admin.purgeAccounting);
|
|
119
|
+
|
|
120
|
+
// Purge special events by year
|
|
121
|
+
router.post(`${adminBase}/special-events/purge`, ...adminMws, admin.purgeSpecialEventsByYear);
|
|
122
|
+
// Purge outings by year
|
|
123
|
+
router.post(`${adminBase}/outings/purge`, ...adminMws, admin.purgeOutingsByYear);
|
|
126
124
|
|
|
127
125
|
// HelloAsso callback endpoint (hardened)
|
|
128
126
|
// - Only accepts POST
|
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -169,6 +169,13 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
169
169
|
.replace(/'/g, ''');
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
function linkifyNotes(str) {
|
|
173
|
+
return escapeHtml(str).replace(
|
|
174
|
+
/https?:\/\/[^\s<>"']+/g,
|
|
175
|
+
url => `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
172
179
|
function getCsrfToken() {
|
|
173
180
|
try {
|
|
174
181
|
return (
|
|
@@ -1809,7 +1816,7 @@ function toDatetimeLocalValue(date) {
|
|
|
1809
1816
|
${calHtml}
|
|
1810
1817
|
${participantsHtml}
|
|
1811
1818
|
${addr ? `<div class="mb-2"><strong>Adresse</strong><br>${addrHtml}</div>` : ''}
|
|
1812
|
-
${notes ? `<div class="mb-2"><strong>Notes</strong><br>${
|
|
1819
|
+
${notes ? `<div class="mb-2"><strong>Notes</strong><br>${linkifyNotes(notes).replace(/\n/g,'<br>')}</div>` : ''}
|
|
1813
1820
|
`;
|
|
1814
1821
|
const canDel = !!(p.canDeleteSpecial || canDeleteSpecial);
|
|
1815
1822
|
const canEdit = !!p.canEditSpecial;
|
|
@@ -1987,7 +1994,7 @@ function toDatetimeLocalValue(date) {
|
|
|
1987
1994
|
${calHtml}
|
|
1988
1995
|
${participantsHtml}
|
|
1989
1996
|
${addr ? `<div class="mb-2"><strong>Adresse</strong><br>${addrHtml}</div>` : ''}
|
|
1990
|
-
${notes ? `<div class="mb-2"><strong>Notes</strong><br>${
|
|
1997
|
+
${notes ? `<div class="mb-2"><strong>Notes</strong><br>${linkifyNotes(notes).replace(/\n/g,'<br>')}</div>` : ''}
|
|
1991
1998
|
`;
|
|
1992
1999
|
const canDel = !!(p.canDeleteOuting);
|
|
1993
2000
|
const canEditOuting = !!p.canEditOuting;
|
|
@@ -2160,7 +2167,7 @@ function toDatetimeLocalValue(date) {
|
|
|
2160
2167
|
${pickupAddress ? `${escapeHtml(pickupAddress)}<br>` : ''}
|
|
2161
2168
|
${pickupTime ? `Heure : ${escapeHtml(pickupTime)}<br>` : ''}
|
|
2162
2169
|
${hasCoords ? `<a href="${osmLink}" target="_blank" rel="noopener">Voir sur la carte</a><br>` : ''}
|
|
2163
|
-
${notes ? `<div class="mt-1"><strong>Notes</strong><br>${
|
|
2170
|
+
${notes ? `<div class="mt-1"><strong>Notes</strong><br>${linkifyNotes(notes).replace(/\n/g,'<br>')}</div>` : ''}
|
|
2164
2171
|
</div>
|
|
2165
2172
|
`
|
|
2166
2173
|
: '';
|