blockmine 1.2.0 → 1.3.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.
Files changed (42) hide show
  1. package/backend/cli.js +17 -15
  2. package/backend/nodemon.json +1 -1
  3. package/backend/package-lock.json +2539 -2539
  4. package/backend/package.json +36 -33
  5. package/backend/prisma/generated/client/default.d.ts +1 -0
  6. package/backend/prisma/generated/client/default.js +1 -0
  7. package/backend/prisma/generated/client/edge.d.ts +1 -0
  8. package/backend/prisma/generated/client/edge.js +280 -0
  9. package/backend/prisma/generated/client/index-browser.js +272 -0
  10. package/backend/prisma/generated/client/index.d.ts +16892 -0
  11. package/backend/prisma/generated/client/index.js +301 -0
  12. package/backend/prisma/generated/client/package.json +97 -0
  13. package/backend/prisma/generated/client/query_engine-windows.dll.node +0 -0
  14. package/backend/prisma/generated/client/runtime/edge-esm.js +31 -0
  15. package/backend/prisma/generated/client/runtime/edge.js +31 -0
  16. package/backend/prisma/generated/client/runtime/index-browser.d.ts +365 -0
  17. package/backend/prisma/generated/client/runtime/index-browser.js +13 -0
  18. package/backend/prisma/generated/client/runtime/library.d.ts +3403 -0
  19. package/backend/prisma/generated/client/runtime/library.js +143 -0
  20. package/backend/prisma/generated/client/runtime/react-native.js +80 -0
  21. package/backend/prisma/generated/client/runtime/wasm.js +32 -0
  22. package/backend/prisma/generated/client/schema.prisma +148 -0
  23. package/backend/prisma/generated/client/wasm.d.ts +1 -0
  24. package/backend/prisma/generated/client/wasm.js +272 -0
  25. package/backend/prisma/migrations/20250615232848_add_scheduled_tasks/migration.sql +13 -0
  26. package/backend/prisma/schema.prisma +150 -137
  27. package/backend/src/api/routes/tasks.js +95 -0
  28. package/backend/src/core/BotManager.js +8 -0
  29. package/backend/src/core/PluginManager.js +63 -17
  30. package/backend/src/core/TaskScheduler.js +117 -0
  31. package/backend/src/real-time/socketHandler.js +30 -30
  32. package/backend/src/server.js +22 -20
  33. package/frontend/dist/assets/index-4S5VJ11r.js +8179 -0
  34. package/frontend/dist/assets/index-B5_cke-P.css +1 -0
  35. package/frontend/dist/favicon.svg +2 -2
  36. package/frontend/dist/index.html +20 -20
  37. package/frontend/dist/logo.svg +178 -178
  38. package/frontend/dist/site.webmanifest +20 -20
  39. package/frontend/package.json +66 -65
  40. package/package.json +38 -38
  41. package/frontend/dist/assets/index-8hxjI7oG.css +0 -1
  42. package/frontend/dist/assets/index-Brxc-96r.js +0 -8179
