adminizer 4.1.0-build.2 → 4.1.0-build.21

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 (197) hide show
  1. package/Readme.md +11 -1
  2. package/assets/{VanillaJSONEditor-FUe77pIA.js → VanillaJSONEditor-D-Lx670g.js} +1 -1
  3. package/assets/add-BP_u3Tjl.js +1 -0
  4. package/assets/add-form-nffmiYTh.js +1 -0
  5. package/assets/add-group-D4vcHlm-.js +1 -0
  6. package/assets/{add-group-form-dzadPSfL.js → add-group-form-gNJW11-q.js} +1 -1
  7. package/assets/add-user-DWh3Nas0.js +1 -0
  8. package/assets/add-user-form-BJ0FsZYJ.js +1 -0
  9. package/assets/{app-DMmad2-f.css → app-C3OdwOHy.css} +1 -1
  10. package/assets/{app-layout-D1m9Kvxq.js → app-layout-DYsRFUuP.js} +1 -1
  11. package/assets/{app-shell-BWMRMkHM.js → app-shell-Dd9Eknik.js} +1 -1
  12. package/assets/app-sidebar-BOmu6-Sl.js +1 -0
  13. package/assets/{app-sidebar-header-DLAFi13E.js → app-sidebar-header-CoXSzWxk.js} +1 -1
  14. package/assets/app.js +2 -2
  15. package/assets/{breadcrumbs-CQNon4Vl.js → breadcrumbs-BmAq4fHT.js} +1 -1
  16. package/assets/{button-CQ9t1kLz.js → button-C9B_5Jf_.js} +1 -1
  17. package/assets/{checkbox-W0nGAXIj.js → checkbox-Fg27sL_1.js} +1 -1
  18. package/assets/{compiler-runtime-tM4jBQ-T.js → compiler-runtime-hB6dAw2d.js} +1 -1
  19. package/assets/dashboard-BOltB2Hq.css +1 -0
  20. package/assets/dashboard-Ddh74NBQ.js +3 -0
  21. package/assets/{date-picker-B__dVVqj.js → date-picker-DI1cCO7K.js} +1 -1
  22. package/assets/{dropdown-menu-SEBnEIiL.js → dropdown-menu-Bhj17ENm.js} +1 -1
  23. package/assets/{field-renderer-CapylJU9.js → field-renderer-DVHZF6HS.js} +3 -3
  24. package/assets/form-BgWdwvz1.js +1 -0
  25. package/assets/form-DgtErfln.js +1 -0
  26. package/assets/{geo-json-CwteYDGB.js → geo-json-BjiyTtMu.js} +1 -1
  27. package/assets/{handsontable-BCnjOpBr.js → handsontable-4mjU_b0n.js} +1 -1
  28. package/assets/home-CHntBHJa.js +2 -0
  29. package/assets/{icon-Bz9BMaD0.js → icon-Dt0vBgDO.js} +1 -1
  30. package/assets/index-B8BS9wMC.js +1 -0
  31. package/assets/{index-DEk3sC8d.js → index-BKCgnGj_.js} +1 -1
  32. package/assets/{index-C0SL3SHw.js → index-BykbU6Ee.js} +1 -1
  33. package/assets/index-CaJgc5EZ.js +1 -0
  34. package/assets/{index-BcE9FUM6.js → index-Cgp8OfuI.js} +1 -1
  35. package/assets/{index-DTRTjOmh.js → index-Cw5o84pO.js} +1 -1
  36. package/assets/{init-user-D9mW-g14.js → init-user-JfCKJ5Ce.js} +1 -1
  37. package/assets/{input-DF7Ue23C.js → input-CvRbIbk4.js} +1 -1
  38. package/assets/{input-error-BBygona6.js → input-error-DMK7cAt7.js} +1 -1
  39. package/assets/{label-Z506NKsW.js → label-CSLFe9Bz.js} +1 -1
  40. package/assets/list-B2Oa5O_Q.js +1 -0
  41. package/assets/{list-table-DB1sEQLF.js → list-table-DA9MhywL.js} +5 -5
  42. package/assets/{login-DrGaTWhY.js → login-DQwGtdis.js} +1 -1
  43. package/assets/manifest.json +491 -470
  44. package/assets/{material-icon-CItZiB53.js → material-icon-BJg8o_fs.js} +1 -1
  45. package/assets/module-DWXp59Vg.js +1 -0
  46. package/assets/{monaco-editor-DqAqwxw4.js → monaco-editor-CJs0_GlD.js} +1 -1
  47. package/assets/{multi-select-oabtVhUP.js → multi-select-BvRpAW8r.js} +1 -1
  48. package/assets/{nav-footer-CM-yHiRs.js → nav-footer-Bs4dmN1d.js} +1 -1
  49. package/assets/{nav-main-Q3xofGRT.js → nav-main-Bq3IMk4C.js} +1 -1
  50. package/assets/{nav-user-Ds8i0Pa2.js → nav-user-CbB22J5O.js} +1 -1
  51. package/assets/{pagination-render-B57pOpFy.js → pagination-render-DuXDDbC_.js} +1 -1
  52. package/assets/{popover-I249Gg2O.js → popover-DtoGI2b1.js} +1 -1
  53. package/assets/{register-C9FQIDtS.js → register-BSogVF0h.js} +1 -1
  54. package/assets/{select-D1N8zRPY.js → select-BWepUw-9.js} +1 -1
  55. package/assets/{sidebar-4D-sX2l4.js → sidebar-CAHsHdjM.js} +2 -2
  56. package/assets/skeleton-COOcAA8f.js +1 -0
  57. package/assets/{sonner-Dzckw3U3.js → sonner-BI0IFOQN.js} +1 -1
  58. package/assets/{toast-editor-FbrFd1ft.js → toast-editor-CMK7QtF1.js} +1 -1
  59. package/assets/{tooltip-D2ehgLlB.js → tooltip-DHwpLKOI.js} +1 -1
  60. package/assets/{use-appearance-Co6mO0dV.js → use-appearance-DRfIqTgw.js} +1 -1
  61. package/assets/{use-window-size-B8l6Bpkf.js → use-window-size-h0Sh_NvX.js} +1 -1
  62. package/assets/{user-info-DBYoAJYJ.js → user-info-DFrmpJ4y.js} +1 -1
  63. package/assets/{user-menu-content-qkvdkUVd.js → user-menu-content-DPXQdERj.js} +1 -1
  64. package/assets/welcome-B4WCIXKf.js +1 -0
  65. package/controllers/add.js +3 -3
  66. package/controllers/addGroup.js +2 -4
  67. package/controllers/addUser.js +4 -6
  68. package/controllers/catalog/Catalog.js +2 -2
  69. package/controllers/catalog/FrontentCatalogAdapter.js +1 -2
  70. package/controllers/ckeditorUpload.js +2 -3
  71. package/controllers/dashboard.js +16 -2
  72. package/controllers/edit.js +3 -4
  73. package/controllers/editGroup.js +2 -4
  74. package/controllers/editUser.js +3 -5
  75. package/controllers/form.js +2 -3
  76. package/controllers/getAllWidgets.js +3 -3
  77. package/controllers/initUser.js +1 -2
  78. package/controllers/list.js +5 -5
  79. package/controllers/login.js +31 -15
  80. package/controllers/media-manager/mediaManagerAdapter.js +1 -2
  81. package/controllers/media-manager/mediaManagerApi.js +2 -2
  82. package/controllers/navigation/edit.js +2 -2
  83. package/controllers/register.js +1 -4
  84. package/controllers/remove.js +3 -3
  85. package/controllers/timezones.js +1 -1
  86. package/controllers/view.js +3 -3
  87. package/controllers/welcome.js +1 -1
  88. package/controllers/widgets/Action.js +2 -2
  89. package/controllers/widgets/Custom.js +2 -2
  90. package/controllers/widgets/Info.js +2 -2
  91. package/controllers/widgets/switch.js +2 -2
  92. package/controllers/widgetsDB.js +5 -5
  93. package/helpers/accessRightsHelper.d.ts +6 -2
  94. package/helpers/accessRightsHelper.js +21 -3
  95. package/helpers/configHelper.js +2 -1
  96. package/helpers/controllerHelper.js +1 -1
  97. package/helpers/fieldsHelper.d.ts +1 -1
  98. package/helpers/fieldsHelper.js +1 -1
  99. package/helpers/inertiaActionsHelper.js +1 -1
  100. package/helpers/inertiaAddHelper.d.ts +1 -1
  101. package/helpers/inertiaAddHelper.js +2 -0
  102. package/helpers/inertiaFromHelper.js +2 -0
  103. package/helpers/inertiaGroupHelper.d.ts +4 -2
  104. package/helpers/inertiaGroupHelper.js +1 -1
  105. package/helpers/inertiaListHelper.js +5 -5
  106. package/helpers/inertiaMenuHelper.js +2 -2
  107. package/helpers/inertiaUserHelper.d.ts +7 -1
  108. package/helpers/inertiaUserHelper.js +5 -1
  109. package/helpers/menuHelper.d.ts +2 -1
  110. package/helpers/menuHelper.js +8 -2
  111. package/index.d.ts +4 -1
  112. package/index.js +7 -1
  113. package/interfaces/adminpanelConfig.d.ts +19 -23
  114. package/interfaces/global.d.ts +8 -26
  115. package/interfaces/types.d.ts +1 -1
  116. package/lib/Adminizer.d.ts +2 -0
  117. package/lib/Adminizer.js +26 -6
  118. package/lib/catalog/AbstractCatalog.js +0 -1
  119. package/lib/catalog/Navigation.js +6 -7
  120. package/lib/datatable/NodeTable.js +2 -5
  121. package/lib/inertia/inertiaAdapter.js +0 -1
  122. package/lib/media-manager/AbstractMediaManager.d.ts +2 -2
  123. package/lib/media-manager/AbstractMediaManager.js +1 -1
  124. package/lib/media-manager/Items.js +0 -3
  125. package/lib/v4/DataAccessor.d.ts +5 -2
  126. package/lib/v4/DataAccessor.js +31 -14
  127. package/lib/v4/I18n.js +2 -0
  128. package/lib/v4/POWCaptcha.js +0 -1
  129. package/lib/v4/PolicyManager.js +0 -1
  130. package/lib/v4/helper/jwt.d.ts +10 -0
  131. package/lib/v4/helper/jwt.js +18 -0
  132. package/lib/v4/model/AbstractModel.d.ts +5 -1
  133. package/lib/v4/model/AbstractModel.js +2 -3
  134. package/lib/v4/model/ModelHandler.js +0 -1
  135. package/lib/v4/model/adapter/sequelize.d.ts +11 -2
  136. package/lib/v4/model/adapter/sequelize.js +451 -118
  137. package/lib/v4/model/adapter/waterline.js +5 -3
  138. package/lib/widgets/abstractAction.d.ts +1 -1
  139. package/lib/widgets/abstractCustom.d.ts +27 -12
  140. package/lib/widgets/abstractCustom.js +8 -2
  141. package/lib/widgets/abstractInfo.d.ts +1 -1
  142. package/lib/widgets/abstractInfo.js +1 -1
  143. package/lib/widgets/abstractLink.d.ts +1 -0
  144. package/lib/widgets/abstractSwitch.d.ts +1 -1
  145. package/lib/widgets/abstractWidgetBase.d.ts +1 -1
  146. package/lib/widgets/widgetHandler.d.ts +27 -3
  147. package/lib/widgets/widgetHandler.js +25 -25
  148. package/models/GroupAP.d.ts +8 -0
  149. package/models/NavigationAP.d.ts +5 -0
  150. package/models/UserAP.d.ts +24 -2
  151. package/models/UserAP.js +2 -2
  152. package/package.json +23 -11
  153. package/policies/checkAuth.js +4 -3
  154. package/policies/setLocale.js +2 -2
  155. package/system/Router.js +6 -14
  156. package/system/bindAccessRights.js +0 -4
  157. package/system/bindAuthorization.js +4 -5
  158. package/system/bindDev.js +1 -0
  159. package/system/bindInertia.js +9 -9
  160. package/system/bindMediaManager.js +0 -1
  161. package/system/bindModels.js +7 -2
  162. package/system/bindNavigation.js +0 -1
  163. package/system/bindReqFunctions.js +15 -0
  164. package/translations/ru.json +17 -8
  165. package/assets/add-ZITr43GJ.js +0 -1
  166. package/assets/add-form-CYOfr0Ef.js +0 -1
  167. package/assets/add-group-B332wN8K.js +0 -1
  168. package/assets/add-user-TC-mYdsB.js +0 -1
  169. package/assets/add-user-form-y2f_1_lM.js +0 -1
  170. package/assets/app-sidebar-BCtaEFGb.js +0 -1
  171. package/assets/dashboard-BR602KhL.js +0 -1
  172. package/assets/form-DOUNk3o2.js +0 -1
  173. package/assets/form-lOKv4Qbw.js +0 -1
  174. package/assets/home-Ch6QfTIt.js +0 -2
  175. package/assets/index-Cdb9ACvz.js +0 -1
  176. package/assets/index-K81GbF6O.js +0 -1
  177. package/assets/list-Qyd7ecQH.js +0 -1
  178. package/assets/module-DBaykv8l.js +0 -1
  179. package/assets/welcome-D2adQ8EU.js +0 -1
  180. package/controllers/processInstallFinalize.d.ts +0 -1
  181. package/controllers/processInstallFinalize.js +0 -16
  182. package/controllers/processInstallStep.d.ts +0 -1
  183. package/controllers/processInstallStep.js +0 -132
  184. package/lib/installStepper/InstallStepAbstract.d.ts +0 -52
  185. package/lib/installStepper/InstallStepAbstract.js +0 -69
  186. package/lib/installStepper/finalizeStep.d.ts +0 -21
  187. package/lib/installStepper/finalizeStep.js +0 -48
  188. package/lib/installStepper/installStepper.d.ts +0 -40
  189. package/lib/installStepper/installStepper.js +0 -195
  190. package/models/MediaManagerAP.d.ts +0 -46
  191. package/models/MediaManagerAP.js +0 -45
  192. package/models/MediaManagerAssociationsAP.d.ts +0 -28
  193. package/models/MediaManagerAssociationsAP.js +0 -27
  194. package/models/MediaManagerMetaAP.d.ts +0 -22
  195. package/models/MediaManagerMetaAP.js +0 -21
  196. package/system/bindInstallStepper.d.ts +0 -2
  197. package/system/bindInstallStepper.js +0 -23
