nodebb-plugin-discord-onekite 1.0.5 → 1.0.7

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/README.md CHANGED
@@ -1,7 +1,5 @@
1
- # nodebb-plugin-discord-onekite (NodeBB v4.x) — v1.0.4
1
+ # nodebb-plugin-discord-onekite — v1.0.6
2
2
 
3
- This version follows the most compatible ACP pattern used by many official/community plugins:
4
-
5
- - Templates are in `templates/` (not `static/templates/`)
6
- - ACP script is loaded via `acpScripts` and runs globally on `action:ajaxify.end`
7
- - No reliance on `modules` name matching
3
+ Fixes:
4
+ - Form action/redirect no longer uses `{config.relative_path}` (was rendering as `undefined` on your install).
5
+ - Categories are fetched server-side via `categories.getCategoriesByPrivilege('categories:cid', uid, 'read', ...)` (returns category objects). citeturn0search10
@@ -1,9 +1,48 @@
1
1
  'use strict';
2
2
 
3
+ const meta = require.main.require('./src/meta');
4
+ const categories = require.main.require('./src/categories');
5
+
6
+ const SETTINGS_KEY = 'discord-onekite';
7
+
8
+ function normalizeCids(v) {
9
+ if (!v) return [];
10
+ if (Array.isArray(v)) return v.map(String).filter(Boolean);
11
+ if (typeof v === 'string') return v.split(',').map(s => s.trim()).filter(Boolean);
12
+ return [];
13
+ }
14
+
15
+ async function getReadableCategories(uid) {
16
+ // NodeBB core uses this helper to get categories for a user by privilege.
17
+ // It returns an array of category objects (cid, name, slug, ...). citeturn0search10
18
+ return await new Promise((resolve) => {
19
+ categories.getCategoriesByPrivilege('categories:cid', uid || 0, 'read', (err, categoriesData) => {
20
+ if (err || !Array.isArray(categoriesData)) return resolve([]);
21
+ resolve(categoriesData.filter(Boolean));
22
+ });
23
+ });
24
+ }
25
+
3
26
  const controllers = {};
4
27
 
5
28
  controllers.renderAdminPage = async function (req, res) {
6
- res.render('admin/plugins/discord-onekite', {});
29
+ const settings = await meta.settings.get(SETTINGS_KEY);
30
+ const savedCids = normalizeCids(settings && settings.cids);
31
+
32
+ const cats = await getReadableCategories(req.uid);
33
+ const categoriesForTpl = (cats || [])
34
+ .filter(c => c && typeof c.cid !== 'undefined' && c.name)
35
+ .map(c => ({
36
+ cid: String(c.cid),
37
+ name: c.name,
38
+ selected: savedCids.includes(String(c.cid)),
39
+ }))
40
+ .sort((a, b) => a.name.localeCompare(b.name));
41
+
42
+ res.render('admin/plugins/discord-onekite', {
43
+ settings: settings || {},
44
+ categories: categoriesForTpl,
45
+ });
7
46
  };
8
47
 
9
48
  module.exports = controllers;
package/library.js CHANGED
@@ -4,6 +4,7 @@ const { request } = require('undici');
4
4
 
5
5
  const routeHelpers = require.main.require('./src/routes/helpers');
6
6
  const meta = require.main.require('./src/meta');
7
+ const middleware = require.main.require('./src/middleware');
7
8
 
8
9
  const topics = require.main.require('./src/topics');
9
10
  const user = require.main.require('./src/user');
@@ -80,6 +81,24 @@ Plugin.init = async ({ router }) => {
80
81
  [],
81
82
  controllers.renderAdminPage
82
83
  );
