nodebb-plugin-discord-onekite 1.1.10 → 1.1.12

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,5 +1,4 @@
1
- # nodebb-plugin-discord-onekite v1.1.7
1
+ # nodebb-plugin-discord-onekite v1.1.4.3
2
2
 
3
- Fixes webpack template build errors by removing `<!-- IMPORT admin/partials/save_button.tpl -->` and using an inline save button.
4
-
5
- Everything else unchanged from v1.1.6.
3
+ Fix: syntax error in library.js (newline in join string).
4
+ Keeps v1.1.4-based changes: single clickable link line + excerpt below.
package/library.js CHANGED
@@ -8,6 +8,7 @@ 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');
11
12
 
12
13
  const controllers = require('./lib/controllers');
13
14
 
@@ -37,6 +38,15 @@ function ensureAbsoluteUrl(baseUrl, maybeUrl) {
37
38
  return s;
38
39
  }
39
40
 
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
+
40
50
  function stripHtml(html) {
41
51
  if (!html) return '';
42
52
  return String(html)
@@ -89,15 +99,15 @@ async function postToDiscord(webhookUrl, payload) {
89
99
  }
90
100
  }
91
101
 
92
- async function sendDiscord(webhookUrl, payload) {
102
+ async function sendDiscord(webhookUrl, payload, fallbackContent) {
93
103
  if (!webhookUrl) return;
104
+
94
105
  try {
95
106
  await postToDiscord(webhookUrl, payload);
96
107
  } catch (e) {
97
- // If Discord rejects embeds, retry with plain content only.
98
- if (e && e.statusCode === 400 && payload && payload.content) {
108
+ if (e && e.statusCode === 400 && fallbackContent) {
99
109
  try {
100
- await postToDiscord(webhookUrl, { content: payload.content });
110
+ await postToDiscord(webhookUrl, { content: fallbackContent });
101
111
  return;
102
112
  } catch (e2) {
103
113
  console.error(e2);
@@ -121,25 +131,39 @@ async function getPostExcerpt(pid) {
121
131
  async function buildPayload({ tid, pid, isReply }) {
122
132
  const baseUrl = normalizeBaseUrl(meta.config.url);
123
133
 
124
- const topicData = await topics.getTopicFields(tid, ['tid', 'cid', 'title', 'slug', 'mainPid']);
134
+ const topicData = await topics.getTopicFields(tid, ['tid', 'uid', 'cid', 'title', 'slug', 'mainPid']);
125
135
  if (!topicData) return null;
126
136
 
137
+ // Always build the forum link like the example: https://www.onekite.com/topic/<tid or slug>
127
138
  const topicUrl = ensureAbsoluteUrl(baseUrl, `/topic/${topicData.slug || topicData.tid}`);
128
- const targetUrl = (isReply && pid) ? `${topicUrl}/${pid}` : topicUrl;
129
139
 
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']);
130
144
  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
+
131
147
  const excerpt = await getPostExcerpt(isReply ? pid : topicData.mainPid);
148
+ const description = truncate(excerpt || (isReply ? `Réponse de ${authorName}` : `Sujet créé par ${authorName}`), 500);
149
+
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;
132
156
 
133
- // Single clickable link line + excerpt below
157
+ // Message format:
158
+ // 1) A single clickable link line: "🆕 Nouveau sujet : [Titre](URL)" (or reply variant)
159
+ // 2) Excerpt below
134
160
  const linkLine = isReply
135
- ? `🗨️ Nouvelle réponse : [${title}](${targetUrl})`
161
+ ? `🗨️ Nouvelle réponse : [${title}](${postUrl})`
136
162
  : `🆕 Nouveau sujet : [${title}](${topicUrl})`;
137
163
 
138
- const content = [linkLine, excerpt].filter(Boolean).join('\n');
139
-
140
- const embed = { title, description: excerpt || '' , url: targetUrl };
164
+ const content = [linkLine, description].filter(Boolean).join('\n');
141
165
 
142
- return { topicData, content, embed };
166
+ return { topicData, embed, content };
143
167
  }
144
168
 
145
169
  function extractTidPid(data) {
@@ -158,8 +182,8 @@ Plugin.init = async ({ router }) => {
158
182
  controllers.renderAdminPage
159
183
  );
160
184
 
161
- // AJAX save endpoint (used by admin.js via api.post)
162
- router.post('/admin/plugins/discord-onekite/save',
185
+ // AJAX save endpoint for ACP (used by admin.js)
186
+ router.post('/api/admin/plugins/discord-onekite/save',
163
187
  middleware.admin.checkPrivileges,
164
188
  async (req, res) => {
165
189
  try {
@@ -196,9 +220,11 @@ Plugin.onTopicPost = async (data) => {
196
220
 
197
221
  const built = await buildPayload({ tid, isReply: false });
198
222
  if (!built) return;
223
+
199
224
  if (!cidAllowed(built.topicData.cid, settings.cids)) return;
200
225
 
201
- await sendDiscord(settings.webhookUrl, { content: built.content, embeds: [built.embed] });
226
+ // Send content + embed (content ensures clickable link always)
227
+ await sendDiscord(settings.webhookUrl, { content: built.content, embeds: [built.embed] }, built.content);
202
228
  };
203
229
 
204
230
  Plugin.onTopicReply = async (data) => {
@@ -211,9 +237,12 @@ Plugin.onTopicReply = async (data) => {
211
237
 
212
238
  const built = await buildPayload({ tid, pid, isReply: true });
213
239
  if (!built) return;
240
+
241
+ if (built.topicData?.mainPid && String(built.topicData.mainPid) === String(pid)) return;
242
+
214
243
  if (!cidAllowed(built.topicData.cid, settings.cids)) return;
215
244
 
216
- await sendDiscord(settings.webhookUrl, { content: built.content, embeds: [built.embed] });
245
+ await sendDiscord(settings.webhookUrl, { content: built.content, embeds: [built.embed] }, built.content);
217
246
  };
218
247
 
219
248
  module.exports = Plugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-discord-onekite",
3
- "version": "1.1.10",
3
+ "version": "1.1.12",
4
4
  "description": "Discord webhook notifier for Onekite (NodeBB v4.x only)",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
@@ -21,7 +21,6 @@ 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/...
25
24
  api.post('/admin/plugins/discord-onekite/save', payload).then(function () {
26
25
  if (window.app && typeof app.alertSuccess === 'function') {
27
26
  app.alertSuccess('Paramètres enregistrés !');
@@ -1,13 +1,8 @@
1
1
  <div class="acp-page-container">
2
- <div class="d-flex justify-content-between align-items-start mb-3">
3
- <div>
4
- <h4 class="mb-1">Discord Onekite</h4>
5
- <p class="text-muted mb-0">Notifications Discord via webhook.</p>
6
- </div>
7
- <button id="save" class="btn btn-primary">
8
- <i class="fa fa-save"></i> Enregistrer
9
- </button>
10
- </div>
2
+ <h4>Discord Onekite</h4>
3
+ <p class="text-muted">
4
+ Notifications Discord via webhook.
5
+ </p>
11
6
 
12
7
  <form role="form" class="discord-onekite-settings">
13
8
  <div class="mb-3">
@@ -33,5 +28,7 @@
33
28
  Si aucune catégorie n’est sélectionnée : <strong>toutes les catégories</strong> seront notifiées.
34
29
  </p>
35
30
  </div>
31
+
32
+ <!-- IMPORT admin/partials/save_button.tpl -->
36
33
  </form>
37
34
  </div>