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 +4 -19
- package/library.js +11 -30
- package/package.json +1 -1
- package/plugin.json +1 -2
- package/static/templates/admin/plugins/discord-onekite.tpl +57 -0
- package/static/lib/admin.js +0 -45
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
|
-
|
|
4
|
-
-
|
|
5
|
-
-
|
|
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
|
-
//
|
|
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
|
|
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
|
|
144
|
-
if (!
|
|
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
|
-
|
|
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
package/plugin.json
CHANGED
|
@@ -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>
|
package/static/lib/admin.js
DELETED
|
@@ -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
|
-
});
|