@@ -0,0 +1,272 @@
1
+
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+
4
+ const {
5
+ Decimal,
6
+ objectEnumValues,
7
+ makeStrictEnum,
8
+ Public,
9
+ getRuntime,
10
+ skip
11
+ } = require('./runtime/index-browser.js')
12
+
13
+
14
+ const Prisma = {}
15
+
16
+ exports.Prisma = Prisma
17
+ exports.$Enums = {}
18
+
19
+ /**
20
+ * Prisma Client JS version: 5.22.0
21
+ * Query Engine version: 605197351a3c8bdd595af2d2a9bc3025bca48ea2
22
+ */
23
+ Prisma.prismaVersion = {
24
+ client: "5.22.0",
25
+ engine: "605197351a3c8bdd595af2d2a9bc3025bca48ea2"
26
+ }
27
+
28
+ Prisma.PrismaClientKnownRequestError = () => {
29
+ const runtimeName = getRuntime().prettyName;
30
+ throw new Error(`PrismaClientKnownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
31
+ In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
32
+ )};
33
+ Prisma.PrismaClientUnknownRequestError = () => {
34
+ const runtimeName = getRuntime().prettyName;
35
+ throw new Error(`PrismaClientUnknownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
36
+ In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
37
+ )}
38
+ Prisma.PrismaClientRustPanicError = () => {
39
+ const runtimeName = getRuntime().prettyName;
40
+ throw new Error(`PrismaClientRustPanicError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
41
+ In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
42
+ )}
43
+ Prisma.PrismaClientInitializationError = () => {
44
+ const runtimeName = getRuntime().prettyName;
45
+ throw new Error(`PrismaClientInitializationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
46
+ In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
47
+ )}
48
+ Prisma.PrismaClientValidationError = () => {
49
+ const runtimeName = getRuntime().prettyName;
50
+ throw new Error(`PrismaClientValidationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
51
+ In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
52
+ )}
53
+ Prisma.NotFoundError = () => {
54
+ const runtimeName = getRuntime().prettyName;
55
+ throw new Error(`NotFoundError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
56
+ In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
57
+ )}
58
+ Prisma.Decimal = Decimal
59
+
60
+ /**
61
+ * Re-export of sql-template-tag
62
+ */
63
+ Prisma.sql = () => {
64
+ const runtimeName = getRuntime().prettyName;
65
+ throw new Error(`sqltag is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
66
+ In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
67
+ )}
68
+ Prisma.empty = () => {
69
+ const runtimeName = getRuntime().prettyName;
70
+ throw new Error(`empty is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
71
+ In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
72
+ )}
73
+ Prisma.join = () => {
74
+ const runtimeName = getRuntime().prettyName;
75
+ throw new Error(`join is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
76
+ In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
77
+ )}
78
+ Prisma.raw = () => {
79
+ const runtimeName = getRuntime().prettyName;
80
+ throw new Error(`raw is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
81
+ In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
82
+ )}
83
+ Prisma.validator = Public.validator
84
+
85
+ /**
86
+ * Extensions
87
+ */
88
+ Prisma.getExtensionContext = () => {
89
+ const runtimeName = getRuntime().prettyName;
90
+ throw new Error(`Extensions.getExtensionContext is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
91
+ In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
92
+ )}
93
+ Prisma.defineExtension = () => {
94
+ const runtimeName = getRuntime().prettyName;
95
+ throw new Error(`Extensions.defineExtension is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
96
+ In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
97
+ )}
98
+
99
+ /**
100
+ * Shorthand utilities for JSON filtering
101
+ */
102
+ Prisma.DbNull = objectEnumValues.instances.DbNull
103
+ Prisma.JsonNull = objectEnumValues.instances.JsonNull
104
+ Prisma.AnyNull = objectEnumValues.instances.AnyNull
105
+
106
+ Prisma.NullTypes = {
107
+ DbNull: objectEnumValues.classes.DbNull,
108
+ JsonNull: objectEnumValues.classes.JsonNull,
109
+ AnyNull: objectEnumValues.classes.AnyNull
110
+ }
111
+
112
+
113
+
114
+ /**
115
+ * Enums
116
+ */
117
+
118
+ exports.Prisma.TransactionIsolationLevel = makeStrictEnum({
119
+ Serializable: 'Serializable'
120
+ });
121
+
122
+ exports.Prisma.ServerScalarFieldEnum = {
123
+ id: 'id',
124
+ name: 'name',
125
+ host: 'host',
126
+ port: 'port',
127
+ version: 'version'
128
+ };
129
+
130
+ exports.Prisma.BotScalarFieldEnum = {
131
+ id: 'id',
132
+ username: 'username',
133
+ password: 'password',
134
+ prefix: 'prefix',
135
+ note: 'note',
136
+ owners: 'owners',
137
+ serverId: 'serverId',
138
+ proxyHost: 'proxyHost',
139
+ proxyPort: 'proxyPort',
140
+ proxyUsername: 'proxyUsername',
141
+ proxyPassword: 'proxyPassword',
142
+ createdAt: 'createdAt',
143
+ updatedAt: 'updatedAt'
144
+ };
145
+
146
+ exports.Prisma.InstalledPluginScalarFieldEnum = {
147
+ id: 'id',
148
+ botId: 'botId',
149
+ name: 'name',
150
+ version: 'version',
151
+ description: 'description',
152
+ sourceType: 'sourceType',
153
+ sourceUri: 'sourceUri',
154
+ path: 'path',
155
+ isEnabled: 'isEnabled',
156
+ manifest: 'manifest',
157
+ settings: 'settings',
158
+ createdAt: 'createdAt'
159
+ };
160
+
161
+ exports.Prisma.CommandScalarFieldEnum = {
162
+ id: 'id',
163
+ botId: 'botId',
164
+ name: 'name',
165
+ isEnabled: 'isEnabled',
166
+ cooldown: 'cooldown',
167
+ aliases: 'aliases',
168
+ description: 'description',
169
+ owner: 'owner',
170
+ permissionId: 'permissionId',
171
+ allowedChatTypes: 'allowedChatTypes'
172
+ };
173
+
174
+ exports.Prisma.UserScalarFieldEnum = {
175
+ id: 'id',
176
+ username: 'username',
177
+ isBlacklisted: 'isBlacklisted',
178
+ botId: 'botId'
179
+ };
180
+
181
+ exports.Prisma.GroupScalarFieldEnum = {
182
+ id: 'id',
183
+ name: 'name',
184
+ owner: 'owner',
185
+ botId: 'botId'
186
+ };
187
+
188
+ exports.Prisma.PermissionScalarFieldEnum = {
189
+ id: 'id',
190
+ name: 'name',
191
+ description: 'description',
192
+ owner: 'owner',
193
+ botId: 'botId'
194
+ };
195
+
196
+ exports.Prisma.UserGroupScalarFieldEnum = {
197
+ userId: 'userId',
198
+ groupId: 'groupId'
199
+ };
200
+
201
+ exports.Prisma.GroupPermissionScalarFieldEnum = {
202
+ groupId: 'groupId',
203
+ permissionId: 'permissionId'
204
+ };
205
+
206
+ exports.Prisma.ScheduledTaskScalarFieldEnum = {
207
+ id: 'id',
208
+ name: 'name',
209
+ cronPattern: 'cronPattern',
210
+ action: 'action',
211
+ targetBotIds: 'targetBotIds',
212
+ payload: 'payload',
213
+ isEnabled: 'isEnabled',
214
+ lastRun: 'lastRun',
215
+ createdAt: 'createdAt',
216
+ updatedAt: 'updatedAt'
217
+ };
218
+
219
+ exports.Prisma.SortOrder = {
220
+ asc: 'asc',
221
+ desc: 'desc'
222
+ };
223
+
224
+ exports.Prisma.NullsOrder = {
225
+ first: 'first',
226
+ last: 'last'
227
+ };
228
+
229
+
230
+ exports.Prisma.ModelName = {
231
+ Server: 'Server',
232
+ Bot: 'Bot',
233
+ InstalledPlugin: 'InstalledPlugin',
234
+ Command: 'Command',
235
+ User: 'User',
236
+ Group: 'Group',
237
+ Permission: 'Permission',
238
+ UserGroup: 'UserGroup',
239
+ GroupPermission: 'GroupPermission',
240
+ ScheduledTask: 'ScheduledTask'
241
+ };
242
+
243
+ /**
244
+ * This is a stub Prisma Client that will error at runtime if called.
245
+ */
246
+ class PrismaClient {
247
+ constructor() {
248
+ return new Proxy(this, {
249
+ get(target, prop) {
250
+ let message
251
+ const runtime = getRuntime()
252
+ if (runtime.isEdge) {
253
+ message = `PrismaClient is not configured to run in ${runtime.prettyName}. In order to run Prisma Client on edge runtime, either:
254
+ - Use Prisma Accelerate: https://pris.ly/d/accelerate
255
+ - Use Driver Adapters: https://pris.ly/d/driver-adapters
256
+ `;
257
+ } else {
258
+ message = 'PrismaClient is unable to run in this browser environment, or has been bundled for the browser (running in `' + runtime.prettyName + '`).'
259
+ }
260
+
261
+ message += `
262
+ If this is unexpected, please open an issue: https://pris.ly/prisma-prisma-bug-report`
263
+
264
+ throw new Error(message)
265
+ }
266
+ })
267
+ }
268
+ }
269
+
270
+ exports.PrismaClient = PrismaClient
271
+
272
+ Object.assign(exports, Prisma)
@@ -0,0 +1,13 @@
1
+ -- CreateTable
2
+ CREATE TABLE "ScheduledTask" (
3
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
4
+ "name" TEXT NOT NULL,
5
+ "cronPattern" TEXT NOT NULL,
6
+ "action" TEXT NOT NULL,
7
+ "targetBotIds" TEXT NOT NULL,
8
+ "payload" TEXT DEFAULT '{}',
9
+ "isEnabled" BOOLEAN NOT NULL DEFAULT true,
10
+ "lastRun" DATETIME,
11
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
12
+ "updatedAt" DATETIME NOT NULL
13
+ );
@@ -1,138 +1,151 @@
1
- // backend/prisma/schema.prisma
2
-
3
- generator client {
4
- provider = "prisma-client-js"
5
- }
6
-
7
- datasource db {
8
- provider = "sqlite"
9
- url = env("DATABASE_URL")
10
- }
11
-
12
- model Server {
13
- id Int @id @default(autoincrement())
14
- name String @unique
15
- host String
16
- port Int @default(25565)
17
- version String
18
- bots Bot[]
19
- }
20
-
21
- model Bot {
22
- id Int @id @default(autoincrement())
23
- username String @unique
24
- password String?
25
- prefix String? @default("@")
26
- note String?
27
- owners String? @default("")
28
-
29
- server Server @relation(fields: [serverId], references: [id])
30
- serverId Int
31
-
32
- proxyHost String?
33
- proxyPort Int?
34
- proxyUsername String?
35
- proxyPassword String?
36
-
37
- installedPlugins InstalledPlugin[]
38
- users User[]
39
- groups Group[]
40
- permissions Permission[]
41
- commands Command[]
42
-
43
- createdAt DateTime @default(now())
44
- updatedAt DateTime @updatedAt
45
- }
46
-
47
-
48
- model InstalledPlugin {
49
- id Int @id @default(autoincrement())
50
- botId Int
51
- bot Bot @relation(fields: [botId], references: [id], onDelete: Cascade)
52
- name String
53
- version String
54
- description String?
55
- sourceType String
56
- sourceUri String?
57
- path String
58
- isEnabled Boolean @default(true)
59
-
60
- manifest String?
61
- settings String? @default("{}")
62
-
63
- createdAt DateTime @default(now())
64
-
65
- @@unique([botId, name])
66
- }
67
-
68
- model Command {
69
- id Int @id @default(autoincrement())
70
- botId Int
71
- bot Bot @relation(fields: [botId], references: [id], onDelete: Cascade)
72
- name String
73
- isEnabled Boolean @default(true)
74
- cooldown Int @default(0)
75
- aliases String @default("[]") // Храним как джсон строку
76
- description String?
77
- owner String?
78
- permissionId Int?
79
- permission Permission? @relation(fields: [permissionId], references: [id], onDelete: SetNull)
80
- allowedChatTypes String @default("[\"chat\", \"private\"]")
81
-
82
- @@unique([botId, name])
83
- }
84
-
85
- model User {
86
- id Int @id @default(autoincrement())
87
- username String
88
- isBlacklisted Boolean @default(false)
89
- botId Int
90
- bot Bot @relation(fields: [botId], references: [id], onDelete: Cascade)
91
- groups UserGroup[]
92
-
93
- @@unique([botId, username])
94
- }
95
-
96
- model Group {
97
- id Int @id @default(autoincrement())
98
- name String
99
- owner String @default("system")
100
- botId Int
101
- bot Bot @relation(fields: [botId], references: [id], onDelete: Cascade)
102
- permissions GroupPermission[]
103
- users UserGroup[]
104
-
105
- @@unique([botId, name])
106
- }
107
-
108
- model Permission {
109
- id Int @id @default(autoincrement())
110
- name String
111
- description String?
112
- owner String @default("system")
113
- botId Int
114
- bot Bot @relation(fields: [botId], references: [id], onDelete: Cascade)
115
- groups GroupPermission[]
116
- commands Command[]
117
-
118
- @@unique([botId, name])
119
- }
120
-
121
-
122
- model UserGroup {
123
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
124
- userId Int
125
- group Group @relation(fields: [groupId], references: [id], onDelete: Cascade)
126
- groupId Int
127
-
128
- @@id([userId, groupId])
129
- }
130
-
131
- model GroupPermission {
132
- group Group @relation(fields: [groupId], references: [id], onDelete: Cascade)
133
- groupId Int
134
- permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
135
- permissionId Int
136
-
137
- @@id([groupId, permissionId])
1
+ generator client {
2
+ provider = "prisma-client-js"
3
+ }
4
+
5
+ datasource db {
6
+ provider = "sqlite"
7
+ url = env("DATABASE_URL")
8
+ }
9
+
10
+ model Server {
11
+ id Int @id @default(autoincrement())
12
+ name String @unique
13
+ host String
14
+ port Int @default(25565)
15
+ version String
16
+ bots Bot[]
17
+ }
18
+
19
+ model Bot {
20
+ id Int @id @default(autoincrement())
21
+ username String @unique
22
+ password String?
23
+ prefix String? @default("@")
24
+ note String?
25
+ owners String? @default("")
26
+
27
+ server Server @relation(fields: [serverId], references: [id])
28
+ serverId Int
29
+
30
+ proxyHost String?
31
+ proxyPort Int?
32
+ proxyUsername String?
33
+ proxyPassword String?
34
+
35
+ installedPlugins InstalledPlugin[]
36
+ users User[]
37
+ groups Group[]
38
+ permissions Permission[]
39
+ commands Command[]
40
+
41
+ createdAt DateTime @default(now())
42
+ updatedAt DateTime @updatedAt
43
+ }
44
+
45
+
46
+ model InstalledPlugin {
47
+ id Int @id @default(autoincrement())
48
+ botId Int
49
+ bot Bot @relation(fields: [botId], references: [id], onDelete: Cascade)
50
+ name String
51
+ version String
52
+ description String?
53
+ sourceType String
54
+ sourceUri String?
55
+ path String
56
+ isEnabled Boolean @default(true)
57
+
58
+ manifest String?
59
+ settings String? @default("{}")
60
+
61
+ createdAt DateTime @default(now())
62
+
63
+ @@unique([botId, name])
64
+ }
65
+
66
+ model Command {
67
+ id Int @id @default(autoincrement())
68
+ botId Int
69
+ bot Bot @relation(fields: [botId], references: [id], onDelete: Cascade)
70
+ name String
71
+ isEnabled Boolean @default(true)
72
+ cooldown Int @default(0)
73
+ aliases String @default("[]") // Храним как джсон строку
74
+ description String?
75
+ owner String?
76
+ permissionId Int?
77
+ permission Permission? @relation(fields: [permissionId], references: [id], onDelete: SetNull)
78
+ allowedChatTypes String @default("[\"chat\", \"private\"]")
79
+
80
+ @@unique([botId, name])
81
+ }
82
+
83
+ model User {
84
+ id Int @id @default(autoincrement())
85
+ username String
86
+ isBlacklisted Boolean @default(false)
87
+ botId Int
88
+ bot Bot @relation(fields: [botId], references: [id], onDelete: Cascade)
89
+ groups UserGroup[]
90
+
91
+ @@unique([botId, username])
92
+ }
93
+
94
+ model Group {
95
+ id Int @id @default(autoincrement())
96
+ name String
97
+ owner String @default("system")
98
+ botId Int
99
+ bot Bot @relation(fields: [botId], references: [id], onDelete: Cascade)
100
+ permissions GroupPermission[]
101
+ users UserGroup[]
102
+
103
+ @@unique([botId, name])
104
+ }
105
+
106
+ model Permission {
107
+ id Int @id @default(autoincrement())
108
+ name String
109
+ description String?
110
+ owner String @default("system")
111
+ botId Int
112
+ bot Bot @relation(fields: [botId], references: [id], onDelete: Cascade)
113
+ groups GroupPermission[]
114
+ commands Command[]
115
+
116
+ @@unique([botId, name])
117
+ }
118
+
119
+
120
+ model UserGroup {
121
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
122
+ userId Int
123
+ group Group @relation(fields: [groupId], references: [id], onDelete: Cascade)
124
+ groupId Int
125
+
126
+ @@id([userId, groupId])
127
+ }
128
+
129
+ model GroupPermission {
130
+ group Group @relation(fields: [groupId], references: [id], onDelete: Cascade)
131
+ groupId Int
132
+ permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
133
+ permissionId Int
134
+
135
+ @@id([groupId, permissionId])
136
+ }
137
+
138
+
139
+
140
+ model ScheduledTask {
141
+ id Int @id @default(autoincrement())
142
+ name String
143
+ cronPattern String
144
+ action String
145
+ targetBotIds String // джсон массив ID ботов или "ALL"
146
+ payload String? @default("{}") // джсон для доп данных, например, команды
147
+ isEnabled Boolean @default(true)
148
+ lastRun DateTime?
149
+ createdAt DateTime @default(now())
150
+ updatedAt DateTime @updatedAt
138
151
  }
@@ -0,0 +1,95 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const { PrismaClient } = require('@prisma/client');
4
+ const TaskScheduler = require('../../core/TaskScheduler');
5
+
6
+ const { CronExpressionParser } = require('cron-parser');
7
+
8
+ const prisma = new PrismaClient();
9
+
10
+ const normalizeCronPattern = (pattern) => {
11
+ if (typeof pattern !== 'string') return '* * * * *';
12
+ return pattern.replace(/\*\/1/g, '*').trim();
13
+ };
14
+
15
+ router.get('/', async (req, res) => {
16
+ try {
17
+ const tasks = await prisma.scheduledTask.findMany({ orderBy: { createdAt: 'desc' } });
18
+ const normalizedTasks = tasks.map(task => ({
19
+ ...task,
20
+ cronPattern: normalizeCronPattern(task.cronPattern),
21
+ }));
22
+ res.json(normalizedTasks);
23
+ } catch (error) {
24
+ console.error("[API /tasks] Ошибка получения списка задач:", error);
25
+ res.status(500).json({ error: 'Не удалось получить список задач' });
26
+ }
27
+ });
28
+
29
+ router.post('/', async (req, res) => {
30
+ try {
31
+ const taskData = { ...req.body, cronPattern: normalizeCronPattern(req.body.cronPattern) };
32
+ const newTask = await prisma.scheduledTask.create({ data: taskData });
33
+ TaskScheduler.scheduleTask(newTask);
34
+ res.status(201).json(newTask);
35
+ } catch (error) {
36
+ console.error("[API /tasks] Ошибка создания задачи:", error);
37
+ res.status(500).json({ error: 'Не удалось создать задачу' });
38
+ }
39
+ });
40
+
41
+ router.put('/:id', async (req, res) => {
42
+ const taskId = parseInt(req.params.id, 10);
43
+ try {
44
+ const { id, createdAt, updatedAt, lastRun, ...dataToUpdate } = req.body;
45
+
46
+ if (dataToUpdate.cronPattern) {
47
+ dataToUpdate.cronPattern = normalizeCronPattern(dataToUpdate.cronPattern);
48
+ }
49
+
50
+ const updatedTask = await prisma.scheduledTask.update({
51
+ where: { id: taskId },
52
+ data: dataToUpdate,
53
+ });
54
+ await TaskScheduler.updateTask(updatedTask);
55
+ res.json(updatedTask);
56
+ } catch (error) {
57
+ console.error(`[API /tasks] Ошибка обновления задачи ${taskId}:`, error);
58
+ res.status(500).json({ error: 'Не удалось обновить задачу' });
59
+ }
60
+ });
61
+
62
+ router.delete('/:id', async (req, res) => {
63
+ const taskId = parseInt(req.params.id, 10);
64
+ try {
65
+ await prisma.scheduledTask.delete({ where: { id: taskId } });
66
+ TaskScheduler.unscheduleTask(taskId);
67
+ res.status(204).send();
68
+ } catch (error) {
69
+ console.error(`[API /tasks] Ошибка удаления задачи ${taskId}:`, error);
70
+ res.status(500).json({ error: 'Не удалось удалить задачу' });
71
+ }
72
+ });
73
+
74
+
75
+ router.post('/describe', (req, res) => {
76
+ const { pattern } = req.body;
77
+
78
+ if (!pattern) {
79
+ return res.status(400).json({ error: 'Невалидный cron-паттерн' });
80
+ }
81
+
82
+ try {
83
+ const interval = CronExpressionParser.parse(pattern);
84
+
85
+ res.json({
86
+ human: interval.stringify(true),
87
+ next: interval.next().toDate().toLocaleString('ru-RU')
88
+ });
89
+ } catch (error) {
90
+ console.error(`[API /tasks/describe] Ошибка парсинга паттерна "${pattern}":`, error.message);
91
+ res.status(500).json({ error: 'Ошибка парсинга паттерна' });
92
+ }
93
+ });
94
+
95
+ module.exports = router;