nodebb-plugin-discord-onekite 1.0.15 → 1.1.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,8 +1,10 @@
1
- # nodebb-plugin-discord-onekite v1.1.4
1
+ # nodebb-plugin-discord-onekite v1.1.6
2
2
 
3
- Discord:
4
- - Always sends the forum topic link (example: https://www.onekite.com/topic/16024/test-discord)
5
- - First line is the raw URL, then a Markdown clickable link `[title](url)`
6
- - Still sends an embed (title clickable via embed.url) + fallback to plain content if embeds are rejected
3
+ This fixes the broken v1.1.5 zip (missing files).
4
+
5
+ ACP:
6
+ - Standard NodeBB save disk button
7
+ - AJAX save endpoint + NodeBB toast
7
8
 
8
- ACP remains with the "disk" save button and NodeBB toast.
9
+ Discord:
10
+ - Single clickable line "Nouveau sujet : [Titre](URL)" then excerpt below
package/library.js CHANGED
@@ -8,7 +8,6 @@ const middleware = require.main.require('./src/middleware');
8
8
 
9
9
  const topics = require.main.require('./src/topics');
10
10
  const posts = require.main.require('./src/posts');
11
- const user = require.main.require('./src/user');
12
11
 
13
12
  const controllers = require('./lib/controllers');
14
13
 
@@ -38,15 +37,6 @@ function ensureAbsoluteUrl(baseUrl, maybeUrl) {
38
37
  return s;
39
38
  }
40
39
 
41
- function isValidHttpUrl(s) {
42
- try {
43
- const u = new URL(s);
44
- return u.protocol === 'http:' || u.protocol === 'https:';
45
- } catch {
46
- return false;
47
- }
48
- }
49
-
50
40
  function stripHtml(html) {
51
41
  if (!html) return '';
52
42
  return String(html)
@@ -99,15 +89,15 @@ async function postToDiscord(webhookUrl, payload) {
99
89
  }
100
90
  }
101
91
 
102
- async function sendDiscord(webhookUrl, payload, fallbackContent) {
92
+ async function sendDiscord(webhookUrl, payload) {
103
93
  if (!webhookUrl) return;
104
-
105
94
  try {
106
95
  await postToDiscord(webhookUrl, payload);
107
96
  } catch (e) {
108
- if (e && e.statusCode === 400 && fallbackContent) {
97
+ // If Discord rejects embeds, retry with plain content only.
98
+ if (e && e.statusCode === 400 && payload && payload.content) {
109
99
  try {
110
- await postToDiscord(webhookUrl, { content: fallbackContent });
100
+ await postToDiscord(webhookUrl, { content: payload.content });
111
101
  return;
112
102
  } catch (e2) {
113
103
  console.error(e2);
@@ -131,37 +121,25 @@ async function getPostExcerpt(pid) {
131
121
  async function buildPayload({ tid, pid, isReply }) {
132
122
  const baseUrl = normalizeBaseUrl(meta.config.url);
133
123
 
134
- const topicData = await topics.getTopicFields(tid, ['tid', 'uid', 'cid', 'title', 'slug', 'mainPid']);
124
+ const topicData = await topics.getTopicFields(tid, ['tid', 'cid', 'title', 'slug', 'mainPid']);
135
125
  if (!topicData) return null;
136
126
 
137
- // Always build the forum link like the example: https://www.onekite.com/topic/<tid or slug>
138
127
  const topicUrl = ensureAbsoluteUrl(baseUrl, `/topic/${topicData.slug || topicData.tid}`);
128
+ const targetUrl = (isReply && pid) ? `${topicUrl}/${pid}` : topicUrl;
139
129
 
140
- // For replies, link directly to the post if possible
141
- const postUrl = (isReply && pid) ? `${topicUrl}/${pid}` : topicUrl;
142
-
143
- const u = await user.getUserFields(topicData.uid, ['username']);
144
130
  const title = (topicData.title || (isReply ? 'Nouvelle réponse' : 'Nouveau sujet')).toString().slice(0, 256);
145
- const authorName = (u && u.username ? String(u.username) : 'Utilisateur').slice(0, 256);
146
-
147
131
  const excerpt = await getPostExcerpt(isReply ? pid : topicData.mainPid);
148
- const description = truncate(excerpt || (isReply ? `Réponse de ${authorName}` : `Sujet créé par ${authorName}`), 500);
149
132
 
150
- // Minimal embed but with URL so the title is clickable
151
- const embed = {
152
- title,
153
- description,
154
- };
155
- if (isValidHttpUrl(postUrl)) embed.url = postUrl;
133
+ // Single clickable link line + excerpt below
134
+ const linkLine = isReply
135
+ ? `🗨️ Nouvelle réponse : [${title}](${targetUrl})`
136
+ : `🆕 Nouveau sujet : [${title}](${topicUrl})`;
137
+
138
+ const content = [linkLine, excerpt].filter(Boolean).join('\n');
156
139
 
157
- // Ensure the message is clickable: markdown link + also raw URL in first line
158
- const content = [
159
- postUrl, // raw URL first line
160
- isReply ? `🗨️ Nouvelle réponse : [${title}](${postUrl})` : `🆕 Nouveau sujet : [${title}](${topicUrl})`,
161
- description ? description : '',
162
- ].filter(Boolean).join('\n');
140
+ const embed = { title, description: excerpt || '' , url: targetUrl };
163
141
 
164
- return { topicData, embed, content };
142
+ return { topicData, content, embed };
165
143
  }
166
144
 
167
145
  function extractTidPid(data) {
@@ -180,8 +158,8 @@ Plugin.init = async ({ router }) => {
180
158
  controllers.renderAdminPage
181
159
  );
182
160
 
183
- // AJAX save endpoint for ACP (used by admin.js)
184
- router.post('/api/admin/plugins/discord-onekite/save',
161
+ // AJAX save endpoint (used by admin.js via api.post)
162
+ router.post('/admin/plugins/discord-onekite/save',
185
163
  middleware.admin.checkPrivileges,
186
164
  async (req, res) => {
187
165
  try {
@@ -218,11 +196,9 @@ Plugin.onTopicPost = async (data) => {
218
196
 
219
197
  const built = await buildPayload({ tid, isReply: false });
220
198
  if (!built) return;
221
-
222
199
  if (!cidAllowed(built.topicData.cid, settings.cids)) return;
223
200
 
224
- // Send content + embed (content ensures clickable link always)
225
- await sendDiscord(settings.webhookUrl, { content: built.content, embeds: [built.embed] }, built.content);
201
+ await sendDiscord(settings.webhookUrl, { content: built.content, embeds: [built.embed] });
226
202
  };
227
203
 
228
204
  Plugin.onTopicReply = async (data) => {
@@ -235,12 +211,9 @@ Plugin.onTopicReply = async (data) => {
235
211
 
236
212
  const built = await buildPayload({ tid, pid, isReply: true });
237
213
  if (!built) return;
238
-
239
- if (built.topicData?.mainPid && String(built.topicData.mainPid) === String(pid)) return;
240
-
241
214
  if (!cidAllowed(built.topicData.cid, settings.cids)) return;
242
215
 
243
- await sendDiscord(settings.webhookUrl, { content: built.content, embeds: [built.embed] }, built.content);
216
+ await sendDiscord(settings.webhookUrl, { content: built.content, embeds: [built.embed] });
244
217
  };
245
218
 
246
219
  module.exports = Plugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-discord-onekite",
3
- "version": "1.0.15",
3
+ "version": "1.1.7",
4
4
  "description": "Discord webhook notifier for Onekite (NodeBB v4.x only)",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
@@ -21,6 +21,7 @@ define('admin/plugins/discord-onekite', ['api'], function (api) {
21
21
  cids: getMultiSelectValues('#cids'),
22
22
  };
23
23
 
24
+ // api.post prefixes /api automatically, so server route must be /admin/...
24
25
  api.post('/admin/plugins/discord-onekite/save', payload).then(function () {
25
26
  if (window.app && typeof app.alertSuccess === 'function') {
26
27
  app.alertSuccess('Paramètres enregistrés !');