@@ -6,6 +6,10 @@ export function inertiaUserHelper(entity, req, groups, user, view = false) {
6
6
  title: req.i18n.__('Back'),
7
7
  link: entity.uri
8
8
  },
9
+ userPretend: {
10
+ label: req.i18n.__('Pretend to be a user'),
11
+ postLink: `${req.adminizer.config.routePrefix}/model/userap/login`
12
+ },
9
13
  passwordError: req.i18n.__('Values in "password" and "repeatPassword" fields should be the same'),
10
14
  btnSave: {
11
15
  title: req.i18n.__('Save')
@@ -58,7 +62,7 @@ export function inertiaUserHelper(entity, req, groups, user, view = false) {
58
62
  value: user?.locale ?? ''
59
63
  });
60
64
  }
61
- if (req.session.UserAP.isAdministrator) {
65
+ if (req.user.isAdministrator) {
62
66
  props.fields.push({
63
67
  label: req.i18n.__('Profile expires'),
64
68
  type: 'date',
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * @constructor
5
5
  */
6
+ import { UserAP } from "models/UserAP";
6
7
  import { ActionType, AdminpanelConfig, HrefConfig, ModelConfig } from "../interfaces/adminpanelConfig";
7
8
  export type MenuItem = {
8
9
  link: string;
@@ -60,5 +61,5 @@ export declare class MenuHelper {
60
61
  *
61
62
  * @returns {Array}
62
63
  */
63
- getMenuItems(): MenuItem[];
64
+ getMenuItems(user: UserAP): MenuItem[];
64
65
  }
@@ -1,3 +1,4 @@
1
+ import { GroupsAccessRightsHelper } from "./accessRightsHelper";
1
2
  export class MenuHelper {
2
3
  static config;
3
4
  constructor(config) {
@@ -98,7 +99,7 @@ export class MenuHelper {
98
99
  *
99
100
  * @returns {Array}
100
101
  */
101
- getMenuItems() {
102
+ getMenuItems(user) {
102
103
  let menus = [];
103
104
  if (MenuHelper.config.navbar.additionalLinks && MenuHelper.config.navbar.additionalLinks.length > 0) {
104
105
  MenuHelper.config.navbar.additionalLinks.forEach(function (additionalLink) {
@@ -118,7 +119,12 @@ export class MenuHelper {
118
119
  }
119
120
  if (MenuHelper.config.models) {
120
121
  Object.entries(MenuHelper.config.models).forEach(function ([key, val]) {
121
- if (!val.hide) {
122
+ const hide = typeof val.navbar?.visible === 'boolean'
123
+ ? !val.navbar.visible
124
+ : val.navbar?.groupsAccessRights
125
+ ? !GroupsAccessRightsHelper.hasAccess(user, val.navbar.groupsAccessRights)
126
+ : false;
127
+ if (!hide) {
122
128
  if (val.tools && val.tools.length > 0 && val.tools[0].id !== "overview") {
123
129
  val.tools.unshift({
124
130
  id: "overview",
package/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from "./helpers/configHelper";
2
2
  export * from "./helpers/accessRightsHelper";
3
- export * from "./lib/installStepper/installStepper";
4
3
  export * from "./lib/widgets/widgetHandler";
5
4
  export * from "./lib/catalog/CatalogHandler";
6
5
  export * from "./lib/media-manager/MediaManagerHandler";
@@ -8,4 +7,8 @@ export * from "./interfaces/adminpanelConfig";
8
7
  export * from "./lib/v4/model/AbstractModel";
9
8
  export * from "./lib/v4/model/adapter/waterline";
10
9
  export * from "./lib/v4/model/adapter/typeorm";
10
+ export * from "./lib/v4/model/adapter/sequelize";
11
11
  export * from "./lib/Adminizer";
12
+ export * from "./models/GroupAP";
13
+ export * from "./models/UserAP";
14
+ export * from "./models/NavigationAP";
package/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from "./helpers/configHelper";
2
2
  export * from "./helpers/accessRightsHelper";
3
- export * from "./lib/installStepper/installStepper";
4
3
  export * from "./lib/widgets/widgetHandler";
5
4
  export * from "./lib/catalog/CatalogHandler";
6
5
  export * from "./lib/media-manager/MediaManagerHandler";
@@ -8,4 +7,11 @@ export * from "./interfaces/adminpanelConfig";
8
7
  export * from "./lib/v4/model/AbstractModel";
9
8
  export * from "./lib/v4/model/adapter/waterline";
10
9
  export * from "./lib/v4/model/adapter/typeorm";
10
+ export * from "./lib/v4/model/adapter/sequelize";
11
11
  export * from "./lib/Adminizer";
12
+ export * from "./models/GroupAP";
13
+ export * from "./models/UserAP";
14
+ // export * from "./models/MediaManagerAP"
15
+ // export * from "./models/MediaManagerAssociationsAP"
16
+ // export * from "./models/MediaManagerMetaAP"
17
+ export * from "./models/NavigationAP";
@@ -1,6 +1,8 @@
1
1
  import { MaterialIcon } from "./MaaterialIcons";
2
2
  import { EditorOptions } from "@toast-ui/editor/types/editor";
3
3
  import { GridSettings as HandsontableSettings } from "handsontable/settings";
4
+ import { GroupAP } from "models/GroupAP";
5
+ import { UserAP } from "models/UserAP";
4
6
  export type AdminpanelIcon = MaterialIcon;
5
7
  export type FieldsTypes = "string" | "password" | "date" | "datetime" | "time" | "integer" | "number" | "float" | "color" | "email" | "month" | "week" | "range" | "boolean" | "binary" | "text" | "longtext" | "mediumtext" | "ckeditor" | "wysiwyg" | "texteditor" | "word" | 'tui' | 'tuieditor' | 'toast-ui' | "jsoneditor" | "json" | "array" | "object" | "ace" | "code" | "html" | "xml" | "aceeditor" | "menu" | "schedule" | "worktime" | "association" | "association-many" | "select" | "select-many" | "table" | "geojson" | "mediamanager" |
6
8
  /**
@@ -121,23 +123,6 @@ export interface AdminpanelConfig {
121
123
  * */
122
124
  set?: SetFunction;
123
125
  };
124
- /**
125
- * Wizards
126
- * */
127
- installStepper?: {
128
- path: string;
129
- data: {
130
- [key: string]: FieldsModels;
131
- };
132
- /**
133
- * Custom getter
134
- * */
135
- get?: GetFunction;
136
- /**
137
- * Custom setter
138
- * */
139
- set?: SetFunction;
140
- };
141
126
  /**
142
127
  * Prime administrator login credentials
143
128
  * */
@@ -199,9 +184,18 @@ export interface ModelConfig {
199
184
  * */
200
185
  model: string;
201
186
  /**
202
- * Hide entity in left navbar
187
+ * If the field is not definitely, then it will appear in Navbar
203
188
  * */
204
- hide?: boolean;
189
+ navbar?: {
190
+ /**
191
+ * @default true
192
+ */
193
+ visible?: boolean;
194
+ /**
195
+ * For which it will be shown if not established will be shown to all groups who have the rights to read
196
+ */
197
+ groupsAccessRights?: string[];
198
+ };
205
199
  /**
206
200
  * Entity fields configuration
207
201
  * */
@@ -264,12 +258,12 @@ export interface ModelConfig {
264
258
  * May be association or association-many to UserAP or GroupAP */
265
259
  userAccessRelation?: {
266
260
  field: string;
267
- via: string;
261
+ via?: string;
268
262
  } | string;
269
263
  userAccessRelationCallback?: (userWithGroups: UserWithGroups, record: any) => boolean;
270
264
  }
271
- type UserWithGroups = ModelsAP["UserAP"] & {
272
- groups: ModelsAP["GroupAP"][];
265
+ type UserWithGroups = UserAP & {
266
+ groups: GroupAP[];
273
267
  };
274
268
  export interface FieldsForms {
275
269
  [key: string]: FormFieldConfig;
@@ -316,6 +310,8 @@ export interface BaseFieldConfig {
316
310
  disabled?: boolean;
317
311
  /** Show as required element HTML */
318
312
  required?: boolean;
313
+ /** show or hode element, default `true` */
314
+ visible?: boolean;
319
315
  }
320
316
  export interface TuiEditorFieldConfig extends BaseFieldConfig {
321
317
  type: 'tui' | 'tuieditor' | 'toast-ui';
@@ -403,7 +399,7 @@ export interface HrefConfig {
403
399
  /**
404
400
  * Only for view, controller still uses his own access rights token
405
401
  * */
406
- accessRightsToken?: string;
402
+ accessRightsToken?: string | undefined;
407
403
  /**
408
404
  * For menu items only
409
405
  * */
@@ -4,15 +4,10 @@ import multer from "multer";
4
4
  import { I18n } from "../lib/v4/I18n";
5
5
  import { Inertia } from "../lib/inertia/inertiaAdapter";
6
6
  import { Flash } from "../lib/inertia/flash";
7
+ import { UserAP } from "models/UserAP";
7
8
  declare global {
9
+ /** @deprecated use import from TS model decalration */
8
10
  type ModelsAP = {
9
- GroupAP: {
10
- id?: number;
11
- name: string;
12
- description?: string;
13
- tokens?: string[];
14
- users?: ModelsAP["UserAP"][];
15
- };
16
11
  MediaManagerAP: {
17
12
  id?: string;
18
13
  parent?: ModelsAP["MediaManagerAP"];
@@ -48,36 +43,20 @@ declare global {
48
43
  label: string;
49
44
  tree: any;
50
45
  };
51
- UserAP: {
52
- id?: number;
53
- login?: string;
54
- fullName?: string;
55
- email?: string;
56
- passwordHashed?: string;
57
- password?: string;
58
- timezone?: string;
59
- expires?: string;
60
- locale?: string;
61
- isDeleted?: boolean;
62
- isActive?: boolean;
63
- isAdministrator?: boolean;
64
- groups?: ModelsAP["GroupAP"][];
65
- widgets?: any;
66
- isConfirmed?: boolean;
67
- };
68
46
  };
69
47
  type reqSession = {
70
48
  flashMessages: Record<string, string[]>;
71
49
  xInertiaCurrentComponent: string | undefined;
72
- UserAP: ModelsAP["UserAP"];
50
+ UserAP: UserAP;
73
51
  messages: {
74
52
  adminError: string[];
75
53
  adminSuccess: string[];
76
54
  };
77
- adminPretender?: ModelsAP["UserAP"];
55
+ userPretended?: UserAP;
78
56
  };
79
57
  type FlashMessages = 'info' | 'error' | 'success' | string;
80
58
  type ReqType = Request & {
59
+ user: UserAP;
81
60
  Inertia: Inertia;
82
61
  flash: Flash<FlashMessages>;
83
62
  session: reqSession;
@@ -96,6 +75,9 @@ declare global {
96
75
  i18n: I18n;
97
76
  };
98
77
  type ResType = Response & {
78
+ /**
79
+ * @deprecated // TODO delete after finish catalog
80
+ */
99
81
  viewAdmin(specifiedPath: string, locals?: any, cb_view?: Function): void;
100
82
  };
101
83
  type MiddlewareType = (req: ReqType, res: ResType, next: NextFunction) => void;
@@ -1,6 +1,6 @@
1
1
  import { AbstractModel } from "../lib/v4/model/AbstractModel";
2
2
  import { ModelConfig } from "./adminpanelConfig";
3
- export type EntityType = "form" | "model" | "wizard";
3
+ export type EntityType = "form" | "model";
4
4
  export interface Entity {
5
5
  name: string;
6
6
  config?: ModelConfig;
@@ -24,8 +24,10 @@ export declare class Adminizer {
24
24
  widgetHandler: WidgetHandler;
25
25
  vite: ViteDevServer;
26
26
  controlsHandler: ControlsHandler;
27
+ jwtSecret: string;
27
28
  static logger: winston.Logger;
28
29
  constructor(ormAdapters: AbstractAdapter[]);
30
+ getMiddleware(): (req: any, res: any) => void;
29
31
  /**
30
32
  * Vite middleware
31
33
  * @protected
package/lib/Adminizer.js CHANGED
@@ -29,6 +29,7 @@ import { bindInertia } from "../system/bindInertia";
29
29
  import { MenuHelper } from "../helpers/menuHelper";
30
30
  import { bindControls } from "../system/bindControls";
31
31
  import { ControlsHandler } from "./controls/ControlsHandler";
32
+ import { v4 as uuid } from "uuid";
32
33
  export class Adminizer {
33
34
  app;
34
35
  config;
@@ -42,8 +43,9 @@ export class Adminizer {
42
43
  widgetHandler;
43
44
  vite;
44
45
  controlsHandler;
46
+ jwtSecret = process.env.JWT_SECRET ?? uuid();
45
47
  static logger = winston.createLogger({
46
- level: "info",
48
+ level: process.env.LOG_LEVEL ?? "debug",
47
49
  format: winston.format.combine(winston.format.timestamp(), winston.format.printf(({ timestamp, level, message, ...meta }) => {
48
50
  const metaString = Object.keys(meta).length ? JSON.stringify(meta) : "";
49
51
  return `[${timestamp}] ${level.toUpperCase()}: ${message} ${metaString}`;
@@ -58,6 +60,21 @@ export class Adminizer {
58
60
  this._emitter = new EventEmitter();
59
61
  this.ormAdapters = ormAdapters;
60
62
  }
63
+ getMiddleware() {
64
+ return (req, res) => {
65
+ this.app(req, res, (err) => {
66
+ if (err) {
67
+ console.error("Error in Adminizer", err);
68
+ res.writeHead(500, { 'Content-Type': 'text/plain' });
69
+ res.end('Internal Server Error');
70
+ }
71
+ else {
72
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
73
+ res.end('Route Not Found in Adminizer');
74
+ }
75
+ });
76
+ };
77
+ }
61
78
  /**
62
79
  * Vite middleware
63
80
  * @protected
@@ -76,6 +93,9 @@ export class Adminizer {
76
93
  async init(config) {
77
94
  // set cookie parser
78
95
  this.app.use(cookieParser());
96
+ if (!config || Object.keys(config).length === 0) {
97
+ Adminizer.log.warn(`Adminizer init > Adminizer config is emtpy`);
98
+ }
79
99
  // Set vite middleware
80
100
  const isViteDev = process.env.VITE_ENV === "dev";
81
101
  if (isViteDev)
@@ -105,7 +125,6 @@ export class Adminizer {
105
125
  set: configForms.set ?? defaultForms.set
106
126
  }
107
127
  };
108
- // console.log("CONFIG", this.config)
109
128
  this.modelHandler = new ModelHandler();
110
129
  await bindModels(this);
111
130
  await bindForms(this);
@@ -113,17 +132,18 @@ export class Adminizer {
113
132
  this.policyManager = new PolicyManager(this);
114
133
  await this.policyManager.loadPolicies();
115
134
  this.accessRightsHelper = new AccessRightsHelper(this);
135
+ // Helpers go to construtor
116
136
  this.configHelper = new ConfigHelper(this);
117
137
  this.menuHelper = new MenuHelper(this.config);
118
138
  this.widgetHandler = new WidgetHandler(this);
119
139
  bindExpressUtils(this.app);
120
140
  bindReqFunctions(this);
121
- // add install stepper policy to check unfilled settings
122
- // bindInstallStepper(this); // TODO It is necessary to provide an opportunity to be inserted by an intermediary after authorization, but before the admin panel, in order to block the user from managing the Installstepper's admin panel.
123
141
  // Bind assets
124
142
  bindAssets(this.app, this.config.routePrefix);
125
- if ((process.env.DEV && process.env.NODE_ENV !== 'production') || process.env.ADMINPANEL_FORCE_BIND_DEV === "TRUE") {
126
- bindDev(this);
143
+ if (!process.env.VITEST) {
144
+ if ((process.env.DEV && process.env.NODE_ENV !== 'production') || process.env.ADMINPANEL_FORCE_BIND_DEV === "TRUE") {
145
+ bindDev(this);
146
+ }
127
147
  }
128
148
  await bindDashboardWidgets(this);
129
149
  // bindNavigation(this);
@@ -207,7 +207,6 @@ export class AbstractCatalog {
207
207
  else {
208
208
  action = this.actionHandlers.find((it) => it.id === actionId);
209
209
  }
210
- // console.log(this.actionHandlers)
211
210
  if (!action)
212
211
  throw `Action with id \`${actionId}\` not found`;
213
212
  return await action.handler(items, config);
@@ -140,7 +140,6 @@
140
140
  // {tree: tree}
141
141
  // )
142
142
  // } catch (e) {
143
- // console.log(e)
144
143
  // throw 'navigation model update error'
145
144
  // }
146
145
  // }
@@ -326,7 +325,7 @@
326
325
  // let items = await this.adminizer.modelHandler.model.get(this.model)["_find"]({})
327
326
  //
328
327
  // // This dirty hack is here because the field of view is disappearing
329
- // req.i18n.setLocale(req.session.UserAP.locale);
328
+ // req.i18n.setLocale(req.user.locale);
330
329
  // const __ = (s: string) => {
331
330
  // return req.i18n.__(s)
332
331
  // }
@@ -354,7 +353,7 @@
354
353
  // let type: 'html' = 'html'
355
354
  //
356
355
  // // This dirty hack is here because the field of view is disappearing
357
- // req.i18n.setLocale(req.session.UserAP.locale);
356
+ // req.i18n.setLocale(req.user.locale);
358
357
  // const __ = (s: string) => {
359
358
  // return req.i18n.__(s)
360
359
  // }
@@ -433,7 +432,7 @@
433
432
  // let type: 'html' = 'html'
434
433
  //
435
434
  // // This dirty hack is here because the field of view is disappearing
436
- // req.i18n.setLocale(req.session.UserAP.locale);
435
+ // req.i18n.setLocale(req.user.locale);
437
436
  // const __ = (s: string) => {
438
437
  // return req.i18n.__(s)
439
438
  // }
@@ -460,7 +459,7 @@
460
459
  // let item = await this.find(id, catalogId)
461
460
  //
462
461
  // // This dirty hack is here because the field of view is disappearing
463
- // req.i18n.setLocale(req.session.UserAP.locale);
462
+ // req.i18n.setLocale(req.user.locale);
464
463
  // const __ = (s: string) => {
465
464
  // return req.i18n.__(s)
466
465
  // }
@@ -496,7 +495,7 @@
496
495
  //
497
496
  // getAddHTML(req: ReqType): Promise<{ type: "link" | "html" | "jsonForm"; data: string }> {
498
497
  // let type: 'html' = 'html'
499
- // req.i18n.setLocale(req.session.UserAP.locale);
498
+ // req.i18n.setLocale(req.user.locale);
500
499
  //
501
500
  // const __ = (s: string) => {
502
501
  // return req.i18n.__(s)
@@ -514,7 +513,7 @@
514
513
  // let type: 'html' = 'html'
515
514
  // let item = await this.find(id, catalogId)
516
515
  //
517
- // req.i18n.setLocale(req.session.UserAP.locale);
516
+ // req.i18n.setLocale(req.user.locale);
518
517
  // const __ = (s: string) => {
519
518
  // return req.i18n.__(s)
520
519
  // }
@@ -98,7 +98,6 @@ export class NodeTable {
98
98
  columnQuery = { [fieldsArray[parseInt(columnName)]]: { contains: searchStr } };
99
99
  break;
100
100
  default:
101
- // Пропускаем json, ref и ассоциации
102
101
  break;
103
102
  }
104
103
  }
@@ -132,10 +131,9 @@ export class NodeTable {
132
131
  async output(callback, dataAccessor) {
133
132
  try {
134
133
  const queryOptions = await this.buildQuery();
135
- const totalRecords = await this.model.count({});
136
- const filteredRecords = await this.model.count(queryOptions.where);
134
+ const totalRecords = await this.model.count({}, dataAccessor);
135
+ const filteredRecords = await this.model.count(queryOptions.where, dataAccessor);
137
136
  const data = await this.model.find(queryOptions, dataAccessor);
138
- console.log(data, "data");
139
137
  const output = {
140
138
  draw: this.request.draw !== "" ? this.request.draw : 0,
141
139
  recordsTotal: totalRecords,
@@ -201,7 +199,6 @@ export class NodeTable {
201
199
  });
202
200
  out.push(row);
203
201
  });
204
- console.log(out);
205
202
  return out;
206
203
  }
207
204
  }
@@ -21,7 +21,6 @@ const inertiaExpressAdapter = function ({ version, html, flashMessages, enableRe
21
21
  if (!['GET', 'HEAD', 'OPTIONS'].includes(req.method)) {
22
22
  const csrfCookie = req.cookies['XSRF-TOKEN'];
23
23
  const csrfHeader = req.headers[csrf.headerName || 'x-xsrf-token'];
24
- // console.log('headers:', req.headers['x-xsrf-token']);
25
24
  if (!csrfCookie || !csrfHeader || csrfCookie !== csrfHeader) {
26
25
  res.status(403).send({ message: 'Invalid CSRF token' });
27
26
  return;
@@ -143,10 +143,10 @@ export declare abstract class AbstractMediaManager {
143
143
  uloadAllowedTypes: string[];
144
144
  dir: string;
145
145
  /**
146
- * Разрешает или нет поиск по названию
146
+
147
147
  */
148
148
  allowSearch: boolean;
149
- /** ⚠️ ВЫШЕ НАСТРОЙКИ КОТОРЫЕ НАДО РЕАЛИЗОВАТЬ */
149
+ /**⚠️ above the settings that need to be implemented*/
150
150
  /**
151
151
  * id for mediamanager instance
152
152
  */
@@ -34,7 +34,7 @@ export class AbstractMediaManager {
34
34
  uloadAllowedTypes;
35
35
  dir;
36
36
  /**
37
- * Разрешает или нет поиск по названию
37
+
38
38
  */
39
39
  allowSearch;
40
40
  itemTypes = [];
@@ -324,12 +324,9 @@
324
324
  // try {
325
325
  // await fs.promises.access(file);
326
326
  // await fs.promises.unlink(file);
327
- // console.log('The file was successfully deleted');
328
327
  // } catch (err) {
329
328
  // if (err.code === 'ENOENT') {
330
- // console.log('The file does not exist');
331
329
  // } else if (err.code === 'EPERM') {
332
- // console.log('You do not have permission to delete this file');
333
330
  // } else {
334
331
  // console.error(`An error occurred: ${err}`);
335
332
  // }
@@ -4,13 +4,16 @@
4
4
  import { Entity } from "../../interfaces/types";
5
5
  import { ActionType } from "../../interfaces/adminpanelConfig";
6
6
  import { Fields } from "../../helpers/fieldsHelper";
7
+ import { Adminizer } from "../Adminizer";
8
+ import { UserAP } from "models/UserAP";
7
9
  export declare class DataAccessor {
8
10
  private readonly adminizer;
9
- user: ModelsAP["UserAP"];
11
+ user: UserAP;
10
12
  entity: Entity;
11
13
  action: ActionType;
12
14
  private fields;
13
- constructor(req: ReqType, entity: Entity, action: ActionType);
15
+ private actionVerb;
16
+ constructor(adminizer: Adminizer, user: UserAP, entity: Entity, action: ActionType);
14
17
  /**
15
18
  * Retrieves the fields for the given entity based on action type,
16
19
  * taking into account access rights and configuration settings.
@@ -6,11 +6,13 @@ export class DataAccessor {
6
6
  entity;
7
7
  action;
8
8
  fields = null;
9
- constructor(req, entity, action) {
10
- this.adminizer = req.adminizer;
11
- this.user = req.session.UserAP;
9
+ actionVerb;
10
+ constructor(adminizer, user, entity, action) {
11
+ this.adminizer = adminizer;
12
+ this.user = user;
12
13
  this.entity = entity;
13
14
  this.action = action;
15
+ this.actionVerb = getTokenAction(this.action);
14
16
  }
15
17
  /**
16
18
  * Retrieves the fields for the given entity based on action type,
@@ -26,10 +28,20 @@ export class DataAccessor {
26
28
  }
27
29
  // get action and field configs
28
30
  const actionConfig = ControllerHelper.findActionConfig(this.entity, this.action);
29
- const fieldsConfig = this.entity.config.fields || {};
31
+ const fieldsConfig = this.entity.config?.fields || {};
30
32
  const modelAttributes = this.entity.model.attributes;
33
+ const tokenId = `${this.actionVerb}-${this.entity.model.modelname}-${this.entity.type}`;
34
+ if (!this.adminizer.accessRightsHelper.hasPermission(tokenId, this.user)) {
35
+ Adminizer.log.debug(`No access rights to ${this.entity.type}: ${this.entity.model.modelname}`);
36
+ return undefined;
37
+ }
31
38
  const result = {};
32
39
  Object.entries(modelAttributes).forEach(([key, modelField]) => {
40
+ console.log(key);
41
+ // The fields that are recorded separately from the connection in some ORMs, because they are processed at the level above them.
42
+ if (modelAttributes[key].primaryKeyForAssociation === true) {
43
+ return undefined;
44
+ }
33
45
  // Checks for short type in Waterline: fieldName: 'string'
34
46
  if (typeof modelField === "string") {
35
47
  modelField = { type: modelField };
@@ -66,13 +78,18 @@ export class DataAccessor {
66
78
  let populatedModelFieldsConfig = {};
67
79
  if (modelField.type === "association" || modelField.type === "association-many") {
68
80
  const modelName = modelField.model || modelField.collection;
81
+ const tokenId = `read-${modelName}-${this.entity.type}`;
82
+ if (!this.adminizer.accessRightsHelper.hasPermission(tokenId, this.user)) {
83
+ Adminizer.log.silly(`No access rights to ${this.entity.type}: ${this.entity.model.modelname}`);
84
+ return undefined;
85
+ }
69
86
  if (modelName) {
70
- const Model = this.adminizer.modelHandler.model.get(modelName);
71
- if (Model) {
87
+ const model = this.adminizer.modelHandler.model.get(modelName);
88
+ if (model) {
72
89
  populatedModelFieldsConfig = this.getAssociatedFieldsConfig(modelName);
73
90
  }
74
91
  else {
75
- Adminizer.log.error(`Model not found: ${modelName}`);
92
+ Adminizer.log.error(`DataAccessor > getFieldsConfig > Model not found: ${modelName} when ${key}`);
76
93
  }
77
94
  }
78
95
  }
@@ -94,10 +111,9 @@ export class DataAccessor {
94
111
  return undefined;
95
112
  }
96
113
  // Check if user has access to the associated model
97
- const actionVerb = getTokenAction(this.action);
98
- const tokenId = `${actionVerb}-${modelName}-${this.entity.type}`;
114
+ const tokenId = `${this.actionVerb}-${modelName}-${this.entity.type}`;
99
115
  if (!this.adminizer.accessRightsHelper.hasPermission(tokenId, this.user)) {
100
- Adminizer.log.warn(`No access rights to ${this.entity.type}: ${modelName}`);
116
+ Adminizer.log.debug(`No access rights to ${this.entity.type}: ${modelName}`);
101
117
  return undefined;
102
118
  }
103
119
  const associatedFields = {};
@@ -327,7 +343,7 @@ export class DataAccessor {
327
343
  throw new Error(`No intermediate record found in model "${intermediateRelation.model}" associated with user ID "${this.user.id}"`);
328
344
  }
329
345
  // Ensure there is only one associated intermediate record
330
- const intermediateRecordCount = await intermediateModel.count({ [via]: this.user.id });
346
+ const intermediateRecordCount = await intermediateModel.count({ [via]: this.user.id }, this);
331
347
  if (intermediateRecordCount > 1) {
332
348
  throw new Error(`Multiple intermediate records found in model "${intermediateRelation.model}" associated with user ID "${this.user.id}". ` +
333
349
  `Expected only one`);
@@ -363,10 +379,11 @@ export class DataAccessor {
363
379
  const relation = modelAttributes[accessField];
364
380
  if (relation && ['userap', 'groupap'].includes(relation.model.toLowerCase())) {
365
381
  if (relation.model.toLowerCase() === 'userap') {
366
- updatedRecord[accessField] = this.user.id;
382
+ if (!this.user.isAdministrator) {
383
+ updatedRecord[accessField] = this.user.id;
384
+ }
367
385
  }
368
386
  else if (relation.model.toLowerCase() === 'groupap') {
369
- // Works only for users with only one group, later it can be resolved with group weight
370
387
  const userGroups = this.user.groups || [];
371
388
  if (userGroups.length === 1) {
372
389
  updatedRecord[accessField] = userGroups[0].id;
@@ -409,7 +426,7 @@ export class DataAccessor {
409
426
  throw new Error(`No intermediate record found in model "${intermediateRelation.model}" linking user "${this.user.id}" to the main record`);
410
427
  }
411
428
  // Ensure there is only one associated intermediate record
412
- const intermediateRecordCount = await intermediateModel.count({ [via]: this.user.id });
429
+ const intermediateRecordCount = await intermediateModel.count({ [via]: this.user.id }, this);
413
430
  if (intermediateRecordCount > 1) {
414
431
  throw new Error(`Multiple intermediate records found in model "${intermediateRelation.model}" associated with user ID "${this.user.id}". ` +
415
432
  `Expected only one`);
package/lib/v4/I18n.js CHANGED
@@ -104,7 +104,9 @@ export class I18n {
104
104
  return;
105
105
  const file = this.locateFile(locale);
106
106
  const tmpFile = `${file}.tmp`;
107
+ const dir = path.dirname(file);
107
108
  try {
109
+ fs.mkdirSync(dir, { recursive: true });
108
110
  fs.writeFileSync(tmpFile, JSON.stringify(I18n.locales[locale], null, this.indent), "utf8");
109
111
  fs.renameSync(tmpFile, file);
110
112
  }
@@ -54,7 +54,6 @@ export class POWCaptcha {
54
54
  if (!task || task.label !== label)
55
55
  return false;
56
56
  // Verify the solution (should be equal to puzzleOptions.message)
57
- // console.log("QUESTION", `${taskId}:${label}`)
58
57
  if (`${taskId}:${label}` === captchaSolution) {
59
58
  this.deleteTask(taskId);
60
59
  return true;
@@ -27,7 +27,6 @@ class PolicyManager {
27
27
  Adminizer.log.info("Adminizer policies loaded");
28
28
  }
29
29
  catch (e) {
30
- console.log(e);
31
30
  Adminizer.log.error("Adminizer > Could not load policies", e);
32
31
  }
33
32
  }