adminizer 4.3.0-build.99 → 4.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 (117) hide show
  1. package/assets/add-9NSjG6Jx.js +1 -0
  2. package/assets/add-form-uUiOWEy_.js +1 -0
  3. package/assets/add-group-Db0HkA1m.js +1 -0
  4. package/assets/add-group-form-DMz0_Oo9.js +1 -0
  5. package/assets/add-user-BMklpOqf.js +1 -0
  6. package/assets/{add-user-form-DrclnTOd.js → add-user-form-izlXhv2-.js} +1 -1
  7. package/assets/{app-D8oqdt8J.css → app-BJd5vD4i.css} +1 -1
  8. package/assets/app-layout-DcgYmhNb.js +1 -0
  9. package/assets/{app-shell-CHEYhVco.js → app-shell-C8Cnr5Hy.js} +1 -1
  10. package/assets/app-sidebar-HwvXNZzk.js +1 -0
  11. package/assets/app-sidebar-header-C8TTx8yd.js +1 -0
  12. package/assets/app.js +5 -5
  13. package/assets/{breadcrumbs-C439DWrC.js → breadcrumbs-DSMzNYiS.js} +1 -1
  14. package/assets/catalog-C2INmTwI.js +6 -0
  15. package/assets/catalog-D4n6dpGl.css +1 -0
  16. package/assets/{dashboard-Bi5KeZu2.js → dashboard-DwFL6nqn.js} +1 -1
  17. package/assets/{date-picker-DbJ8nHp5.js → date-picker-kW3wZQr_.js} +1 -1
  18. package/assets/{del-modal-_b3CSNHb.js → del-modal-DyIWFflP.js} +1 -1
  19. package/assets/{field-renderer-4obZ_jUo.js → field-renderer-BNQVfOir.js} +3 -3
  20. package/assets/form-CAIoGuhZ.js +1 -0
  21. package/assets/form-NUd-JZJN.js +1 -0
  22. package/assets/{geo-json-CadjdhwW.js → geo-json-YeWQOYnT.js} +1 -1
  23. package/assets/{home-BUoDaWe0.js → home-CteDT1us.js} +2 -2
  24. package/assets/{icon-DM49pZW3.js → icon-DpkedrXG.js} +1 -1
  25. package/assets/{init-user-DNrB8Xt5.js → init-user-DaOvt0vG.js} +1 -1
  26. package/assets/{input-error--IOnWghB.js → input-error-CmXZF6xy.js} +1 -1
  27. package/assets/list-CXQmJbH8.js +1 -0
  28. package/assets/{list-table-BKxxQkCW.js → list-table-BPpHDVPf.js} +4 -4
  29. package/assets/{login-6Xb8bcPq.js → login-DR6fvKtm.js} +1 -1
  30. package/assets/manifest.json +82 -82
  31. package/assets/{material-icon-BedgD2NE.js → material-icon-DwkE6wKL.js} +1 -1
  32. package/assets/media-manager-DYOfUh8F.js +14 -0
  33. package/assets/{module-B4-7WkY5.js → module-BIUqcf4-.js} +1 -1
  34. package/assets/{nav-footer-BwkQkwow.js → nav-footer-B85HLj-j.js} +1 -1
  35. package/assets/{nav-main-9Eb_A0rf.js → nav-main-BqKm87JZ.js} +1 -1
  36. package/assets/nav-user-DuCZNsZX.js +1 -0
  37. package/assets/notification-BQTjxH2H.js +27 -0
  38. package/assets/pagination-render-io0M2m2O.js +1 -0
  39. package/assets/{register-BIyjCy8M.js → register-hJD1ETdf.js} +1 -1
  40. package/assets/{tabs-BK_5wdPA.js → tabs-BhkFoerH.js} +1 -1
  41. package/assets/{theme-switcher-CKiJbMkh.js → theme-switcher-cgyA7_cO.js} +1 -1
  42. package/assets/{toast-editor-BZM5RHph.js → toast-editor-DwRk6WqT.js} +1 -1
  43. package/assets/{user-info-CcYdmjMZ.js → user-info-BGQvqBmO.js} +1 -1
  44. package/assets/{user-menu-content-DbUk8ZeY.js → user-menu-content-BDm88xaM.js} +1 -1
  45. package/assets/welcome-ks57d2us.js +1 -0
  46. package/controllers/add.js +1 -1
  47. package/controllers/catalog/Catalog.js +21 -20
  48. package/controllers/catalog/FrontendCatalogAdapter.d.ts +82 -0
  49. package/controllers/catalog/FrontendCatalogAdapter.js +228 -0
  50. package/controllers/catalog/FrontentCatalogAdapter.d.ts +4 -4
  51. package/controllers/catalog/FrontentCatalogAdapter.js +28 -10
  52. package/controllers/edit.js +14 -5
  53. package/controllers/form.js +8 -6
  54. package/controllers/login.js +3 -0
  55. package/controllers/media-manager/ThumbController.js +1 -1
  56. package/controllers/media-manager/mediaManagerAdapter.js +1 -1
  57. package/controllers/media-manager/mediaManagerApi.js +1 -2
  58. package/controllers/notifications/NotificationController.d.ts +1 -1
  59. package/controllers/notifications/NotificationController.js +5 -4
  60. package/controllers/view.js +5 -3
  61. package/helpers/inertiaAddHelper.js +1 -2
  62. package/helpers/inertiaFromHelper.js +1 -2
  63. package/index.d.ts +5 -0
  64. package/index.js +5 -0
  65. package/interfaces/adminpanelConfig.d.ts +12 -0
  66. package/lib/Adminizer.d.ts +4 -3
  67. package/lib/Adminizer.js +16 -22
  68. package/lib/catalog/AbstractCatalog.d.ts +6 -4
  69. package/lib/catalog/AbstractCatalog.js +5 -4
  70. package/lib/catalog/Navigation.d.ts +9 -7
  71. package/lib/catalog/Navigation.js +69 -40
  72. package/lib/inertia/inertiaAdapter.js +31 -13
  73. package/lib/media-manager/AbstractMediaManager.d.ts +5 -3
  74. package/lib/media-manager/DefaultMediaManager.d.ts +3 -3
  75. package/lib/media-manager/DefaultMediaManager.js +18 -13
  76. package/lib/media-manager/Items.js +5 -4
  77. package/lib/media-manager/MediaManagerHandler.d.ts +3 -3
  78. package/lib/media-manager/MediaManagerHandler.js +3 -3
  79. package/lib/media-manager/Thumb.d.ts +2 -1
  80. package/lib/media-manager/Thumb.js +3 -4
  81. package/lib/media-manager/helpers/MediaManagerHelper.d.ts +7 -2
  82. package/lib/media-manager/helpers/MediaManagerHelper.js +12 -8
  83. package/lib/model/adapter/waterline.js +6 -0
  84. package/package.json +3 -1
  85. package/system/Router.js +10 -8
  86. package/system/bindAccessRights.js +7 -0
  87. package/system/bindCors.d.ts +2 -0
  88. package/system/bindCors.js +41 -0
  89. package/system/bindInertia.js +1 -1
  90. package/system/bindMediaManager.js +1 -2
  91. package/system/bindNavigation.d.ts +1 -1
  92. package/system/bindNavigation.js +33 -35
  93. package/system/bindNotifications.js +4 -4
  94. package/system/bindReqFunctions.js +4 -1
  95. package/system/defaults.js +8 -0
  96. package/translations/ru.json +121 -120
  97. package/ui/components/handsontable.js +6 -3
  98. package/ui/lib/utils.d.ts +1 -0
  99. package/ui/lib/utils.js +16 -0
  100. package/assets/add-1E1UsMVZ.js +0 -1
  101. package/assets/add-form-CGa9QbwE.js +0 -1
  102. package/assets/add-group-7yAK6uFY.js +0 -1
  103. package/assets/add-group-form-BNmpvW8K.js +0 -1
  104. package/assets/add-user-NoYkTfZi.js +0 -1
  105. package/assets/app-layout-i2zN9Rn-.js +0 -1
  106. package/assets/app-sidebar-DeF8WNmW.js +0 -1
  107. package/assets/app-sidebar-header-DdM1EOrb.js +0 -1
  108. package/assets/catalog-B9hdop59.js +0 -6
  109. package/assets/catalog-C71LuRag.css +0 -1
  110. package/assets/form-Bte5kzjB.js +0 -1
  111. package/assets/form-oUlsuu7h.js +0 -1
  112. package/assets/list-C04Krl_W.js +0 -1
  113. package/assets/media-manager-UQT6RhI8.js +0 -14
  114. package/assets/nav-user-CRAfyE-x.js +0 -1
  115. package/assets/notification-ma2x7vka.js +0 -27
  116. package/assets/pagination-render-D3UyVAlr.js +0 -1
  117. package/assets/welcome-cWh1qnl_.js +0 -1