84
+
85
+ // POST save - keep it very simple and redirect to the canonical path
86
+ router.post('/admin/plugins/discord-onekite/save',
87
+ middleware.admin.checkPrivileges,
88
+ async (req, res) => {
89
+ try {
90
+ const payload = {
91
+ webhookUrl: req.body.webhookUrl || '',
92
+ notifyReplies: req.body.notifyReplies ? 'on' : '',
93
+ cids: req.body.cids || '',
94
+ };
95
+ await meta.settings.set(SETTINGS_KEY, payload);
96
+ } catch (e) {
97
+ console.error('[discord-onekite] save failed', e);
98
+ }
99
+ res.redirect('/admin/plugins/discord-onekite');
100
+ }
101
+ );
83
102
  };
84
103
 
85
104
  Plugin.addAdminNavigation = (header) => {
package/package.json CHANGED
@@ -1,14 +1,20 @@
1
1
  {
2
2
  "name": "nodebb-plugin-discord-onekite",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Discord webhook notifier for Onekite (NodeBB v4.x only)",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
7
- "keywords": ["nodebb", "plugin", "discord", "webhook", "notifications"],
7
+ "keywords": [
8
+ "nodebb",
9
+ "plugin",
10
+ "discord",
11
+ "webhook",
12
+ "notifications"
13
+ ],
8
14
  "dependencies": {
9
15
  "undici": "^6.0.0"
10
16
  },
11
17
  "nbbpm": {
12
18
  "compatibility": "^4.0.0"
13
19
  }
14
- }
20
+ }
package/plugin.json CHANGED
@@ -1,14 +1,25 @@
1
1
  {
2
2
  "id": "nodebb-plugin-discord-onekite",
3
3
  "name": "Discord Onekite Notifier",
4
- "description": "Notifie Discord via webhook pour nouveaux sujets et/ou réponses, filtrable par catégories (NodeBB v4.x uniquement).",
4
+ "description": "Notifie Discord via webhook pour nouveaux sujets et/ou r\u00e9ponses, filtrable par cat\u00e9gories (NodeBB v4.x uniquement).",
5
5
  "library": "./library.js",
6
6
  "hooks": [
7
- { "hook": "static:app.load", "method": "init" },
8
- { "hook": "filter:admin.header.build", "method": "addAdminNavigation" },
9
- { "hook": "action:topic.save", "method": "onTopicSave" },
10
- { "hook": "action:post.save", "method": "onPostSave" }
7
+ {
8
+ "hook": "static:app.load",
9
+ "method": "init"
10
+ },
11
+ {
12
+ "hook": "filter:admin.header.build",
13
+ "method": "addAdminNavigation"
14
+ },
15
+ {
16
+ "hook": "action:topic.save",
17
+ "method": "onTopicSave"
18
+ },
19
+ {
20
+ "hook": "action:post.save",
21
+ "method": "onPostSave"
22
+ }
11
23
  ],
12
- "templates": "templates",
13
- "acpScripts": ["static/lib/admin.js"]
14
- }
24
+ "templates": "templates"
25
+ }
@@ -1,17 +1,19 @@
1
1
  <div class="acp-page-container">
2
2
  <h4>Discord Onekite</h4>
3
3
  <p class="text-muted">
4
- Notifications Discord via webhook.
4
+ Notifications Discord via webhook (page ACP en rendu serveur).
5
5
  </p>
6
6
 
7
- <form role="form" class="discord-onekite-settings">
7
+ <form role="form" method="post" action="/admin/plugins/discord-onekite/save">
8
+ <input type="hidden" name="_csrf" value="{config.csrf_token}" />
9
+
8
10
  <div class="mb-3">
9
11
  <label class="form-label" for="webhookUrl">Discord Webhook URL</label>
10
- <input type="text" class="form-control" id="webhookUrl" name="webhookUrl" placeholder="https://discord.com/api/webhooks/..." />
12
+ <input type="text" class="form-control" id="webhookUrl" name="webhookUrl" value="{settings.webhookUrl}" placeholder="https://discord.com/api/webhooks/..." />
11
13
  </div>
12
14
 
13
15
  <div class="form-check mb-3">
