adminizer 4.1.0-build.16 → 4.1.0-build.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.
@@ -376,10 +376,11 @@ export class DataAccessor {
376
376
  const relation = modelAttributes[accessField];
377
377
  if (relation && ['userap', 'groupap'].includes(relation.model.toLowerCase())) {
378
378
  if (relation.model.toLowerCase() === 'userap') {
379
- updatedRecord[accessField] = this.user.id;
379
+ if (!this.user.isAdministrator) {
380
+ updatedRecord[accessField] = this.user.id;
381
+ }
380
382
  }
381
383
  else if (relation.model.toLowerCase() === 'groupap') {
382
- // Works only for users with only one group, later it can be resolved with group weight
383
384
  const userGroups = this.user.groups || [];
384
385
  if (userGroups.length === 1) {
385
386
  updatedRecord[accessField] = userGroups[0].id;
@@ -431,6 +432,7 @@ export class DataAccessor {
431
432
  updatedRecord[field] = intermediateRecord.id;
432
433
  }
433
434
  }
435
+ console.log(updatedRecord, "<<<<<<<<<<<<<<<<<<<,");
434
436
  return updatedRecord;
435
437
  }
436
438
  }
@@ -3,6 +3,64 @@ import { AbstractAdapter, AbstractModel } from "../AbstractModel";
3
3
  import path from "path";
4
4
  import fs from "fs";
5
5
  import { pathToFileURL } from "url";
6
+ function generateAssociationsFromSchema(models, schemas) {
7
+ for (const modelName in schemas) {
8
+ const schema = schemas[modelName];
9
+ const model = models[modelName];
10
+ if (!model)
11
+ continue;
12
+ for (const fieldName in schema) {
13
+ const field = schema[fieldName];
14
+ if (field.collection && field.via) {
15
+ const targetModel = models[field.collection];
16
+ const targetSchema = schemas[field.collection];
17
+ const inverseField = targetSchema?.[field.via];
18
+ const throughTableName = [modelName, field.collection].sort().join("");
19
+ // 💡 M:N связь
20
+ if (inverseField && inverseField.collection === modelName) {
21
+ model.belongsToMany(targetModel, {
22
+ through: throughTableName,
23
+ as: fieldName,
24
+ foreignKey: `${modelName}Id`,
25
+ otherKey: `${field.collection}Id`
26
+ });
27
+ }
28
+ // 💡 O:M связь (один ко многим)
29
+ else {
30
+ model.hasMany(targetModel, {
31
+ as: fieldName,
32
+ foreignKey: `${modelName}Id`,
33
+ });
34
+ targetModel.belongsTo(model, {
35
+ as: field.via,
36
+ foreignKey: `${modelName}Id`,
37
+ });
38
+ }
39
+ }
40
+ // 💡 O:1 или 1:1 (belongsTo)
41
+ if (field.model) {
42
+ const targetModel = models[field.model];
43
+ if (!targetModel)
44
+ continue;
45
+ // Avoid naming collision by making FK explicit: `${fieldName}Id`
46
+ const foreignKey = `${fieldName}Id`;
47
+ const alias = fieldName;
48
+ // Если поле уже существует — избегаем конфликта
49
+ if (model.rawAttributes[alias]) {
50
+ model.belongsTo(targetModel, {
51
+ as: alias,
52
+ foreignKey,
53
+ });
54
+ }
55
+ else {
56
+ model.belongsTo(targetModel, {
57
+ foreignKey: alias, // если нет конфликта, можно использовать alias как FK
58
+ });
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
6
64
  function resolveType(type) {
7
65
  const sqlType = typeof type.toString === "function"
8
66
  ? type.toString().toLowerCase()
@@ -401,19 +459,22 @@ export class SequelizeAdapter extends AbstractAdapter {
401
459
  static async registerSystemModels(sequelize) {
402
460
  const modelsDir = path.resolve(import.meta.dirname, "../../../../models");
403
461
  let files = fs.readdirSync(modelsDir).filter(f => f.endsWith(".js"));
404
- // Try with ts files (exclude .d.ts)
405
462
  if (!files.length) {
406
463
  files = fs.readdirSync(modelsDir).filter(f => f.endsWith(".ts") && !f.endsWith(".d.ts"));
407
464
  }
408
465
  if (!files.length) {
409
466
  throw `Model files not found in dir ${modelsDir}`;
410
467
  }
468
+ const schemas = {};
411
469
  for (const file of files) {
412
470
  const modelName = path.basename(file, path.extname(file));
413
471
  const filePath = path.resolve(modelsDir, file);
414
- const definition = (await import(pathToFileURL(filePath).href)).default;
472
+ const mod = await import(pathToFileURL(filePath).href);
473
+ const definition = mod.default;
474
+ schemas[modelName] = definition;
415
475
  generateSequelizeModel(sequelize, modelName, definition);
416
476
  }
477
+ generateAssociationsFromSchema(sequelize.models, schemas);
417
478
  await sequelize.sync();
418
479
  }
419
480
  }
@@ -8,7 +8,7 @@ declare const _default: {
8
8
  primaryKey: boolean;
9
9
  required: boolean;
10
10
  };
11
- parent: {
11
+ parentMedia: {
12
12
  model: string;
13
13
  };
14
14
  variants: {
@@ -6,7 +6,8 @@ export default {
6
6
  primaryKey: true,
7
7
  required: true
8
8
  },
9
- parent: {
9
+ // WARN!!! renamed from parent is confict
10
+ parentMedia: {
10
11
  model: "MediaManagerAP"
11
12
  },
12
13
  variants: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "adminizer",
3
3
  "type": "module",
4
- "version": "4.1.0-build.16",
4
+ "version": "4.1.0-build.17",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "test": "vitest --reporter verbose",
@@ -51,6 +51,7 @@
51
51
  "devDependencies": {
52
52
  "@babel/plugin-proposal-decorators": "^7.27.1",
53
53
  "@ckeditor/ckeditor5-react": "^9.5.0",
54
+ "@eslint/compat": "^1.2.9",
54
55
  "@faker-js/faker": "^9.7.0",
55
56
  "@handsontable/react": "^15.2.0",
56
57
  "@inertiajs/react": "^2.0.0",
@@ -61,14 +62,14 @@
61
62
  "@radix-ui/react-dialog": "^1.1.7",
62
63
  "@radix-ui/react-dropdown-menu": "^2.1.6",
63
64
  "@radix-ui/react-label": "^2.1.2",
64
- "@radix-ui/react-popover": "^1.1.7",
65
65
  "@radix-ui/react-menubar": "^1.1.12",
66
+ "@radix-ui/react-popover": "^1.1.7",
66
67
  "@radix-ui/react-portal": "^1.1.6",
67
- "@radix-ui/react-switch": "^1.2.4",
68
68
  "@radix-ui/react-select": "^2.1.6",
69
69
  "@radix-ui/react-separator": "^1.1.3",
70
70
  "@radix-ui/react-slider": "^1.2.3",
71
71
  "@radix-ui/react-slot": "^1.2.0",
72
+ "@radix-ui/react-switch": "^1.2.4",
72
73
  "@radix-ui/react-tooltip": "^1.1.8",
73
74
  "@tailwindcss/vite": "^4.0.15",
74
75
  "@tanstack/react-table": "^8.21.2",
@@ -91,12 +92,14 @@
91
92
  "@types/sprintf-js": "^1.1.4",
92
93
  "@types/uuid": "^10.0.0",
93
94
  "@types/waterline": "^0.13.9",
95
+ "@typescript-eslint/eslint-plugin": "^8.32.1",
94
96
  "@vitejs/plugin-react": "^4.3.4",
95
97
  "babel-plugin-react-compiler": "^19.0.0-beta-e993439-20250405",
96
98
  "ckeditor5": "^45.0.0",
97
99
  "class-variance-authority": "^0.7.1",
98
100
  "clsx": "^2.1.1",
99
101
  "cross-env": "^7.0.3",
102
+ "eslint": "^9.26.0",
100
103
  "handsontable": "^15.2.0",
101
104
  "json-schema": "^0.4.0",
102
105
  "leaflet": "^1.9.4",
@@ -33,7 +33,6 @@ export default function bindReqFunctions(adminizer) {
33
33
  if (res.locals) {
34
34
  req.i18n.registerMethods(res.locals, req);
35
35
  }
36
- // TODO: I made it quickly, you need to spread for architecture to different files, or re -ize this file to a girlfriend
37
36
  // NOTE: This is here because inertia should receive data to routes
38
37
  // JWT token
39
38
  const cookies = parse(req.headers.cookie || '');