nodebb-plugin-discord-onekite 1.0.9 → 1.0.11
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 -1
- package/lib/controllers.js +8 -32
- package/library.js +24 -41
- package/package.json +2 -2
- package/plugin.json +9 -6
- package/static/lib/acp-toast.js +26 -0
- package/templates/admin/plugins/discord-onekite.tpl +9 -12
package/README.md
CHANGED
package/lib/controllers.js
CHANGED
|
@@ -12,28 +12,13 @@ function normalizeCids(v) {
|
|
|
12
12
|
return [];
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
async function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (err) {
|
|
22
|
-
result.error = err.message || String(err);
|
|
23
|
-
return resolve([]);
|
|
24
|
-
}
|
|
25
|
-
if (!Array.isArray(categoriesData)) return resolve([]);
|
|
26
|
-
resolve(categoriesData.filter(Boolean));
|
|
27
|
-
});
|
|
28
|
-
} catch (e) {
|
|
29
|
-
result.error = e.message || String(e);
|
|
30
|
-
resolve([]);
|
|
31
|
-
}
|
|
15
|
+
async function getReadableCategories(uid) {
|
|
16
|
+
return await new Promise((resolve) => {
|
|
17
|
+
categories.getCategoriesByPrivilege('categories:cid', uid || 0, 'read', (err, categoriesData) => {
|
|
18
|
+
if (err || !Array.isArray(categoriesData)) return resolve([]);
|
|
19
|
+
resolve(categoriesData.filter(Boolean));
|
|
20
|
+
});
|
|
32
21
|
});
|
|
33
|
-
|
|
34
|
-
result.count = cats.length;
|
|
35
|
-
result.sample = cats.slice(0, 5).map(c => ({ cid: c.cid, name: c.name }));
|
|
36
|
-
return { cats, result };
|
|
37
22
|
}
|
|
38
23
|
|
|
39
24
|
const controllers = {};
|
|
@@ -42,7 +27,7 @@ controllers.renderAdminPage = async function (req, res) {
|
|
|
42
27
|
const settings = await meta.settings.get(SETTINGS_KEY);
|
|
43
28
|
const savedCids = normalizeCids(settings && settings.cids);
|
|
44
29
|
|
|
45
|
-
const
|
|
30
|
+
const cats = await getReadableCategories(req.uid);
|
|
46
31
|
const categoriesForTpl = (cats || [])
|
|
47
32
|
.filter(c => c && typeof c.cid !== 'undefined' && c.name)
|
|
48
33
|
.map(c => ({
|
|
@@ -52,19 +37,10 @@ controllers.renderAdminPage = async function (req, res) {
|
|
|
52
37
|
}))
|
|
53
38
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
54
39
|
|
|
55
|
-
const debug = {
|
|
56
|
-
uid: req.uid,
|
|
57
|
-
relative_path: meta.config && meta.config.relative_path,
|
|
58
|
-
url: meta.config && meta.config.url,
|
|
59
|
-
categories: result,
|
|
60
|
-
savedCidsCount: savedCids.length,
|
|
61
|
-
now: new Date().toISOString(),
|
|
62
|
-
};
|
|
63
|
-
|
|
64
40
|
res.render('admin/plugins/discord-onekite', {
|
|
65
41
|
settings: settings || {},
|
|
66
42
|
categories: categoriesForTpl,
|
|
67
|
-
|
|
43
|
+
saved: req.query && (req.query.saved === '1' || req.query.saved === 'true'),
|
|
68
44
|
});
|
|
69
45
|
};
|
|
70
46
|
|
package/library.js
CHANGED
|
@@ -49,7 +49,7 @@ async function postToDiscord(webhookUrl, payload) {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
async function buildTopicEmbed({ tid, pid,
|
|
52
|
+
async function buildTopicEmbed({ tid, pid, isReply }) {
|
|
53
53
|
const baseUrl = meta.config.url;
|
|
54
54
|
|
|
55
55
|
const topicData = await topics.getTopicFields(tid, ['tid', 'uid', 'cid', 'title', 'slug', 'timestamp', 'mainPid']);
|
|
@@ -58,11 +58,10 @@ async function buildTopicEmbed({ tid, pid, type }) {
|
|
|
58
58
|
const topicUrl = `${baseUrl}/topic/${topicData.slug || topicData.tid}`;
|
|
59
59
|
const u = await user.getUserFields(topicData.uid, ['username', 'picture']);
|
|
60
60
|
|
|
61
|
-
const isReply = type === 'reply';
|
|
62
61
|
const embed = {
|
|
63
62
|
title: topicData.title || (isReply ? 'Nouvelle réponse' : 'Nouveau sujet'),
|
|
64
63
|
url: isReply && pid ? `${topicUrl}/${pid}` : topicUrl,
|
|
65
|
-
timestamp: new Date(
|
|
64
|
+
timestamp: new Date(Date.now()).toISOString(),
|
|
66
65
|
author: u?.username ? { name: u.username, icon_url: u.picture || undefined } : undefined,
|
|
67
66
|
footer: { text: 'NodeBB → Discord (Onekite)' },
|
|
68
67
|
};
|
|
@@ -72,11 +71,15 @@ async function buildTopicEmbed({ tid, pid, type }) {
|
|
|
72
71
|
return { topicData, embed };
|
|
73
72
|
}
|
|
74
73
|
|
|
74
|
+
function extractTidPid(data) {
|
|
75
|
+
const tid = data?.tid || data?.topic?.tid || data?.post?.tid;
|
|
76
|
+
const pid = data?.pid || data?.post?.pid;
|
|
77
|
+
return { tid, pid };
|
|
78
|
+
}
|
|
79
|
+
|
|
75
80
|
const Plugin = {};
|
|
76
81
|
|
|
77
82
|
Plugin.init = async ({ router }) => {
|
|
78
|
-
console.log('[discord-onekite] init hook fired');
|
|
79
|
-
|
|
80
83
|
routeHelpers.setupAdminPageRoute(
|
|
81
84
|
router,
|
|
82
85
|
'/admin/plugins/discord-onekite',
|
|
@@ -94,26 +97,11 @@ Plugin.init = async ({ router }) => {
|
|
|
94
97
|
cids: req.body.cids || '',
|
|
95
98
|
};
|
|
96
99
|
await meta.settings.set(SETTINGS_KEY, payload);
|
|
97
|
-
console.log('[discord-onekite] settings saved');
|
|
98
100
|
} catch (e) {
|
|
101
|
+
// eslint-disable-next-line no-console
|
|
99
102
|
console.error('[discord-onekite] save failed', e);
|
|
100
103
|
}
|
|
101
|
-
res.redirect('/admin/plugins/discord-onekite');
|
|
102
|
-
}
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
router.get('/admin/plugins/discord-onekite/ping',
|
|
106
|
-
middleware.admin.checkPrivileges,
|
|
107
|
-
(req, res) => {
|
|
108
|
-
res.json({
|
|
109
|
-
ok: true,
|
|
110
|
-
plugin: 'nodebb-plugin-discord-onekite',
|
|
111
|
-
version: '1.0.7',
|
|
112
|
-
uid: req.uid,
|
|
113
|
-
relative_path: meta.config && meta.config.relative_path,
|
|
114
|
-
url: meta.config && meta.config.url,
|
|
115
|
-
time: new Date().toISOString(),
|
|
116
|
-
});
|
|
104
|
+
res.redirect('/admin/plugins/discord-onekite?saved=1');
|
|
117
105
|
}
|
|
118
106
|
);
|
|
119
107
|
};
|
|
@@ -122,58 +110,53 @@ Plugin.addAdminNavigation = (header) => {
|
|
|
122
110
|
header.plugins.push({
|
|
123
111
|
route: '/plugins/discord-onekite',
|
|
124
112
|
icon: 'fa-bell',
|
|
125
|
-
name: 'Discord Onekite
|
|
113
|
+
name: 'Discord Onekite',
|
|
126
114
|
});
|
|
127
115
|
return header;
|
|
128
116
|
};
|
|
129
117
|
|
|
130
|
-
|
|
118
|
+
// Fired when a new topic is posted (creation)
|
|
119
|
+
Plugin.onTopicPost = async (data) => {
|
|
131
120
|
try {
|
|
132
121
|
const settings = await getSettings();
|
|
133
122
|
if (!settings.webhookUrl) return;
|
|
134
123
|
|
|
135
|
-
const tid = data
|
|
124
|
+
const { tid } = extractTidPid(data);
|
|
136
125
|
if (!tid) return;
|
|
137
126
|
|
|
138
|
-
const
|
|
139
|
-
data?.isNew === true ||
|
|
140
|
-
data?.topic?.isNew === true ||
|
|
141
|
-
(typeof data?.topic?.postcount === 'number' && data.topic.postcount === 1);
|
|
142
|
-
|
|
143
|
-
if (!isNew) return;
|
|
144
|
-
|
|
145
|
-
const built = await buildTopicEmbed({ tid, type: 'topic' });
|
|
127
|
+
const built = await buildTopicEmbed({ tid, isReply: false });
|
|
146
128
|
if (!built) return;
|
|
147
129
|
|
|
148
130
|
if (!cidAllowed(built.topicData.cid, settings.cids)) return;
|
|
149
131
|
|
|
150
132
|
await postToDiscord(settings.webhookUrl, { embeds: [built.embed] });
|
|
151
133
|
} catch (err) {
|
|
134
|
+
// eslint-disable-next-line no-console
|
|
152
135
|
console.error(err);
|
|
153
136
|
}
|
|
154
137
|
};
|
|
155
138
|
|
|
156
|
-
|
|
139
|
+
// Fired when a reply is made in a topic
|
|
140
|
+
Plugin.onTopicReply = async (data) => {
|
|
157
141
|
try {
|
|
158
142
|
const settings = await getSettings();
|
|
159
143
|
if (!settings.notifyReplies) return;
|
|
160
144
|
if (!settings.webhookUrl) return;
|
|
161
145
|
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
if (!pid || !tid) return;
|
|
146
|
+
const { tid, pid } = extractTidPid(data);
|
|
147
|
+
if (!tid || !pid) return;
|
|
165
148
|
|
|
166
|
-
const
|
|
167
|
-
if (!isNew) return;
|
|
168
|
-
|
|
169
|
-
const built = await buildTopicEmbed({ tid, pid, type: 'reply' });
|
|
149
|
+
const built = await buildTopicEmbed({ tid, pid, isReply: true });
|
|
170
150
|
if (!built) return;
|
|
171
151
|
|
|
152
|
+
// Safety: don't notify if somehow this is the main post
|
|
172
153
|
if (built.topicData?.mainPid && String(built.topicData.mainPid) === String(pid)) return;
|
|
154
|
+
|
|
173
155
|
if (!cidAllowed(built.topicData.cid, settings.cids)) return;
|
|
174
156
|
|
|
175
157
|
await postToDiscord(settings.webhookUrl, { embeds: [built.embed] });
|
|
176
158
|
} catch (err) {
|
|
159
|
+
// eslint-disable-next-line no-console
|
|
177
160
|
console.error(err);
|
|
178
161
|
}
|
|
179
162
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodebb-plugin-discord-onekite",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Discord webhook notifier for Onekite (NodeBB v4.x only)
|
|
3
|
+
"version": "1.0.11",
|
|
4
|
+
"description": "Discord webhook notifier for Onekite (NodeBB v4.x only)",
|
|
5
5
|
"main": "library.js",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "nodebb-plugin-discord-onekite",
|
|
3
3
|
"name": "Discord Onekite Notifier",
|
|
4
|
-
"description": "Notifie Discord via webhook (v4.x
|
|
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
7
|
{
|
|
@@ -13,13 +13,16 @@
|
|
|
13
13
|
"method": "addAdminNavigation"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
|
-
"hook": "action:topic.
|
|
17
|
-
"method": "
|
|
16
|
+
"hook": "action:topic.post",
|
|
17
|
+
"method": "onTopicPost"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
|
-
"hook": "action:
|
|
21
|
-
"method": "
|
|
20
|
+
"hook": "action:topic.reply",
|
|
21
|
+
"method": "onTopicReply"
|
|
22
22
|
}
|
|
23
23
|
],
|
|
24
|
-
"templates": "templates"
|
|
24
|
+
"templates": "templates",
|
|
25
|
+
"acpScripts": [
|
|
26
|
+
"static/lib/acp-toast.js"
|
|
27
|
+
]
|
|
25
28
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/* global $, app, ajaxify */
|
|
3
|
+
|
|
4
|
+
(function () {
|
|
5
|
+
function showToastIfSaved() {
|
|
6
|
+
if (!ajaxify || !ajaxify.data || ajaxify.data.template !== 'admin/plugins/discord-onekite') return;
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
const url = new URL(window.location.href);
|
|
10
|
+
const saved = url.searchParams.get('saved');
|
|
11
|
+
if (saved === '1' || saved === 'true') {
|
|
12
|
+
if (window.app && typeof app.alertSuccess === 'function') {
|
|
13
|
+
app.alertSuccess('Paramètres enregistrés !');
|
|
14
|
+
}
|
|
15
|
+
// remove the query param to avoid re-toasting on navigation
|
|
16
|
+
url.searchParams.delete('saved');
|
|
17
|
+
window.history.replaceState({}, document.title, url.toString());
|
|
18
|
+
}
|
|
19
|
+
} catch (e) {
|
|
20
|
+
// ignore
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
$(window).on('action:ajaxify.end', showToastIfSaved);
|
|
25
|
+
$(showToastIfSaved);
|
|
26
|
+
})();
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
<div class="acp-page-container">
|
|
2
|
-
<h4>Discord Onekite
|
|
2
|
+
<h4>Discord Onekite</h4>
|
|
3
3
|
<p class="text-muted">
|
|
4
|
-
|
|
4
|
+
Notifications Discord via webhook (rendu serveur).
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
+
<!-- IF saved -->
|
|
8
|
+
<div class="alert alert-success" role="alert">
|
|
9
|
+
Paramètres enregistrés !
|
|
10
|
+
</div>
|
|
11
|
+
<!-- ENDIF saved -->
|
|
12
|
+
|
|
7
13
|
<form role="form" method="post" action="/admin/plugins/discord-onekite/save">
|
|
8
14
|
<input type="hidden" name="_csrf" value="{config.csrf_token}" />
|
|
9
15
|
|
|
@@ -15,7 +21,7 @@
|
|
|
15
21
|
<div class="form-check mb-3">
|
|
16
22
|
<input class="form-check-input" type="checkbox" id="notifyReplies" name="notifyReplies" <!-- IF settings.notifyReplies -->checked<!-- ENDIF settings.notifyReplies -->>
|
|
17
23
|
<label class="form-check-label" for="notifyReplies">
|
|
18
|
-
Notifier aussi les réponses
|
|
24
|
+
Notifier aussi les réponses (si décoché : uniquement les nouveaux sujets)
|
|
19
25
|
</label>
|
|
20
26
|
</div>
|
|
21
27
|
|
|
@@ -33,13 +39,4 @@
|
|
|
33
39
|
|
|
34
40
|
<button type="submit" class="btn btn-primary">Enregistrer</button>
|
|
35
41
|
</form>
|
|
36
|
-
|
|
37
|
-
<hr />
|
|
38
|
-
|
|
39
|
-
<h5>Debug</h5>
|
|
40
|
-
<pre style="white-space: pre-wrap;">{debug}</pre>
|
|
41
|
-
<p>
|
|
42
|
-
Endpoint de test (doit répondre JSON) :
|
|
43
|
-
<code>/admin/plugins/discord-onekite/ping</code>
|
|
44
|
-
</p>
|
|
45
42
|
</div>
|