adminizer 4.7.0-build.222 → 5.0.0-build.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.
- package/Readme.md +2 -1
- package/assets/add-a4odXvQk.js +1 -0
- package/assets/add-group-D-NleXth.js +1 -0
- package/assets/add-user-B4SVJT5P.js +1 -0
- package/assets/app-CtWuWD5N.css +1 -0
- package/assets/app-layout-eaSzcROf.js +1 -0
- package/assets/app.js +35 -39
- package/assets/catalog-ByUICd5z.js +6 -0
- package/assets/controls/chunks/_commonjsHelpers-C6fGbg64.js +6 -0
- package/assets/controls/chunks/index-CjiZ2FIa.js +93 -0
- package/assets/controls/chunks/jsx-runtime-jIxVPx5o.js +31 -0
- package/assets/controls/chunks/use-appearance-CFLOwiSX.js +38 -0
- package/assets/controls/chunks/use-window-size-BXgBKW65.js +19 -0
- package/assets/controls/chunks/vanilla-picker-Dg97NL4h.js +529 -0
- package/assets/{RelationDialogStack-CnHFOYyR.css → controls/ckeditor.css} +1 -1
- package/assets/controls/ckeditor.es.js +83663 -0
- package/assets/controls/handsontable.css +1 -0
- package/assets/controls/handsontable.es.js +70550 -0
- package/assets/controls/jsoneditor.css +1 -0
- package/assets/controls/jsoneditor.es.js +42009 -0
- package/assets/controls/leaflet.css +1 -0
- package/assets/controls/leaflet.es.js +10299 -0
- package/assets/controls/monaco.es.js +618 -0
- package/assets/controls/toast-ui.css +1 -0
- package/assets/controls/toast-ui.es.js +41768 -0
- package/assets/dashboard-BYd8G2cW.js +3 -0
- package/assets/debounce-BMmXVQ06.js +1 -0
- package/assets/history-B8KIDy44.js +1 -0
- package/assets/init-user-8aUohVDq.js +1 -0
- package/assets/list-ChmtBGjG.js +4 -0
- package/assets/login-CO4laf6m.js +1 -0
- package/assets/manifest.json +60 -615
- package/assets/{media-manager-WcKe1EvD.js → media-manager-BDbpSSjH.js} +3 -3
- package/assets/module-D59aE9uv.js +1 -0
- package/assets/notification-DNoyfNmT.js +20 -0
- package/assets/register-DBYIMXGQ.js +1 -0
- package/assets/{ru-eW0WKkga.js → ru-rYKdQbWF.js} +1 -1
- package/assets/use-appearance-_EbbjHTh.js +1 -0
- package/assets/user-filters-list-BMFRwkYF.js +1 -0
- package/assets/welcome-37rNVUHt.js +1 -0
- package/controllers/add.d.ts +1 -1
- package/controllers/addGroup.js +3 -3
- package/controllers/addUser.js +3 -3
- package/controllers/catalog/Catalog.d.ts +1 -1
- package/controllers/catalog/Catalog.js +2 -1
- package/controllers/catalog/FrontendCatalogAdapter.d.ts +2 -12
- package/controllers/catalog/FrontendCatalogAdapter.js +3 -16
- package/controllers/catalog/FrontentCatalogAdapter.d.ts +2 -12
- package/controllers/catalog/FrontentCatalogAdapter.js +0 -16
- package/controllers/edit.js +6 -11
- package/controllers/editGroup.d.ts +1 -1
- package/controllers/editGroup.js +3 -3
- package/controllers/editUser.d.ts +1 -1
- package/controllers/editUser.js +3 -3
- package/controllers/feed.js +1 -1
- package/controllers/filter-fields/columns.js +1 -1
- package/controllers/filter-fields/getAllUserFilters.js +2 -2
- package/controllers/filter-fields/groups.js +2 -2
- package/controllers/filter-fields/savedFilters.js +1 -1
- package/controllers/history-actions/HistoryController.js +1 -1
- package/controllers/initUser.js +2 -2
- package/controllers/list.d.ts +1 -1
- package/controllers/login.d.ts +1 -1
- package/controllers/login.js +3 -3
- package/controllers/media-manager/ThumbController.js +2 -2
- package/controllers/media-manager/mediaManagerApi.js +13 -15
- package/controllers/register.d.ts +1 -1
- package/controllers/register.js +5 -5
- package/controllers/remove.d.ts +1 -1
- package/controllers/userApiKey.js +2 -2
- package/controllers/view.d.ts +1 -1
- package/controllers/view.js +5 -5
- package/controllers/widgets/Action.js +5 -2
- package/controllers/widgets/Info.js +1 -1
- package/controllers/widgets/filterInfo.js +1 -1
- package/files/favicon.png +0 -0
- package/helpers/accessRightsHelper.d.ts +6 -4
- package/helpers/accessRightsHelper.js +13 -0
- package/helpers/diffHelpers.js +1 -1
- package/helpers/fieldsHelper.d.ts +1 -1
- package/helpers/fieldsHelper.js +8 -4
- package/helpers/filterDatetimeHelper.d.ts +1 -1
- package/helpers/inertiaAddHelper.d.ts +6 -5
- package/helpers/inertiaAddHelper.js +45 -37
- package/helpers/inertiaAutHelper.js +5 -5
- package/helpers/inertiaGroupHelper.d.ts +4 -4
- package/helpers/inertiaMenuHelper.js +1 -1
- package/helpers/inertiaUserHelper.d.ts +3 -3
- package/helpers/inertiaUserHelper.js +1 -1
- package/helpers/menuHelper.d.ts +2 -2
- package/index.d.ts +18 -6
- package/index.js +18 -6
- package/interfaces/adminpanelConfig.d.ts +10 -33
- package/interfaces/global.d.ts +10 -15
- package/interfaces/listQueryBuilder.d.ts +1 -1
- package/lib/Adminizer.d.ts +25 -2
- package/lib/Adminizer.js +124 -50
- package/lib/DataAccessor.d.ts +9 -5
- package/lib/DataAccessor.js +89 -42
- package/lib/access-rights/AccessRightsHandler.d.ts +17 -0
- package/lib/access-rights/AccessRightsHandler.js +63 -0
- package/lib/ai-assistant/AbstractAiModelService.d.ts +5 -8
- package/lib/ai-assistant/AbstractAiModelService.js +3 -14
- package/lib/ai-assistant/AiAssistantHandler.d.ts +2 -2
- package/lib/app-manager/AdminizerApp.d.ts +228 -0
- package/lib/app-manager/AdminizerApp.js +17 -0
- package/lib/app-manager/AppManager.d.ts +18 -0
- package/lib/app-manager/AppManager.js +537 -0
- package/lib/app-manager/AssetHandler.d.ts +17 -0
- package/lib/app-manager/AssetHandler.js +67 -0
- package/lib/app-manager/ConfigLayerHandler.d.ts +18 -0
- package/lib/app-manager/ConfigLayerHandler.js +119 -0
- package/lib/app-manager/ControllerHandler.d.ts +25 -0
- package/lib/app-manager/ControllerHandler.js +140 -0
- package/lib/catalog/AbstractCatalog.d.ts +28 -19
- package/lib/catalog/AbstractCatalog.js +41 -10
- package/lib/catalog/CatalogHandler.d.ts +13 -0
- package/lib/catalog/CatalogHandler.js +48 -2
- package/lib/catalog/CatalogTemplateComponentHandler.d.ts +23 -0
- package/lib/catalog/CatalogTemplateComponentHandler.js +59 -0
- package/lib/controls/Control.d.ts +17 -0
- package/lib/controls/Control.js +1 -0
- package/lib/controls/ControlsHandler.d.ts +5 -6
- package/lib/controls/ControlsHandler.js +0 -13
- package/lib/controls/codeEditor/MonacoEditor.d.ts +3 -4
- package/lib/controls/codeEditor/MonacoEditor.js +13 -8
- package/lib/controls/geojsoneditor/GeoEditor.d.ts +3 -4
- package/lib/controls/geojsoneditor/GeoEditor.js +14 -9
- package/lib/controls/jsoneditor/JsonEditor.d.ts +5 -6
- package/lib/controls/jsoneditor/JsonEditor.js +14 -13
- package/lib/controls/markdown/ToastUiEditor.d.ts +5 -6
- package/lib/controls/markdown/ToastUiEditor.js +14 -13
- package/lib/controls/table/Handsontable.d.ts +5 -6
- package/lib/controls/table/Handsontable.js +14 -13
- package/lib/controls/wysiwyg/CKeditor.d.ts +5 -6
- package/lib/controls/wysiwyg/CKeditor.js +14 -13
- package/lib/filters/ConditionValidator.d.ts +1 -1
- package/lib/filters/FilterService.d.ts +18 -18
- package/lib/filters/FilterService.js +11 -11
- package/lib/history-actions/AbstractHistoryAdapter.d.ts +14 -14
- package/lib/history-actions/AbstractHistoryAdapter.js +5 -6
- package/lib/history-actions/DefaultHistoryAdapter.d.ts +7 -7
- package/lib/history-actions/DefaultHistoryAdapter.js +2 -2
- package/lib/list-query-builder/ListQueryBuilder.d.ts +1 -1
- package/lib/media-manager/AbstractMediaManager.d.ts +14 -3
- package/lib/media-manager/AbstractMediaManager.js +16 -5
- package/lib/media-manager/MediaManagerHandler.d.ts +3 -0
- package/lib/media-manager/MediaManagerHandler.js +30 -5
- package/lib/media-manager/Thumb.js +7 -13
- package/lib/media-manager/helpers/MediaManagerHelper.d.ts +6 -4
- package/lib/media-manager/helpers/MediaManagerHelper.js +18 -18
- package/lib/model/AbstractModel.d.ts +9 -5
- package/lib/model/AbstractModel.js +9 -13
- package/lib/model/InternalModelAccessFactory.js +9 -10
- package/lib/model/ModelHandler.d.ts +45 -7
- package/lib/model/ModelHandler.js +168 -11
- package/lib/model/adapter/sequelize.d.ts +2 -4
- package/lib/model/adapter/sequelize.js +16 -193
- package/lib/model/adapter/typeorm.d.ts +2 -4
- package/lib/model/adapter/typeorm.js +2 -35
- package/lib/notifications/AbstractNotificationService.d.ts +9 -9
- package/lib/notifications/AbstractNotificationService.js +8 -8
- package/lib/notifications/GeneralNotificationService.js +1 -1
- package/lib/notifications/SystemNotificationService.js +1 -1
- package/lib/ui-i18n/uiTranslationKeys.d.ts +1 -1
- package/lib/ui-i18n/uiTranslationKeys.js +1 -0
- package/lib/widgets/abstractCustom.d.ts +7 -2
- package/lib/widgets/abstractCustom.js +6 -0
- package/lib/widgets/abstractInfo.d.ts +4 -1
- package/lib/widgets/abstractWidgetBase.d.ts +2 -0
- package/lib/widgets/abstractWidgetBase.js +2 -0
- package/lib/widgets/widgetHandler.d.ts +6 -2
- package/lib/widgets/widgetHandler.js +70 -19
- package/models/{FilterAP.d.ts → Filter.d.ts} +4 -70
- package/models/Filter.js +1 -0
- package/models/FilterColumn.d.ts +10 -0
- package/models/FilterColumn.js +1 -0
- package/models/Group.d.ts +8 -0
- package/models/Group.js +1 -0
- package/models/HistoryActions.d.ts +14 -0
- package/models/HistoryActions.js +1 -0
- package/models/MediaManagerAP.d.ts +2 -54
- package/models/MediaManagerAP.js +1 -51
- package/models/MediaManagerAssociationsAP.d.ts +1 -35
- package/models/MediaManagerAssociationsAP.js +1 -33
- package/models/MediaManagerMetaAP.d.ts +2 -30
- package/models/MediaManagerMetaAP.js +1 -27
- package/models/Notification.d.ts +13 -0
- package/models/Notification.js +1 -0
- package/models/User.d.ts +23 -0
- package/models/User.js +1 -0
- package/models/UserNotification.d.ts +7 -0
- package/models/UserNotification.js +1 -0
- package/package.json +25 -30
- package/services/FeedService.d.ts +5 -5
- package/services/FeedService.js +1 -1
- package/system/Router.js +2 -10
- package/system/bindAccessRights.js +1 -1
- package/system/bindAuthorization.js +2 -2
- package/system/bindControls.js +7 -6
- package/system/bindDashboardWidgets.js +3 -2
- package/system/bindDev.js +1 -1
- package/system/bindHistory.d.ts +1 -1
- package/system/bindHistory.js +1 -1
- package/system/bindInertia.js +0 -6
- package/system/bindMediaManager.js +4 -17
- package/system/bindNotifications.d.ts +1 -1
- package/system/bindNotifications.js +1 -1
- package/system/bindReqFunctions.d.ts +1 -0
- package/system/bindReqFunctions.js +20 -3
- package/system/buildInternalModelAccess.js +2 -15
- package/system/defaults.js +5 -10
- package/system/systemModelContracts.d.ts +22 -0
- package/system/systemModelContracts.js +155 -0
- package/system/validateSystemModels.d.ts +2 -0
- package/system/validateSystemModels.js +101 -0
- package/translations/ar.json +2 -1
- package/translations/cn.json +2 -1
- package/translations/de.json +2 -1
- package/translations/en.json +1 -0
- package/translations/es.json +2 -1
- package/translations/fr.json +2 -1
- package/translations/hi.json +2 -1
- package/translations/jp.json +2 -1
- package/translations/ko.json +2 -1
- package/translations/pt.json +2 -1
- package/translations/ru.json +2 -1
- package/translations/ua.json +2 -1
- package/translations/uz.json +2 -1
- package/translations/vi.json +2 -1
- package/ui/components/VanillaJSONEditor.d.ts +1 -1
- package/ui/components/handsontable.d.ts +1 -1
- package/ui/components/ui/avatar.d.ts +3 -3
- package/ui/components/ui/badge.d.ts +1 -1
- package/ui/components/ui/breadcrumb.d.ts +7 -7
- package/ui/components/ui/button.d.ts +1 -1
- package/ui/components/ui/calendar.d.ts +1 -1
- package/ui/components/ui/card.d.ts +7 -7
- package/ui/components/ui/checkbox.d.ts +1 -1
- package/ui/components/ui/collapsible.d.ts +3 -3
- package/ui/components/ui/command.d.ts +9 -9
- package/ui/components/ui/context-menu.d.ts +15 -15
- package/ui/components/ui/dialog-stack.d.ts +10 -10
- package/ui/components/ui/dialog.d.ts +10 -10
- package/ui/components/ui/dropdown-menu.d.ts +15 -15
- package/ui/components/ui/input.d.ts +1 -1
- package/ui/components/ui/label.d.ts +1 -1
- package/ui/components/ui/menubar.d.ts +16 -16
- package/ui/components/ui/pagination.d.ts +7 -7
- package/ui/components/ui/popover.d.ts +4 -4
- package/ui/components/ui/select.d.ts +10 -10
- package/ui/components/ui/separator.d.ts +1 -1
- package/ui/components/ui/sheet.d.ts +8 -8
- package/ui/components/ui/sidebar.d.ts +23 -23
- package/ui/components/ui/skeleton.d.ts +1 -1
- package/ui/components/ui/slider.d.ts +1 -1
- package/ui/components/ui/sonner.d.ts +1 -1
- package/ui/components/ui/switch.d.ts +1 -1
- package/ui/components/ui/table.d.ts +8 -8
- package/ui/components/ui/tabs.d.ts +4 -4
- package/ui/components/ui/textarea.d.ts +1 -1
- package/ui/components/ui/tooltip.d.ts +4 -4
- package/assets/RelationDialogStack-DI2bZxQX.js +0 -20
- package/assets/add-DCQ7ZW4B.js +0 -1
- package/assets/add-group-DCVPryBo.js +0 -1
- package/assets/add-group-form-DKRXC2n-.js +0 -1
- package/assets/add-user-B7OOiYxv.js +0 -1
- package/assets/add-user-form-UXAToWQd.js +0 -1
- package/assets/app-AKbNCggP.css +0 -1
- package/assets/app-layout-6EwNBvnR.js +0 -1
- package/assets/app-shell-D8wtkECO.js +0 -1
- package/assets/app-sidebar-DfGjL-2K.js +0 -1
- package/assets/app-sidebar-header-BZbIBQjq.js +0 -1
- package/assets/breadcrumbs-CODaqVkB.js +0 -1
- package/assets/catalog-DVvFGa2X.js +0 -6
- package/assets/dashboard-BadoiH_a.js +0 -3
- package/assets/date-picker-DSOkNiNo.js +0 -1
- package/assets/del-modal-Cd4M7af8.js +0 -1
- package/assets/dynamic-controls-BsrJhPDY.js +0 -1
- package/assets/geo-json-CzR5JBXL.js +0 -1
- package/assets/handsontable-BI98OF5R.js +0 -336
- package/assets/history-D1iLA6rs.js +0 -1
- package/assets/home-DbWj-W_k.js +0 -2
- package/assets/icon-C2JNaLxH.js +0 -1
- package/assets/init-user-D2HSyXup.js +0 -1
- package/assets/input-error-CH2caTtO.js +0 -1
- package/assets/jsoneditor-DVNQmA6G.js +0 -3869
- package/assets/list-CVoljVUw.js +0 -4
- package/assets/login-DFSLEO17.js +0 -1
- package/assets/material-icon-Bx9pGQiQ.js +0 -1
- package/assets/module-DJsC37CM.js +0 -1
- package/assets/monaco-Bl4zdWCn.js +0 -11
- package/assets/nav-footer-BiSQkPt4.js +0 -1
- package/assets/nav-main-rTH0PfDw.js +0 -1
- package/assets/nav-user-Bj6cWs0a.js +0 -1
- package/assets/notification-DKrNfaAB.js +0 -20
- package/assets/pagination-render-AKJvTIRA.js +0 -1
- package/assets/register-BTP4uxsK.js +0 -1
- package/assets/theme-switcher-Dm8EOGzx.js +0 -1
- package/assets/toast-editor-DOg_gvSp.js +0 -668
- package/assets/user-filters-list-C9R9J6Om.js +0 -1
- package/assets/user-info-BgSbT02v.js +0 -1
- package/assets/user-menu-content-TQTXHIv6.js +0 -1
- package/assets/vanilla-picker-B3LgXoKV.js +0 -2
- package/assets/vendor-l0sNRNKZ.js +0 -1
- package/assets/welcome-BwDlAOGh.js +0 -1
- package/controllers/navigation/edit.d.ts +0 -1
- package/controllers/navigation/edit.js +0 -8
- package/lib/ai-assistant/DummyAiModelService.d.ts +0 -8
- package/lib/ai-assistant/DummyAiModelService.js +0 -14
- package/lib/ai-assistant/OpenAiModelService.d.ts +0 -24
- package/lib/ai-assistant/OpenAiModelService.js +0 -184
- package/lib/catalog/Navigation.d.ts +0 -49
- package/lib/catalog/Navigation.js +0 -492
- package/lib/controls/AbstractControls.d.ts +0 -30
- package/lib/controls/AbstractControls.js +0 -14
- package/lib/media-manager/DefaultMediaManager.d.ts +0 -20
- package/lib/media-manager/DefaultMediaManager.js +0 -127
- package/lib/media-manager/Items.d.ts +0 -50
- package/lib/media-manager/Items.js +0 -296
- package/models/FilterAP.js +0 -68
- package/models/FilterColumnAP.d.ts +0 -32
- package/models/FilterColumnAP.js +0 -21
- package/models/GroupAP.d.ts +0 -31
- package/models/GroupAP.js +0 -22
- package/models/HistoryActionsAP.d.ts +0 -56
- package/models/HistoryActionsAP.js +0 -42
- package/models/NavigationAP.d.ts +0 -22
- package/models/NavigationAP.js +0 -16
- package/models/NotificationAP.d.ts +0 -44
- package/models/NotificationAP.js +0 -30
- package/models/UserAP.d.ts +0 -81
- package/models/UserAP.js +0 -57
- package/models/UserNotificationAP.d.ts +0 -26
- package/models/UserNotificationAP.js +0 -18
- package/system/bindAiAssistant.d.ts +0 -2
- package/system/bindAiAssistant.js +0 -30
- package/system/bindModels.d.ts +0 -2
- package/system/bindModels.js +0 -48
- package/system/bindNavigation.d.ts +0 -2
- package/system/bindNavigation.js +0 -38
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
import { Adminizer } from "../Adminizer.js";
|
|
2
2
|
import { InternalModelAccessFactory } from "./InternalModelAccessFactory.js";
|
|
3
|
+
import { createInternalModelRepository } from "./internalModelRepository.js";
|
|
4
|
+
function normalizeName(name) {
|
|
5
|
+
return name.toLowerCase();
|
|
6
|
+
}
|
|
7
|
+
export class AppModelAccess {
|
|
8
|
+
getModel;
|
|
9
|
+
appName;
|
|
10
|
+
allowedModels;
|
|
11
|
+
constructor(getModel, appName, allowedModels) {
|
|
12
|
+
this.getModel = getModel;
|
|
13
|
+
this.appName = appName;
|
|
14
|
+
this.allowedModels = allowedModels;
|
|
15
|
+
}
|
|
16
|
+
get(modelName) {
|
|
17
|
+
const normalizedModelName = normalizeName(modelName);
|
|
18
|
+
if (!this.allowedModels().has(normalizedModelName)) {
|
|
19
|
+
throw new Error(`App model access denied: app "${this.appName}" cannot use model "${modelName}"`);
|
|
20
|
+
}
|
|
21
|
+
const model = this.getModel(modelName);
|
|
22
|
+
if (!model) {
|
|
23
|
+
throw new Error(`App model access failed: model "${modelName}" was not found`);
|
|
24
|
+
}
|
|
25
|
+
return createInternalModelRepository(modelName, model);
|
|
26
|
+
}
|
|
27
|
+
has(modelName) {
|
|
28
|
+
return this.allowedModels().has(normalizeName(modelName)) && Boolean(this.getModel(modelName));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
3
31
|
/**
|
|
4
32
|
* Central registry (service locator) for all AbstractModel instances in the application.
|
|
5
33
|
* A single instance is created in Adminizer and shared across the entire app via `req.adminizer.modelHandler`.
|
|
@@ -7,27 +35,105 @@ import { InternalModelAccessFactory } from "./InternalModelAccessFactory.js";
|
|
|
7
35
|
* Models are registered at startup via `bindModels`, then looked up by name from controllers,
|
|
8
36
|
* services, helpers, and system utilities — without importing each model directly.
|
|
9
37
|
*
|
|
10
|
-
* Lookup is case-insensitive
|
|
38
|
+
* Lookup is case-insensitive and can resolve aliases registered at startup via system model bindings.
|
|
11
39
|
*/
|
|
12
40
|
export class ModelHandler {
|
|
13
41
|
models = new Map();
|
|
42
|
+
modelAliases = new Map();
|
|
14
43
|
internalAccess;
|
|
15
|
-
|
|
44
|
+
appAccessRecords = new Map();
|
|
45
|
+
add(modelName, modelInstance, aliases = []) {
|
|
16
46
|
const modelname = modelName.toLowerCase();
|
|
17
|
-
this.models.set(modelname,
|
|
47
|
+
this.models.set(modelname, {
|
|
48
|
+
id: modelname,
|
|
49
|
+
name: modelName,
|
|
50
|
+
model: modelInstance,
|
|
51
|
+
enabled: true,
|
|
52
|
+
});
|
|
53
|
+
this.registerAliases(modelName, aliases);
|
|
18
54
|
Adminizer.log.debug(`Model with name [${modelname}] was registered`);
|
|
19
55
|
}
|
|
20
|
-
|
|
21
|
-
|
|
56
|
+
register(appName, modelName, modelInstance) {
|
|
57
|
+
const normalizedModelName = normalizeName(modelName);
|
|
58
|
+
if (this.models.has(normalizedModelName)) {
|
|
59
|
+
throw new Error(`Model "${modelName}" is already registered`);
|
|
60
|
+
}
|
|
61
|
+
this.models.set(normalizedModelName, {
|
|
62
|
+
id: normalizedModelName,
|
|
63
|
+
name: modelName,
|
|
64
|
+
model: modelInstance,
|
|
65
|
+
ownerApp: appName,
|
|
66
|
+
enabled: true,
|
|
67
|
+
});
|
|
68
|
+
Adminizer.log.debug(`Model with name [${normalizedModelName}] was registered by app [${appName}]`);
|
|
69
|
+
return normalizedModelName;
|
|
70
|
+
}
|
|
71
|
+
unregister(id) {
|
|
72
|
+
const record = this.models.get(normalizeName(id));
|
|
73
|
+
if (!record?.ownerApp) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
this.models.delete(normalizeName(id));
|
|
77
|
+
}
|
|
78
|
+
disable(id) {
|
|
79
|
+
const record = this.models.get(normalizeName(id));
|
|
80
|
+
if (!record?.ownerApp) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
record.enabled = false;
|
|
84
|
+
}
|
|
85
|
+
enable(id) {
|
|
86
|
+
const record = this.models.get(normalizeName(id));
|
|
87
|
+
if (!record?.ownerApp) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
record.enabled = true;
|
|
91
|
+
}
|
|
92
|
+
getByApp(appName) {
|
|
93
|
+
return Array.from(this.models.values()).filter((record) => record.ownerApp === appName);
|
|
94
|
+
}
|
|
95
|
+
registerAppAccess(appName, id, models) {
|
|
96
|
+
const resourceId = `${appName}:${id}`;
|
|
97
|
+
if (this.appAccessRecords.has(resourceId)) {
|
|
98
|
+
throw new Error(`App model access "${resourceId}" is already registered`);
|
|
99
|
+
}
|
|
100
|
+
const missingModels = models.filter((modelName) => !this.model.has(modelName));
|
|
101
|
+
if (missingModels.length) {
|
|
102
|
+
throw new Error(`App "${appName}" requested missing models: ${missingModels.join(", ")}`);
|
|
103
|
+
}
|
|
104
|
+
this.appAccessRecords.set(resourceId, {
|
|
105
|
+
id: resourceId,
|
|
106
|
+
appName,
|
|
107
|
+
models: Array.from(new Set(models.map(normalizeName))),
|
|
108
|
+
});
|
|
109
|
+
return resourceId;
|
|
110
|
+
}
|
|
111
|
+
unregisterAppAccess(id) {
|
|
112
|
+
this.appAccessRecords.delete(id);
|
|
113
|
+
}
|
|
114
|
+
getAppAccessRecords(appName) {
|
|
115
|
+
return Array.from(this.appAccessRecords.values()).filter((record) => record.appName === appName);
|
|
116
|
+
}
|
|
117
|
+
createAppAccess(appName) {
|
|
118
|
+
return new AppModelAccess((modelName) => this.model.get(modelName), appName, () => this.getAllowedAppModels(appName));
|
|
119
|
+
}
|
|
120
|
+
// TODO: 'hot reload' need add method for delete model & unbind
|
|
121
|
+
/** Improved model getter with case-insensitive lookup and configured alias support. */
|
|
22
122
|
get model() {
|
|
23
123
|
return {
|
|
24
|
-
get: (modelName) => this.models.get(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
124
|
+
get: (modelName) => this.models.get(this.resolveName(modelName))?.enabled
|
|
125
|
+
? this.models.get(this.resolveName(modelName)).model
|
|
126
|
+
: undefined,
|
|
127
|
+
has: (modelName) => Boolean(this.models.get(this.resolveName(modelName))?.enabled),
|
|
128
|
+
entries: () => this.enabledModelEntries(),
|
|
129
|
+
keys: () => this.enabledModelKeys(),
|
|
130
|
+
values: () => this.enabledModelValues(),
|
|
29
131
|
};
|
|
30
132
|
}
|
|
133
|
+
resolveModelName(modelName) {
|
|
134
|
+
const resolvedName = this.resolveName(modelName);
|
|
135
|
+
return this.models.get(resolvedName)?.name ?? modelName;
|
|
136
|
+
}
|
|
31
137
|
configureInternalAccess(accessMap) {
|
|
32
138
|
this.internalAccess = new InternalModelAccessFactory((modelName) => this.model.get(modelName), accessMap);
|
|
33
139
|
}
|
|
@@ -45,11 +151,62 @@ export class ModelHandler {
|
|
|
45
151
|
*/
|
|
46
152
|
get all() {
|
|
47
153
|
try {
|
|
48
|
-
return Array.from(this.
|
|
154
|
+
return Array.from(this.enabledModelValues());
|
|
49
155
|
}
|
|
50
156
|
catch (e) {
|
|
51
157
|
Adminizer.log.error(e);
|
|
52
158
|
return [];
|
|
53
159
|
}
|
|
54
160
|
}
|
|
161
|
+
getAllowedAppModels(appName) {
|
|
162
|
+
const allowedModels = new Set();
|
|
163
|
+
for (const record of this.getAppAccessRecords(appName)) {
|
|
164
|
+
for (const modelName of record.models) {
|
|
165
|
+
allowedModels.add(modelName);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return allowedModels;
|
|
169
|
+
}
|
|
170
|
+
registerAliases(modelName, aliases) {
|
|
171
|
+
const normalizedModelName = normalizeName(modelName);
|
|
172
|
+
for (const alias of aliases) {
|
|
173
|
+
const normalizedAlias = normalizeName(alias);
|
|
174
|
+
if (normalizedAlias === normalizedModelName) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const existingTarget = this.modelAliases.get(normalizedAlias);
|
|
178
|
+
if (existingTarget && existingTarget !== normalizedModelName) {
|
|
179
|
+
throw new Error(`Model alias "${alias}" is already registered for model "${existingTarget}"`);
|
|
180
|
+
}
|
|
181
|
+
if (this.models.has(normalizedAlias) && normalizedAlias !== normalizedModelName) {
|
|
182
|
+
throw new Error(`Model alias "${alias}" conflicts with a registered model`);
|
|
183
|
+
}
|
|
184
|
+
this.modelAliases.set(normalizedAlias, normalizedModelName);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
resolveName(modelName) {
|
|
188
|
+
const normalizedModelName = normalizeName(modelName);
|
|
189
|
+
return this.modelAliases.get(normalizedModelName) ?? normalizedModelName;
|
|
190
|
+
}
|
|
191
|
+
*enabledModelEntries() {
|
|
192
|
+
for (const [modelName, record] of this.models.entries()) {
|
|
193
|
+
if (record.enabled) {
|
|
194
|
+
yield [modelName, record.model];
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
*enabledModelKeys() {
|
|
199
|
+
for (const [modelName, record] of this.models.entries()) {
|
|
200
|
+
if (record.enabled) {
|
|
201
|
+
yield modelName;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
*enabledModelValues() {
|
|
206
|
+
for (const record of this.models.values()) {
|
|
207
|
+
if (record.enabled) {
|
|
208
|
+
yield record.model;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
55
212
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Sequelize, ModelStatic } from "sequelize";
|
|
2
|
-
import { AbstractAdapter, AbstractModel, Attribute } from "../AbstractModel";
|
|
2
|
+
import { AbstractAdapter, AbstractAdapterOptions, AbstractModel, Attribute } from "../AbstractModel";
|
|
3
3
|
import { QueryCriteria } from "../../../interfaces/queryCriteria";
|
|
4
4
|
export declare function mapSequelizeToAdminizerAttributes(model: ModelStatic<any>): Record<string, Attribute>;
|
|
5
5
|
export declare class SequelizeModel<T> extends AbstractModel<T> {
|
|
@@ -47,10 +47,8 @@ export declare class SequelizeModel<T> extends AbstractModel<T> {
|
|
|
47
47
|
export declare class SequelizeAdapter extends AbstractAdapter {
|
|
48
48
|
sequelize: Sequelize;
|
|
49
49
|
Model: typeof SequelizeModel;
|
|
50
|
-
constructor(sequelize: Sequelize);
|
|
50
|
+
constructor(sequelize: Sequelize, options?: AbstractAdapterOptions);
|
|
51
51
|
get models(): Record<string, any>;
|
|
52
52
|
getModel(modelName: string): any;
|
|
53
53
|
getAttributes(modelName: string): any;
|
|
54
|
-
/** Registration of system models */
|
|
55
|
-
static registerSystemModels(sequelize: Sequelize, alter?: boolean): Promise<void>;
|
|
56
54
|
}
|
|
@@ -1,82 +1,5 @@
|
|
|
1
|
-
import { Sequelize,
|
|
1
|
+
import { Sequelize, Op, HasMany } from "sequelize";
|
|
2
2
|
import { AbstractAdapter, AbstractModel } from "../AbstractModel.js";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import fs from "fs";
|
|
5
|
-
import { pathToFileURL } from "url";
|
|
6
|
-
import { fileURLToPath } from "url";
|
|
7
|
-
function generateAssociationsFromSchema(models, schemas) {
|
|
8
|
-
for (const modelName in schemas) {
|
|
9
|
-
const schema = schemas[modelName];
|
|
10
|
-
const model = models[modelName];
|
|
11
|
-
if (!model)
|
|
12
|
-
continue;
|
|
13
|
-
for (const fieldName in schema) {
|
|
14
|
-
const field = schema[fieldName];
|
|
15
|
-
if (field.collection && field.via) {
|
|
16
|
-
const targetModel = models[field.collection];
|
|
17
|
-
const targetSchema = schemas[field.collection];
|
|
18
|
-
const inverseField = targetSchema?.[field.via];
|
|
19
|
-
// Normalize join table to lowercase for consistency across dialects
|
|
20
|
-
const throughTableName = [modelName, field.collection]
|
|
21
|
-
.sort()
|
|
22
|
-
.join("")
|
|
23
|
-
.toLowerCase();
|
|
24
|
-
// 💡 M:N connection
|
|
25
|
-
if (inverseField && inverseField.collection === modelName) {
|
|
26
|
-
model.belongsToMany(targetModel, {
|
|
27
|
-
through: throughTableName,
|
|
28
|
-
as: fieldName,
|
|
29
|
-
foreignKey: `${modelName}Id`,
|
|
30
|
-
otherKey: `${field.collection}Id`
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
// 💡 O:M communication (one to many)
|
|
34
|
-
else {
|
|
35
|
-
let foreignKey = `${modelName}Id`;
|
|
36
|
-
if (field.collection === modelName) {
|
|
37
|
-
foreignKey = `${field.via}Id`;
|
|
38
|
-
}
|
|
39
|
-
model.hasMany(targetModel, {
|
|
40
|
-
as: fieldName,
|
|
41
|
-
foreignKey,
|
|
42
|
-
});
|
|
43
|
-
const alias = field.via;
|
|
44
|
-
const belongsToOptions = { foreignKey };
|
|
45
|
-
if (targetModel.rawAttributes[alias] || targetModel.associations[alias]) {
|
|
46
|
-
belongsToOptions.as = `${alias}Ref`;
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
belongsToOptions.as = alias;
|
|
50
|
-
}
|
|
51
|
-
targetModel.belongsTo(model, belongsToOptions);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
// 💡 O:1 or 1:1 (belongsTo)
|
|
55
|
-
if (field.model) {
|
|
56
|
-
const targetModel = models[field.model];
|
|
57
|
-
if (!targetModel)
|
|
58
|
-
continue;
|
|
59
|
-
// Avoid naming collisions by using an explicit foreign key
|
|
60
|
-
const alias = fieldName;
|
|
61
|
-
const foreignKey = `${alias}Id`;
|
|
62
|
-
// Reuse the attribute name unless it already exists on the model or association
|
|
63
|
-
let asName = alias;
|
|
64
|
-
if (model.rawAttributes[alias] || model.associations[alias]) {
|
|
65
|
-
asName = `${alias}Ref`;
|
|
66
|
-
}
|
|
67
|
-
const belongsToOptions = {
|
|
68
|
-
as: asName,
|
|
69
|
-
foreignKey,
|
|
70
|
-
};
|
|
71
|
-
// Add onDelete constraint if specified
|
|
72
|
-
if (field.onDelete) {
|
|
73
|
-
belongsToOptions.onDelete = field.onDelete;
|
|
74
|
-
}
|
|
75
|
-
model.belongsTo(targetModel, belongsToOptions);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
3
|
function resolveType(type) {
|
|
81
4
|
const sqlType = typeof type.toString === "function"
|
|
82
5
|
? type.toString().toLowerCase()
|
|
@@ -117,7 +40,7 @@ export function mapSequelizeToAdminizerAttributes(model) {
|
|
|
117
40
|
switch (assoc.associationType) {
|
|
118
41
|
case "BelongsTo": {
|
|
119
42
|
const a = assoc;
|
|
120
|
-
result
|
|
43
|
+
markAssociationForeignKey(result, a.foreignKey);
|
|
121
44
|
result[alias] = {
|
|
122
45
|
type: "association",
|
|
123
46
|
model: a.target.name,
|
|
@@ -127,7 +50,7 @@ export function mapSequelizeToAdminizerAttributes(model) {
|
|
|
127
50
|
}
|
|
128
51
|
case "HasOne": {
|
|
129
52
|
const a = assoc;
|
|
130
|
-
result
|
|
53
|
+
markAssociationForeignKey(result, a.foreignKey);
|
|
131
54
|
result[alias] = {
|
|
132
55
|
type: "association",
|
|
133
56
|
model: a.target.name,
|
|
@@ -159,6 +82,11 @@ export function mapSequelizeToAdminizerAttributes(model) {
|
|
|
159
82
|
}
|
|
160
83
|
return result;
|
|
161
84
|
}
|
|
85
|
+
function markAssociationForeignKey(attributes, foreignKey) {
|
|
86
|
+
if (typeof foreignKey === "string" && attributes[foreignKey]) {
|
|
87
|
+
attributes[foreignKey].primaryKeyForAssociation = true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
162
90
|
function capitalize(str) {
|
|
163
91
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
164
92
|
}
|
|
@@ -868,16 +796,16 @@ export class SequelizeModel extends AbstractModel {
|
|
|
868
796
|
_buildIncludes() {
|
|
869
797
|
return Object.keys(this.model.associations).map(key => ({ association: key }));
|
|
870
798
|
}
|
|
871
|
-
_buildAttributes(select) {
|
|
799
|
+
_buildAttributes(select, rawAttributes = this.model.rawAttributes) {
|
|
872
800
|
if (!select) {
|
|
873
801
|
return undefined;
|
|
874
802
|
}
|
|
875
803
|
if (Array.isArray(select)) {
|
|
876
|
-
const attributes = select.filter((field) =>
|
|
804
|
+
const attributes = select.filter((field) => rawAttributes?.[field]);
|
|
877
805
|
return attributes.length ? attributes : undefined;
|
|
878
806
|
}
|
|
879
807
|
const attributes = Object.entries(select)
|
|
880
|
-
.filter(([field, enabled]) => enabled &&
|
|
808
|
+
.filter(([field, enabled]) => enabled && rawAttributes?.[field])
|
|
881
809
|
.map(([field]) => field);
|
|
882
810
|
return attributes.length ? attributes : undefined;
|
|
883
811
|
}
|
|
@@ -886,8 +814,10 @@ export class SequelizeModel extends AbstractModel {
|
|
|
886
814
|
if (nestedCriteria === true) {
|
|
887
815
|
return { association };
|
|
888
816
|
}
|
|
889
|
-
const { where,
|
|
817
|
+
const { where, order, limit, } = this._convertAdminizerCriteriaToSequelizeOptions(nestedCriteria);
|
|
890
818
|
const include = { association };
|
|
819
|
+
const targetAttributes = this.model.associations[association]?.target?.rawAttributes;
|
|
820
|
+
const attributes = this._buildAttributes(nestedCriteria.select, targetAttributes);
|
|
891
821
|
if (where && (Object.keys(where).length > 0 || Object.getOwnPropertySymbols(where).length > 0)) {
|
|
892
822
|
include.where = where;
|
|
893
823
|
}
|
|
@@ -910,8 +840,8 @@ export class SequelizeModel extends AbstractModel {
|
|
|
910
840
|
export class SequelizeAdapter extends AbstractAdapter {
|
|
911
841
|
sequelize;
|
|
912
842
|
Model = SequelizeModel;
|
|
913
|
-
constructor(sequelize) {
|
|
914
|
-
super("sequelize", sequelize);
|
|
843
|
+
constructor(sequelize, options = {}) {
|
|
844
|
+
super("sequelize", sequelize, options);
|
|
915
845
|
this.sequelize = sequelize;
|
|
916
846
|
}
|
|
917
847
|
get models() {
|
|
@@ -928,111 +858,4 @@ export class SequelizeAdapter extends AbstractAdapter {
|
|
|
928
858
|
const model = this.getModel(modelName);
|
|
929
859
|
return model?.getAttributes();
|
|
930
860
|
}
|
|
931
|
-
/** Registration of system models */
|
|
932
|
-
static async registerSystemModels(sequelize, alter = true) {
|
|
933
|
-
// Get current file directory from import.meta.url
|
|
934
|
-
const currentDir = import.meta.url ? path.dirname(fileURLToPath(import.meta.url)) : process.cwd();
|
|
935
|
-
// Try multiple possible model locations
|
|
936
|
-
const possiblePaths = [
|
|
937
|
-
path.resolve(currentDir, "../../../../models"),
|
|
938
|
-
path.resolve(currentDir, "../../../../src/models"),
|
|
939
|
-
path.resolve(currentDir, "../../../models"),
|
|
940
|
-
path.resolve(currentDir, "../../../src/models"),
|
|
941
|
-
path.resolve(process.cwd(), "node_modules/adminizer/src/models"),
|
|
942
|
-
path.resolve(process.cwd(), "node_modules/adminizer/models")
|
|
943
|
-
];
|
|
944
|
-
let modelsDir = null;
|
|
945
|
-
for (const possiblePath of possiblePaths) {
|
|
946
|
-
if (fs.existsSync(possiblePath)) {
|
|
947
|
-
modelsDir = possiblePath;
|
|
948
|
-
break;
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
if (!modelsDir) {
|
|
952
|
-
return;
|
|
953
|
-
}
|
|
954
|
-
let files = fs.readdirSync(modelsDir).filter((f) => f.endsWith(".js"));
|
|
955
|
-
if (!files.length) {
|
|
956
|
-
files = fs.readdirSync(modelsDir).filter((f) => f.endsWith(".ts") && !f.endsWith(".d.ts"));
|
|
957
|
-
}
|
|
958
|
-
if (!files.length) {
|
|
959
|
-
return;
|
|
960
|
-
}
|
|
961
|
-
const schemas = {};
|
|
962
|
-
for (const file of files) {
|
|
963
|
-
const modelName = path.basename(file, path.extname(file));
|
|
964
|
-
const filePath = path.resolve(modelsDir, file);
|
|
965
|
-
const mod = await import(pathToFileURL(filePath).href);
|
|
966
|
-
const definition = mod.default;
|
|
967
|
-
schemas[modelName] = definition;
|
|
968
|
-
generateSequelizeModel(sequelize, modelName, definition);
|
|
969
|
-
}
|
|
970
|
-
generateAssociationsFromSchema(sequelize.models, schemas);
|
|
971
|
-
// Check ORM_ALTER environment variable before sync
|
|
972
|
-
if (process.env.ORM_ALTER !== 'false' && alter) {
|
|
973
|
-
await sequelize.sync();
|
|
974
|
-
}
|
|
975
|
-
else {
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
/** Generation of the Sequelize model from Adminizer's model definition */
|
|
980
|
-
function generateSequelizeModel(sequelize, modelName, rawAttributes) {
|
|
981
|
-
const attributes = {};
|
|
982
|
-
let primaryKey = null;
|
|
983
|
-
for (const field in rawAttributes) {
|
|
984
|
-
const attr = { ...rawAttributes[field] };
|
|
985
|
-
// 💥 Skip associations (handled separately)
|
|
986
|
-
if (attr.model || attr.collection) {
|
|
987
|
-
continue;
|
|
988
|
-
}
|
|
989
|
-
if (attr.primaryKey) {
|
|
990
|
-
primaryKey = field;
|
|
991
|
-
attr.primaryKey = true;
|
|
992
|
-
}
|
|
993
|
-
if (attr.uuid && attr.type === "string") {
|
|
994
|
-
attr.type = DataTypes.UUID;
|
|
995
|
-
attr.defaultValue = DataTypes.UUIDV4;
|
|
996
|
-
delete attr.uuid;
|
|
997
|
-
}
|
|
998
|
-
if (attr.autoIncrement) {
|
|
999
|
-
attr.autoIncrement = true;
|
|
1000
|
-
}
|
|
1001
|
-
if (attr.unique) {
|
|
1002
|
-
attr.unique = true;
|
|
1003
|
-
}
|
|
1004
|
-
if (typeof attr.type === "string") {
|
|
1005
|
-
switch (attr.type) {
|
|
1006
|
-
case "string":
|
|
1007
|
-
attr.type = DataTypes.STRING;
|
|
1008
|
-
break;
|
|
1009
|
-
case "number":
|
|
1010
|
-
attr.type = DataTypes.INTEGER;
|
|
1011
|
-
break;
|
|
1012
|
-
case "boolean":
|
|
1013
|
-
attr.type = DataTypes.BOOLEAN;
|
|
1014
|
-
break;
|
|
1015
|
-
case "json":
|
|
1016
|
-
attr.type = DataTypes.JSON;
|
|
1017
|
-
break;
|
|
1018
|
-
case "ref":
|
|
1019
|
-
attr.type = DataTypes.JSON;
|
|
1020
|
-
break;
|
|
1021
|
-
case "datetime":
|
|
1022
|
-
case "date":
|
|
1023
|
-
attr.type = DataTypes.DATE;
|
|
1024
|
-
break;
|
|
1025
|
-
default:
|
|
1026
|
-
throw new Error(`Unrecognized datatype "${attr.type}" for field "${field}" in model "${modelName}"`);
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
attributes[field] = attr;
|
|
1030
|
-
}
|
|
1031
|
-
if (!primaryKey) {
|
|
1032
|
-
throw new Error(`Model "${modelName}" must have a primary key`);
|
|
1033
|
-
}
|
|
1034
|
-
return sequelize.define(modelName, attributes, {
|
|
1035
|
-
tableName: modelName.toLowerCase(),
|
|
1036
|
-
timestamps: true,
|
|
1037
|
-
});
|
|
1038
861
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DataSource, EntityMetadata, EntitySchema, ObjectLiteral } from "typeorm";
|
|
2
|
-
import { AbstractAdapter, AbstractModel, ModelAttributes } from "../AbstractModel";
|
|
2
|
+
import { AbstractAdapter, AbstractAdapterOptions, AbstractModel, ModelAttributes } from "../AbstractModel";
|
|
3
3
|
import { QueryCriteria } from "../../../interfaces/queryCriteria";
|
|
4
4
|
/**
|
|
5
5
|
* Experimental TypeORM adapter.
|
|
@@ -11,7 +11,6 @@ import { QueryCriteria } from "../../../interfaces/queryCriteria";
|
|
|
11
11
|
type AdminizerSchema = Record<string, any>;
|
|
12
12
|
export declare function mapTypeOrmToAdminizerAttributes(metadata: EntityMetadata): ModelAttributes;
|
|
13
13
|
export declare function createTypeOrmEntitySchemaFromAdminizerSchema(modelName: string, schema: AdminizerSchema, allSchemas: Record<string, AdminizerSchema>): EntitySchema;
|
|
14
|
-
export declare function loadSystemTypeOrmEntities(): Promise<EntitySchema[]>;
|
|
15
14
|
export declare class TypeOrmModel<T extends ObjectLiteral> extends AbstractModel<T> {
|
|
16
15
|
private readonly metadata;
|
|
17
16
|
private readonly repository;
|
|
@@ -52,11 +51,10 @@ export declare class TypeOrmModel<T extends ObjectLiteral> extends AbstractModel
|
|
|
52
51
|
export declare class TypeOrmAdapter extends AbstractAdapter {
|
|
53
52
|
dataSource: DataSource;
|
|
54
53
|
Model: typeof TypeOrmModel;
|
|
55
|
-
constructor(dataSource: DataSource);
|
|
54
|
+
constructor(dataSource: DataSource, options?: AbstractAdapterOptions);
|
|
56
55
|
get models(): Record<string, EntityMetadata>;
|
|
57
56
|
getModel(modelName: string): EntityMetadata | undefined;
|
|
58
57
|
getAttributes(modelName: string): ModelAttributes | undefined;
|
|
59
58
|
static createEntitySchema(modelName: string, schema: AdminizerSchema, allSchemas?: Record<string, AdminizerSchema>): EntitySchema;
|
|
60
|
-
static loadSystemEntities(): Promise<EntitySchema[]>;
|
|
61
59
|
}
|
|
62
60
|
export {};
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { pathToFileURL, fileURLToPath } from "url";
|
|
4
1
|
import { Brackets, EntitySchema, NotBrackets, } from "typeorm";
|
|
5
2
|
import { v4 as uuid } from "uuid";
|
|
6
3
|
import { AbstractAdapter, AbstractModel } from "../AbstractModel.js";
|
|
@@ -216,33 +213,6 @@ export function createTypeOrmEntitySchemaFromAdminizerSchema(modelName, schema,
|
|
|
216
213
|
relations,
|
|
217
214
|
});
|
|
218
215
|
}
|
|
219
|
-
export async function loadSystemTypeOrmEntities() {
|
|
220
|
-
const currentDir = import.meta.url ? path.dirname(fileURLToPath(import.meta.url)) : process.cwd();
|
|
221
|
-
const possiblePaths = [
|
|
222
|
-
path.resolve(currentDir, "../../../../models"),
|
|
223
|
-
path.resolve(currentDir, "../../../../src/models"),
|
|
224
|
-
path.resolve(currentDir, "../../../models"),
|
|
225
|
-
path.resolve(currentDir, "../../../src/models"),
|
|
226
|
-
path.resolve(process.cwd(), "node_modules/adminizer/src/models"),
|
|
227
|
-
path.resolve(process.cwd(), "node_modules/adminizer/models"),
|
|
228
|
-
];
|
|
229
|
-
const modelsDir = possiblePaths.find((possiblePath) => fs.existsSync(possiblePath));
|
|
230
|
-
if (!modelsDir) {
|
|
231
|
-
return [];
|
|
232
|
-
}
|
|
233
|
-
let files = fs.readdirSync(modelsDir).filter((file) => file.endsWith(".js"));
|
|
234
|
-
if (!files.length) {
|
|
235
|
-
files = fs.readdirSync(modelsDir).filter((file) => file.endsWith(".ts") && !file.endsWith(".d.ts"));
|
|
236
|
-
}
|
|
237
|
-
const schemas = {};
|
|
238
|
-
for (const file of files) {
|
|
239
|
-
const modelName = path.basename(file, path.extname(file));
|
|
240
|
-
const filePath = path.resolve(modelsDir, file);
|
|
241
|
-
const mod = await import(pathToFileURL(filePath).href);
|
|
242
|
-
schemas[modelName] = mod.default;
|
|
243
|
-
}
|
|
244
|
-
return Object.entries(schemas).map(([modelName, schema]) => createTypeOrmEntitySchemaFromAdminizerSchema(modelName, schema, schemas));
|
|
245
|
-
}
|
|
246
216
|
export class TypeOrmModel extends AbstractModel {
|
|
247
217
|
metadata;
|
|
248
218
|
repository;
|
|
@@ -750,8 +720,8 @@ export class TypeOrmModel extends AbstractModel {
|
|
|
750
720
|
export class TypeOrmAdapter extends AbstractAdapter {
|
|
751
721
|
dataSource;
|
|
752
722
|
Model = TypeOrmModel;
|
|
753
|
-
constructor(dataSource) {
|
|
754
|
-
super("typeorm", dataSource);
|
|
723
|
+
constructor(dataSource, options = {}) {
|
|
724
|
+
super("typeorm", dataSource, options);
|
|
755
725
|
this.dataSource = dataSource;
|
|
756
726
|
}
|
|
757
727
|
get models() {
|
|
@@ -771,7 +741,4 @@ export class TypeOrmAdapter extends AbstractAdapter {
|
|
|
771
741
|
static createEntitySchema(modelName, schema, allSchemas = { [modelName]: schema }) {
|
|
772
742
|
return createTypeOrmEntitySchemaFromAdminizerSchema(modelName, schema, allSchemas);
|
|
773
743
|
}
|
|
774
|
-
static async loadSystemEntities() {
|
|
775
|
-
return await loadSystemTypeOrmEntities();
|
|
776
|
-
}
|
|
777
744
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
2
|
import { Adminizer } from '../Adminizer';
|
|
3
3
|
import { INotification, INotificationEvent } from '../../interfaces/types';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { NotificationModel } from "../../models/Notification";
|
|
5
|
+
import { User } from "../../models/User";
|
|
6
6
|
/**
|
|
7
7
|
* ░█████╗░██████╗░░██████╗████████╗██████╗░░█████╗░░█████╗░████████╗
|
|
8
8
|
* ██╔══██╗██╔══██╗██╔════╝╚══██╔══╝██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝
|
|
@@ -58,7 +58,7 @@ export declare abstract class AbstractNotificationService extends EventEmitter {
|
|
|
58
58
|
constructor(adminizer: Adminizer);
|
|
59
59
|
protected notificationModel(): import("../..").InternalModelRepository<any>;
|
|
60
60
|
protected userNotificationModel(): import("../..").InternalModelRepository<any>;
|
|
61
|
-
protected userModel(): import("../..").InternalModelRepository<
|
|
61
|
+
protected userModel(): import("../..").InternalModelRepository<User>;
|
|
62
62
|
private _bindAccessRight;
|
|
63
63
|
/**
|
|
64
64
|
* Registers a client for a user and associates it with a send function.
|
|
@@ -66,9 +66,9 @@ export declare abstract class AbstractNotificationService extends EventEmitter {
|
|
|
66
66
|
* The client is then added to the user's Map with the provided send function.
|
|
67
67
|
* @param {string} clientId - The unique identifier of the client to be registered.
|
|
68
68
|
* @param {(event: INotificationEvent) => void} sendFn - The function used to send notifications to the client.
|
|
69
|
-
* @param {
|
|
69
|
+
* @param {User} user - The user associated with the client.
|
|
70
70
|
*/
|
|
71
|
-
addClient(clientId: string, sendFn: (event: INotificationEvent) => void, user:
|
|
71
|
+
addClient(clientId: string, sendFn: (event: INotificationEvent) => void, user: User): void;
|
|
72
72
|
/**
|
|
73
73
|
* Removes a client from the internal tracking structure.
|
|
74
74
|
* If the user associated with the client has no more clients after removal, the user's Map is also removed.
|
|
@@ -113,7 +113,7 @@ export declare abstract class AbstractNotificationService extends EventEmitter {
|
|
|
113
113
|
*/
|
|
114
114
|
sendHeartbeat(clientId: string): void;
|
|
115
115
|
/**
|
|
116
|
-
* Creates a new user notification record in the '
|
|
116
|
+
* Creates a new user notification record in the 'UserNotification' model.
|
|
117
117
|
* This method is used to associate a notification with a specific user and mark it as unread.
|
|
118
118
|
* @param {string} notificationId - The unique identifier of the notification.
|
|
119
119
|
* @param {number} [userId] - The ID of the user to associate the notification with. Optional.
|
|
@@ -121,7 +121,7 @@ export declare abstract class AbstractNotificationService extends EventEmitter {
|
|
|
121
121
|
*/
|
|
122
122
|
protected createUserNotification(notificationId: string, userId?: number): Promise<void>;
|
|
123
123
|
/**
|
|
124
|
-
* Retrieves a user notification record from the '
|
|
124
|
+
* Retrieves a user notification record from the 'UserNotification' model.
|
|
125
125
|
* The record is fetched based on the provided notification ID and user ID.
|
|
126
126
|
* @param {string} notificationId - The unique identifier of the notification.
|
|
127
127
|
* @param {number} userId - The ID of the user associated with the notification.
|
|
@@ -139,11 +139,11 @@ export declare abstract class AbstractNotificationService extends EventEmitter {
|
|
|
139
139
|
getNotifications(userId: number, limit?: number, skip?: number, unreadOnly?: boolean): Promise<INotification[]>;
|
|
140
140
|
/**
|
|
141
141
|
* Prepares notification data by enriching it with user-specific read status and icon information.
|
|
142
|
-
* @param {
|
|
142
|
+
* @param {NotificationModel[]} notificationsDB - An array of raw notification records from the database.
|
|
143
143
|
* @param {number} userId - The ID of the user for whom the read status is determined.
|
|
144
144
|
* @returns {Promise<INotification[]>} A promise that resolves with an array of enriched notification objects.
|
|
145
145
|
*/
|
|
146
|
-
protected prepareNotification(notificationsDB:
|
|
146
|
+
protected prepareNotification(notificationsDB: NotificationModel[], userId: number): Promise<INotification[]>;
|
|
147
147
|
/**
|
|
148
148
|
* Searches for notifications for a specific user based on a message keyword.
|
|
149
149
|
* @param {string} s - The search string used to filter notifications by message content.
|