14
- <input class="form-check-input" type="checkbox" id="notifyReplies" name="notifyReplies">
16
+ <input class="form-check-input" type="checkbox" id="notifyReplies" name="notifyReplies" <!-- IF settings.notifyReplies -->checked<!-- ENDIF settings.notifyReplies -->>
15
17
  <label class="form-check-label" for="notifyReplies">
16
18
  Notifier aussi les réponses (si décoché : uniquement les nouveaux sujets)
17
19
  </label>
@@ -19,12 +21,16 @@
19
21
 
20
22
  <div class="mb-3">
21
23
  <label class="form-label" for="cids">Catégories à notifier</label>
22
- <select class="form-select" id="cids" name="cids" multiple size="12"></select>
24
+ <select class="form-select" id="cids" name="cids" multiple size="12">
25
+ <!-- BEGIN categories -->
26
+ <option value="{categories.cid}" <!-- IF categories.selected -->selected<!-- ENDIF categories.selected -->>{categories.name}</option>
27
+ <!-- END categories -->
28
+ </select>
23
29
  <p class="form-text text-muted">
24
30
  Si aucune catégorie n’est sélectionnée : <strong>toutes les catégories</strong> seront notifiées.
25
31
  </p>
26
32
  </div>
27
33
 
28
- <!-- IMPORT admin/partials/save_button.tpl -->
34
+ <button type="submit" class="btn btn-primary">Enregistrer</button>
29
35
  </form>
30
36
  </div>
@@ -1,67 +0,0 @@
1
- 'use strict';
2
- /* global $, app, ajaxify */
3
-
4
- (function () {
5
- function initOnekiteACP() {
6
- if (!ajaxify || !ajaxify.data || ajaxify.data.template !== 'admin/plugins/discord-onekite') {
7
- return;
8
- }
9
-
10
- // Use NodeBB's AMD loader to access core helpers
11
- require(['settings', 'api'], function (settings, api) {
12
- const $form = $('.discord-onekite-settings');
13
- if (!$form.length) return;
14
-
15
- // Avoid double-binding
16
- if ($form.data('onekite-initialized')) return;
17
- $form.data('onekite-initialized', true);
18
-
19
- function normalizeCids(v) {
20
- if (!v) return [];
21
- if (Array.isArray(v)) return v.map(String).filter(Boolean);
22
- if (typeof v === 'string') return v.split(',').map(s => s.trim()).filter(Boolean);
23
- return [];
24
- }
25
-
26
- // Load saved settings into the form
27
- settings.load('discord-onekite', $form);
28
-
29
- // Get raw settings so we can pre-select categories
30
- settings.get('discord-onekite', function (saved) {
31
- saved = saved || {};
32
- const savedCids = normalizeCids(saved.cids);
33
-
34
- // Load categories (admin should have access)
35
- api.get('/categories').then(function (res) {
36
- const categories = (res && res.categories) ? res.categories : [];
37
- const $select = $('#cids');
38
- $select.empty();
39
-
40
- categories
41
- .filter(c => c && typeof c.cid !== 'undefined' && c.name)
42
- .forEach(c => {
43
- const cid = String(c.cid);
44
- const $opt = $('<option/>').val(cid).text(c.name);
45
- if (savedCids.includes(cid)) $opt.prop('selected', true);
46
- $opt.appendTo($select);
47
- });
48
- }).catch(function (e) {
49
- // eslint-disable-next-line no-console
50
- console.error('[discord-onekite] GET /api/categories failed', e);
51
- if (app && app.alertError) app.alertError('Impossible de charger les catégories (GET /api/categories).');
52
- });
53
- });
54
-
55
- // Save
56
- $('#save').off('click.discordOnekite').on('click.discordOnekite', function () {
57
- settings.save('discord-onekite', $form, function () {
58
- if (app && app.alertSuccess) app.alertSuccess('Paramètres enregistrés !');
59
- });
60
- });
61
- });
62
- }
63
-
64
- // Run on initial load and after ajax navigation in ACP
65
- $(window).on('action:ajaxify.end', initOnekiteACP);
66
- $(initOnekiteACP);
67
- })();