nodebb-plugin-discord-onekite 1.0.0 → 1.0.1

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,20 +1,5 @@
1
- # nodebb-plugin-discord-onekite (NodeBB v4.x)
1
+ # nodebb-plugin-discord-onekite (NodeBB v4.x) — v1.0.0 (ACP fix)
2
2
 
3
- Plugin NodeBB qui notifie un salon Discord via **webhook** lors :
4
- - des **nouveaux sujets**
5
- - et optionnellement des **réponses**
6
-
7
- ## Installation (local)
8
- Depuis le dossier NodeBB :
9
-
10
- ```bash
11
- npm install /chemin/vers/nodebb-plugin-discord-onekite
12
- ./nodebb build
13
- ./nodebb restart
14
- ```
15
-
16
- ## Configuration
17
- ACP → Plugins → **Discord Onekite**
18
- - Webhook URL
19
- - (option) Notifier les réponses
20
- - Catégories à notifier (si aucune sélection : toutes)
3
+ - Catégories listées dans l'ACP (chargées via /api/categories)
4
+ - Sauvegarde via settings.save
5
+ - Aucune catégorie sélectionnée => toutes
package/library.js CHANGED
@@ -10,19 +10,13 @@ const user = require.main.require('./src/user');
10
10
 
11
11
  const controllers = require('./lib/controllers');
12
12
 
13
- // Settings are stored under this key in NodeBB's settings system
14
13
  const SETTINGS_KEY = 'discord-onekite';
15
14
 
16
15
  function normalizeCids(value) {
17
16
  if (!value) return [];
18
17
  if (Array.isArray(value)) return value.map(v => String(v)).filter(Boolean);
19
-
20
- // Sometimes saved as "1,2,3"
21
18
  if (typeof value === 'string') {
22
- return value
23
- .split(',')
24
- .map(s => s.trim())
25
- .filter(Boolean);
19
+ return value.split(',').map(s => s.trim()).filter(Boolean);
26
20
  }
27
21
  return [];
28
22
  }
@@ -37,7 +31,7 @@ async function getSettings() {
37
31
  }
38
32
 
39
33
  function cidAllowed(topicCid, allowedCids) {
40
- // IMPORTANT (per request): if no categories are selected => notify ALL categories.
34
+ // requirement: none selected => ALL
41
35
  if (!allowedCids || allowedCids.length === 0) return true;
42
36
  return allowedCids.includes(String(topicCid));
43
37
  }
@@ -51,7 +45,6 @@ async function postToDiscord(webhookUrl, payload) {
51
45
  body: JSON.stringify(payload),
52
46
  });
53
47
 
