nodebb-plugin-onekite-calendar 1.0.4 → 1.0.5

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/scheduler.js CHANGED
@@ -3,7 +3,6 @@
3
3
  const meta = require.main.require('./src/meta');
4
4
  const db = require.main.require('./src/database');
5
5
  const dbLayer = require('./db');
6
- const log = require('./log');
7
6
 
8
7
  let timer = null;
9
8
 
@@ -16,7 +15,7 @@ function getSetting(settings, key, fallback) {
16
15
 
17
16
  // Pending holds: short lock after a user creates a request (defaults to 5 minutes)
18
17
  async function expirePending() {
19
- const settings = await meta.settings.get('onekite-calendar');
18
+ const settings = await meta.settings.get('calendar-onekite');
20
19
  const holdMins = parseInt(getSetting(settings, 'pendingHoldMinutes', '5'), 10) || 5;
21
20
  const now = Date.now();
22
21
 
@@ -44,7 +43,7 @@ async function expirePending() {
44
43
  // - We send a reminder after `paymentHoldMinutes` (default 60)
45
44
  // - We expire (and remove) after `2 * paymentHoldMinutes`
46
45
  async function processAwaitingPayment() {
47
- const settings = await meta.settings.get('onekite-calendar');
46
+ const settings = await meta.settings.get('calendar-onekite');
48
47
  const holdMins = parseInt(
49
48
  getSetting(settings, 'paymentHoldMinutes', getSetting(settings, 'holdMinutes', '60')),
50
49
  10
@@ -84,7 +83,11 @@ async function processAwaitingPayment() {
84
83
  }
85
84
  } catch (err) {
86
85
  // eslint-disable-next-line no-console
87
- log.warn('Failed to send email (scheduler)', { template, toEmail, err: String((err && err.message) || err) });
86
+ console.warn('[calendar-onekite] Failed to send email (scheduler)', {
87
+ template,
88
+ toEmail,
89
+ err: String((err && err.message) || err),
90
+ });
88
91
  }
89
92
  }
90
93
 
@@ -108,7 +111,7 @@ async function processAwaitingPayment() {
108
111
 
109
112
  if (!r.reminderSent && now >= reminderAt && now < expireAt) {
110
113
  // Send reminder once (guarded across clustered NodeBB processes)
111
- const reminderKey = 'onekite-calendar:email:reminderSent';
114
+ const reminderKey = 'calendar-onekite:email:reminderSent';
112
115
  const first = await db.setAdd(reminderKey, rid);
113
116
  if (!first) {
114
117
  // another process already sent it
@@ -119,7 +122,7 @@ async function processAwaitingPayment() {
119
122
  }
120
123
  const u = await user.getUserFields(r.uid, ['username', 'email']);
121
124
  if (u && u.email) {
122
- await sendEmail('onekite-calendar_reminder', u.email, 'Location matériel - Rappel', {
125
+ await sendEmail('calendar-onekite_reminder', u.email, 'Location matériel - Rappel', {
123
126
  username: u.username,
124
127
  itemName: (Array.isArray(r.itemNames) ? r.itemNames.join(', ') : (r.itemName || '')),
125
128
  itemNames: (Array.isArray(r.itemNames) ? r.itemNames : (r.itemName ? [r.itemName] : [])),
@@ -138,12 +141,12 @@ async function processAwaitingPayment() {
138
141
  if (now >= expireAt) {
139
142
  // Expire: remove reservation so it disappears from calendar and frees items
140
143
  // Guard email send across clustered NodeBB processes
141
- const expiredKey = 'onekite-calendar:email:expiredSent';
144
+ const expiredKey = 'calendar-onekite:email:expiredSent';
142
145
  const firstExpired = await db.setAdd(expiredKey, rid);
143
146
  const shouldEmail = !!firstExpired;
144
147
  const u = await user.getUserFields(r.uid, ['username', 'email']);
145
148
  if (shouldEmail && u && u.email) {
146
- await sendEmail('onekite-calendar_expired', u.email, 'Location matériel - Rappel', {
149
+ await sendEmail('calendar-onekite_expired', u.email, 'Location matériel - Rappel', {
147
150
  username: u.username,
148
151
  itemName: (Array.isArray(r.itemNames) ? r.itemNames.join(', ') : (r.itemName || '')),
149
152
  itemNames: (Array.isArray(r.itemNames) ? r.itemNames : (r.itemName ? [r.itemName] : [])),
package/lib/widgets.js CHANGED
@@ -40,8 +40,8 @@ widgets.defineWidgets = async function (widgetData) {
40
40
  }
41
41
 
42
42
  list.push({
43
- widget: 'onekite-calendar-twoweeks',
44
- name: 'Calendrier Onekite',
43
+ widget: 'calendar-onekite-twoweeks',
44
+ name: 'Calendrier OneKite (2 semaines)',
45
45
  description: 'Affiche la semaine courante + la semaine suivante (FullCalendar via CDN).',
46
46
  content: '',
47
47
  });
@@ -54,7 +54,7 @@ widgets.renderTwoWeeksWidget = async function (data) {
54
54
  const id = makeDomId();
55
55
  const calUrl = widgetCalendarUrl();
56
56
  const apiBase = forumBaseUrl();
57
- const eventsEndpoint = `${apiBase}/api/v3/plugins/onekite-calendar/events`;
57
+ const eventsEndpoint = `${apiBase}/api/v3/plugins/calendar-onekite/events`;
58
58
 
59
59
  const idJson = JSON.stringify(id);
60
60
  const calUrlJson = JSON.stringify(calUrl);
@@ -63,7 +63,7 @@ widgets.renderTwoWeeksWidget = async function (data) {
63
63
  const html = `
64
64
  <div class="onekite-twoweeks">
65
65
  <div class="d-flex justify-content-between align-items-center mb-1">
66
- <div style="font-weight: 600;">Calendrier</div>
66
+ <div style="font-weight: 600;">Calendrier (2 semaines)</div>
67
67
  <a href="${escapeHtml(calUrl)}" class="btn btn-sm btn-outline-secondary" style="line-height: 1.1;">Ouvrir</a>
68
68
  </div>
69
69
  <div id="${escapeHtml(id)}"></div>
@@ -137,130 +137,21 @@ widgets.renderTwoWeeksWidget = async function (data) {
137
137
  },
138
138
  navLinks: false,
139
139
  eventTimeFormat: { hour: '2-digit', minute: '2-digit', hour12: false },
140
- eventContent: function(arg) {
141
- // Render a simple dot instead of text.
142
- const wrap = document.createElement('span');
143
- wrap.className = 'onekite-dot';
144
- wrap.setAttribute('aria-label', arg.event.title || '');
145
- // Mark the node so eventDidMount can find it.
146
- wrap.setAttribute('data-onekite-dot', '1');
147
- return { domNodes: [wrap] };
148
- },
149
140
  events: function(info, successCallback, failureCallback) {
150
141
  const qs = new URLSearchParams({ start: info.startStr, end: info.endStr });
151
- const url1 = eventsEndpoint + '?' + qs.toString();
152
- fetch(url1, { credentials: 'same-origin' })
142
+ fetch(eventsEndpoint + '?' + qs.toString(), { credentials: 'same-origin' })
153
143
  .then((r) => r.json())
154
144
  .then((json) => successCallback(json || []))
155
145
  .catch((e) => failureCallback(e));
156
146
  },
157
- eventDidMount: function(info) {
158
- // Native tooltip + click popup (Bootbox when available).
159
- const title = info.event && info.event.title ? String(info.event.title) : '';
160
- const start = info.event && info.event.start ? info.event.start : null;
161
- const end = info.event && info.event.end ? info.event.end : null;
162
- const fmt = (d) => {
163
- try {
164
- return new Intl.DateTimeFormat('fr-FR', { dateStyle: 'medium' }).format(d);
165
- } catch (e) {
166
- return d ? d.toISOString().slice(0, 10) : '';
167
- }
168
- };
169
- const period = start ? (end ? (fmt(start) + ' → ' + fmt(end)) : fmt(start)) : '';
170
- const body = [title, period].filter(Boolean).join('\n');
171
- if (info.el) {
172
- // Make dot color match the FullCalendar event colors.
173
- try {
174
- const dot = info.el.querySelector && info.el.querySelector('[data-onekite-dot="1"]');
175
- if (dot) {
176
- // Prefer explicit event colors, otherwise fall back to computed styles.
177
- const bg = (info.event && (info.event.backgroundColor || info.event.borderColor)) || '';
178
- if (bg) {
179
- dot.style.backgroundColor = bg;
180
- } else {
181
- const cs = window.getComputedStyle(info.el);
182
- const bgs = cs && cs.backgroundColor;
183
- if (bgs && bgs !== 'rgba(0, 0, 0, 0)' && bgs !== 'transparent') {
184
- dot.style.backgroundColor = bgs;
185
- }
186
- }
187
- }
188
- } catch (e) {
189
- // ignore
190
- }
191
-
192
- info.el.title = body;
193
- info.el.style.cursor = 'pointer';
194
- info.el.addEventListener('click', function(ev) {
195
- ev.preventDefault();
196
- ev.stopPropagation();
197
- const html = '<div style="white-space:pre-line;">' + (body || '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;') + '</div>';
198
- if (window.bootbox && typeof window.bootbox.alert === 'function') {
199
- window.bootbox.alert({ message: html });
200
- } else {
201
- // Fallback
202
- alert(body);
203
- }
204
- }, { passive: false });
205
- }
206
- },
207
- // On mobile, users can tap the calendar background to open the full page.
208
147
  dateClick: function() {
209
148
  window.location.href = calUrl;
210
149
  },
211
- // Do not redirect on eventClick: we show a popup in eventDidMount.
212
- eventClick: function(info) {
213
- try { if (info && info.jsEvent) info.jsEvent.preventDefault(); } catch (e) {}
150
+ eventClick: function() {
151
+ window.location.href = calUrl;
214
152
  },
215
153
  });
216
154
 
217
- // Mobile: swipe left/right to change week (2-week view).
218
- (function enableSwipe() {
219
- try {
220
- if (!('ontouchstart' in window)) return;
221
- const target = el; // calendar root
222
- let sx = 0;
223
- let sy = 0;
224
- let st = 0;
225
- let tracking = false;
226
-
227
- target.addEventListener('touchstart', function (e) {
228
- if (!e.touches || e.touches.length !== 1) return;
229
- const t = e.touches[0];
230
- sx = t.clientX;
231
- sy = t.clientY;
232
- st = Date.now();
233
- tracking = true;
234
- }, { passive: true });
235
-
236
- target.addEventListener('touchend', function (e) {
237
- if (!tracking) return;
238
- tracking = false;
239
- const changed = e.changedTouches && e.changedTouches[0];
240
- if (!changed) return;
241
- const dx = changed.clientX - sx;
242
- const dy = changed.clientY - sy;
243
- const adx = Math.abs(dx);
244
- const ady = Math.abs(dy);
245
- const dt = Date.now() - st;
246
-
247
- // Must be a quick-ish horizontal swipe.
248
- if (dt > 800) return;
249
- if (adx < 50) return;
250
- if (ady > adx * 0.75) return;
251
-
252
- // Move by one week per swipe, even though the view spans 2 weeks.
253
- if (dx < 0) {
254
- calendar.incrementDate({ weeks: 1 });
255
- } else {
256
- calendar.incrementDate({ weeks: -1 });
257
- }
258
- }, { passive: true });
259
- } catch (e) {
260
- // ignore
261
- }
262
- })();
263
-
264
155
  calendar.render();
265
156
  }
266
157
 
@@ -274,18 +165,7 @@ widgets.renderTwoWeeksWidget = async function (data) {
274
165
  .onekite-twoweeks .fc .fc-button { padding: .2rem .35rem; font-size: .75rem; }
275
166
  .onekite-twoweeks .fc .fc-daygrid-day-number { font-size: .75rem; padding: 2px; }
276
167
  .onekite-twoweeks .fc .fc-col-header-cell-cushion { font-size: .75rem; }
277
- .onekite-twoweeks .fc .fc-event-title { display: none; }
278
- .onekite-twoweeks .fc .fc-event-time { display: none; }
279
- .onekite-twoweeks .onekite-dot {
280
- display: inline-block;
281
- width: 8px;
282
- height: 8px;
283
- border-radius: 50%;
284
- background: var(--fc-event-bg-color, currentColor);
285
- border: 1px solid var(--fc-event-border-color, transparent);
286
- opacity: 0.85;
287
- margin: 0 2px;
288
- }
168
+ .onekite-twoweeks .fc .fc-event-title { font-size: .72rem; }
289
169
  </style>
290
170
  `;
291
171
 
package/library.js CHANGED
@@ -1,5 +1,10 @@
1
1
  'use strict';
2
2
 
3
+ // We use NodeBB's route helpers for page routes so the rendered page includes
4
+ // the normal client bundle (ajaxify/requirejs). The helper signatures differ
5
+ // across NodeBB versions, but for NodeBB v4.x the order is:
6
+ // setupPageRoute(router, path, middlewaresArray, handler)
7
+ // setupAdminPageRoute(router, path, middlewaresArray, handler)
3
8
  const routeHelpers = require.main.require('./src/routes/helpers');
4
9
 
5
10
  const controllers = require('./lib/controllers.js');
@@ -8,7 +13,6 @@ const admin = require('./lib/admin');
8
13
  const scheduler = require('./lib/scheduler');
9
14
  const helloassoWebhook = require('./lib/helloassoWebhook');
10
15
  const widgets = require('./lib/widgets');
11
- const { NAMESPACE } = require('./lib/constants');
12
16
  const bodyParser = require('body-parser');
13
17
 
14
18
  const Plugin = {};
@@ -19,8 +23,16 @@ const mw = (...fns) => fns.filter(isFn);
19
23
  Plugin.init = async function (params) {
20
24
  const { router, middleware } = params;
21
25
 
22
- const publicExpose = mw(middleware && (middleware.authenticate || middleware.exposeUid));
26
+ // Build middleware arrays safely and always spread them into Express route methods.
27
+ // Express will throw if any callback is undefined, so we filter strictly.
28
+ // Auth middlewares differ slightly depending on NodeBB configuration.
29
+ // In v4, some installs rely on middleware.authenticate rather than exposeUid.
30
+ const baseExpose = mw(middleware && (middleware.authenticate || middleware.exposeUid));
31
+ const publicExpose = baseExpose;
32
+ const publicAuth = mw(middleware && (middleware.authenticate || middleware.exposeUid), middleware && middleware.ensureLoggedIn);
23
33
 
34
+ // Robust admin guard: avoid middleware.admin.checkPrivileges() signature differences
35
+ // across NodeBB versions. We treat membership in the 'administrators' group as admin.
24
36
  const Groups = require.main.require('./src/groups');
25
37
  async function adminOnly(req, res, next) {
26
38
  try {
@@ -37,7 +49,6 @@ Plugin.init = async function (params) {
37
49
  return next(err);
38
50
  }
39
51
  }
40
-
41
52
  const adminMws = mw(
42
53
  middleware && (middleware.authenticate || middleware.exposeUid),
43
54
  middleware && middleware.ensureLoggedIn,
@@ -45,58 +56,67 @@ Plugin.init = async function (params) {
45
56
  );
46
57
 
47
58
  // Page routes (HTML)
59
+ // IMPORTANT: pass an ARRAY for middlewares (even if empty), otherwise
60
+ // setupPageRoute will throw "middlewares is not iterable".
48
61
  routeHelpers.setupPageRoute(router, '/calendar', mw(), controllers.renderCalendar);
62
+ routeHelpers.setupAdminPageRoute(router, '/admin/plugins/calendar-onekite', mw(), admin.renderAdmin);
49
63
 
50
- // Admin page route
51
- routeHelpers.setupAdminPageRoute(router, `/admin/plugins/${NAMESPACE}`, mw(), admin.renderAdmin);
52
-
53
- // Public API (JSON) NodeBB 4.x (v3 API)
54
- router.get(`/api/v3/plugins/${NAMESPACE}/events`, ...publicExpose, api.getEvents);
55
- router.get(`/api/v3/plugins/${NAMESPACE}/items`, ...publicExpose, api.getItems);
56
- router.get(`/api/v3/plugins/${NAMESPACE}/capabilities`, ...publicExpose, api.getCapabilities);
64
+ // Public API (JSON) — NodeBB 4.x only (v3 API)
65
+ router.get('/api/v3/plugins/calendar-onekite/events', ...publicExpose, api.getEvents);
66
+ router.get('/api/v3/plugins/calendar-onekite/items', ...publicExpose, api.getItems);
67
+ router.get('/api/v3/plugins/calendar-onekite/capabilities', ...publicExpose, api.getCapabilities);
57
68
 
58
- router.post(`/api/v3/plugins/${NAMESPACE}/reservations`, ...publicExpose, api.createReservation);
59
- router.get(`/api/v3/plugins/${NAMESPACE}/reservations/:rid`, ...publicExpose, api.getReservationDetails);
60
- router.put(`/api/v3/plugins/${NAMESPACE}/reservations/:rid/approve`, ...publicExpose, api.approveReservation);
61
- router.put(`/api/v3/plugins/${NAMESPACE}/reservations/:rid/refuse`, ...publicExpose, api.refuseReservation);
62
- router.put(`/api/v3/plugins/${NAMESPACE}/reservations/:rid/cancel`, ...publicExpose, api.cancelReservation);
69
+ router.post('/api/v3/plugins/calendar-onekite/reservations', ...publicExpose, api.createReservation);
70
+ router.get('/api/v3/plugins/calendar-onekite/reservations/:rid', ...publicExpose, api.getReservationDetails);
71
+ router.put('/api/v3/plugins/calendar-onekite/reservations/:rid/approve', ...publicExpose, api.approveReservation);
72
+ router.put('/api/v3/plugins/calendar-onekite/reservations/:rid/refuse', ...publicExpose, api.refuseReservation);
73
+ router.put('/api/v3/plugins/calendar-onekite/reservations/:rid/cancel', ...publicExpose, api.cancelReservation);
63
74
 
64
- router.post(`/api/v3/plugins/${NAMESPACE}/special-events`, ...publicExpose, api.createSpecialEvent);
65
- router.get(`/api/v3/plugins/${NAMESPACE}/special-events/:eid`, ...publicExpose, api.getSpecialEventDetails);
66
- router.delete(`/api/v3/plugins/${NAMESPACE}/special-events/:eid`, ...publicExpose, api.deleteSpecialEvent);
75
+ router.post('/api/v3/plugins/calendar-onekite/special-events', ...publicExpose, api.createSpecialEvent);
76
+ router.get('/api/v3/plugins/calendar-onekite/special-events/:eid', ...publicExpose, api.getSpecialEventDetails);
77
+ router.delete('/api/v3/plugins/calendar-onekite/special-events/:eid', ...publicExpose, api.deleteSpecialEvent);
67
78
 
68
79
  // Admin API (JSON)
69
- const base = `/api/v3/admin/plugins/${NAMESPACE}`;
70
-
71
- router.get(`${base}/settings`, ...adminMws, admin.getSettings);
72
- router.put(`${base}/settings`, ...adminMws, admin.saveSettings);
80
+ const adminBases = ['/api/v3/admin/plugins/calendar-onekite'];
73
81
 
74
- router.get(`${base}/pending`, ...adminMws, admin.listPending);
75
- router.put(`${base}/reservations/:rid/approve`, ...adminMws, admin.approveReservation);
76
- router.put(`${base}/reservations/:rid/refuse`, ...adminMws, admin.refuseReservation);
82
+ adminBases.forEach((base) => {
83
+ router.get(`${base}/settings`, ...adminMws, admin.getSettings);
84
+ router.put(`${base}/settings`, ...adminMws, admin.saveSettings);
77
85
 
78
- router.post(`${base}/purge`, ...adminMws, admin.purgeByYear);
86
+ router.get(`${base}/pending`, ...adminMws, admin.listPending);
87
+ router.put(`${base}/reservations/:rid/approve`, ...adminMws, admin.approveReservation);
88
+ router.put(`${base}/reservations/:rid/refuse`, ...adminMws, admin.refuseReservation);
79
89
 
80
- router.get(`${base}/accounting`, ...adminMws, admin.getAccounting);
81
- router.get(`${base}/accounting.csv`, ...adminMws, admin.exportAccountingCsv);
82
- router.post(`${base}/accounting/purge`, ...adminMws, admin.purgeAccounting);
90
+ router.post(`${base}/purge`, ...adminMws, admin.purgeByYear);
91
+ router.get(`${base}/debug`, ...adminMws, admin.debugHelloAsso);
92
+ // Accounting / exports
93
+ router.get(`${base}/accounting`, ...adminMws, admin.getAccounting);
94
+ router.get(`${base}/accounting.csv`, ...adminMws, admin.exportAccountingCsv);
95
+ router.post(`${base}/accounting/purge`, ...adminMws, admin.purgeAccounting);
83
96
 
84
- router.post(`${base}/special-events/purge`, ...adminMws, admin.purgeSpecialEventsByYear);
97
+ // Purge special events by year
98
+ router.post(`${base}/special-events/purge`, ...adminMws, admin.purgeSpecialEventsByYear);
99
+ });
85
100
 
86
- // HelloAsso webhook endpoint (signature verified)
101
+ // HelloAsso callback endpoint (hardened)
102
+ // - Only accepts POST
103
+ // - Verifies x-ha-signature (HMAC SHA-256) using the configured client secret
104
+ // - Basic replay protection
105
+ // NOTE: we capture the raw body for signature verification.
87
106
  const helloassoJson = bodyParser.json({
88
107
  verify: (req, _res, buf) => {
89
108
  req.rawBody = buf;
90
109
  },
91
110
  type: ['application/json', 'application/*+json'],
92
111
  });
93
-
112
+ // Accept webhook on both legacy root path and namespaced plugin path.
113
+ // Some reverse proxies block unknown root paths, so /plugins/... is recommended.
94
114
  router.post('/helloasso', helloassoJson, helloassoWebhook.handler);
95
- router.post(`/plugins/${NAMESPACE}/helloasso`, helloassoJson, helloassoWebhook.handler);
115
+ router.post('/plugins/calendar-onekite/helloasso', helloassoJson, helloassoWebhook.handler);
96
116
 
97
- // Optional health checks
117
+ // Optional: health checks
98
118
  router.get('/helloasso', (req, res) => res.json({ ok: true }));
99
- router.get(`/plugins/${NAMESPACE}/helloasso`, (req, res) => res.json({ ok: true }));
119
+ router.get('/plugins/calendar-onekite/helloasso', (req, res) => res.json({ ok: true }));
100
120
 
101
121
  scheduler.start();
102
122
  };
@@ -104,20 +124,24 @@ Plugin.init = async function (params) {
104
124
  Plugin.addAdminNavigation = async function (header) {
105
125
  header.plugins = header.plugins || [];
106
126
  header.plugins.push({
107
- route: `/plugins/${NAMESPACE}`,
127
+ route: '/plugins/calendar-onekite',
108
128
  icon: 'fa-calendar',
109
- name: 'Onekite Calendar',
129
+ name: 'Calendar OneKite',
110
130
  });
111
131
  return header;
112
132
  };
113
133
 
134
+
114
135
  // Ensure our transactional emails always get a subject.
136
+ // NodeBB's Emailer.sendToEmail signature expects (template, email, language, params),
137
+ // so plugins typically inject/modify the subject via this hook.
115
138
  Plugin.emailModify = async function (data) {
116
139
  try {
117
140
  if (!data || !data.template) return data;
118
141
  const tpl = String(data.template);
119
- if (!tpl.startsWith('onekite-calendar_')) return data;
142
+ if (!tpl.startsWith('calendar-onekite_')) return data;
120
143
 
144
+ // If the caller provided a subject (we pass it in params.subject), copy it to data.subject.
121
145
  const provided = data.params && data.params.subject ? String(data.params.subject) : '';
122
146
  if (provided && (!data.subject || !String(data.subject).trim())) {
123
147
  data.subject = provided;
@@ -130,4 +154,4 @@ Plugin.emailModify = async function (data) {
130
154
  Plugin.defineWidgets = widgets.defineWidgets;
131
155
  Plugin.renderTwoWeeksWidget = widgets.renderTwoWeeksWidget;
132
156
 
133
- module.exports = Plugin;
157
+ module.exports = Plugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-onekite-calendar",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "nodebb-plugin-onekite-calendar",
3
- "name": "Onekite Calendar",
3
+ "name": "OneKite Calendar",
4
4
  "description": "Equipment reservation calendar (FullCalendar) with admin approval & HelloAsso checkout",
5
5
  "url": "https://www.onekite.com/calendar",
6
6
  "hooks": [
@@ -21,7 +21,7 @@
21
21
  "method": "defineWidgets"
22
22
  },
23
23
  {
24
- "hook": "filter:widget.render:onekite-calendar-twoweeks",
24
+ "hook": "filter:widget.render:calendar-onekite-twoweeks",
25
25
  "method": "renderTwoWeeksWidget"
26
26
  }
27
27
  ],
@@ -30,8 +30,14 @@
30
30
  },
31
31
  "templates": "./templates",
32
32
  "modules": {
33
- "admin/plugins/onekite-calendar": "./public/admin.js",
34
- "forum/onekite-calendar": "./public/client.js"
33
+ "../admin/plugins/calendar-onekite.js": "./public/admin.js",
34
+ "admin/plugins/calendar-onekite": "./public/admin.js"
35
35
  },
36
- "version": "1.1.0"
36
+ "scripts": [
37
+ "public/client.js"
38
+ ],
39
+ "acpScripts": [
40
+ "public/admin.js"
41
+ ],
42
+ "version": "1.0.3"
37
43
  }