nodebb-plugin-discord-onekite 1.0.0 → 1.0.2
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 +5 -18
- package/library.js +11 -28
- package/package.json +1 -1
- package/static/lib/admin.js +37 -15
package/README.md
CHANGED
|
@@ -1,20 +1,7 @@
|
|
|
1
|
-
# nodebb-plugin-discord-onekite (NodeBB v4.x)
|
|
1
|
+
# nodebb-plugin-discord-onekite (NodeBB v4.x) — v1.0.1
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
- des **nouveaux sujets**
|
|
5
|
-
- et optionnellement des **réponses**
|
|
3
|
+
Fix: template build errors by removing inline <script> from the .tpl and using acpScripts properly.
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
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)
|
|
5
|
+
- Categories list loads in ACP
|
|
6
|
+
- Settings save works
|
|
7
|
+
- No categories selected => notify all
|
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
|
-
//
|
|
34
|
+
// 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
|
|
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,38 +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
121
|
// eslint-disable-next-line no-console
|
|
136
122
|
console.error(err);
|
|
137
123
|
}
|
|
138
124
|
};
|
|
139
125
|
|
|
140
|
-
// REPLIES (optional)
|
|
141
126
|
Plugin.onPostSave = async (data) => {
|
|
142
127
|
try {
|
|
143
|
-
const
|
|
144
|
-
if (!
|
|
128
|
+
const settings = await getSettings();
|
|
129
|
+
if (!settings.notifyReplies) return;
|
|
130
|
+
if (!settings.webhookUrl) return;
|
|
145
131
|
|
|
146
132
|
const pid = data?.pid || data?.post?.pid;
|
|
147
133
|
const tid = data?.tid || data?.post?.tid;
|
|
148
134
|
if (!pid || !tid) return;
|
|
149
135
|
|
|
150
|
-
// Only new posts (avoid edits). v4.x commonly provides isNew for creates.
|
|
151
136
|
const isNew = data?.isNew === true || data?.post?.isNew === true;
|
|
152
137
|
if (!isNew) return;
|
|
153
138
|
|
|
154
139
|
const built = await buildTopicEmbed({ tid, pid, type: 'reply' });
|
|
155
140
|
if (!built) return;
|
|
156
141
|
|
|
157
|
-
// Avoid notifying the main post (already covered by topic.save)
|
|
158
142
|
if (built.topicData?.mainPid && String(built.topicData.mainPid) === String(pid)) return;
|
|
143
|
+
if (!cidAllowed(built.topicData.cid, settings.cids)) return;
|
|
159
144
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
await postToDiscord(webhookUrl, { embeds: [built.embed] });
|
|
145
|
+
await postToDiscord(settings.webhookUrl, { embeds: [built.embed] });
|
|
163
146
|
} catch (err) {
|
|
164
147
|
// eslint-disable-next-line no-console
|
|
165
148
|
console.error(err);
|
package/package.json
CHANGED
package/static/lib/admin.js
CHANGED
|
@@ -1,41 +1,63 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
2
|
/* global $, app */
|
|
4
3
|
|
|
5
4
|
define('admin/plugins/discord-onekite', ['settings', 'api'], function (settings, api) {
|
|
6
5
|
const ACP = {};
|
|
7
6
|
|
|
7
|
+
function normalizeCids(v) {
|
|
8
|
+
if (!v) return [];
|
|
9
|
+
if (Array.isArray(v)) return v.map(String).filter(Boolean);
|
|
10
|
+
if (typeof v === 'string') {
|
|
11
|
+
return v.split(',').map(s => s.trim()).filter(Boolean);
|
|
12
|
+
}
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
|
|
8
16
|
ACP.init = async function () {
|
|
9
|
-
|
|
10
|
-
|
|
17
|
+
const $form = $('.discord-onekite-settings');
|
|
18
|
+
const $select = $('#cids');
|
|
19
|
+
|
|
20
|
+
// Load current saved settings (including cids) BEFORE fetching categories,
|
|
21
|
+
// so we can apply selection after options are created.
|
|
22
|
+
let saved = {};
|
|
23
|
+
try {
|
|
24
|
+
saved = await new Promise((resolve) => {
|
|
25
|
+
settings.get('discord-onekite', (data) => resolve(data || {}));
|
|
26
|
+
});
|
|
27
|
+
} catch (e) {
|
|
28
|
+
saved = {};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Populate simple fields (webhookUrl, notifyReplies, etc.)
|
|
32
|
+
settings.load('discord-onekite', $form);
|
|
11
33
|
|
|
12
|
-
|
|
34
|
+
const savedCids = normalizeCids(saved.cids);
|
|
35
|
+
|
|
36
|
+
// Fetch categories list and populate select
|
|
13
37
|
try {
|
|
14
38
|
const res = await api.get('/categories');
|
|
15
39
|
const categories = (res && res.categories) ? res.categories : [];
|
|
16
40
|
|
|
17
|
-
const $select = $('#cids');
|
|
18
41
|
$select.empty();
|
|
19
|
-
|
|
20
42
|
categories
|
|
21
43
|
.filter(c => c && typeof c.cid !== 'undefined' && c.name)
|
|
22
44
|
.forEach(c => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
.
|
|
45
|
+
const cid = String(c.cid);
|
|
46
|
+
const $opt = $('<option />').val(cid).text(c.name);
|
|
47
|
+
if (savedCids.includes(cid)) {
|
|
48
|
+
$opt.prop('selected', true);
|
|
49
|
+
}
|
|
50
|
+
$opt.appendTo($select);
|
|
27
51
|
});
|
|
28
|
-
|
|
29
|
-
// Recharge settings pour re-sélectionner les catégories déjà sauvegardées
|
|
30
|
-
settings.load('discord-onekite', $('.discord-onekite-settings'));
|
|
31
52
|
} catch (e) {
|
|
32
53
|
// eslint-disable-next-line no-console
|
|
33
54
|
console.error('[discord-onekite] Could not load categories', e);
|
|
34
55
|
app.alertError('Impossible de charger la liste des catégories.');
|
|
35
56
|
}
|
|
36
57
|
|
|
37
|
-
|
|
38
|
-
|
|
58
|
+
// Save button
|
|
59
|
+
$('#save').off('click.discordOnekite').on('click.discordOnekite', function () {
|
|
60
|
+
settings.save('discord-onekite', $form, function () {
|
|
39
61
|
app.alertSuccess('Paramètres enregistrés !');
|
|
40
62
|
});
|
|
41
63
|
});
|