blockmine 1.18.4 → 1.19.0
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/CHANGELOG.md +144 -117
- package/backend/cli.js +59 -57
- package/backend/prisma/migrations/20250701190321_add/migration.sql +2 -2
- package/backend/prisma/migrations/20250709150611_add_run_on_startup_to_tasks/migration.sql +21 -21
- package/backend/prisma/migrations/20250709151124_make_cron_pattern_optional/migration.sql +21 -21
- package/backend/prisma/migrations/20250718181335_add_plugin_data_store/migration.sql +14 -14
- package/backend/prisma/migrations/20250719115906_add_plugin_owner_to_graphs/migration.sql +45 -45
- package/backend/prisma/migrations/20250723160648_add_bot_sort_order/migration.sql +2 -2
- package/backend/prisma/migrations/20250816083216_add_panel_user_bot_access/migration.sql +30 -0
- package/backend/prisma/migrations/migration_lock.toml +2 -2
- package/backend/prisma/schema.prisma +244 -229
- package/backend/src/api/middleware/botAccess.js +35 -0
- package/backend/src/api/routes/auth.js +633 -595
- package/backend/src/api/routes/bots.js +251 -127
- package/backend/src/api/routes/eventGraphs.js +459 -459
- package/backend/src/api/routes/servers.js +27 -0
- package/backend/src/core/GraphExecutionEngine.js +917 -917
- package/backend/src/core/PluginLoader.js +208 -86
- package/backend/src/core/PluginManager.js +465 -427
- package/backend/src/core/commands/dev.js +6 -1
- package/backend/src/real-time/presence.js +74 -0
- package/backend/src/real-time/socketHandler.js +2 -0
- package/backend/src/server.js +193 -186
- package/frontend/dist/assets/index-5m_JZxJ-.js +8352 -0
- package/frontend/dist/assets/index-BFd7YoAj.css +1 -0
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
- package/frontend/dist/assets/index-CA3XrPPP.css +0 -1
- package/frontend/dist/assets/index-CM9ljR30.js +0 -8352
|
@@ -13,6 +13,7 @@ const { randomUUID } = require('crypto');
|
|
|
13
13
|
const eventGraphsRouter = require('./eventGraphs');
|
|
14
14
|
const pluginIdeRouter = require('./pluginIde');
|
|
15
15
|
const { deepMergeSettings } = require('../../core/utils/settingsMerger');
|
|
16
|
+
const { checkBotAccess } = require('../middleware/botAccess');
|
|
16
17
|
|
|
17
18
|
const multer = require('multer');
|
|
18
19
|
const archiver = require('archiver');
|
|
@@ -23,6 +24,8 @@ const upload = multer({ storage: multer.memoryStorage() });
|
|
|
23
24
|
|
|
24
25
|
const router = express.Router();
|
|
25
26
|
|
|
27
|
+
router.use('/:botId(\\d+)/*', authenticate, (req, res, next) => checkBotAccess(req, res, next));
|
|
28
|
+
|
|
26
29
|
const conditionalRestartAuth = (req, res, next) => {
|
|
27
30
|
if (process.env.DEBUG === 'true' || process.env.NODE_ENV === 'development') {
|
|
28
31
|
console.log('[Debug] Роут перезапуска бота доступен без проверки прав');
|
|
@@ -60,18 +63,16 @@ const conditionalStartStopAuth = (req, res, next) => {
|
|
|
60
63
|
};
|
|
61
64
|
|
|
62
65
|
const conditionalListAuth = (req, res, next) => {
|
|
63
|
-
if (process.env.DEBUG === 'true' || process.env.NODE_ENV === 'development') {
|
|
64
|
-
console.log('[Debug] Роут списка ботов/состояния доступен без проверки прав');
|
|
65
|
-
return next();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
66
|
return authenticate(req, res, (err) => {
|
|
69
67
|
if (err) return next(err);
|
|
68
|
+
if (process.env.DEBUG === 'true' || process.env.NODE_ENV === 'development') {
|
|
69
|
+
return next();
|
|
70
|
+
}
|
|
70
71
|
return authorize('bot:list')(req, res, next);
|
|
71
72
|
});
|
|
72
73
|
};
|
|
73
74
|
|
|
74
|
-
router.post('/:id/restart', conditionalRestartAuth, async (req, res) => {
|
|
75
|
+
router.post('/:id/restart', conditionalRestartAuth, authenticate, checkBotAccess, async (req, res) => {
|
|
75
76
|
try {
|
|
76
77
|
const botId = parseInt(req.params.id, 10);
|
|
77
78
|
botManager.stopBot(botId);
|
|
@@ -89,7 +90,7 @@ router.post('/:id/restart', conditionalRestartAuth, async (req, res) => {
|
|
|
89
90
|
}
|
|
90
91
|
});
|
|
91
92
|
|
|
92
|
-
router.post('/:id/chat', conditionalChatAuth, (req, res) => {
|
|
93
|
+
router.post('/:id/chat', conditionalChatAuth, authenticate, checkBotAccess, (req, res) => {
|
|
93
94
|
try {
|
|
94
95
|
const botId = parseInt(req.params.id, 10);
|
|
95
96
|
const { message } = req.body;
|
|
@@ -100,7 +101,7 @@ router.post('/:id/chat', conditionalChatAuth, (req, res) => {
|
|
|
100
101
|
} catch (error) { res.status(500).json({ error: 'Внутренняя ошибка сервера: ' + error.message }); }
|
|
101
102
|
});
|
|
102
103
|
|
|
103
|
-
router.post('/:id/start', conditionalStartStopAuth, async (req, res) => {
|
|
104
|
+
router.post('/:id/start', conditionalStartStopAuth, authenticate, checkBotAccess, async (req, res) => {
|
|
104
105
|
try {
|
|
105
106
|
const botId = parseInt(req.params.id, 10);
|
|
106
107
|
const botConfig = await prisma.bot.findUnique({ where: { id: botId }, include: { server: true } });
|
|
@@ -115,7 +116,7 @@ router.post('/:id/start', conditionalStartStopAuth, async (req, res) => {
|
|
|
115
116
|
}
|
|
116
117
|
});
|
|
117
118
|
|
|
118
|
-
router.post('/:id/stop', conditionalStartStopAuth, (req, res) => {
|
|
119
|
+
router.post('/:id/stop', conditionalStartStopAuth, authenticate, checkBotAccess, (req, res) => {
|
|
119
120
|
try {
|
|
120
121
|
const botId = parseInt(req.params.id, 10);
|
|
121
122
|
botManager.stopBot(botId);
|
|
@@ -142,8 +143,21 @@ router.get('/', conditionalListAuth, async (req, res) => {
|
|
|
142
143
|
});
|
|
143
144
|
}
|
|
144
145
|
}
|
|
146
|
+
|
|
147
|
+
let whereFilter = {};
|
|
148
|
+
if (req.user && typeof req.user.userId === 'number') {
|
|
149
|
+
const panelUser = await prisma.panelUser.findUnique({
|
|
150
|
+
where: { id: req.user.userId },
|
|
151
|
+
include: { botAccess: { select: { botId: true } } }
|
|
152
|
+
});
|
|
153
|
+
if (panelUser && panelUser.allBots === false) {
|
|
154
|
+
const allowedIds = panelUser.botAccess.map(a => a.botId);
|
|
155
|
+
whereFilter = { id: { in: allowedIds.length ? allowedIds : [-1] } };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
145
158
|
|
|
146
159
|
const bots = await prisma.bot.findMany({
|
|
160
|
+
where: whereFilter,
|
|
147
161
|
include: { server: true },
|
|
148
162
|
orderBy: { sortOrder: 'asc' }
|
|
149
163
|
});
|
|
@@ -161,7 +175,119 @@ router.get('/state', conditionalListAuth, (req, res) => {
|
|
|
161
175
|
} catch (error) { res.status(500).json({ error: 'Не удалось получить состояние ботов' }); }
|
|
162
176
|
});
|
|
163
177
|
|
|
164
|
-
router.
|
|
178
|
+
router.put('/bulk-proxy-update', authenticate, authorize('bot:update'), async (req, res) => {
|
|
179
|
+
try {
|
|
180
|
+
const { botIds, proxySettings } = req.body;
|
|
181
|
+
|
|
182
|
+
if (!Array.isArray(botIds) || botIds.length === 0) {
|
|
183
|
+
return res.status(400).json({ error: 'Bot IDs array is required and cannot be empty' });
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (!proxySettings || !proxySettings.proxyHost || !proxySettings.proxyPort) {
|
|
187
|
+
return res.status(400).json({ error: 'Proxy host and port are required' });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (proxySettings.proxyPort < 1 || proxySettings.proxyPort > 65535) {
|
|
191
|
+
return res.status(400).json({ error: 'Proxy port must be between 1 and 65535' });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const accessibleBots = [];
|
|
195
|
+
const inaccessibleBots = [];
|
|
196
|
+
|
|
197
|
+
for (const botId of botIds) {
|
|
198
|
+
try {
|
|
199
|
+
const userId = req.user?.userId;
|
|
200
|
+
if (!userId) {
|
|
201
|
+
inaccessibleBots.push(botId);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const botIdInt = parseInt(botId, 10);
|
|
206
|
+
if (isNaN(botIdInt)) {
|
|
207
|
+
inaccessibleBots.push(botId);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const user = await prisma.panelUser.findUnique({
|
|
212
|
+
where: { id: userId },
|
|
213
|
+
include: { botAccess: { select: { botId: true } } }
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
if (!user) {
|
|
217
|
+
inaccessibleBots.push(botId);
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (user.allBots !== false || user.botAccess.some((a) => a.botId === botIdInt)) {
|
|
222
|
+
accessibleBots.push(botIdInt);
|
|
223
|
+
} else {
|
|
224
|
+
inaccessibleBots.push(botId);
|
|
225
|
+
}
|
|
226
|
+
} catch (error) {
|
|
227
|
+
console.error(`Error checking access for bot ${botId}:`, error);
|
|
228
|
+
inaccessibleBots.push(botId);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (accessibleBots.length === 0) {
|
|
233
|
+
return res.status(403).json({ error: 'No accessible bots in the provided list' });
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const encryptedSettings = {
|
|
237
|
+
proxyHost: proxySettings.proxyHost.trim(),
|
|
238
|
+
proxyPort: parseInt(proxySettings.proxyPort),
|
|
239
|
+
proxyUsername: proxySettings.proxyUsername ? encrypt(proxySettings.proxyUsername.trim()) : null,
|
|
240
|
+
proxyPassword: proxySettings.proxyPassword ? encrypt(proxySettings.proxyPassword) : null
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const updatedBots = await prisma.$transaction(
|
|
244
|
+
accessibleBots.map(botId =>
|
|
245
|
+
prisma.bot.update({
|
|
246
|
+
where: { id: parseInt(botId) },
|
|
247
|
+
data: encryptedSettings,
|
|
248
|
+
include: {
|
|
249
|
+
server: {
|
|
250
|
+
select: {
|
|
251
|
+
id: true,
|
|
252
|
+
name: true,
|
|
253
|
+
host: true,
|
|
254
|
+
port: true,
|
|
255
|
+
version: true
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
)
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
if (req.io) {
|
|
264
|
+
req.io.emit('bots-updated', updatedBots);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
res.json({
|
|
268
|
+
success: true,
|
|
269
|
+
message: `Proxy settings updated for ${updatedBots.length} bot(s)`,
|
|
270
|
+
updatedBots: updatedBots.map(bot => ({
|
|
271
|
+
id: bot.id,
|
|
272
|
+
username: bot.username,
|
|
273
|
+
proxyHost: bot.proxyHost,
|
|
274
|
+
proxyPort: bot.proxyPort,
|
|
275
|
+
server: bot.server
|
|
276
|
+
})),
|
|
277
|
+
inaccessibleBots: inaccessibleBots,
|
|
278
|
+
errors: inaccessibleBots.length > 0 ? [`Access denied to ${inaccessibleBots.length} bot(s)`] : []
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
} catch (error) {
|
|
282
|
+
console.error('Bulk proxy update error:', error);
|
|
283
|
+
res.status(500).json({
|
|
284
|
+
error: 'Failed to update proxy settings',
|
|
285
|
+
details: error.message
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
router.get('/:id/logs', conditionalListAuth, authenticate, checkBotAccess, (req, res) => {
|
|
165
291
|
try {
|
|
166
292
|
const botId = parseInt(req.params.id, 10);
|
|
167
293
|
const { limit = 50, offset = 0 } = req.query;
|
|
@@ -264,7 +390,7 @@ router.post('/', authorize('bot:create'), async (req, res) => {
|
|
|
264
390
|
}
|
|
265
391
|
});
|
|
266
392
|
|
|
267
|
-
router.put('/:id', authorize('bot:update'), async (req, res) => {
|
|
393
|
+
router.put('/:id', authenticate, checkBotAccess, authorize('bot:update'), async (req, res) => {
|
|
268
394
|
try {
|
|
269
395
|
const {
|
|
270
396
|
username, password, prefix, serverId, note, owners,
|
|
@@ -337,7 +463,7 @@ router.put('/:id', authorize('bot:update'), async (req, res) => {
|
|
|
337
463
|
}
|
|
338
464
|
});
|
|
339
465
|
|
|
340
|
-
router.put('/:id/sort-order', authorize('bot:update'), async (req, res) => {
|
|
466
|
+
router.put('/:id/sort-order', authenticate, checkBotAccess, authorize('bot:update'), async (req, res) => {
|
|
341
467
|
try {
|
|
342
468
|
const { newPosition } = req.body;
|
|
343
469
|
const botId = parseInt(req.params.id, 10);
|
|
@@ -414,7 +540,7 @@ router.put('/:id/sort-order', authorize('bot:update'), async (req, res) => {
|
|
|
414
540
|
}
|
|
415
541
|
});
|
|
416
542
|
|
|
417
|
-
router.delete('/:id', authorize('bot:delete'), async (req, res) => {
|
|
543
|
+
router.delete('/:id', authenticate, checkBotAccess, authorize('bot:delete'), async (req, res) => {
|
|
418
544
|
try {
|
|
419
545
|
const botId = parseInt(req.params.id, 10);
|
|
420
546
|
if (botManager.bots.has(botId)) return res.status(400).json({ error: 'Нельзя удалить запущенного бота' });
|
|
@@ -433,7 +559,7 @@ router.get('/servers', authorize('bot:list'), async (req, res) => {
|
|
|
433
559
|
}
|
|
434
560
|
});
|
|
435
561
|
|
|
436
|
-
router.get('/:botId/plugins', authorize('plugin:list'), async (req, res) => {
|
|
562
|
+
router.get('/:botId/plugins', authenticate, checkBotAccess, authorize('plugin:list'), async (req, res) => {
|
|
437
563
|
try {
|
|
438
564
|
const botId = parseInt(req.params.botId);
|
|
439
565
|
const plugins = await prisma.installedPlugin.findMany({ where: { botId } });
|
|
@@ -441,7 +567,7 @@ router.get('/:botId/plugins', authorize('plugin:list'), async (req, res) => {
|
|
|
441
567
|
} catch (error) { res.status(500).json({ error: 'Не удалось получить плагины бота' }); }
|
|
442
568
|
});
|
|
443
569
|
|
|
444
|
-
router.post('/:botId/plugins/install/github', authorize('plugin:install'), async (req, res) => {
|
|
570
|
+
router.post('/:botId/plugins/install/github', authenticate, checkBotAccess, authorize('plugin:install'), async (req, res) => {
|
|
445
571
|
const { botId } = req.params;
|
|
446
572
|
const { repoUrl } = req.body;
|
|
447
573
|
try {
|
|
@@ -452,7 +578,7 @@ router.post('/:botId/plugins/install/github', authorize('plugin:install'), async
|
|
|
452
578
|
}
|
|
453
579
|
});
|
|
454
580
|
|
|
455
|
-
router.post('/:botId/plugins/install/local', authorize('plugin:install'), async (req, res) => {
|
|
581
|
+
router.post('/:botId/plugins/install/local', authenticate, checkBotAccess, authorize('plugin:install'), async (req, res) => {
|
|
456
582
|
const { botId } = req.params;
|
|
457
583
|
const { path } = req.body;
|
|
458
584
|
try {
|
|
@@ -463,7 +589,7 @@ router.post('/:botId/plugins/install/local', authorize('plugin:install'), async
|
|
|
463
589
|
}
|
|
464
590
|
});
|
|
465
591
|
|
|
466
|
-
router.delete('/:botId/plugins/:pluginId', authorize('plugin:delete'), async (req, res) => {
|
|
592
|
+
router.delete('/:botId/plugins/:pluginId', authenticate, checkBotAccess, authorize('plugin:delete'), async (req, res) => {
|
|
467
593
|
const { pluginId } = req.params;
|
|
468
594
|
try {
|
|
469
595
|
await pluginManager.deletePlugin(parseInt(pluginId));
|
|
@@ -473,7 +599,7 @@ router.delete('/:botId/plugins/:pluginId', authorize('plugin:delete'), async (re
|
|
|
473
599
|
}
|
|
474
600
|
});
|
|
475
601
|
|
|
476
|
-
router.get('/:botId/plugins/:pluginId/settings', authorize('plugin:settings:view'), async (req, res) => {
|
|
602
|
+
router.get('/:botId/plugins/:pluginId/settings', authenticate, checkBotAccess, authorize('plugin:settings:view'), async (req, res) => {
|
|
477
603
|
try {
|
|
478
604
|
const pluginId = parseInt(req.params.pluginId);
|
|
479
605
|
const plugin = await prisma.installedPlugin.findUnique({ where: { id: pluginId } });
|
|
@@ -531,120 +657,107 @@ router.get('/:botId/plugins/:pluginId/settings', authorize('plugin:settings:view
|
|
|
531
657
|
}
|
|
532
658
|
});
|
|
533
659
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
if (!plugin) return res.status(404).json({ error: 'Установленный плагин не найден' });
|
|
540
|
-
|
|
541
|
-
const rows = await prisma.pluginDataStore.findMany({
|
|
542
|
-
where: { botId: plugin.botId, pluginName: plugin.name },
|
|
543
|
-
orderBy: { updatedAt: 'desc' }
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
const result = rows.map(r => {
|
|
547
|
-
let value;
|
|
548
|
-
try { value = JSON.parse(r.value); } catch { value = r.value; }
|
|
549
|
-
return { key: r.key, value, createdAt: r.createdAt, updatedAt: r.updatedAt };
|
|
550
|
-
});
|
|
551
|
-
res.json(result);
|
|
552
|
-
} catch (error) {
|
|
553
|
-
console.error('[API Error] GET plugin data:', error);
|
|
554
|
-
res.status(500).json({ error: 'Не удалось получить данные плагина' });
|
|
555
|
-
}
|
|
556
|
-
});
|
|
660
|
+
router.get('/:botId/plugins/:pluginId/data', authenticate, checkBotAccess, authorize('plugin:settings:view'), async (req, res) => {
|
|
661
|
+
try {
|
|
662
|
+
const pluginId = parseInt(req.params.pluginId);
|
|
663
|
+
const plugin = await prisma.installedPlugin.findUnique({ where: { id: pluginId } });
|
|
664
|
+
if (!plugin) return res.status(404).json({ error: 'Установленный плагин не найден' });
|
|
557
665
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
const plugin = await prisma.installedPlugin.findUnique({ where: { id: pluginId } });
|
|
563
|
-
if (!plugin) return res.status(404).json({ error: 'Установленный плагин не найден' });
|
|
666
|
+
const rows = await prisma.pluginDataStore.findMany({
|
|
667
|
+
where: { botId: plugin.botId, pluginName: plugin.name },
|
|
668
|
+
orderBy: { updatedAt: 'desc' }
|
|
669
|
+
});
|
|
564
670
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
}
|
|
573
|
-
});
|
|
574
|
-
if (!row) return res.status(404).json({ error: 'Ключ не найден' });
|
|
575
|
-
let value; try { value = JSON.parse(row.value); } catch { value = row.value; }
|
|
576
|
-
res.json({ key: row.key, value, createdAt: row.createdAt, updatedAt: row.updatedAt });
|
|
577
|
-
} catch (error) {
|
|
578
|
-
console.error('[API Error] GET plugin data by key:', error);
|
|
579
|
-
res.status(500).json({ error: 'Не удалось получить значение по ключу' });
|
|
580
|
-
}
|
|
671
|
+
const result = rows.map(r => {
|
|
672
|
+
let value;
|
|
673
|
+
try { value = JSON.parse(r.value); } catch { value = r.value; }
|
|
674
|
+
return { key: r.key, value, createdAt: r.createdAt, updatedAt: r.updatedAt };
|
|
675
|
+
});
|
|
676
|
+
res.json(result);
|
|
677
|
+
} catch (error) { res.status(500).json({ error: 'Не удалось получить данные плагина' }); }
|
|
581
678
|
});
|
|
582
679
|
|
|
583
|
-
router.
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
let parsed; try { parsed = JSON.parse(upserted.value); } catch { parsed = upserted.value; }
|
|
604
|
-
res.json({ key: upserted.key, value: parsed, createdAt: upserted.createdAt, updatedAt: upserted.updatedAt });
|
|
605
|
-
} catch (error) {
|
|
606
|
-
console.error('[API Error] PUT plugin data by key:', error);
|
|
607
|
-
res.status(500).json({ error: 'Не удалось сохранить значение' });
|
|
608
|
-
}
|
|
680
|
+
router.get('/:botId/plugins/:pluginId/data/:key', authenticate, checkBotAccess, authorize('plugin:settings:view'), async (req, res) => {
|
|
681
|
+
try {
|
|
682
|
+
const pluginId = parseInt(req.params.pluginId);
|
|
683
|
+
const { key } = req.params;
|
|
684
|
+
const plugin = await prisma.installedPlugin.findUnique({ where: { id: pluginId } });
|
|
685
|
+
if (!plugin) return res.status(404).json({ error: 'Установленный плагин не найден' });
|
|
686
|
+
|
|
687
|
+
const row = await prisma.pluginDataStore.findUnique({
|
|
688
|
+
where: {
|
|
689
|
+
pluginName_botId_key: {
|
|
690
|
+
pluginName: plugin.name,
|
|
691
|
+
botId: plugin.botId,
|
|
692
|
+
key
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
if (!row) return res.status(404).json({ error: 'Ключ не найден' });
|
|
697
|
+
let value; try { value = JSON.parse(row.value); } catch { value = row.value; }
|
|
698
|
+
res.json({ key: row.key, value, createdAt: row.createdAt, updatedAt: row.updatedAt });
|
|
699
|
+
} catch (error) { res.status(500).json({ error: 'Не удалось получить значение по ключу' }); }
|
|
609
700
|
});
|
|
610
701
|
|
|
611
|
-
router.
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
702
|
+
router.put('/:botId/plugins/:pluginId/data/:key', authenticate, checkBotAccess, authorize('plugin:settings:edit'), async (req, res) => {
|
|
703
|
+
try {
|
|
704
|
+
const pluginId = parseInt(req.params.pluginId);
|
|
705
|
+
const { key } = req.params;
|
|
706
|
+
const { value } = req.body;
|
|
707
|
+
const plugin = await prisma.installedPlugin.findUnique({ where: { id: pluginId } });
|
|
708
|
+
if (!plugin) return res.status(404).json({ error: 'Установленный плагин не найден' });
|
|
709
|
+
|
|
710
|
+
const jsonValue = JSON.stringify(value ?? null);
|
|
711
|
+
const upserted = await prisma.pluginDataStore.upsert({
|
|
712
|
+
where: {
|
|
713
|
+
pluginName_botId_key: {
|
|
714
|
+
pluginName: plugin.name,
|
|
715
|
+
botId: plugin.botId,
|
|
716
|
+
key
|
|
717
|
+
}
|
|
718
|
+
},
|
|
719
|
+
update: { value: jsonValue },
|
|
720
|
+
create: { pluginName: plugin.name, botId: plugin.botId, key, value: jsonValue }
|
|
721
|
+
});
|
|
722
|
+
let parsed; try { parsed = JSON.parse(upserted.value); } catch { parsed = upserted.value; }
|
|
723
|
+
res.json({ key: upserted.key, value: parsed, createdAt: upserted.createdAt, updatedAt: upserted.updatedAt });
|
|
724
|
+
} catch (error) { res.status(500).json({ error: 'Не удалось сохранить значение' }); }
|
|
725
|
+
});
|
|
617
726
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
727
|
+
router.delete('/:botId/plugins/:pluginId/data/:key', authenticate, checkBotAccess, authorize('plugin:settings:edit'), async (req, res) => {
|
|
728
|
+
try {
|
|
729
|
+
const pluginId = parseInt(req.params.pluginId);
|
|
730
|
+
const { key } = req.params;
|
|
731
|
+
const plugin = await prisma.installedPlugin.findUnique({ where: { id: pluginId } });
|
|
732
|
+
if (!plugin) return res.status(404).json({ error: 'Установленный плагин не найден' });
|
|
733
|
+
|
|
734
|
+
await prisma.pluginDataStore.delete({
|
|
735
|
+
where: {
|
|
736
|
+
pluginName_botId_key: {
|
|
737
|
+
pluginName: plugin.name,
|
|
738
|
+
botId: plugin.botId,
|
|
739
|
+
key
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
});
|
|
743
|
+
res.status(204).send();
|
|
744
|
+
} catch (error) { res.status(500).json({ error: 'Не удалось удалить значение' }); }
|
|
632
745
|
});
|
|
633
746
|
|
|
634
|
-
router.put('/:botId/plugins/:pluginId', authorize('plugin:settings:edit'), async (req, res) => {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
747
|
+
router.put('/:botId/plugins/:pluginId', authenticate, checkBotAccess, authorize('plugin:settings:edit'), async (req, res) => {
|
|
748
|
+
try {
|
|
749
|
+
const pluginId = parseInt(req.params.pluginId);
|
|
750
|
+
const { isEnabled, settings } = req.body;
|
|
751
|
+
const dataToUpdate = {};
|
|
752
|
+
if (typeof isEnabled === 'boolean') dataToUpdate.isEnabled = isEnabled;
|
|
753
|
+
if (settings) dataToUpdate.settings = JSON.stringify(settings);
|
|
754
|
+
if (Object.keys(dataToUpdate).length === 0) return res.status(400).json({ error: "Нет данных для обновления" });
|
|
755
|
+
const updated = await prisma.installedPlugin.update({ where: { id: pluginId }, data: dataToUpdate });
|
|
756
|
+
res.json(updated);
|
|
757
|
+
} catch (error) { res.status(500).json({ error: 'Не удалось обновить плагин' }); }
|
|
645
758
|
});
|
|
646
759
|
|
|
647
|
-
router.get('/:botId/management-data', authorize('management:view'), async (req, res) => {
|
|
760
|
+
router.get('/:botId/management-data', authenticate, checkBotAccess, authorize('management:view'), async (req, res) => {
|
|
648
761
|
try {
|
|
649
762
|
const botId = parseInt(req.params.botId, 10);
|
|
650
763
|
if (isNaN(botId)) return res.status(400).json({ error: 'Неверный ID бота' });
|
|
@@ -1007,7 +1120,7 @@ router.post('/stop-all', authorize('bot:start_stop'), (req, res) => {
|
|
|
1007
1120
|
}
|
|
1008
1121
|
});
|
|
1009
1122
|
|
|
1010
|
-
router.get('/:id/settings/all', authorize('bot:update'), async (req, res) => {
|
|
1123
|
+
router.get('/:id/settings/all', authenticate, checkBotAccess, authorize('bot:update'), async (req, res) => {
|
|
1011
1124
|
try {
|
|
1012
1125
|
const botId = parseInt(req.params.id, 10);
|
|
1013
1126
|
|
|
@@ -1086,7 +1199,7 @@ router.get('/:id/settings/all', authorize('bot:update'), async (req, res) => {
|
|
|
1086
1199
|
|
|
1087
1200
|
const nodeRegistry = require('../../core/NodeRegistry');
|
|
1088
1201
|
|
|
1089
|
-
router.get('/:botId/visual-editor/nodes', authorize('management:view'), (req, res) => {
|
|
1202
|
+
router.get('/:botId/visual-editor/nodes', authenticate, checkBotAccess, authorize('management:view'), (req, res) => {
|
|
1090
1203
|
try {
|
|
1091
1204
|
const { graphType } = req.query;
|
|
1092
1205
|
const nodesByCategory = nodeRegistry.getNodesByCategory(graphType);
|
|
@@ -1097,7 +1210,7 @@ router.get('/:botId/visual-editor/nodes', authorize('management:view'), (req, re
|
|
|
1097
1210
|
}
|
|
1098
1211
|
});
|
|
1099
1212
|
|
|
1100
|
-
router.get('/:botId/visual-editor/node-config', authorize('management:view'), (req, res) => {
|
|
1213
|
+
router.get('/:botId/visual-editor/node-config', authenticate, checkBotAccess, authorize('management:view'), (req, res) => {
|
|
1101
1214
|
try {
|
|
1102
1215
|
const { types } = req.query;
|
|
1103
1216
|
if (!types) {
|
|
@@ -1112,7 +1225,7 @@ router.get('/:botId/visual-editor/node-config', authorize('management:view'), (r
|
|
|
1112
1225
|
}
|
|
1113
1226
|
});
|
|
1114
1227
|
|
|
1115
|
-
router.get('/:botId/visual-editor/permissions', authorize('management:view'), async (req, res) => {
|
|
1228
|
+
router.get('/:botId/visual-editor/permissions', authenticate, checkBotAccess, authorize('management:view'), async (req, res) => {
|
|
1116
1229
|
try {
|
|
1117
1230
|
const botId = parseInt(req.params.botId, 10);
|
|
1118
1231
|
const permissions = await prisma.permission.findMany({
|
|
@@ -1733,7 +1846,7 @@ router.post('/:botId/plugins/:pluginName/action', authorize('plugin:list'), asyn
|
|
|
1733
1846
|
});
|
|
1734
1847
|
|
|
1735
1848
|
|
|
1736
|
-
router.get('/:botId/export', authorize('bot:export'), async (req, res) => {
|
|
1849
|
+
router.get('/:botId/export', authenticate, checkBotAccess, authorize('bot:export'), async (req, res) => {
|
|
1737
1850
|
try {
|
|
1738
1851
|
const botId = parseInt(req.params.botId, 10);
|
|
1739
1852
|
const {
|
|
@@ -1964,7 +2077,18 @@ router.post('/import', authorize('bot:create'), upload.single('file'), async (re
|
|
|
1964
2077
|
}
|
|
1965
2078
|
}
|
|
1966
2079
|
|
|
1967
|
-
|
|
2080
|
+
try {
|
|
2081
|
+
await pluginManager._installDependencies(newPluginPath);
|
|
2082
|
+
} catch (e) {
|
|
2083
|
+
console.warn(`[Import] Не удалось установить зависимости для плагина ${pluginName}: ${e.message}`);
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
let newPlugin;
|
|
2087
|
+
try {
|
|
2088
|
+
newPlugin = await pluginManager.registerPlugin(newBot.id, newPluginPath, 'LOCAL', newPluginPath);
|
|
2089
|
+
} catch (e) {
|
|
2090
|
+
newPlugin = await prisma.installedPlugin.create({ data: pluginData });
|
|
2091
|
+
}
|
|
1968
2092
|
pluginMap.set(oldPluginId, newPlugin.id);
|
|
1969
2093
|
}
|
|
1970
2094
|
}
|