@@ -1,7 +1,7 @@
1
1
  import { AbstractCatalog, AbstractGroup, AbstractItem } from "./AbstractCatalog";
2
2
  import { v4 as uuid } from "uuid";
3
3
  import { Adminizer } from "../Adminizer";
4
- class StorageService {
4
+ export class StorageService {
5
5
  storageMap = new Map();
6
6
  id;
7
7
  model;
@@ -30,7 +30,7 @@ class StorageService {
30
30
  return this.id;
31
31
  }
32
32
  async buildTree() {
33
- const rootElements = await this.findElementsByParentId(0, null);
33
+ const rootElements = await this.findElementsByParentId(null, null);
34
34
  const buildSubTree = async (elements) => {
35
35
  const tree = [];
36
36
  for (const element of elements) {
@@ -56,9 +56,9 @@ class StorageService {
56
56
  return tree;
57
57
  }
58
58
  async populateFromTree(tree) {
59
- const traverseTree = async (node, parentId = 0) => {
59
+ const traverseTree = async (node, parentId = null) => {
60
60
  const { children, ...itemData } = node;
61
- const item = { ...itemData, parentId };
61
+ const item = { ...itemData, parentId: itemData.parentId === 0 ? null : itemData.parentId };
62
62
  await this.setElement(item.id, item, true);
63
63
  if (children && children.length > 0) {
64
64
  for (const child of children) {
@@ -109,6 +109,8 @@ class StorageService {
109
109
  async findElementsByParentId(parentId, type) {
110
110
  const elements = [];
111
111
  for (const item of this.storageMap.values()) {
112
+ if (parentId === 0)
113
+ parentId = null;
112
114
  if (type === null && item.parentId === parentId) {
113
115
  elements.push(item);
114
116
  continue;
@@ -138,14 +140,16 @@ class StorageService {
138
140
  }
139
141
  }
140
142
  export class StorageServices {
141
- static storages = [];
142
- static add(storage) {
143
+ storages = [];
144
+ constructor() {
145
+ }
146
+ add(storage) {
143
147
  this.storages.push(storage);
144
148
  }
145
- static get(id) {
149
+ get(id) {
146
150
  return this.storages.find(storage => storage.getId() === id);
147
151
  }
148
- static getAll() {
152
+ getAll() {
149
153
  return this.storages;
150
154
  }
151
155
  }
@@ -155,17 +159,21 @@ export class Navigation extends AbstractCatalog {
155
159
  icon = "box";
156
160
  actionHandlers = [];
157
161
  idList = [];
162
+ storageServices;
158
163
  constructor(adminizer, config) {
159
164
  let items = [];
165
+ const storageServices = new StorageServices();
160
166
  for (const configElement of config.items) {
161
- items.push(new NavigationItem(adminizer, configElement.title, configElement.model, config.model, configElement.urlPath));
167
+ items.push(new NavigationItem(adminizer, configElement.title, configElement.model, config.model, configElement.urlPath, storageServices));
162
168
  }
163
- items.push(new NavigationGroup(adminizer, config.groupField));
164
- items.push(new LinkItem(adminizer));
169
+ items.push(new NavigationGroup(adminizer, config.groupField, storageServices));
170
+ items.push(new LinkItem(adminizer, storageServices));
171
+ super(adminizer, items);
172
+ this.storageServices = storageServices;
173
+ adminizer.storageServices = storageServices;
165
174
  for (const section of config.sections) {
166
- StorageServices.add(new StorageService(adminizer, section, config.model));
175
+ this.storageServices.add(new StorageService(adminizer, section, config.model));
167
176
  }
168
- super(adminizer, items);
169
177
  this.movingGroupsRootOnly = config.movingGroupsRootOnly;
170
178
  this.idList = config.sections ?? [];
171
179
  }
@@ -183,7 +191,7 @@ class NavigationItem extends AbstractItem {
183
191
  actionHandlers = [];
184
192
  urlPath;
185
193
  adminizer;
186
- constructor(adminizer, name, model, navigationModel, urlPath) {
194
+ constructor(adminizer, name, model, navigationModel, urlPath, storageServices) {
187
195
  super();
188
196
  this.name = name;
189
197
  this.navigationModel = navigationModel;
@@ -193,9 +201,10 @@ class NavigationItem extends AbstractItem {
193
201
  let configModel = adminizer.config.models[this.model];
194
202
  this.icon = configModel?.icon ?? 'file_present';
195
203
  this.adminizer = adminizer;
204
+ this.storageServices = storageServices;
196
205
  }
197
206
  async create(data, catalogId) {
198
- let storage = StorageServices.get(catalogId);
207
+ let storage = this.storageServices.get(catalogId);
199
208
  let storageData = null;
200
209
  if (data._method === 'select') {
201
210
  // Direct call by model adapter
@@ -203,7 +212,8 @@ class NavigationItem extends AbstractItem {
203
212
  storageData = await this.dataPreparation({
204
213
  record: record,
205
214
  parentId: data.parentId,
206
- targetBlank: data.targetBlank
215
+ targetBlank: data.targetBlank,
216
+ visible: data.visible
207
217
  }, catalogId);
208
218
  }
209
219
  else {
@@ -212,13 +222,17 @@ class NavigationItem extends AbstractItem {
212
222
  return await storage.setElement(data.id, storageData);
213
223
  }
214
224
  async dataPreparation(data, catalogId, sortOrder) {
215
- let storage = StorageServices.get(catalogId);
225
+ let storage = this.storageServices.get(catalogId);
216
226
  let urlPath = eval('`' + this.urlPath + '`');
217
- let parentId = data.parentId ? data.parentId : 0; // changed from null to 0
227
+ let parentId = data.parentId ? data.parentId : null; // changed from 0 to null
228
+ if (parentId === 0)
229
+ parentId = null;
218
230
  return {
219
231
  id: uuid(),
220
232
  modelId: data.record.id,
221
233
  targetBlank: data.targetBlank ?? data.record.targetBlank,
234
+ visible: data.visible ?? data.record.visible,
235
+ isNavigation: true,
222
236
  name: data.record.name ?? data.record.title ?? data.record.id,
223
237
  parentId: parentId,
224
238
  sortOrder: sortOrder ?? (await storage.findElementsByParentId(parentId, null)).length,
@@ -228,7 +242,7 @@ class NavigationItem extends AbstractItem {
228
242
  };
229
243
  }
230
244
  async updateModelItems(modelId, data, catalogId) {
231
- let storage = StorageServices.get(catalogId);
245
+ let storage = this.storageServices.get(catalogId);
232
246
  let items = await storage.findElementByModelId(modelId);
233
247
  let urlPath = eval('`' + this.urlPath + '`');
234
248
  let response = [];
@@ -237,21 +251,22 @@ class NavigationItem extends AbstractItem {
237
251
  item.urlPath = urlPath;
238
252
  if (item.id === data.record.treeId) {
239
253
  item.targetBlank = data.record.targetBlank;
254
+ item.visible = data.record.visible;
240
255
  }
241
256
  response.push(await storage.setElement(item.id, item));
242
257
  }
243
258
  return response[0];
244
259
  }
245
260
  async update(itemId, data, catalogId) {
246
- let storage = StorageServices.get(catalogId);
261
+ let storage = this.storageServices.get(catalogId);
247
262
  return await storage.setElement(itemId, data);
248
263
  }
249
264
  async deleteItem(itemId, catalogId) {
250
- let storage = StorageServices.get(catalogId);
265
+ let storage = this.storageServices.get(catalogId);
251
266
  return await storage.removeElementById(itemId);
252
267
  }
253
268
  async find(itemId, catalogId) {
254
- let storage = StorageServices.get(catalogId);
269
+ let storage = this.storageServices.get(catalogId);
255
270
  return await storage.findElementById(itemId);
256
271
  }
257
272
  /**
@@ -259,7 +274,7 @@ class NavigationItem extends AbstractItem {
259
274
  * // TODO: need passing custom React module
260
275
  */
261
276
  async getAddTemplate(req) {
262
- let type = 'model';
277
+ let type = 'model.link';
263
278
  // Direct call by model adapter
264
279
  let itemsDB = await this.adminizer.modelHandler.model.get(this.model)["_find"]({});
265
280
  let items = itemsDB.map((item) => {
@@ -278,24 +293,25 @@ class NavigationItem extends AbstractItem {
278
293
  createTitle: `${req.i18n.__('create new')} ${req.i18n.__(this.name + 's')}`,
279
294
  OR: req.i18n.__('OR'),
280
295
  openInNewWindow: req.i18n.__('Open in a new window'),
296
+ visible: req.i18n.__('Visible')
281
297
  }
282
298
  }
283
299
  };
284
300
  }
285
301
  async getChilds(parentId, catalogId) {
286
- let storage = StorageServices.get(catalogId);
302
+ let storage = this.storageServices.get(catalogId);
287
303
  return await storage.findElementsByParentId(parentId, this.type);
288
304
  }
289
305
  async getEditTemplate(id, catalogId, req, modelId) {
290
306
  return Promise.resolve({
291
- type: 'model',
307
+ type: 'model.link',
292
308
  data: {
293
309
  item: await this.find(id, catalogId)
294
310
  }
295
311
  });
296
312
  }
297
313
  async search(s, catalogId) {
298
- let storage = StorageServices.get(catalogId);
314
+ let storage = this.storageServices.get(catalogId);
299
315
  return await storage.search(s, this.type);
300
316
  }
301
317
  }
@@ -304,13 +320,14 @@ class NavigationGroup extends AbstractGroup {
304
320
  name = "Group";
305
321
  groupField;
306
322
  adminizer;
307
- constructor(adminizer, groupField) {
323
+ constructor(adminizer, groupField, storageServices) {
308
324
  super();
309
325
  this.groupField = groupField;
310
326
  this.adminizer = adminizer;
327
+ this.storageServices = storageServices;
311
328
  }
312
329
  async create(data, catalogId) {
313
- let storage = StorageServices.get(catalogId);
330
+ let storage = this.storageServices.get(catalogId);
314
331
  let storageData = await this.dataPreparation(data, catalogId);
315
332
  delete data.name;
316
333
  delete data.parentId;
@@ -318,12 +335,16 @@ class NavigationGroup extends AbstractGroup {
318
335
  return await storage.setElement(storageData.id, storageData);
319
336
  }
320
337
  async dataPreparation(data, catalogId, sortOrder) {
321
- let storage = StorageServices.get(catalogId);
322
- let parentId = data.parentId ? data.parentId : 0; // changed from null to 0
338
+ let storage = this.storageServices.get(catalogId);
339
+ let parentId = data.parentId ? data.parentId : null; // changed from 0 to null
340
+ if (parentId === 0)
341
+ parentId = null;
323
342
  return {
324
343
  id: uuid(),
325
344
  name: data.name,
326
345
  targetBlank: data.targetBlank,
346
+ visible: data.visible,
347
+ isNavigation: true,
327
348
  parentId: parentId,
328
349
  sortOrder: sortOrder ?? (await storage.findElementsByParentId(parentId, null)).length,
329
350
  icon: this.icon,
@@ -331,19 +352,19 @@ class NavigationGroup extends AbstractGroup {
331
352
  };
332
353
  }
333
354
  async deleteItem(itemId, catalogId) {
334
- let storage = StorageServices.get(catalogId);
355
+ let storage = this.storageServices.get(catalogId);
335
356
  return await storage.removeElementById(itemId);
336
357
  }
337
358
  async find(itemId, catalogId) {
338
- let storage = StorageServices.get(catalogId);
359
+ let storage = this.storageServices.get(catalogId);
339
360
  return await storage.findElementById(itemId);
340
361
  }
341
362
  async update(itemId, data, catalogId) {
342
- let storage = StorageServices.get(catalogId);
363
+ let storage = this.storageServices.get(catalogId);
343
364
  return await storage.setElement(itemId, data);
344
365
  }
345
366
  async updateModelItems(modelId, data, catalogId) {
346
- let storage = StorageServices.get(catalogId);
367
+ let storage = this.storageServices.get(catalogId);
347
368
  return await storage.setElement(modelId, data);
348
369
  }
349
370
  getAddTemplate(req) {
@@ -353,6 +374,7 @@ class NavigationGroup extends AbstractGroup {
353
374
  resItems = this.groupField.map((field) => {
354
375
  return {
355
376
  name: field.name,
377
+ label: field.label,
356
378
  required: field.required
357
379
  };
358
380
  });
@@ -363,6 +385,7 @@ class NavigationGroup extends AbstractGroup {
363
385
  items: resItems,
364
386
  labels: {
365
387
  openInNewWindow: req.i18n.__('Open in a new window'),
388
+ visible: req.i18n.__('Visible'),
366
389
  title: req.i18n.__('Title'),
367
390
  save: req.i18n.__('Save')
368
391
  }
@@ -377,6 +400,7 @@ class NavigationGroup extends AbstractGroup {
377
400
  resItems = this.groupField.map((field) => {
378
401
  return {
379
402
  name: field.name,
403
+ label: field.label,
380
404
  required: field.required
381
405
  };
382
406
  });
@@ -388,6 +412,7 @@ class NavigationGroup extends AbstractGroup {
388
412
  item: item,
389
413
  labels: {
390
414
  openInNewWindow: req.i18n.__('Open in a new window'),
415
+ visible: req.i18n.__('Visible'),
391
416
  title: req.i18n.__('Title'),
392
417
  save: req.i18n.__('Save')
393
418
  }
@@ -395,11 +420,11 @@ class NavigationGroup extends AbstractGroup {
395
420
  });
396
421
  }
397
422
  async getChilds(parentId, catalogId) {
398
- let storage = StorageServices.get(catalogId);
423
+ let storage = this.storageServices.get(catalogId);
399
424
  return await storage.findElementsByParentId(parentId, this.type);
400
425
  }
401
426
  async search(s, catalogId) {
402
- let storage = StorageServices.get(catalogId);
427
+ let storage = this.storageServices.get(catalogId);
403
428
  return await storage.search(s, this.type);
404
429
  }
405
430
  }
@@ -409,14 +434,15 @@ class LinkItem extends NavigationGroup {
409
434
  name = 'Link';
410
435
  type = 'link';
411
436
  isGroup = false;
412
- constructor(adminizer) {
413
- super(adminizer, []);
437
+ constructor(adminizer, storageServices) {
438
+ super(adminizer, [], storageServices);
414
439
  }
415
440
  getAddTemplate(req) {
416
441
  let type = 'navigation.link';
417
442
  let resItems = [
418
443
  {
419
- name: req.i18n.__('Link'),
444
+ label: req.i18n.__('Link'),
445
+ name: "link",
420
446
  required: true
421
447
  }
422
448
  ];
@@ -427,6 +453,7 @@ class LinkItem extends NavigationGroup {
427
453
  labels: {
428
454
  title: req.i18n.__('Title'),
429
455
  openInNewWindow: req.i18n.__('Open in a new window'),
456
+ visible: req.i18n.__('Visible'),
430
457
  save: req.i18n.__('Save')
431
458
  }
432
459
  }
@@ -437,7 +464,8 @@ class LinkItem extends NavigationGroup {
437
464
  let type = 'navigation.group';
438
465
  let resItems = [
439
466
  {
440
- name: req.i18n.__('Link'),
467
+ label: req.i18n.__('Link'),
468
+ name: 'link',
441
469
  required: true
442
470
  }
443
471
  ];
@@ -448,6 +476,7 @@ class LinkItem extends NavigationGroup {
448
476
  item: item,
449
477
  labels: {
450
478
  openInNewWindow: req.i18n.__('Open in a new window'),
479
+ visible: req.i18n.__('Visible'),
451
480
  title: req.i18n.__('Title'),
452
481
  save: req.i18n.__('Save')
453
482
  }
@@ -11,19 +11,24 @@ const inertiaExpressAdapter = function ({ version, html, flashMessages, enableRe
11
11
  }) {
12
12
  return (req, res, next) => {
13
13
  if (csrf.enabled) {
14
- const csrfToken = randomBytes(32).toString('hex');
15
- res.cookie('XSRF-TOKEN', csrfToken, {
16
- httpOnly: false,
17
- secure: process.env.NODE_ENV === 'production' && process.env.CSRF_COOKIE_INSECURE !== '1',
18
- sameSite: 'lax',
19
- });
20
- // Check CSRF token for non-GET requests
21
- if (!['GET', 'HEAD', 'OPTIONS'].includes(req.method)) {
22
- const csrfCookie = req.cookies['XSRF-TOKEN'];
23
- const csrfHeader = req.headers[csrf.headerName || 'x-xsrf-token'];
24
- if (!csrfCookie || !csrfHeader || csrfCookie !== csrfHeader) {
25
- res.status(403).send({ message: 'Invalid CSRF token' });
26
- return;
14
+ const isApiRoute = isApiRequest(req);
15
+ if (!isApiRoute) {
16
+ const csrfToken = randomBytes(32).toString('hex');
17
+ res.cookie('XSRF-TOKEN', csrfToken, {
18
+ httpOnly: false,
19
+ secure: process.env.NODE_ENV === 'production' && process.env.CSRF_COOKIE_INSECURE !== '1',
20
+ sameSite: 'lax',
21
+ });
22
+ // Проверяем CSRF только для не-GET запросов И не-API routes
23
+ if (!['GET', 'HEAD', 'OPTIONS'].includes(req.method)) {
24
+ const csrfCookie = req.cookies['XSRF-TOKEN'];
25
+ const csrfHeader = req.headers[csrf.headerName || 'x-xsrf-token'];
26
+ if (!csrfCookie || !csrfHeader || csrfCookie !== csrfHeader) {
27
+ return res.status(403).json({
28
+ message: 'Invalid CSRF token',
29
+ type: 'csrf_error'
30
+ });
31
+ }
27
32
  }
28
33
  }
29
34
  }
@@ -129,4 +134,17 @@ const inertiaExpressAdapter = function ({ version, html, flashMessages, enableRe
129
134
  return next();
130
135
  };
131
136
  };
137
+ // Вспомогательная функция для определения API routes
138
+ function isApiRequest(req) {
139
+ const adminizer = req.adminizer;
140
+ if (!adminizer?.config?.cors?.enabled) {
141
+ return false;
142
+ }
143
+ const corsConfig = adminizer.config.cors;
144
+ const routePrefix = adminizer.config.routePrefix || '';
145
+ // Создаем базовый путь для API
146
+ const apiBasePath = `${routePrefix}/${corsConfig.path?.replace('*', '')}`;
147
+ // Проверяем начинается ли путь с API base path
148
+ return req.path.startsWith(apiBasePath);
149
+ }
132
150
  export default inertiaExpressAdapter;
@@ -36,8 +36,10 @@ export interface MediaManagerWidgetClientItem extends MediaManagerWidgetItem {
36
36
  url?: string;
37
37
  }
38
38
  export interface MediaManagerWidgetJSON {
39
- list: MediaManagerWidgetItem[];
40
39
  mediaManagerId: string;
40
+ model: string;
41
+ widgetName: string;
42
+ modelId: string | number;
41
43
  }
42
44
  export interface MediaManagerWidgetData {
43
45
  id: string;
@@ -207,8 +209,8 @@ export declare abstract class AbstractMediaManager {
207
209
  /**
208
210
  * widget Id in the model in which the mediafile was added
209
211
  */
210
- modelId: string, widgetName: string): Promise<void>;
211
- abstract getItemsList(items: MediaManagerWidgetItem[]): Promise<MediaManagerWidgetClientItem[]>;
212
+ modelId: number, widgetName: string): Promise<void>;
213
+ abstract getRelations(model: string, widgetName: string, modelId: string | number): Promise<MediaManagerWidgetClientItem[]>;
212
214
  /**
213
215
  * Search all items.
214
216
  * If not this.allowSearch = true then it will not come here
@@ -1,4 +1,4 @@
1
- import { AbstractMediaManager, MediaManagerItem, File, MediaManagerWidgetItem, MediaManagerWidgetData, MediaManagerWidgetClientItem, SortCriteria } from "./AbstractMediaManager";
1
+ import { AbstractMediaManager, MediaManagerItem, File, MediaManagerWidgetData, MediaManagerWidgetClientItem, SortCriteria } from "./AbstractMediaManager";
2
2
  import { Adminizer } from "../Adminizer";
3
3
  export declare class DefaultMediaManager extends AbstractMediaManager {
4
4
  readonly itemTypes: File<MediaManagerItem>[];
@@ -12,6 +12,6 @@ export declare class DefaultMediaManager extends AbstractMediaManager {
12
12
  next: boolean;
13
13
  }>;
14
14
  searchAll(s: string, group: string): Promise<MediaManagerItem[]>;
15
- setRelations(data: MediaManagerWidgetData[], model: string, modelId: string, widgetName: string): Promise<void>;
16
- getItemsList(items: MediaManagerWidgetItem[]): Promise<MediaManagerWidgetClientItem[]>;
15
+ setRelations(data: MediaManagerWidgetData[], model: string, modelId: number, widgetName: string): Promise<void>;
16
+ getRelations(model: string, widgetName: string, modelId: string | number): Promise<MediaManagerWidgetClientItem[]>;
17
17
  }
@@ -57,7 +57,7 @@ export class DefaultMediaManager extends AbstractMediaManager {
57
57
  }
58
58
  async setRelations(data, model, modelId, widgetName) {
59
59
  let modelAssociations = await this.adminizer.modelHandler.model.get(this.modelAssoc)["_find"]({
60
- where: { modelId: modelId, model: model, widgetName: widgetName },
60
+ where: { modelId: +modelId, model: model.toLowerCase(), widgetName: widgetName },
61
61
  });
62
62
  for (const modelAssociation of modelAssociations) {
63
63
  const q = {};
@@ -69,26 +69,31 @@ export class DefaultMediaManager extends AbstractMediaManager {
69
69
  for (const [key, widgetItem] of data.entries()) {
70
70
  await this.adminizer.modelHandler.model.get(this.modelAssoc)["_create"]({
71
71
  mediaManagerId: this.id,
72
- model: model,
73
- modelId: modelId,
72
+ model: model.toLowerCase(),
73
+ modelId: +modelId,
74
74
  [fieldName]: widgetItem.id,
75
75
  widgetName: widgetName,
76
76
  sortOrder: key + 1,
77
77
  });
78
78
  }
79
79
  }
80
- async getItemsList(items) {
80
+ async getRelations(model, widgetName, modelId) {
81
81
  let widgetItems = [];
82
- for (const item of items) {
83
- //TODO refactor CRUD functions for DataAccessor usage
84
- let file = (await this.adminizer.modelHandler.model.get(this.model)["_find"]({
85
- where: { id: item.id }
86
- }, { populate: [["variants", { sort: "createdAt DESC" }]] }))[0];
82
+ const fieldName = this.adminizer.ormAdapters[0].ormType === 'sequelize' ? 'fileRef' : 'file';
83
+ let files = await this.adminizer.modelHandler.model.get(this.modelAssoc)['_find']({
84
+ where: {
85
+ model: model.toLowerCase(),
86
+ widgetName: widgetName,
87
+ modelId: +modelId
88
+ },
89
+ sort: "sortOrder ASC"
90
+ }, { populate: [[fieldName, {}]] });
91
+ for (const file of files) {
87
92
  widgetItems.push({
88
- id: file.id,
89
- mimeType: file.mimeType,
90
- url: file.url,
91
- variants: file.variants,
93
+ id: file[fieldName].id,
94
+ mimeType: file[fieldName].mimeType,
95
+ url: file[fieldName].url,
96
+ variants: []
92
97
  });
93
98
  }
94
99
  return widgetItems;
@@ -4,6 +4,7 @@ import sizeOf from "image-size";
4
4
  import sharp from "sharp";
5
5
  import * as fs from 'fs';
6
6
  import * as path from 'path';
7
+ import * as process from "node:process";
7
8
  export class ImageItem extends File {
8
9
  type = "image";
9
10
  model = "mediamanagerap";
@@ -55,7 +56,7 @@ export class ImageItem extends File {
55
56
  parent: null,
56
57
  mimeType: file.mimetype,
57
58
  size: file.size,
58
- path: file.path,
59
+ path: `${this.fileStoragePath}/${this.urlPathPrefix}/${filename}`,
59
60
  group: group,
60
61
  tag: "origin",
61
62
  filename: origFileName,
@@ -64,7 +65,7 @@ export class ImageItem extends File {
64
65
  await this.createMeta(parent.id);
65
66
  await this.addFileMeta(file.path, parent.id);
66
67
  // create file variants
67
- if (Object.keys(this.imageSizes).length) {
68
+ if (Object.keys(this.imageSizes).length && file.mimetype !== 'image/svg+xml') {
68
69
  await this.createVariants(file, parent, filename, group);
69
70
  }
70
71
  // TODO refactor CRUD functions for DataAccessor usage
@@ -148,7 +149,7 @@ export class ImageItem extends File {
148
149
  }
149
150
  async resizeImage(input, output, width, height) {
150
151
  // Get the directory from the output path
151
- const outputDir = path.dirname(output);
152
+ const outputDir = `${process.cwd()}/${path.dirname(output)}`;
152
153
  // Check if the directory exists, and create it if it doesn't
153
154
  if (!fs.existsSync(outputDir)) {
154
155
  fs.mkdirSync(outputDir, { recursive: true });
@@ -209,7 +210,7 @@ export class TextItem extends ImageItem {
209
210
  parent: null,
210
211
  mimeType: file.mimetype,
211
212
  size: file.size,
212
- path: file.path,
213
+ path: `${this.fileStoragePath}/${filename}`,
213
214
  group: group,
214
215
  filename: origFileName,
215
216
  tag: "origin",
@@ -1,6 +1,6 @@
1
1
  import { AbstractMediaManager } from "./AbstractMediaManager";
2
2
  export declare class MediaManagerHandler {
3
- private static managers;
4
- static add(manager: AbstractMediaManager): void;
5
- static get(id: string): AbstractMediaManager;
3
+ private managers;
4
+ add(manager: AbstractMediaManager): void;
5
+ get(id: string): AbstractMediaManager;
6
6
  }
@@ -1,10 +1,10 @@
1
1
  import { Adminizer } from "../Adminizer";
2
2
  export class MediaManagerHandler {
3
- static managers = [];
4
- static add(manager) {
3
+ managers = [];
4
+ add(manager) {
5
5
  this.managers.push(manager);
6
6
  }
7
- static get(id) {
7
+ get(id) {
8
8
  let instance = this.managers.find(e => e.id === id);
9
9
  /**
10
10
  * ✨ We magically get one
@@ -1,3 +1,4 @@
1
+ import { Adminizer } from "../Adminizer";
1
2
  export declare class MediaManagerThumb {
2
- static getThumb(id: string, managerId: string): Promise<Buffer<ArrayBufferLike>>;
3
+ static getThumb(id: string, managerId: string, adminizer: Adminizer): Promise<Buffer<ArrayBufferLike>>;
3
4
  }
@@ -1,10 +1,9 @@
1
1
  import sharp from "sharp";
2
2
  import { promises as fs } from 'fs';
3
- import { MediaManagerHandler } from "./MediaManagerHandler";
4
3
  export class MediaManagerThumb {
5
- static async getThumb(id, managerId) {
4
+ static async getThumb(id, managerId, adminizer) {
6
5
  const fileExists = async (path) => !!(await fs.stat(path).catch(e => false));
7
- const manager = MediaManagerHandler.get(managerId);
6
+ const manager = adminizer.mediaManagerHandler.get(managerId);
8
7
  const path = await manager.getOrigin(id);
9
8
  const baseThumbPath = `${process.cwd()}/.tmp/thumbs`;
10
9
  await fs.mkdir(baseThumbPath, { recursive: true });
@@ -13,7 +12,7 @@ export class MediaManagerThumb {
13
12
  return await fs.readFile(thumb);
14
13
  }
15
14
  else {
16
- await sharp(path)
15
+ await sharp(`${process.cwd()}/${path}`)
17
16
  .resize({ width: 150, height: 150 })
18
17
  .toFile(thumb);
19
18
  return await fs.readFile(thumb);
@@ -11,19 +11,24 @@ type PostParams = Record<string, string | number | boolean | object | string[] |
11
11
  export declare function randomFileName(filenameOrig: string, type: string, prefix: boolean): string;
12
12
  /**
13
13
  * Save media manager relations to database.
14
+ * @param adminizer
14
15
  * @param fields
15
16
  * @param reqData
16
17
  * @param model
17
18
  * @param recordId
18
19
  */
19
- export declare function saveRelationsMediaManager(fields: Fields, reqData: PostParams, model: string, recordId: string): Promise<void>;
20
+ export declare function saveRelationsMediaManager(adminizer: Adminizer, fields: Fields, reqData: PostParams, model: string, recordId: number): Promise<void>;
20
21
  /**
21
22
  * Get realtions
23
+ * @param adminizer
22
24
  * @param data
25
+ * @param model
26
+ * @param widgetName
23
27
  */
24
- export declare function getRelationsMediaManager(data: MediaManagerWidgetJSON): Promise<import("../AbstractMediaManager").MediaManagerWidgetClientItem[]>;
28
+ export declare function getRelationsMediaManager(adminizer: Adminizer, data: MediaManagerWidgetJSON): Promise<import("../AbstractMediaManager").MediaManagerWidgetClientItem[]>;
25
29
  /**
26
30
  * Delate Ralations
31
+ * @param adminizer
27
32
  * @param model
28
33
  * @param record
29
34
  */