54
- // Discord webhook success is commonly 204 No Content
55
48
  if (res.statusCode < 200 || res.statusCode >= 300) {
56
49
  const text = await res.body.text().catch(() => '');
57
50
  throw new Error(`[discord-onekite] Discord webhook HTTP ${res.statusCode}: ${text}`);
@@ -61,13 +54,10 @@ async function postToDiscord(webhookUrl, payload) {
61
54
  async function buildTopicEmbed({ tid, pid, type }) {
62
55
  const baseUrl = meta.config.url;
63
56
 
64
- // For v4.x, these fields are stable and enough for URL + title
65
57
  const topicData = await topics.getTopicFields(tid, ['tid', 'uid', 'cid', 'title', 'slug', 'timestamp', 'mainPid']);
66
58
  if (!topicData) return null;
67
59
 
68
60
  const topicUrl = `${baseUrl}/topic/${topicData.slug || topicData.tid}`;
69
-
70
- // Author (topic author). If you prefer reply author, adjust to read post author.
71
61
  const u = await user.getUserFields(topicData.uid, ['username', 'picture']);
72
62
 
73
63
  const isReply = type === 'reply';
@@ -88,7 +78,6 @@ async function buildTopicEmbed({ tid, pid, type }) {
88
78
 
89
79
  const Plugin = {};
90
80
 
91
- // Mount ACP page route (NodeBB v4.x)
92
81
  Plugin.init = async ({ router }) => {
93
82
  routeHelpers.setupAdminPageRoute(
94
83
  router,
@@ -98,7 +87,6 @@ Plugin.init = async ({ router }) => {
98
87
  );
99
88
  };
100
89
 
101
- // Add entry under ACP -> Plugins
102
90
  Plugin.addAdminNavigation = (header) => {
103
91
  header.plugins.push({
104
92
  route: '/plugins/discord-onekite',
@@ -108,16 +96,14 @@ Plugin.addAdminNavigation = (header) => {
108
96
  return header;
109
97
  };
110
98
 
111
- // NEW TOPICS ONLY (unless notifyReplies enabled for posts)
112
99
  Plugin.onTopicSave = async (data) => {
113
100
  try {
114
- const { webhookUrl, cids } = await getSettings();
115
- if (!webhookUrl) return;
101
+ const settings = await getSettings();
102
+ if (!settings.webhookUrl) return;
116
103
 
117
104
  const tid = data?.tid || data?.topic?.tid;
118
105
  if (!tid) return;
119
106
 
120
- // In v4.x, new topics often expose isNew; as a fallback, we detect postcount=1 if present.
121
107
  const isNew =
122
108
  data?.isNew === true ||
123
109
  data?.topic?.isNew === true ||
@@ -128,40 +114,35 @@ Plugin.onTopicSave = async (data) => {
128
114
  const built = await buildTopicEmbed({ tid, type: 'topic' });
129
115
  if (!built) return;
130
116
 
131
- if (!cidAllowed(built.topicData.cid, cids)) return;
117
+ if (!cidAllowed(built.topicData.cid, settings.cids)) return;
132
118
 
133
- await postToDiscord(webhookUrl, { embeds: [built.embed] });
119
+ await postToDiscord(settings.webhookUrl, { embeds: [built.embed] });
134
120
  } catch (err) {
135
- // eslint-disable-next-line no-console
136
121
  console.error(err);
137
122
  }
138
123
  };
139
124
 
140
- // REPLIES (optional)
141
125
  Plugin.onPostSave = async (data) => {
142
126
  try {
143
- const { webhookUrl, notifyReplies, cids } = await getSettings();
144
- if (!webhookUrl || !notifyReplies) return;
127
+ const settings = await getSettings();
128
+ if (!settings.notifyReplies) return;
129
+ if (!settings.webhookUrl) return;
145
130
 
146
131
  const pid = data?.pid || data?.post?.pid;
147
132
  const tid = data?.tid || data?.post?.tid;
148
133
  if (!pid || !tid) return;
149
134
 
150
- // Only new posts (avoid edits). v4.x commonly provides isNew for creates.
151
135
  const isNew = data?.isNew === true || data?.post?.isNew === true;
152
136
  if (!isNew) return;
153
137
 
154
138
  const built = await buildTopicEmbed({ tid, pid, type: 'reply' });
155
139
  if (!built) return;
156
140
 
157
- // Avoid notifying the main post (already covered by topic.save)
158
141
  if (built.topicData?.mainPid && String(built.topicData.mainPid) === String(pid)) return;
142
+ if (!cidAllowed(built.topicData.cid, settings.cids)) return;
159
143
 
160
- if (!cidAllowed(built.topicData.cid, cids)) return;
161
-
162
- await postToDiscord(webhookUrl, { embeds: [built.embed] });
144
+ await postToDiscord(settings.webhookUrl, { embeds: [built.embed] });
163
145
  } catch (err) {
164
- // eslint-disable-next-line no-console
165
146
  console.error(err);
166
147
  }
167
148
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-discord-onekite",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Discord webhook notifier for Onekite (NodeBB v4.x only)",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
package/plugin.json CHANGED
@@ -9,6 +9,5 @@
9
9
  { "hook": "action:topic.save", "method": "onTopicSave" },
10
10
  { "hook": "action:post.save", "method": "onPostSave" }
11
11
  ],
12
- "templates": "static/templates",
13
- "acpScripts": ["static/lib/admin.js"]
12
+ "templates": "static/templates"
14
13
  }
@@ -31,3 +31,60 @@
31
31
  <!-- IMPORT admin/partials/save_button.tpl -->
32
32
  </form>
33
33
  </div>
34
+
35
+ <script>
36
+ require(['settings', 'api'], function (settings, api) {
37
+ var $form = $('.discord-onekite-settings');
38
+ var $select = $('#cids');
39
+
40
+ function normalizeCids(v) {
41
+ if (!v) { return []; }
42
+ if (Array.isArray(v)) { return v.map(String); }
43
+ if (typeof v === 'string') {
44
+ return v.split(',').map(function (s) { return s.trim(); }).filter(Boolean);
45
+ }
46
+ return [];
47
+ }
48
+
49
+ // 1) Load saved settings (fills webhookUrl + checkbox; we also keep cids for later)
50
+ settings.get('discord-onekite', function (saved) {
51
+ saved = saved || {};
52
+ // Populate simple fields now
53
+ settings.load('discord-onekite', $form);
54
+
55
+ var savedCids = normalizeCids(saved.cids);
56
+
57
+ // 2) Load categories, then build options, then apply saved selection
58
+ api.get('/categories', {}).then(function (res) {
59
+ var categories = (res && res.categories) ? res.categories : [];
60
+ $select.empty();
61
+
62
+ categories
63
+ .filter(function (c) { return c && typeof c.cid !== 'undefined' && c.name; })
64
+ .forEach(function (c) {
65
+ var opt = $('<option />').val(String(c.cid)).text(c.name);
66
+ if (savedCids.includes(String(c.cid))) {
67
+ opt.prop('selected', true);
68
+ }
69
+ opt.appendTo($select);
70
+ });
71
+ }).catch(function (e) {
72
+ console.error('[discord-onekite] Could not load categories', e);
73
+ if (window.app && app.alertError) {
74
+ app.alertError('Impossible de charger la liste des catégories.');
75
+ } else {
76
+ alert('Impossible de charger la liste des catégories.');
77
+ }
78
+ });
79
+
80
+ // 3) Save handler
81
+ $('#save').off('click.discordOnekite').on('click.discordOnekite', function () {
82
+ settings.save('discord-onekite', $form, function () {
83
+ if (window.app && app.alertSuccess) {
84
+ app.alertSuccess('Paramètres enregistrés !');
85
+ }
86
+ });
87
+ });
88
+ });
89
+ });
90
+ </script>
@@ -1,45 +0,0 @@
1
- 'use strict';
2
-
3
- /* global $, app */
4
-
5
- define('admin/plugins/discord-onekite', ['settings', 'api'], function (settings, api) {
6
- const ACP = {};
7
-
8
- ACP.init = async function () {
9
- // Charge settings existants (webhookUrl, notifyReplies, cids)
10
- settings.load('discord-onekite', $('.discord-onekite-settings'));
11
-
12
- // Charge les catégories via l'API NodeBB (client api module ajoute /api)
13
- try {
14
- const res = await api.get('/categories');
15
- const categories = (res && res.categories) ? res.categories : [];
16
-
17
- const $select = $('#cids');
18
- $select.empty();
19
-
20
- categories
21
- .filter(c => c && typeof c.cid !== 'undefined' && c.name)
22
- .forEach(c => {
23
- $('<option />')
24
- .val(String(c.cid))
25
- .text(c.name)
26
- .appendTo($select);
27
- });
28
-
29
- // Recharge settings pour re-sélectionner les catégories déjà sauvegardées
30
- settings.load('discord-onekite', $('.discord-onekite-settings'));
31
- } catch (e) {
32
- // eslint-disable-next-line no-console
33
- console.error('[discord-onekite] Could not load categories', e);
34
- app.alertError('Impossible de charger la liste des catégories.');
35
- }
36
-
37
- $('#save').on('click', function () {
38
- settings.save('discord-onekite', $('.discord-onekite-settings'), function () {
39
- app.alertSuccess('Paramètres enregistrés !');
40
- });
41
- });
42
- };
43
-
44
- return ACP;
45
- });