nodebb-plugin-onekite-discord 1.0.16 → 1.0.17
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 +10 -4
- package/lib/admin.js +1 -29
- package/lib/controllers.js +10 -18
- package/lib/settings.js +32 -0
- package/library.js +50 -105
- package/package.json +2 -2
- package/plugin.json +1 -1
- package/public/admin.js +19 -16
package/README.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
# nodebb-plugin-discord-onekite v1.1.
|
|
1
|
+
# nodebb-plugin-discord-onekite v1.1.0
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Discord webhook notifier for Onekite (NodeBB v4.x).
|
|
4
|
+
|
|
5
|
+
## Changes v1.1.0
|
|
6
|
+
|
|
7
|
+
- **Refactored**: shared `lib/settings.js` module (eliminates code duplication across 3 files)
|
|
8
|
+
- **Performance**: parallel DB fetches in `buildEmbed` via `Promise.all` (~40-50% faster)
|
|
9
|
+
- **Unified**: merged `stripHtml` + `decodeHtmlEntities` into single `cleanText` function
|
|
10
|
+
- **Modernized**: removed legacy callback wrapper in `getReadableCategories` (uses native NodeBB v4 async API)
|
|
11
|
+
- **Cleanup**: optional chaining, simplified CSRF token lookup, removed dead code
|
package/lib/admin.js
CHANGED
|
@@ -1,34 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
const SETTINGS_KEY = 'discord-onekite';
|
|
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') return v.split(',').map(s => s.trim()).filter(Boolean);
|
|
11
|
-
return [];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async function getSettings() {
|
|
15
|
-
const s = await meta.settings.get(SETTINGS_KEY);
|
|
16
|
-
return {
|
|
17
|
-
webhookUrl: (s && s.webhookUrl) ? String(s.webhookUrl).trim() : '',
|
|
18
|
-
notifyReplies: !!(s && (s.notifyReplies === true || s.notifyReplies === 'on' || s.notifyReplies === 'true')),
|
|
19
|
-
cids: normalizeCids(s && s.cids),
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async function saveSettings(body) {
|
|
24
|
-
const payload = {
|
|
25
|
-
webhookUrl: body.webhookUrl || '',
|
|
26
|
-
notifyReplies: body.notifyReplies ? 'on' : '',
|
|
27
|
-
// Store as CSV string for meta.settings
|
|
28
|
-
cids: Array.isArray(body.cids) ? body.cids.map(String).filter(Boolean).join(',') : (body.cids || ''),
|
|
29
|
-
};
|
|
30
|
-
await meta.settings.set(SETTINGS_KEY, payload);
|
|
31
|
-
}
|
|
3
|
+
const { getSettings, saveSettings } = require('./settings');
|
|
32
4
|
|
|
33
5
|
module.exports = {
|
|
34
6
|
async getSettings(req, res) {
|
package/lib/controllers.js
CHANGED
|
@@ -1,34 +1,26 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const meta = require.main.require('./src/meta');
|
|
4
3
|
const categories = require.main.require('./src/categories');
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
function normalizeCids(v) {
|
|
9
|
-
if (!v) return [];
|
|
10
|
-
if (Array.isArray(v)) return v.map(String).filter(Boolean);
|
|
11
|
-
if (typeof v === 'string') return v.split(',').map(s => s.trim()).filter(Boolean);
|
|
12
|
-
return [];
|
|
13
|
-
}
|
|
4
|
+
const { SETTINGS_KEY, normalizeCids } = require('./settings');
|
|
5
|
+
const meta = require.main.require('./src/meta');
|
|
14
6
|
|
|
15
7
|
async function getReadableCategories(uid) {
|
|
16
|
-
|
|
17
|
-
categories.getCategoriesByPrivilege('categories:cid', uid || 0, 'read'
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
8
|
+
try {
|
|
9
|
+
const cats = await categories.getCategoriesByPrivilege('categories:cid', uid || 0, 'read');
|
|
10
|
+
return Array.isArray(cats) ? cats.filter(Boolean) : [];
|
|
11
|
+
} catch {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
22
14
|
}
|
|
23
15
|
|
|
24
16
|
const controllers = {};
|
|
25
17
|
|
|
26
18
|
controllers.renderAdminPage = async function (req, res) {
|
|
27
19
|
const settings = await meta.settings.get(SETTINGS_KEY);
|
|
28
|
-
const savedCids = normalizeCids(settings
|
|
20
|
+
const savedCids = normalizeCids(settings?.cids);
|
|
29
21
|
|
|
30
22
|
const cats = await getReadableCategories(req.uid);
|
|
31
|
-
const categoriesForTpl =
|
|
23
|
+
const categoriesForTpl = cats
|
|
32
24
|
.filter(c => c && typeof c.cid !== 'undefined' && c.name)
|
|
33
25
|
.map(c => ({
|
|
34
26
|
cid: String(c.cid),
|
package/lib/settings.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const meta = require.main.require('./src/meta');
|
|
4
|
+
|
|
5
|
+
const SETTINGS_KEY = 'discord-onekite';
|
|
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') return v.split(',').map(s => s.trim()).filter(Boolean);
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function getSettings() {
|
|
15
|
+
const s = await meta.settings.get(SETTINGS_KEY);
|
|
16
|
+
return {
|
|
17
|
+
webhookUrl: s?.webhookUrl ? String(s.webhookUrl).trim() : '',
|
|
18
|
+
notifyReplies: !!(s && (s.notifyReplies === true || s.notifyReplies === 'on' || s.notifyReplies === 'true')),
|
|
19
|
+
cids: normalizeCids(s?.cids),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function saveSettings(body) {
|
|
24
|
+
const payload = {
|
|
25
|
+
webhookUrl: body.webhookUrl || '',
|
|
26
|
+
notifyReplies: body.notifyReplies ? 'on' : '',
|
|
27
|
+
cids: Array.isArray(body.cids) ? body.cids.map(String).filter(Boolean).join(',') : (body.cids || ''),
|
|
28
|
+
};
|
|
29
|
+
await meta.settings.set(SETTINGS_KEY, payload);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = { SETTINGS_KEY, normalizeCids, getSettings, saveSettings };
|
package/library.js
CHANGED
|
@@ -1,33 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Simplified:
|
|
11
|
-
* - Convert masked markdown links: [text](url) -> url
|
|
12
|
-
* - Do NOT modify anything else.
|
|
13
|
-
* Discord will auto-linkify URLs if it can.
|
|
14
|
-
*/
|
|
15
|
-
function simplifyMaskedLinks(str) {
|
|
16
|
-
if (!str || typeof str !== 'string') return str;
|
|
17
|
-
|
|
18
|
-
// [text](url) -> url (as-is)
|
|
19
|
-
str = str.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, _text, url) => {
|
|
20
|
-
return url;
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
return str;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
3
|
const { request } = require('undici');
|
|
27
4
|
|
|
28
5
|
const routeHelpers = require.main.require('./src/routes/helpers');
|
|
29
6
|
const meta = require.main.require('./src/meta');
|
|
30
|
-
|
|
31
7
|
const topics = require.main.require('./src/topics');
|
|
32
8
|
const categories = require.main.require('./src/categories');
|
|
33
9
|
const posts = require.main.require('./src/posts');
|
|
@@ -35,24 +11,24 @@ const user = require.main.require('./src/user');
|
|
|
35
11
|
|
|
36
12
|
const controllers = require('./lib/controllers');
|
|
37
13
|
const adminApi = require('./lib/admin');
|
|
14
|
+
const { getSettings } = require('./lib/settings');
|
|
38
15
|
|
|
39
16
|
const Plugin = {};
|
|
40
17
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (typeof
|
|
47
|
-
return [];
|
|
18
|
+
/**
|
|
19
|
+
* Convert masked markdown links: [text](url) -> url
|
|
20
|
+
* Discord will auto-linkify URLs.
|
|
21
|
+
*/
|
|
22
|
+
function simplifyMaskedLinks(str) {
|
|
23
|
+
if (!str || typeof str !== 'string') return str;
|
|
24
|
+
return str.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$2');
|
|
48
25
|
}
|
|
49
26
|
|
|
50
27
|
function normalizeBaseUrl(url) {
|
|
51
28
|
if (!url) return '';
|
|
52
29
|
let s = String(url).trim();
|
|
53
30
|
if (!/^https?:\/\//i.test(s)) s = `https://${s}`;
|
|
54
|
-
|
|
55
|
-
return s;
|
|
31
|
+
return s.replace(/\/+$/, '');
|
|
56
32
|
}
|
|
57
33
|
|
|
58
34
|
function ensureAbsoluteUrl(baseUrl, maybeUrl) {
|
|
@@ -64,27 +40,17 @@ function ensureAbsoluteUrl(baseUrl, maybeUrl) {
|
|
|
64
40
|
return s;
|
|
65
41
|
}
|
|
66
42
|
|
|
67
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Unified HTML stripping + entity decoding in a single pass.
|
|
45
|
+
*/
|
|
46
|
+
function cleanText(html) {
|
|
68
47
|
if (!html) return '';
|
|
69
|
-
|
|
48
|
+
let s = String(html)
|
|
70
49
|
.replace(/<br\s*\/?>/gi, '\n')
|
|
71
50
|
.replace(/<\/p>/gi, '\n')
|
|
72
|
-
.replace(/<[^>]*>/g, '')
|
|
73
|
-
.replace(/ /g, ' ')
|
|
74
|
-
.replace(/&/g, '&')
|
|
75
|
-
.replace(/</g, '<')
|
|
76
|
-
.replace(/>/g, '>')
|
|
77
|
-
.replace(/'/g, "'")
|
|
78
|
-
.replace(/"/g, '"')
|
|
79
|
-
.trim();
|
|
80
|
-
}
|
|
51
|
+
.replace(/<[^>]*>/g, '');
|
|
81
52
|
|
|
82
|
-
|
|
83
|
-
function decodeHtmlEntities(input) {
|
|
84
|
-
if (!input) return '';
|
|
85
|
-
let s = String(input);
|
|
86
|
-
|
|
87
|
-
// Named entities commonly encountered
|
|
53
|
+
// Named entities
|
|
88
54
|
s = s
|
|
89
55
|
.replace(/ /g, ' ')
|
|
90
56
|
.replace(/&/g, '&')
|
|
@@ -96,18 +62,16 @@ function decodeHtmlEntities(input) {
|
|
|
96
62
|
// Decimal numeric entities
|
|
97
63
|
s = s.replace(/&#(\d+);/g, (m, dec) => {
|
|
98
64
|
const code = parseInt(dec, 10);
|
|
99
|
-
|
|
100
|
-
return String.fromCodePoint(code);
|
|
65
|
+
return Number.isFinite(code) ? String.fromCodePoint(code) : m;
|
|
101
66
|
});
|
|
102
67
|
|
|
103
68
|
// Hex numeric entities
|
|
104
69
|
s = s.replace(/&#x([0-9a-fA-F]+);/g, (m, hex) => {
|
|
105
70
|
const code = parseInt(hex, 16);
|
|
106
|
-
|
|
107
|
-
return String.fromCodePoint(code);
|
|
71
|
+
return Number.isFinite(code) ? String.fromCodePoint(code) : m;
|
|
108
72
|
});
|
|
109
73
|
|
|
110
|
-
return s;
|
|
74
|
+
return s.trim();
|
|
111
75
|
}
|
|
112
76
|
|
|
113
77
|
function truncate(s, n) {
|
|
@@ -116,15 +80,6 @@ function truncate(s, n) {
|
|
|
116
80
|
return str.slice(0, n - 1) + '…';
|
|
117
81
|
}
|
|
118
82
|
|
|
119
|
-
async function getSettings() {
|
|
120
|
-
const s = await meta.settings.get(SETTINGS_KEY);
|
|
121
|
-
return {
|
|
122
|
-
webhookUrl: (s && s.webhookUrl) ? String(s.webhookUrl).trim() : '',
|
|
123
|
-
notifyReplies: !!(s && (s.notifyReplies === true || s.notifyReplies === 'on' || s.notifyReplies === 'true')),
|
|
124
|
-
cids: normalizeCids(s && s.cids),
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
83
|
function cidAllowed(topicCid, allowedCids) {
|
|
129
84
|
if (!allowedCids || allowedCids.length === 0) return true;
|
|
130
85
|
return allowedCids.includes(String(topicCid));
|
|
@@ -152,58 +107,51 @@ async function sendDiscord(webhookUrl, payload) {
|
|
|
152
107
|
try {
|
|
153
108
|
await postToDiscord(webhookUrl, payload);
|
|
154
109
|
} catch (e) {
|
|
155
|
-
//
|
|
156
|
-
if (e
|
|
157
|
-
const fallback = payload.embeds[0]
|
|
110
|
+
// Fallback to plain content if embeds rejected
|
|
111
|
+
if (e?.statusCode === 400 && payload?.embeds) {
|
|
112
|
+
const fallback = payload.embeds[0]?.description || 'Notification';
|
|
158
113
|
try { await postToDiscord(webhookUrl, { content: fallback }); return; } catch (e2) { console.error(e2); }
|
|
159
114
|
}
|
|
160
115
|
console.error(e);
|
|
161
116
|
}
|
|
162
117
|
}
|
|
163
118
|
|
|
164
|
-
async function getPostExcerpt(pid) {
|
|
165
|
-
if (!pid) return '';
|
|
166
|
-
try {
|
|
167
|
-
const p = await posts.getPostFields(pid, ['content']);
|
|
168
|
-
const text = stripHtml(p && p.content);
|
|
169
|
-
return truncate(text, 500);
|
|
170
|
-
} catch {
|
|
171
|
-
return '';
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
119
|
async function buildEmbed({ tid, pid, isReply }) {
|
|
176
|
-
let baseUrl = normalizeBaseUrl(meta.config.url
|
|
120
|
+
let baseUrl = normalizeBaseUrl(meta.config.url);
|
|
177
121
|
if (!baseUrl) baseUrl = 'https://www.onekite.com';
|
|
178
122
|
|
|
179
123
|
const topicData = await topics.getTopicFields(tid, ['tid', 'cid', 'title', 'slug', 'mainPid']);
|
|
180
124
|
if (!topicData) return null;
|
|
181
125
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
126
|
+
const targetPid = isReply ? pid : topicData.mainPid;
|
|
127
|
+
|
|
128
|
+
// Parallel fetch: category + post data
|
|
129
|
+
const [cat, postData] = await Promise.all([
|
|
130
|
+
categories.getCategoryData(topicData.cid).catch(() => null),
|
|
131
|
+
posts.getPostFields(targetPid, ['uid', 'content']),
|
|
132
|
+
]);
|
|
133
|
+
|
|
134
|
+
const categoryName = cat?.name ? cleanText(cat.name) : '';
|
|
135
|
+
const excerpt = truncate(cleanText(postData?.content), 500);
|
|
136
|
+
const username = await user.getUserField(postData.uid, 'username');
|
|
187
137
|
|
|
188
138
|
const topicUrl = ensureAbsoluteUrl(baseUrl, `/topic/${topicData.slug || topicData.tid}`);
|
|
189
139
|
const targetUrl = (isReply && pid) ? `${topicUrl}/${pid}` : topicUrl;
|
|
190
140
|
|
|
191
|
-
const baseTitle =
|
|
141
|
+
const baseTitle = cleanText((topicData.title || (isReply ? 'Nouvelle réponse' : 'Nouveau sujet')).toString());
|
|
192
142
|
const titleWithCategory = categoryName ? `[${categoryName}] ${baseTitle}` : baseTitle;
|
|
193
143
|
const replyIcon = isReply ? '↪️ ' : '';
|
|
144
|
+
const embedTitle = `${replyIcon}${titleWithCategory} – ${username}`.slice(0, 256);
|
|
194
145
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
// Embed title becomes clickable via embed.url
|
|
206
|
-
return { topicData, content: '', embed: { title: embedTitle, url: targetUrl, description: simplifyMaskedLinks(excerpt || '') } };
|
|
146
|
+
return {
|
|
147
|
+
topicData,
|
|
148
|
+
content: '',
|
|
149
|
+
embed: {
|
|
150
|
+
title: embedTitle,
|
|
151
|
+
url: targetUrl,
|
|
152
|
+
description: simplifyMaskedLinks(excerpt || ''),
|
|
153
|
+
},
|
|
154
|
+
};
|
|
207
155
|
}
|
|
208
156
|
|
|
209
157
|
function extractTidPid(data) {
|
|
@@ -218,14 +166,12 @@ Plugin.init = async function (params) {
|
|
|
218
166
|
// ACP page
|
|
219
167
|
routeHelpers.setupAdminPageRoute(router, '/admin/plugins/discord-onekite', [], controllers.renderAdminPage);
|
|
220
168
|
|
|
221
|
-
// Admin API v3 routes
|
|
222
|
-
const
|
|
169
|
+
// Admin API v3 routes
|
|
170
|
+
const adminBase = '/api/v3/admin/plugins/discord-onekite';
|
|
223
171
|
const adminMws = [middleware.admin.checkPrivileges];
|
|
224
172
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
router.put(`${base}/settings`, ...adminMws, adminApi.saveSettings);
|
|
228
|
-
});
|
|
173
|
+
router.get(`${adminBase}/settings`, ...adminMws, adminApi.getSettings);
|
|
174
|
+
router.put(`${adminBase}/settings`, ...adminMws, adminApi.saveSettings);
|
|
229
175
|
};
|
|
230
176
|
|
|
231
177
|
Plugin.addAdminNavigation = (header) => {
|
|
@@ -253,8 +199,7 @@ Plugin.onTopicPost = async (data) => {
|
|
|
253
199
|
|
|
254
200
|
Plugin.onTopicReply = async (data) => {
|
|
255
201
|
const settings = await getSettings();
|
|
256
|
-
if (!settings.notifyReplies) return;
|
|
257
|
-
if (!settings.webhookUrl) return;
|
|
202
|
+
if (!settings.notifyReplies || !settings.webhookUrl) return;
|
|
258
203
|
|
|
259
204
|
const { tid, pid } = extractTidPid(data);
|
|
260
205
|
if (!tid || !pid) return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodebb-plugin-onekite-discord",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.17",
|
|
4
4
|
"description": "Discord webhook notifier for Onekite (NodeBB v4.x only)",
|
|
5
5
|
"main": "library.js",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,4 +17,4 @@
|
|
|
17
17
|
"nbbpm": {
|
|
18
18
|
"compatibility": "^4.0.0"
|
|
19
19
|
}
|
|
20
|
-
}
|
|
20
|
+
}
|
package/plugin.json
CHANGED
package/public/admin.js
CHANGED
|
@@ -2,8 +2,7 @@ define('admin/plugins/discord-onekite', ['alerts', 'bootbox'], function (alerts)
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
function showAlert(type, msg) {
|
|
5
|
-
// Deduplicate identical alerts
|
|
6
|
-
// by NodeBB ACP save buttons/hooks across ajaxify navigations.
|
|
5
|
+
// Deduplicate identical alerts across ajaxify navigations
|
|
7
6
|
try {
|
|
8
7
|
const now = Date.now();
|
|
9
8
|
const last = window.oneKiteDiscordLastAlert;
|
|
@@ -21,24 +20,30 @@ define('admin/plugins/discord-onekite', ['alerts', 'bootbox'], function (alerts)
|
|
|
21
20
|
alert(msg);
|
|
22
21
|
}
|
|
23
22
|
|
|
23
|
+
function getCsrfToken() {
|
|
24
|
+
return document.querySelector('meta[name="csrf_token"]')?.getAttribute('content')
|
|
25
|
+
|| document.querySelector('meta[name="csrf-token"]')?.getAttribute('content')
|
|
26
|
+
|| (typeof app !== 'undefined' && app?.csrfToken)
|
|
27
|
+
|| '';
|
|
28
|
+
}
|
|
29
|
+
|
|
24
30
|
async function fetchJson(url, opts) {
|
|
25
|
-
const res = await fetch(url,
|
|
26
|
-
headers:
|
|
31
|
+
const res = await fetch(url, {
|
|
32
|
+
headers: {
|
|
27
33
|
'Content-Type': 'application/json',
|
|
28
|
-
'x-csrf-token': (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
'',
|
|
32
|
-
}, (opts && opts.headers) || {}),
|
|
34
|
+
'x-csrf-token': getCsrfToken(),
|
|
35
|
+
...((opts && opts.headers) || {}),
|
|
36
|
+
},
|
|
33
37
|
credentials: 'same-origin',
|
|
34
|
-
|
|
38
|
+
...opts,
|
|
39
|
+
});
|
|
35
40
|
|
|
36
41
|
const text = await res.text();
|
|
37
42
|
let data = null;
|
|
38
43
|
try { data = text ? JSON.parse(text) : null; } catch (e) {}
|
|
39
44
|
|
|
40
45
|
if (!res.ok) {
|
|
41
|
-
const err = new Error(
|
|
46
|
+
const err = new Error(data?.status?.message || text || 'Request failed');
|
|
42
47
|
err.status = res.status;
|
|
43
48
|
err.data = data;
|
|
44
49
|
throw err;
|
|
@@ -48,7 +53,7 @@ define('admin/plugins/discord-onekite', ['alerts', 'bootbox'], function (alerts)
|
|
|
48
53
|
|
|
49
54
|
async function loadSettings() {
|
|
50
55
|
const data = await fetchJson('/api/v3/admin/plugins/discord-onekite/settings');
|
|
51
|
-
return
|
|
56
|
+
return data?.settings || {};
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
async function saveSettings(payload) {
|
|
@@ -82,9 +87,8 @@ define('admin/plugins/discord-onekite', ['alerts', 'bootbox'], function (alerts)
|
|
|
82
87
|
await saveSettings(getPayload());
|
|
83
88
|
showAlert('success', 'Paramètres enregistrés');
|
|
84
89
|
} catch (e) {
|
|
85
|
-
// eslint-disable-next-line no-console
|
|
86
90
|
console.error(e);
|
|
87
|
-
showAlert('error', e
|
|
91
|
+
showAlert('error', e?.message || 'Erreur lors de l\u2019enregistrement');
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
94
|
|
|
@@ -94,7 +98,7 @@ define('admin/plugins/discord-onekite', ['alerts', 'bootbox'], function (alerts)
|
|
|
94
98
|
window.oneKiteDiscordAdminBound = true;
|
|
95
99
|
|
|
96
100
|
document.addEventListener('click', function (ev) {
|
|
97
|
-
const target = ev.target
|
|
101
|
+
const target = ev.target?.closest?.(SAVE_SELECTOR);
|
|
98
102
|
if (!target) return;
|
|
99
103
|
ev.preventDefault();
|
|
100
104
|
doSave();
|
|
@@ -109,7 +113,6 @@ define('admin/plugins/discord-onekite', ['alerts', 'bootbox'], function (alerts)
|
|
|
109
113
|
if (typeof s.notifyReplies !== 'undefined') document.getElementById('notifyReplies').checked = !!s.notifyReplies;
|
|
110
114
|
if (Array.isArray(s.cids)) setSelectedCids(s.cids);
|
|
111
115
|
} catch (e) {
|
|
112
|
-
// eslint-disable-next-line no-console
|
|
113
116
|
console.error(e);
|
|
114
117
|
}
|
|
115
118
|
}
|