adminizer 4.6.0 → 4.7.0-build.222
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Readme.md +12 -0
- package/assets/RelationDialogStack-CnHFOYyR.css +1 -0
- package/assets/RelationDialogStack-DI2bZxQX.js +20 -0
- package/assets/add-DCQ7ZW4B.js +1 -0
- package/assets/add-group-DCVPryBo.js +1 -0
- package/assets/add-group-form-DKRXC2n-.js +1 -0
- package/assets/add-user-B7OOiYxv.js +1 -0
- package/assets/add-user-form-UXAToWQd.js +1 -0
- package/assets/app-AKbNCggP.css +1 -0
- package/assets/app-layout-6EwNBvnR.js +1 -0
- package/assets/app-shell-D8wtkECO.js +1 -0
- package/assets/app-sidebar-DfGjL-2K.js +1 -0
- package/assets/app-sidebar-header-BZbIBQjq.js +1 -0
- package/assets/app.js +59 -7990
- package/assets/breadcrumbs-CODaqVkB.js +1 -0
- package/assets/catalog-DVvFGa2X.js +6 -0
- package/assets/dashboard-BadoiH_a.js +3 -0
- package/assets/date-picker-DSOkNiNo.js +1 -0
- package/assets/del-modal-Cd4M7af8.js +1 -0
- package/assets/dynamic-controls-BsrJhPDY.js +1 -0
- package/assets/geo-json-CzR5JBXL.js +1 -0
- package/assets/handsontable-BI98OF5R.js +336 -0
- package/assets/history-D1iLA6rs.js +1 -0
- package/assets/home-DbWj-W_k.js +2 -0
- package/assets/icon-C2JNaLxH.js +1 -0
- package/assets/init-user-D2HSyXup.js +1 -0
- package/assets/input-error-CH2caTtO.js +1 -0
- package/assets/jsoneditor-DVNQmA6G.js +3869 -0
- package/assets/list-CVoljVUw.js +4 -0
- package/assets/login-DFSLEO17.js +1 -0
- package/assets/manifest.json +246 -273
- package/assets/material-icon-Bx9pGQiQ.js +1 -0
- package/assets/media-manager-WcKe1EvD.js +6 -0
- package/assets/module-DJsC37CM.js +1 -0
- package/assets/monaco-Bl4zdWCn.js +11 -0
- package/assets/nav-footer-BiSQkPt4.js +1 -0
- package/assets/nav-main-rTH0PfDw.js +1 -0
- package/assets/nav-user-Bj6cWs0a.js +1 -0
- package/assets/notification-DKrNfaAB.js +20 -0
- package/assets/pagination-render-AKJvTIRA.js +1 -0
- package/assets/register-BTP4uxsK.js +1 -0
- package/assets/ru-eW0WKkga.js +1 -0
- package/assets/theme-switcher-Dm8EOGzx.js +1 -0
- package/assets/toast-editor-DOg_gvSp.js +668 -0
- package/assets/user-filters-list-C9R9J6Om.js +1 -0
- package/assets/user-info-BgSbT02v.js +1 -0
- package/assets/user-menu-content-TQTXHIv6.js +1 -0
- package/assets/{vanilla-picker-l5rcX3cq.js → vanilla-picker-B3LgXoKV.js} +1 -7
- package/assets/welcome-BwDlAOGh.js +1 -0
- package/controllers/add.d.ts +1 -1
- package/controllers/add.js +20 -26
- package/controllers/addGroup.d.ts +1 -1
- package/controllers/addGroup.js +7 -15
- package/controllers/addUser.d.ts +1 -1
- package/controllers/addUser.js +10 -16
- package/controllers/catalog/Catalog.d.ts +1 -1
- package/controllers/catalog/Catalog.js +1 -10
- package/controllers/catalog/FrontendCatalogAdapter.d.ts +3 -3
- package/controllers/catalog/FrontendCatalogAdapter.js +0 -6
- package/controllers/catalog/FrontentCatalogAdapter.d.ts +3 -3
- package/controllers/catalog/FrontentCatalogAdapter.js +0 -4
- package/controllers/ckeditorUpload.js +2 -18
- package/controllers/dashboard.d.ts +1 -1
- package/controllers/dashboard.js +2 -5
- package/controllers/edit.js +24 -37
- package/controllers/editGroup.d.ts +1 -1
- package/controllers/editGroup.js +10 -21
- package/controllers/editUser.d.ts +1 -1
- package/controllers/editUser.js +11 -23
- package/controllers/exportData.d.ts +6 -0
- package/controllers/exportData.js +315 -0
- package/controllers/feed.d.ts +6 -0
- package/controllers/feed.js +73 -0
- package/controllers/feedback/feedbackController.d.ts +1 -1
- package/controllers/feedback/feedbackController.js +5 -7
- package/controllers/filter-fields/columns.d.ts +11 -0
- package/controllers/filter-fields/columns.js +106 -0
- package/controllers/filter-fields/filterFields.d.ts +10 -0
- package/controllers/filter-fields/filterFields.js +141 -0
- package/controllers/filter-fields/getAllUserFilters.d.ts +6 -0
- package/controllers/filter-fields/getAllUserFilters.js +115 -0
- package/controllers/filter-fields/groups.d.ts +5 -0
- package/controllers/filter-fields/groups.js +26 -0
- package/controllers/filter-fields/savedFilters.d.ts +25 -0
- package/controllers/filter-fields/savedFilters.js +317 -0
- package/controllers/getAllWidgets.d.ts +1 -1
- package/controllers/getAllWidgets.js +1 -9
- package/controllers/history-actions/HistoryController.js +6 -31
- package/controllers/initUser.js +6 -5
- package/controllers/inlineUpdate.d.ts +7 -0
- package/controllers/inlineUpdate.js +148 -0
- package/controllers/list.d.ts +1 -1
- package/controllers/list.js +383 -70
- package/controllers/listUserFilters.d.ts +5 -0
- package/controllers/listUserFilters.js +26 -0
- package/controllers/login.js +2 -2
- package/controllers/media-manager/mediaManagerApi.js +0 -9
- package/controllers/navigation/edit.js +3 -9
- package/controllers/notifications/NotificationController.d.ts +1 -1
- package/controllers/notifications/NotificationController.js +12 -36
- package/controllers/register.js +10 -9
- package/controllers/remove.js +10 -19
- package/controllers/timezones.d.ts +1 -1
- package/controllers/timezones.js +0 -6
- package/controllers/userApiKey.d.ts +7 -0
- package/controllers/userApiKey.js +36 -0
- package/controllers/view.js +14 -26
- package/controllers/welcome.d.ts +1 -1
- package/controllers/welcome.js +0 -4
- package/controllers/widgets/Action.d.ts +1 -1
- package/controllers/widgets/Action.js +1 -9
- package/controllers/widgets/Custom.d.ts +1 -1
- package/controllers/widgets/Custom.js +1 -9
- package/controllers/widgets/Info.d.ts +1 -1
- package/controllers/widgets/Info.js +1 -9
- package/controllers/widgets/filterInfo.d.ts +1 -0
- package/controllers/widgets/filterInfo.js +44 -0
- package/controllers/widgets/switch.d.ts +1 -1
- package/controllers/widgets/switch.js +1 -9
- package/controllers/widgetsDB.d.ts +1 -1
- package/controllers/widgetsDB.js +2 -8
- package/helpers/accessRightsHelper.d.ts +1 -1
- package/helpers/accessRightsHelper.js +5 -4
- package/helpers/apiKeyHelper.d.ts +5 -0
- package/helpers/apiKeyHelper.js +8 -0
- package/helpers/configHelper.js +12 -15
- package/helpers/controllerHelper.d.ts +14 -21
- package/helpers/controllerHelper.js +50 -83
- package/helpers/fieldsHelper.js +3 -3
- package/helpers/filterDatetimeHelper.d.ts +5 -0
- package/helpers/filterDatetimeHelper.js +84 -0
- package/helpers/inertiaActionsHelper.d.ts +2 -2
- package/helpers/inertiaActionsHelper.js +5 -4
- package/helpers/inertiaAddHelper.d.ts +3 -414
- package/helpers/inertiaAddHelper.js +39 -15
- package/helpers/inertiaGroupHelper.d.ts +2 -2
- package/helpers/inertiaGroupHelper.js +3 -3
- package/helpers/inertiaListHelper.d.ts +7 -3
- package/helpers/inertiaListHelper.js +26 -12
- package/helpers/inertiaMenuHelper.d.ts +1 -0
- package/helpers/inertiaMenuHelper.js +15 -3
- package/helpers/inertiaUserHelper.d.ts +3 -2
- package/helpers/inertiaUserHelper.js +7 -3
- package/helpers/menuHelper.d.ts +5 -2
- package/helpers/menuHelper.js +64 -12
- package/helpers/viteHelper.js +1 -2
- package/index.d.ts +6 -2
- package/index.js +6 -2
- package/interfaces/adminpanelConfig.d.ts +126 -39
- package/interfaces/internalModelAccess.d.ts +37 -0
- package/interfaces/internalModelAccess.js +1 -0
- package/interfaces/listQueryBuilder.d.ts +22 -0
- package/interfaces/listQueryBuilder.js +1 -0
- package/interfaces/queryCriteria.d.ts +54 -0
- package/interfaces/queryCriteria.js +1 -0
- package/interfaces/types.d.ts +1 -13
- package/lib/Adminizer.d.ts +4 -2
- package/lib/Adminizer.js +29 -10
- package/lib/DataAccessor.d.ts +8 -5
- package/lib/DataAccessor.js +89 -42
- package/lib/I18n.d.ts +5 -1
- package/lib/I18n.js +45 -19
- package/lib/MiddlewareManager.d.ts +8 -0
- package/lib/MiddlewareManager.js +53 -0
- package/lib/ai-assistant/OpenAiModelService.d.ts +3 -3
- package/lib/ai-assistant/OpenAiModelService.js +23 -24
- package/lib/catalog/Navigation.d.ts +1 -0
- package/lib/catalog/Navigation.js +12 -11
- package/lib/controls/jsoneditor/JsonEditor.d.ts +1 -2
- package/lib/controls/markdown/ToastUiEditor.d.ts +1 -2
- package/lib/feedback/FeedbackHandler.js +2 -2
- package/lib/filters/ConditionValidator.d.ts +107 -0
- package/lib/filters/ConditionValidator.js +483 -0
- package/lib/filters/CustomFilterHandler.d.ts +122 -0
- package/lib/filters/CustomFilterHandler.js +131 -0
- package/lib/filters/FilterCustomFieldHandler.d.ts +2 -0
- package/lib/filters/FilterCustomFieldHandler.js +2 -0
- package/lib/filters/FilterService.d.ts +82 -0
- package/lib/filters/FilterService.js +323 -0
- package/lib/filters/index.d.ts +6 -0
- package/lib/filters/index.js +4 -0
- package/lib/history-actions/AbstractHistoryAdapter.d.ts +5 -4
- package/lib/history-actions/AbstractHistoryAdapter.js +45 -30
- package/lib/history-actions/DefaultHistoryAdapter.d.ts +2 -0
- package/lib/history-actions/DefaultHistoryAdapter.js +12 -6
- package/lib/history-actions/HistoryHandler.js +1 -1
- package/lib/list-query-builder/ListQueryBuilder.d.ts +117 -0
- package/lib/list-query-builder/ListQueryBuilder.js +707 -0
- package/lib/media-manager/AbstractMediaManager.d.ts +9 -8
- package/lib/media-manager/DefaultMediaManager.d.ts +2 -0
- package/lib/media-manager/DefaultMediaManager.js +27 -15
- package/lib/media-manager/Items.d.ts +4 -1
- package/lib/media-manager/Items.js +62 -59
- package/lib/media-manager/MediaManagerHandler.js +1 -1
- package/lib/media-manager/helpers/MediaManagerHelper.d.ts +5 -1
- package/lib/media-manager/helpers/MediaManagerHelper.js +38 -4
- package/lib/model/AbstractModel.d.ts +33 -25
- package/lib/model/AbstractModel.js +54 -2
- package/lib/model/InternalModelAccessFactory.d.ts +18 -0
- package/lib/model/InternalModelAccessFactory.js +82 -0
- package/lib/model/ModelHandler.d.ts +6 -0
- package/lib/model/ModelHandler.js +14 -0
- package/lib/model/adapter/sequelize.d.ts +32 -10
- package/lib/model/adapter/sequelize.js +409 -62
- package/lib/model/adapter/typeorm.d.ts +62 -0
- package/lib/model/adapter/typeorm.js +777 -0
- package/lib/model/internalModelAccessToken.d.ts +1 -0
- package/lib/model/internalModelAccessToken.js +1 -0
- package/lib/model/internalModelRepository.d.ts +3 -0
- package/lib/model/internalModelRepository.js +4 -0
- package/lib/notifications/AbstractNotificationService.d.ts +3 -0
- package/lib/notifications/AbstractNotificationService.js +42 -36
- package/lib/notifications/GeneralNotificationService.js +37 -40
- package/lib/notifications/SystemNotificationService.js +33 -36
- package/lib/requestProcessor.js +0 -3
- package/lib/ui-i18n/getUiTranslations.d.ts +1 -0
- package/lib/ui-i18n/getUiTranslations.js +3 -0
- package/lib/ui-i18n/uiTranslationKeys.d.ts +6 -0
- package/lib/ui-i18n/uiTranslationKeys.js +268 -0
- package/lib/widgets/widgetHandler.d.ts +7 -2
- package/lib/widgets/widgetHandler.js +98 -18
- package/models/FilterAP.d.ts +116 -0
- package/models/FilterAP.js +68 -0
- package/models/FilterColumnAP.d.ts +32 -0
- package/models/FilterColumnAP.js +21 -0
- package/models/GroupAP.d.ts +1 -1
- package/models/HistoryActionsAP.d.ts +3 -3
- package/models/MediaManagerMetaAP.d.ts +1 -1
- package/models/NavigationAP.d.ts +1 -1
- package/models/UserAP.d.ts +6 -1
- package/models/UserAP.js +4 -0
- package/package.json +39 -32
- package/policies/authPolicies.d.ts +12 -0
- package/policies/authPolicies.js +104 -0
- package/policies/permissionResolvers.d.ts +12 -0
- package/policies/permissionResolvers.js +52 -0
- package/services/FeedService.d.ts +70 -0
- package/services/FeedService.js +334 -0
- package/system/Router.d.ts +1 -0
- package/system/Router.js +136 -59
- package/system/bindAccessRights.js +11 -30
- package/system/bindAuthorization.js +18 -18
- package/system/bindCors.js +16 -1
- package/system/bindCustomFilterHandlers.d.ts +2 -0
- package/system/bindCustomFilterHandlers.js +4 -0
- package/system/bindInertia.js +18 -61
- package/system/bindReqFunctions.js +10 -2
- package/system/bindTranslations.js +7 -3
- package/system/buildInternalModelAccess.d.ts +4 -0
- package/system/buildInternalModelAccess.js +59 -0
- package/system/defaults.js +18 -14
- package/system/routePolicies.d.ts +2 -0
- package/system/routePolicies.js +29 -0
- package/translations/en.json +151 -39
- package/translations/ru.json +211 -64
- package/ui/components/handsontable.js +13 -27
- package/ui/components/ui/dialog-stack.js +1 -3
- package/ui/components/ui/popover.js +1 -1
- package/ui/components/ui/sidebar.js +1 -1
- package/assets/RelationDialogStack-D9UVEF9s.js +0 -407
- package/assets/RelationDialogStack-DV8OITPR.css +0 -4
- package/assets/add-BlvzWQKF.js +0 -1
- package/assets/add-group-1Uoq9NWe.js +0 -1
- package/assets/add-group-form-B01gwDGu.js +0 -1
- package/assets/add-user-BQCAsaRy.js +0 -1
- package/assets/add-user-form-Cgwc9JkI.js +0 -1
- package/assets/app-DaOMy1nl.css +0 -72
- package/assets/app-layout-CAm60qoE.js +0 -1
- package/assets/app-shell-QWCtn9ye.js +0 -1
- package/assets/app-sidebar-CfaYbnSy.js +0 -1
- package/assets/app-sidebar-header-BsPFDhZ8.js +0 -1
- package/assets/breadcrumbs-CZZirDj8.js +0 -1
- package/assets/catalog-k5myk7fk.js +0 -6
- package/assets/dashboard-BkL9ybBw.js +0 -3
- package/assets/date-picker-B5AZ_7Q9.js +0 -1
- package/assets/del-modal-BoyXZloG.js +0 -1
- package/assets/dynamic-controls-k61T9W2P.js +0 -1
- package/assets/form-1WGY0YgG.js +0 -1
- package/assets/form-DJapG3qF.js +0 -1
- package/assets/geo-json-DsMUHo0l.js +0 -4
- package/assets/handsontable-PxYdjN8c.js +0 -298
- package/assets/history-CluyR-yJ.js +0 -1
- package/assets/home-Dug9zBzM.js +0 -2
- package/assets/icon-DfDLMG5f.js +0 -1
- package/assets/init-user-CF80MEnT.js +0 -1
- package/assets/input-error-DuuqFgZa.js +0 -1
- package/assets/jsoneditor-De1FvcYu.js +0 -3882
- package/assets/list-CuexshNt.js +0 -1
- package/assets/list-table-BsEWjTKY.js +0 -22
- package/assets/login-eDemYzN-.js +0 -1
- package/assets/material-icon-DMT8KdmE.js +0 -1
- package/assets/media-manager-DfYa_mT_.js +0 -14
- package/assets/module-Cd4Tm6uq.js +0 -1
- package/assets/monaco-BhBYtg3d.js +0 -11
- package/assets/nav-footer-D3olYxtz.js +0 -1
- package/assets/nav-main-BctqyzeV.js +0 -1
- package/assets/nav-user-Bn1Lt-BZ.js +0 -1
- package/assets/notification-D64qvni-.js +0 -27
- package/assets/pagination-render-DxD78ahJ.js +0 -1
- package/assets/register-349PwYbe.js +0 -1
- package/assets/theme-switcher-DfExsHW2.js +0 -1
- package/assets/toast-editor-ESK5iWPx.js +0 -845
- package/assets/user-info-DtBK5Kh8.js +0 -1
- package/assets/user-menu-content-0XYOCMaA.js +0 -1
- package/assets/welcome-PDp-gUei.js +0 -1
- package/controllers/form.d.ts +0 -1
- package/controllers/form.js +0 -86
- package/helpers/formHelper.d.ts +0 -6
- package/helpers/formHelper.js +0 -38
- package/helpers/inertiaFromHelper.d.ts +0 -11
- package/helpers/inertiaFromHelper.js +0 -98
- package/helpers/runtimeMode.d.ts +0 -1
- package/helpers/runtimeMode.js +0 -3
- package/lib/PolicyManager.d.ts +0 -8
- package/lib/PolicyManager.js +0 -53
- package/lib/datatable/NodeTable.d.ts +0 -49
- package/lib/datatable/NodeTable.js +0 -207
- package/lib/model/adapter/waterline.d.ts +0 -32
- package/lib/model/adapter/waterline.js +0 -180
- package/migrations/index.d.ts +0 -3
- package/migrations/index.js +0 -4
- package/migrations/knex/20250106000001_adminizer_init.d.ts +0 -8
- package/migrations/knex/20250106000001_adminizer_init.js +0 -164
- package/migrations/umzug/0001.d.ts +0 -7
- package/migrations/umzug/0001.js +0 -121
- package/migrations/umzugExports.d.ts +0 -2
- package/migrations/umzugExports.js +0 -9
- package/system/bindForms.d.ts +0 -2
- package/system/bindForms.js +0 -20
- /package/{policies → middlewares}/addMessages.d.ts +0 -0
- /package/{policies → middlewares}/addMessages.js +0 -0
- /package/{policies → middlewares}/checkAuth.d.ts +0 -0
- /package/{policies → middlewares}/checkAuth.js +0 -0
- /package/{policies → middlewares}/setLocale.d.ts +0 -0
- /package/{policies → middlewares}/setLocale.js +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { FilterCondition } from "../models/FilterAP";
|
|
2
|
+
/**
|
|
3
|
+
* Input format for list/feed/export query builder.
|
|
4
|
+
* This is not the internal model query language.
|
|
5
|
+
*/
|
|
6
|
+
export interface ListQueryBuilderParams {
|
|
7
|
+
page: number;
|
|
8
|
+
limit: number;
|
|
9
|
+
sort?: string;
|
|
10
|
+
sortDirection?: "ASC" | "DESC";
|
|
11
|
+
filters?: FilterCondition[];
|
|
12
|
+
globalSearch?: string;
|
|
13
|
+
fields?: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface ListQueryBuilderResult<T = any> {
|
|
16
|
+
data: T[];
|
|
17
|
+
total: number;
|
|
18
|
+
filtered: number;
|
|
19
|
+
page: number;
|
|
20
|
+
limit: number;
|
|
21
|
+
pages: number;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export type CriteriaPrimitive = string | number | boolean | Date | null;
|
|
2
|
+
export type CriteriaSortDirection = "ASC" | "DESC" | "asc" | "desc";
|
|
3
|
+
export type CriteriaSelect = string[] | Record<string, boolean>;
|
|
4
|
+
export type CriteriaSort = string | Record<string, CriteriaSortDirection>;
|
|
5
|
+
export interface CriteriaOperatorValue<TValue = unknown> {
|
|
6
|
+
eq?: TValue;
|
|
7
|
+
ne?: TValue;
|
|
8
|
+
gt?: TValue;
|
|
9
|
+
gte?: TValue;
|
|
10
|
+
lt?: TValue;
|
|
11
|
+
lte?: TValue;
|
|
12
|
+
contains?: TValue;
|
|
13
|
+
startsWith?: TValue;
|
|
14
|
+
endsWith?: TValue;
|
|
15
|
+
in?: TValue[];
|
|
16
|
+
notIn?: TValue[];
|
|
17
|
+
between?: [TValue, TValue];
|
|
18
|
+
isNull?: boolean;
|
|
19
|
+
isNotNull?: boolean;
|
|
20
|
+
regex?: unknown;
|
|
21
|
+
arrayContains?: unknown;
|
|
22
|
+
arrayOverlap?: unknown[];
|
|
23
|
+
jsonContains?: unknown;
|
|
24
|
+
}
|
|
25
|
+
export type CriteriaFieldInput<TValue = unknown> = TValue extends Array<infer Item> ? Item | Item[] | TValue : TValue;
|
|
26
|
+
export type CriteriaFieldValue<TValue = unknown> = null | CriteriaFieldInput<TValue> | CriteriaOperatorValue<CriteriaFieldInput<TValue>>;
|
|
27
|
+
export type CriteriaKnownFields<TModel = any> = {
|
|
28
|
+
[Field in Extract<keyof TModel, string>]?: CriteriaFieldValue<TModel[Field]>;
|
|
29
|
+
};
|
|
30
|
+
export interface CriteriaWhereLogic<TModel = any> {
|
|
31
|
+
and?: CriteriaWhere<TModel>[];
|
|
32
|
+
or?: CriteriaWhere<TModel>[];
|
|
33
|
+
not?: CriteriaWhere<TModel>;
|
|
34
|
+
}
|
|
35
|
+
export type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
36
|
+
export type CriteriaWhere<TModel = any> = IsAny<TModel> extends true ? CriteriaWhereLogic<TModel> & {
|
|
37
|
+
[field: string]: unknown;
|
|
38
|
+
} : CriteriaWhereLogic<TModel> & CriteriaKnownFields<TModel>;
|
|
39
|
+
type PopulatableElement<T> = NonNullable<T> extends Array<infer Item> ? Item : NonNullable<T>;
|
|
40
|
+
type PopulatableKeys<TModel> = {
|
|
41
|
+
[K in keyof TModel]-?: NonNullable<TModel[K]> extends string | number | boolean | Date ? never : K;
|
|
42
|
+
}[keyof TModel];
|
|
43
|
+
export type CriteriaPopulate<TModel = any> = IsAny<TModel> extends true ? Record<string, true | QueryCriteria<any>> : {
|
|
44
|
+
[K in Extract<PopulatableKeys<TModel>, string>]?: true | QueryCriteria<PopulatableElement<TModel[K]>>;
|
|
45
|
+
};
|
|
46
|
+
export interface QueryCriteria<TModel = any> {
|
|
47
|
+
where?: CriteriaWhere<TModel>;
|
|
48
|
+
select?: CriteriaSelect;
|
|
49
|
+
populate?: CriteriaPopulate<TModel>;
|
|
50
|
+
sort?: CriteriaSort;
|
|
51
|
+
limit?: number;
|
|
52
|
+
skip?: number;
|
|
53
|
+
}
|
|
54
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/interfaces/types.d.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { AbstractModel } from "../lib/model/AbstractModel";
|
|
2
2
|
import { ModelConfig } from "./adminpanelConfig";
|
|
3
|
-
export
|
|
4
|
-
export interface Entity {
|
|
3
|
+
export interface ModelResource {
|
|
5
4
|
name: string;
|
|
6
5
|
config?: ModelConfig;
|
|
7
6
|
model?: AbstractModel<any>;
|
|
8
7
|
uri: string;
|
|
9
|
-
type: EntityType;
|
|
10
8
|
}
|
|
11
9
|
export interface AccessRightsToken {
|
|
12
10
|
name: string;
|
|
@@ -72,13 +70,3 @@ export interface AiAssistantModelInfo {
|
|
|
72
70
|
name: string;
|
|
73
71
|
description?: string;
|
|
74
72
|
}
|
|
75
|
-
export type Migration = {
|
|
76
|
-
name: string;
|
|
77
|
-
timestamp: number;
|
|
78
|
-
up: (args: {
|
|
79
|
-
context: any;
|
|
80
|
-
}) => Promise<unknown> | unknown;
|
|
81
|
-
down: (args: {
|
|
82
|
-
context: any;
|
|
83
|
-
}) => Promise<unknown> | unknown;
|
|
84
|
-
};
|
package/lib/Adminizer.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import express, { Express } from "express";
|
|
|
2
2
|
import winston from "winston";
|
|
3
3
|
import EventEmitter from 'events';
|
|
4
4
|
import { AdminpanelConfig } from "../interfaces/adminpanelConfig";
|
|
5
|
-
import
|
|
5
|
+
import MiddlewareManager from "./MiddlewareManager";
|
|
6
6
|
import Router from "./../system/Router";
|
|
7
7
|
import { ModelHandler } from "./model/ModelHandler";
|
|
8
8
|
import { WidgetHandler } from "./widgets/widgetHandler";
|
|
@@ -20,6 +20,7 @@ import { INotification } from "../interfaces/types";
|
|
|
20
20
|
import { MediaManagerHandler } from "./media-manager/MediaManagerHandler";
|
|
21
21
|
import { StorageServices } from "./catalog/Navigation";
|
|
22
22
|
import { HistoryHandler } from "./history-actions/HistoryHandler";
|
|
23
|
+
import { CustomFilterHandler } from "./filters/CustomFilterHandler";
|
|
23
24
|
import { FeedbackHandler } from "./feedback/FeedbackHandler";
|
|
24
25
|
export declare class Adminizer {
|
|
25
26
|
/**
|
|
@@ -31,7 +32,7 @@ export declare class Adminizer {
|
|
|
31
32
|
config: AdminpanelConfig;
|
|
32
33
|
private readonly _emitter;
|
|
33
34
|
ormAdapters: AbstractAdapter[];
|
|
34
|
-
|
|
35
|
+
middlewareManager: MiddlewareManager;
|
|
35
36
|
accessRightsHelper: AccessRightsHelper;
|
|
36
37
|
configHelper: ConfigHelper;
|
|
37
38
|
menuHelper: MenuHelper;
|
|
@@ -41,6 +42,7 @@ export declare class Adminizer {
|
|
|
41
42
|
aiAssistantHandler?: AiAssistantHandler;
|
|
42
43
|
modelHandler: ModelHandler;
|
|
43
44
|
widgetHandler: WidgetHandler;
|
|
45
|
+
customFilterHandler: CustomFilterHandler;
|
|
44
46
|
vite: ViteDevServer;
|
|
45
47
|
controlsHandler: ControlsHandler;
|
|
46
48
|
catalogHandler: CatalogHandler;
|
package/lib/Adminizer.js
CHANGED
|
@@ -2,8 +2,9 @@ import express from "express";
|
|
|
2
2
|
import cookieParser from 'cookie-parser';
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import winston from "winston";
|
|
5
|
+
import chalk from "chalk";
|
|
5
6
|
import EventEmitter from 'events';
|
|
6
|
-
import
|
|
7
|
+
import MiddlewareManager from "./MiddlewareManager.js";
|
|
7
8
|
import Router from "./../system/Router.js";
|
|
8
9
|
import bindAssets from "../system/bindAssets.js";
|
|
9
10
|
import bindDev from "../system/bindDev.js";
|
|
@@ -13,7 +14,6 @@ import bindMediaManager from "../system/bindMediaManager.js";
|
|
|
13
14
|
import bindAccessRights from "../system/bindAccessRights.js";
|
|
14
15
|
import bindAuthorization from "../system/bindAuthorization.js";
|
|
15
16
|
import bindModels from "../system/bindModels.js";
|
|
16
|
-
import bindForms from "../system/bindForms.js";
|
|
17
17
|
import bindTranslations from "../system/bindTranslations.js";
|
|
18
18
|
import { ModelHandler } from "./model/ModelHandler.js";
|
|
19
19
|
import { WidgetHandler } from "./widgets/widgetHandler.js";
|
|
@@ -34,8 +34,9 @@ import { bindAiAssistant } from "../system/bindAiAssistant.js";
|
|
|
34
34
|
import { MediaManagerHandler } from "./media-manager/MediaManagerHandler.js";
|
|
35
35
|
import { bindCors } from "../system/bindCors.js";
|
|
36
36
|
import bindHistory from "../system/bindHistory.js";
|
|
37
|
-
import
|
|
37
|
+
import bindCustomFilterHandlers from "../system/bindCustomFilterHandlers.js";
|
|
38
38
|
import { FeedbackHandler } from "./feedback/FeedbackHandler.js";
|
|
39
|
+
import { buildInternalModelAccess } from "../system/buildInternalModelAccess.js";
|
|
39
40
|
export class Adminizer {
|
|
40
41
|
// Preconfigures
|
|
41
42
|
/**
|
|
@@ -48,7 +49,7 @@ export class Adminizer {
|
|
|
48
49
|
config;
|
|
49
50
|
_emitter;
|
|
50
51
|
ormAdapters;
|
|
51
|
-
|
|
52
|
+
middlewareManager;
|
|
52
53
|
accessRightsHelper;
|
|
53
54
|
configHelper;
|
|
54
55
|
menuHelper;
|
|
@@ -58,6 +59,7 @@ export class Adminizer {
|
|
|
58
59
|
aiAssistantHandler;
|
|
59
60
|
modelHandler;
|
|
60
61
|
widgetHandler;
|
|
62
|
+
customFilterHandler;
|
|
61
63
|
vite;
|
|
62
64
|
controlsHandler;
|
|
63
65
|
catalogHandler;
|
|
@@ -73,7 +75,23 @@ export class Adminizer {
|
|
|
73
75
|
return `[${timestamp}] ${level.toUpperCase()}: ${message} ${metaString}`;
|
|
74
76
|
})),
|
|
75
77
|
transports: [
|
|
76
|
-
new winston.transports.Console(
|
|
78
|
+
new winston.transports.Console({
|
|
79
|
+
format: winston.format.combine(winston.format.timestamp(), winston.format.printf(({ timestamp, level, message, ...meta }) => {
|
|
80
|
+
const metaString = Object.keys(meta).length ? JSON.stringify(meta) : "";
|
|
81
|
+
const colors = {
|
|
82
|
+
error: chalk.red,
|
|
83
|
+
warn: chalk.yellow,
|
|
84
|
+
info: chalk.green,
|
|
85
|
+
http: chalk.magenta,
|
|
86
|
+
verbose: chalk.cyan,
|
|
87
|
+
debug: chalk.blue,
|
|
88
|
+
silly: chalk.gray,
|
|
89
|
+
};
|
|
90
|
+
const colorize = colors[level] ?? chalk.white;
|
|
91
|
+
const line = `[${timestamp}] ${level.toUpperCase()}: ${message} ${metaString}`;
|
|
92
|
+
return colorize(line);
|
|
93
|
+
}))
|
|
94
|
+
}),
|
|
77
95
|
new winston.transports.File({ filename: "logs/app.log" }),
|
|
78
96
|
],
|
|
79
97
|
});
|
|
@@ -170,17 +188,18 @@ export class Adminizer {
|
|
|
170
188
|
// set cookie parser
|
|
171
189
|
this.app.use(cookieParser());
|
|
172
190
|
// Set vite middleware
|
|
173
|
-
const isViteDev =
|
|
191
|
+
const isViteDev = process.env.ADMINIZER_ENV === "dev";
|
|
174
192
|
if (isViteDev)
|
|
175
193
|
await this.viteMiddleware();
|
|
176
194
|
this.emitter.emit('adminizer:init');
|
|
177
195
|
this.modelHandler = new ModelHandler();
|
|
178
|
-
// TODO: 'hot reload' unbind models
|
|
196
|
+
// TODO: 'hot reload' unbind models
|
|
179
197
|
await bindModels(this);
|
|
180
|
-
|
|
198
|
+
this.modelHandler.configureInternalAccess(buildInternalModelAccess(this.config, this.modelHandler));
|
|
199
|
+
bindCustomFilterHandlers(this);
|
|
181
200
|
this.config.rootPath = path.resolve(import.meta.dirname + "/..");
|
|
182
|
-
this.
|
|
183
|
-
await this.
|
|
201
|
+
this.middlewareManager = new MiddlewareManager(this);
|
|
202
|
+
await this.middlewareManager.loadMiddlewares();
|
|
184
203
|
// TODO: 'hot reload' problem with deleting access right tokens
|
|
185
204
|
this.accessRightsHelper = new AccessRightsHelper(this);
|
|
186
205
|
// Helpers go to construtor
|
package/lib/DataAccessor.d.ts
CHANGED
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The class manages the interaction between the user and the database entry, taking into account user permissions and the main config file settings.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { ModelResource } from "../interfaces/types";
|
|
5
5
|
import { ActionType } from "../interfaces/adminpanelConfig";
|
|
6
6
|
import { Fields } from "../helpers/fieldsHelper";
|
|
7
7
|
import { Adminizer } from "./Adminizer";
|
|
8
8
|
import { UserAP } from "../models/UserAP";
|
|
9
|
+
import { QueryCriteria } from "../interfaces/queryCriteria";
|
|
9
10
|
export declare class DataAccessor {
|
|
10
11
|
readonly adminizer: Adminizer;
|
|
11
12
|
user: UserAP;
|
|
12
|
-
|
|
13
|
+
modelResource: ModelResource;
|
|
13
14
|
action: ActionType;
|
|
14
15
|
private fields;
|
|
15
16
|
private actionVerb;
|
|
16
|
-
constructor(adminizer: Adminizer, user: UserAP,
|
|
17
|
+
constructor(adminizer: Adminizer, user: UserAP, modelResource: ModelResource, action: ActionType);
|
|
17
18
|
private getModelConfig;
|
|
19
|
+
private accessRelationModel;
|
|
18
20
|
/**
|
|
19
|
-
* Retrieves the fields for the given
|
|
21
|
+
* Retrieves the fields for the given ModelResource based on action type,
|
|
20
22
|
* taking into account access rights and configuration settings.
|
|
21
23
|
* @returns {Fields} An object with configured fields and their properties.
|
|
22
24
|
*/
|
|
23
25
|
getFieldsConfig(): Fields;
|
|
26
|
+
private orderFieldsByConfig;
|
|
24
27
|
private getAssociatedFieldsConfig;
|
|
25
28
|
private checkFieldAccess;
|
|
26
29
|
/**
|
|
@@ -31,6 +34,6 @@ export declare class DataAccessor {
|
|
|
31
34
|
private filterAssociatedRecord;
|
|
32
35
|
/** Process for an array of records */
|
|
33
36
|
processMany<T>(records: T[]): Partial<T>[];
|
|
34
|
-
sanitizeUserRelationAccess
|
|
37
|
+
sanitizeUserRelationAccess(criteria?: QueryCriteria): Promise<QueryCriteria>;
|
|
35
38
|
setUserRelationAccess<T>(record: T): Promise<Partial<T>>;
|
|
36
39
|
}
|
package/lib/DataAccessor.js
CHANGED
|
@@ -1,17 +1,48 @@
|
|
|
1
1
|
import { ControllerHelper } from "../helpers/controllerHelper.js";
|
|
2
2
|
import { Adminizer } from "./Adminizer.js";
|
|
3
3
|
import { isObject } from "../helpers/JsUtils.js";
|
|
4
|
+
const MODEL_TOKEN_SUFFIX = "model";
|
|
5
|
+
function hasCriteriaContent(criteria) {
|
|
6
|
+
return Object.keys(criteria).length > 0 || Object.getOwnPropertySymbols(criteria).length > 0;
|
|
7
|
+
}
|
|
8
|
+
function isPlainCriteriaWhere(where) {
|
|
9
|
+
if (!isObject(where)) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
const prototype = Object.getPrototypeOf(where);
|
|
13
|
+
return prototype === Object.prototype || prototype === null;
|
|
14
|
+
}
|
|
15
|
+
function mergeCriteriaWhere(criteriaWhere, sanitizedCriteria) {
|
|
16
|
+
if (!hasCriteriaContent(sanitizedCriteria)) {
|
|
17
|
+
return criteriaWhere;
|
|
18
|
+
}
|
|
19
|
+
if (!criteriaWhere) {
|
|
20
|
+
return sanitizedCriteria;
|
|
21
|
+
}
|
|
22
|
+
if (isPlainCriteriaWhere(criteriaWhere)) {
|
|
23
|
+
return {
|
|
24
|
+
...criteriaWhere,
|
|
25
|
+
...sanitizedCriteria
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
and: [
|
|
30
|
+
criteriaWhere,
|
|
31
|
+
sanitizedCriteria
|
|
32
|
+
]
|
|
33
|
+
};
|
|
34
|
+
}
|
|
4
35
|
export class DataAccessor {
|
|
5
36
|
adminizer;
|
|
6
37
|
user;
|
|
7
|
-
|
|
38
|
+
modelResource;
|
|
8
39
|
action;
|
|
9
40
|
fields = null;
|
|
10
41
|
actionVerb;
|
|
11
|
-
constructor(adminizer, user,
|
|
42
|
+
constructor(adminizer, user, modelResource, action) {
|
|
12
43
|
this.adminizer = adminizer;
|
|
13
44
|
this.user = user;
|
|
14
|
-
this.
|
|
45
|
+
this.modelResource = modelResource;
|
|
15
46
|
this.action = action;
|
|
16
47
|
this.actionVerb = getTokenAction(this.action);
|
|
17
48
|
}
|
|
@@ -21,8 +52,11 @@ export class DataAccessor {
|
|
|
21
52
|
const config = entry ? entry[1] : undefined;
|
|
22
53
|
return isObject(config) ? config : undefined;
|
|
23
54
|
}
|
|
55
|
+
accessRelationModel(modelName) {
|
|
56
|
+
return this.adminizer.modelHandler.internal("data-accessor").get(modelName);
|
|
57
|
+
}
|
|
24
58
|
/**
|
|
25
|
-
* Retrieves the fields for the given
|
|
59
|
+
* Retrieves the fields for the given ModelResource based on action type,
|
|
26
60
|
* taking into account access rights and configuration settings.
|
|
27
61
|
* @returns {Fields} An object with configured fields and their properties.
|
|
28
62
|
*/
|
|
@@ -30,16 +64,16 @@ export class DataAccessor {
|
|
|
30
64
|
if (this.fields !== null) {
|
|
31
65
|
return this.fields;
|
|
32
66
|
}
|
|
33
|
-
if (!this.
|
|
67
|
+
if (!this.modelResource.model || !this.modelResource.model.attributes) {
|
|
34
68
|
return {};
|
|
35
69
|
}
|
|
36
70
|
// get action and field configs
|
|
37
|
-
const actionConfig = ControllerHelper.findActionConfig(this.
|
|
38
|
-
const fieldsConfig = this.
|
|
39
|
-
const modelAttributes = this.
|
|
40
|
-
const tokenId = `${this.actionVerb}-${this.
|
|
71
|
+
const actionConfig = ControllerHelper.findActionConfig(this.modelResource, this.action);
|
|
72
|
+
const fieldsConfig = this.modelResource.config?.fields || {};
|
|
73
|
+
const modelAttributes = this.modelResource.model.attributes;
|
|
74
|
+
const tokenId = `${this.actionVerb}-${this.modelResource.model.modelname}-${MODEL_TOKEN_SUFFIX}`;
|
|
41
75
|
if (!this.adminizer.accessRightsHelper.hasPermission(tokenId, this.user)) {
|
|
42
|
-
Adminizer.log.debug(`getFieldsConfig > No access rights to ${this.actionVerb}
|
|
76
|
+
Adminizer.log.debug(`getFieldsConfig > No access rights to ${this.actionVerb} model: ${this.modelResource.model.modelname}`);
|
|
43
77
|
return undefined;
|
|
44
78
|
}
|
|
45
79
|
const result = {};
|
|
@@ -48,7 +82,7 @@ export class DataAccessor {
|
|
|
48
82
|
if (modelAttributes[key].primaryKeyForAssociation === true) {
|
|
49
83
|
return undefined;
|
|
50
84
|
}
|
|
51
|
-
//
|
|
85
|
+
// Supports shorthand model attributes: fieldName: 'string'
|
|
52
86
|
if (typeof modelField === "string") {
|
|
53
87
|
modelField = { type: modelField };
|
|
54
88
|
}
|
|
@@ -82,9 +116,9 @@ export class DataAccessor {
|
|
|
82
116
|
let populatedModelFieldsConfig = {};
|
|
83
117
|
if (modelField.type === "association" || modelField.type === "association-many") {
|
|
84
118
|
const modelName = modelField.model || modelField.collection;
|
|
85
|
-
const tokenId = `read-${modelName}-${
|
|
119
|
+
const tokenId = `read-${modelName}-${MODEL_TOKEN_SUFFIX}`;
|
|
86
120
|
if (!this.adminizer.accessRightsHelper.hasPermission(tokenId, this.user)) {
|
|
87
|
-
Adminizer.log.silly(`No access rights to
|
|
121
|
+
Adminizer.log.silly(`No access rights to model: ${this.modelResource.model.modelname}`);
|
|
88
122
|
return undefined;
|
|
89
123
|
}
|
|
90
124
|
if (modelName) {
|
|
@@ -106,15 +140,31 @@ export class DataAccessor {
|
|
|
106
140
|
}
|
|
107
141
|
// Set required and type attributes
|
|
108
142
|
fldConfig.required = Boolean(fldConfig.required ?? modelField.required);
|
|
109
|
-
// Default type for field. Could be fetched
|
|
143
|
+
// Default type for field. Could be fetched from config file or model if not defined in config file.
|
|
110
144
|
fldConfig.type = (fldConfig.type || modelField.type).toLowerCase();
|
|
111
145
|
// Normalize final configuration (fldConfig is always an object here, normalize never returns undefined)
|
|
112
146
|
fldConfig = this.adminizer.configHelper.normalizeFieldConfig(this.adminizer, fldConfig, key, modelField);
|
|
113
147
|
// Add new field to result set
|
|
114
148
|
result[key] = { config: fldConfig, model: modelField, populated: populatedModelFieldsConfig, modelConfig: associatedModelConfig };
|
|
115
149
|
});
|
|
116
|
-
this.fields = result;
|
|
117
|
-
return
|
|
150
|
+
this.fields = this.orderFieldsByConfig(result, fieldsConfig, actionConfig.fields);
|
|
151
|
+
return this.fields;
|
|
152
|
+
}
|
|
153
|
+
orderFieldsByConfig(fields, globalFieldsConfig = {}, actionFieldsConfig = {}) {
|
|
154
|
+
const orderedFields = {};
|
|
155
|
+
const appendField = (fieldName) => {
|
|
156
|
+
if (!Object.prototype.hasOwnProperty.call(fields, fieldName)) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (Object.prototype.hasOwnProperty.call(orderedFields, fieldName)) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
orderedFields[fieldName] = fields[fieldName];
|
|
163
|
+
};
|
|
164
|
+
Object.keys(actionFieldsConfig || {}).forEach(appendField);
|
|
165
|
+
Object.keys(globalFieldsConfig || {}).forEach(appendField);
|
|
166
|
+
Object.keys(fields).forEach(appendField);
|
|
167
|
+
return orderedFields;
|
|
118
168
|
}
|
|
119
169
|
getAssociatedFieldsConfig(modelName) {
|
|
120
170
|
const model = this.adminizer.modelHandler.model.get(modelName);
|
|
@@ -123,9 +173,9 @@ export class DataAccessor {
|
|
|
123
173
|
return undefined;
|
|
124
174
|
}
|
|
125
175
|
// Check if user has access to the associated model
|
|
126
|
-
const tokenId = `read-${modelName}-${
|
|
176
|
+
const tokenId = `read-${modelName}-${MODEL_TOKEN_SUFFIX}`;
|
|
127
177
|
if (!this.adminizer.accessRightsHelper.hasPermission(tokenId, this.user)) {
|
|
128
|
-
Adminizer.log.debug(`getAssociatedFieldsConfig > No access rights to ${this.actionVerb}
|
|
178
|
+
Adminizer.log.debug(`getAssociatedFieldsConfig > No access rights to ${this.actionVerb} model: ${modelName}`);
|
|
129
179
|
return undefined;
|
|
130
180
|
}
|
|
131
181
|
const associatedFields = {};
|
|
@@ -181,7 +231,7 @@ export class DataAccessor {
|
|
|
181
231
|
return associatedFields;
|
|
182
232
|
}
|
|
183
233
|
checkFieldAccess(key, fieldConfig) {
|
|
184
|
-
if (this.
|
|
234
|
+
if (this.modelResource.model.primaryKey === key) {
|
|
185
235
|
return true;
|
|
186
236
|
}
|
|
187
237
|
if (this.user.isAdministrator) {
|
|
@@ -208,7 +258,7 @@ export class DataAccessor {
|
|
|
208
258
|
}
|
|
209
259
|
const filteredRecord = {};
|
|
210
260
|
// Set the primary key value
|
|
211
|
-
const primaryKey = (this.
|
|
261
|
+
const primaryKey = (this.modelResource.model.primaryKey ?? 'id');
|
|
212
262
|
filteredRecord[primaryKey] = record[primaryKey];
|
|
213
263
|
for (const fieldKey in record) {
|
|
214
264
|
const fieldConfig = this.fields[fieldKey];
|
|
@@ -278,19 +328,21 @@ export class DataAccessor {
|
|
|
278
328
|
processMany(records) {
|
|
279
329
|
return records.map(record => this.process(record));
|
|
280
330
|
}
|
|
281
|
-
async sanitizeUserRelationAccess(criteria) {
|
|
331
|
+
async sanitizeUserRelationAccess(criteria = {}) {
|
|
282
332
|
let sanitizedCriteria = {};
|
|
283
333
|
// Retrieve model configuration from adminpanel config
|
|
284
|
-
const modelName = this.
|
|
285
|
-
const modelConfig = this.
|
|
334
|
+
const modelName = this.modelResource.model.modelname;
|
|
335
|
+
const modelConfig = this.modelResource.config;
|
|
286
336
|
// Check if the model has `userAccessRelation` configured
|
|
287
337
|
if (!this.user.isAdministrator && modelConfig && modelConfig.userAccessRelation) {
|
|
338
|
+
Adminizer.log.warn(`[userAccessRelation] Model "${modelName}" has userAccessRelation="${modelConfig.userAccessRelation}". ` +
|
|
339
|
+
`User "${this.user.login}" (id: ${this.user.id}) will only see records they own.`);
|
|
288
340
|
// Get access field from userAccessRelation
|
|
289
341
|
const userAccessRelation = modelConfig.userAccessRelation;
|
|
290
342
|
if (typeof userAccessRelation === 'string') {
|
|
291
343
|
let accessField = userAccessRelation;
|
|
292
344
|
// Check if the relation points to `UserAP` or `GroupAP` in the model's attributes
|
|
293
|
-
const modelAttributes = this.
|
|
345
|
+
const modelAttributes = this.modelResource.model.attributes;
|
|
294
346
|
const relation = modelAttributes[accessField];
|
|
295
347
|
if (!relation || !['userap', 'groupap'].includes(relation.model.toLowerCase() || relation.collection.toLowerCase())) {
|
|
296
348
|
throw new Error(`Invalid userAccessRelation configuration for model ${modelName}`);
|
|
@@ -307,7 +359,7 @@ export class DataAccessor {
|
|
|
307
359
|
sanitizedCriteria = { ...sanitizedCriteria, [accessField]: { in: userGroups } };
|
|
308
360
|
}
|
|
309
361
|
}
|
|
310
|
-
/** Warning:
|
|
362
|
+
/** Warning: collection relation access is not supported and needs adapter-level processing */
|
|
311
363
|
if (relation.collection) {
|
|
312
364
|
Adminizer.log.warn(`Collection relation is not supported and was not tested. You may have an error here: ${JSON.stringify(relation, null, 2)}`);
|
|
313
365
|
if (relation.collection.toLowerCase() === 'userap') {
|
|
@@ -325,7 +377,7 @@ export class DataAccessor {
|
|
|
325
377
|
// If userAccessRelation is an object
|
|
326
378
|
const { field, via } = userAccessRelation;
|
|
327
379
|
// Get attributes of the current model and validate the intermediate relation
|
|
328
|
-
const modelAttributes = this.
|
|
380
|
+
const modelAttributes = this.modelResource.model.attributes;
|
|
329
381
|
const intermediateRelation = modelAttributes[field];
|
|
330
382
|
if (!intermediateRelation || !intermediateRelation.model) {
|
|
331
383
|
throw new Error(`Invalid intermediate relation configuration for field "${field}" in model ${modelName}`);
|
|
@@ -343,28 +395,23 @@ export class DataAccessor {
|
|
|
343
395
|
`Currently, only relations to "userap" are supported`);
|
|
344
396
|
}
|
|
345
397
|
// Fetch all intermediate records associated with the user
|
|
346
|
-
const intermediateRecords = await
|
|
398
|
+
const intermediateRecords = await this.accessRelationModel(intermediateRelation.model).find({ where: { [via]: this.user.id } });
|
|
347
399
|
const intermediateIds = (intermediateRecords || []).map((r) => r.id);
|
|
348
400
|
// Filter main model by all matching intermediate record IDs
|
|
349
401
|
sanitizedCriteria = { ...sanitizedCriteria, [field]: { in: intermediateIds } };
|
|
350
402
|
}
|
|
351
403
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
}
|
|
357
|
-
else {
|
|
358
|
-
_criteria = { ..._criteria, ...sanitizedCriteria };
|
|
359
|
-
}
|
|
360
|
-
return _criteria;
|
|
404
|
+
return {
|
|
405
|
+
...criteria,
|
|
406
|
+
where: mergeCriteriaWhere(criteria.where, sanitizedCriteria)
|
|
407
|
+
};
|
|
361
408
|
}
|
|
362
409
|
async setUserRelationAccess(record) {
|
|
363
410
|
let updatedRecord = { ...record };
|
|
364
411
|
// Check if model has `userAccessRelation` configured
|
|
365
|
-
if (this.
|
|
412
|
+
if (this.modelResource.config && this.modelResource.config.userAccessRelation) {
|
|
366
413
|
// Get access field from userAccessRelation
|
|
367
|
-
const userAccessRelation = this.
|
|
414
|
+
const userAccessRelation = this.modelResource.config.userAccessRelation;
|
|
368
415
|
if (typeof userAccessRelation === 'string') {
|
|
369
416
|
let accessField = userAccessRelation;
|
|
370
417
|
// only admin can set user access relation manually
|
|
@@ -372,7 +419,7 @@ export class DataAccessor {
|
|
|
372
419
|
delete updatedRecord[accessField];
|
|
373
420
|
}
|
|
374
421
|
// Check if the relation points to `UserAP` or `GroupAP` in the model's attributes
|
|
375
|
-
const modelAttributes = this.
|
|
422
|
+
const modelAttributes = this.modelResource.model.attributes;
|
|
376
423
|
const relation = modelAttributes[accessField];
|
|
377
424
|
if (relation && ['userap', 'groupap'].includes(relation.model.toLowerCase())) {
|
|
378
425
|
if (relation.model.toLowerCase() === 'userap') {
|
|
@@ -399,10 +446,10 @@ export class DataAccessor {
|
|
|
399
446
|
if (!via) {
|
|
400
447
|
throw new Error(`Invalid userAccessRelation configuration: "via" is required`);
|
|
401
448
|
}
|
|
402
|
-
const modelAttributes = this.
|
|
449
|
+
const modelAttributes = this.modelResource.model.attributes;
|
|
403
450
|
const intermediateRelation = modelAttributes[field];
|
|
404
451
|
if (!intermediateRelation || !intermediateRelation.model) {
|
|
405
|
-
throw new Error(`Invalid intermediate relation configuration for field "${field}" in model ${this.
|
|
452
|
+
throw new Error(`Invalid intermediate relation configuration for field "${field}" in model ${this.modelResource.model.modelname}`);
|
|
406
453
|
}
|
|
407
454
|
const intermediateModel = this.adminizer.modelHandler.model.get(intermediateRelation.model.toLowerCase());
|
|
408
455
|
if (!intermediateModel) {
|
|
@@ -419,7 +466,7 @@ export class DataAccessor {
|
|
|
419
466
|
const chosenId = typeof updatedRecord[field] === 'object'
|
|
420
467
|
? updatedRecord[field][intermediatePk]
|
|
421
468
|
: updatedRecord[field];
|
|
422
|
-
const record = await
|
|
469
|
+
const record = await this.accessRelationModel(intermediateRelation.model).findOne({ where: { [intermediatePk]: chosenId, [via]: this.user.id } });
|
|
423
470
|
if (!record) {
|
|
424
471
|
throw new Error(`Access denied: "${field}" does not belong to the current user`);
|
|
425
472
|
}
|
package/lib/I18n.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ type I18nOptions = {
|
|
|
5
5
|
locales?: string[];
|
|
6
6
|
defaultLocale?: string;
|
|
7
7
|
directory?: string;
|
|
8
|
+
missingDirectory?: string;
|
|
8
9
|
extension?: string;
|
|
9
10
|
cookieName?: string;
|
|
10
11
|
sessionVarName?: string;
|
|
@@ -19,7 +20,10 @@ export declare class I18n {
|
|
|
19
20
|
private devMode;
|
|
20
21
|
private static locales;
|
|
21
22
|
private defaultLocale;
|
|
23
|
+
private defaultDirectory;
|
|
22
24
|
private directory;
|
|
25
|
+
private customDirectory?;
|
|
26
|
+
private missingDirectory?;
|
|
23
27
|
private extension;
|
|
24
28
|
private cookieName;
|
|
25
29
|
private sessionVarName;
|
|
@@ -37,8 +41,8 @@ export declare class I18n {
|
|
|
37
41
|
isPreferredLocale(): boolean;
|
|
38
42
|
translate(locale: string, singular: string, plural?: string): any;
|
|
39
43
|
private readFile;
|
|
40
|
-
private writeFile;
|
|
41
44
|
private locateFile;
|
|
45
|
+
private writeMissingTranslation;
|
|
42
46
|
static appendLocale(locale: string, data: any): void;
|
|
43
47
|
static getLocales(): Record<string, LocaleData>;
|
|
44
48
|
}
|