@ruiapp/rapid-core 0.1.19 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/actionHandler.d.ts +2 -0
- package/dist/core/pluginManager.d.ts +3 -0
- package/dist/core/request.d.ts +2 -1
- package/dist/core/routeContext.d.ts +4 -1
- package/dist/core/server.d.ts +8 -2
- package/dist/dataAccess/dataAccessor.d.ts +2 -1
- package/dist/facilities/log/LogFacility.d.ts +33 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +288 -264
- package/dist/plugins/auth/AuthPlugin.d.ts +0 -9
- package/dist/plugins/dataManage/DataManagePlugin.d.ts +0 -10
- package/dist/plugins/entityAccessControl/EntityAccessControlPlugin.d.ts +17 -0
- package/dist/plugins/fileManage/FileManagePlugin.d.ts +0 -10
- package/dist/plugins/metaManage/MetaManagePlugin.d.ts +0 -8
- package/dist/plugins/routeManage/RouteManagePlugin.d.ts +0 -9
- package/dist/plugins/webhooks/WebhooksPlugin.d.ts +0 -6
- package/dist/server.d.ts +8 -3
- package/dist/types.d.ts +11 -0
- package/dist/utilities/accessControlUtility.d.ts +5 -0
- package/package.json +5 -2
- package/rollup.config.js +1 -18
- package/src/core/actionHandler.ts +2 -0
- package/src/core/pluginManager.ts +12 -0
- package/src/core/request.ts +6 -2
- package/src/core/routeContext.ts +6 -1
- package/src/core/routesBuilder.ts +16 -6
- package/src/core/server.ts +8 -2
- package/src/dataAccess/dataAccessor.ts +13 -9
- package/src/dataAccess/entityManager.ts +24 -24
- package/src/facilities/log/LogFacility.ts +36 -0
- package/src/helpers/inputHelper.ts +3 -3
- package/src/helpers/runCollectionEntityActionHandler.ts +4 -9
- package/src/index.ts +2 -1
- package/src/plugins/auth/AuthPlugin.ts +3 -31
- package/src/plugins/dataManage/DataManagePlugin.ts +0 -32
- package/src/plugins/dataManage/actionHandlers/addEntityRelations.ts +3 -7
- package/src/plugins/dataManage/actionHandlers/createCollectionEntitiesBatch.ts +3 -7
- package/src/plugins/dataManage/actionHandlers/createCollectionEntity.ts +3 -7
- package/src/plugins/dataManage/actionHandlers/deleteCollectionEntityById.ts +2 -2
- package/src/plugins/dataManage/actionHandlers/findCollectionEntities.ts +0 -1
- package/src/plugins/dataManage/actionHandlers/findCollectionEntityById.ts +2 -2
- package/src/plugins/dataManage/actionHandlers/queryDatabase.ts +5 -9
- package/src/plugins/dataManage/actionHandlers/removeEntityRelations.ts +2 -6
- package/src/plugins/dataManage/actionHandlers/updateCollectionEntityById.ts +3 -8
- package/src/plugins/entityAccessControl/EntityAccessControlPlugin.ts +107 -0
- package/src/plugins/fileManage/FileManagePlugin.ts +0 -31
- package/src/plugins/metaManage/MetaManagePlugin.ts +16 -39
- package/src/plugins/routeManage/RouteManagePlugin.ts +4 -30
- package/src/plugins/routeManage/actionHandlers/httpProxy.ts +2 -1
- package/src/plugins/webhooks/WebhooksPlugin.ts +26 -36
- package/src/queryBuilder/queryBuilder.ts +3 -3
- package/src/server.ts +53 -17
- package/src/types.ts +13 -0
- package/src/utilities/accessControlUtility.ts +33 -0
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var lodash = require('lodash');
|
|
6
6
|
var events = require('events');
|
|
7
7
|
var Router = require('koa-tree-router');
|
|
8
8
|
var qs = require('qs');
|
|
@@ -14,25 +14,6 @@ var uuid = require('uuid');
|
|
|
14
14
|
|
|
15
15
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
16
16
|
|
|
17
|
-
function _interopNamespace(e) {
|
|
18
|
-
if (e && e.__esModule) return e;
|
|
19
|
-
var n = Object.create(null);
|
|
20
|
-
if (e) {
|
|
21
|
-
Object.keys(e).forEach(function (k) {
|
|
22
|
-
if (k !== 'default') {
|
|
23
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
24
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
25
|
-
enumerable: true,
|
|
26
|
-
get: function () { return e[k]; }
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
n["default"] = e;
|
|
32
|
-
return Object.freeze(n);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
var ___namespace = /*#__PURE__*/_interopNamespace(_);
|
|
36
17
|
var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router);
|
|
37
18
|
var qs__default = /*#__PURE__*/_interopDefaultLegacy(qs);
|
|
38
19
|
var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
|
|
@@ -46,10 +27,12 @@ function fixBigIntJSONSerialize() {
|
|
|
46
27
|
}
|
|
47
28
|
|
|
48
29
|
class DataAccessor {
|
|
30
|
+
#logger;
|
|
49
31
|
#model;
|
|
50
32
|
#queryBuilder;
|
|
51
33
|
#databaseAccessor;
|
|
52
|
-
constructor(databaseAccessor, options) {
|
|
34
|
+
constructor(server, databaseAccessor, options) {
|
|
35
|
+
this.#logger = server.getLogger();
|
|
53
36
|
this.#databaseAccessor = databaseAccessor;
|
|
54
37
|
this.#queryBuilder = options.queryBuilder;
|
|
55
38
|
this.#model = options.model;
|
|
@@ -63,7 +46,7 @@ class DataAccessor {
|
|
|
63
46
|
};
|
|
64
47
|
const query = this.#queryBuilder.insert(this.#model, options);
|
|
65
48
|
const result = await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
|
|
66
|
-
return
|
|
49
|
+
return lodash.first(result);
|
|
67
50
|
}
|
|
68
51
|
async updateById(id, entity) {
|
|
69
52
|
const options = {
|
|
@@ -78,17 +61,17 @@ class DataAccessor {
|
|
|
78
61
|
};
|
|
79
62
|
const query = this.#queryBuilder.update(this.#model, options);
|
|
80
63
|
const result = await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
|
|
81
|
-
return
|
|
64
|
+
return lodash.first(result);
|
|
82
65
|
}
|
|
83
66
|
async find(options) {
|
|
84
|
-
|
|
67
|
+
this.#logger.debug(`Finding '${this.#model.singularCode}' entity.`, { options });
|
|
85
68
|
const query = this.#queryBuilder.select(this.#model, options);
|
|
86
69
|
return await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
|
|
87
70
|
}
|
|
88
71
|
async findOne(options) {
|
|
89
|
-
|
|
72
|
+
lodash.set(options, "pagination.limit", 1);
|
|
90
73
|
const list = await this.find(options);
|
|
91
|
-
return
|
|
74
|
+
return lodash.first(list);
|
|
92
75
|
}
|
|
93
76
|
async findById(id) {
|
|
94
77
|
const options = {
|
|
@@ -102,12 +85,12 @@ class DataAccessor {
|
|
|
102
85
|
};
|
|
103
86
|
const query = this.#queryBuilder.select(this.#model, options);
|
|
104
87
|
const result = await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
|
|
105
|
-
return
|
|
88
|
+
return lodash.first(result);
|
|
106
89
|
}
|
|
107
90
|
async count(options) {
|
|
108
91
|
const query = this.#queryBuilder.count(this.#model, options);
|
|
109
92
|
const result = await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
|
|
110
|
-
const row =
|
|
93
|
+
const row = lodash.first(result);
|
|
111
94
|
if (row) {
|
|
112
95
|
return row;
|
|
113
96
|
}
|
|
@@ -233,7 +216,7 @@ class QueryBuilder {
|
|
|
233
216
|
}
|
|
234
217
|
let property = null;
|
|
235
218
|
if (model) {
|
|
236
|
-
property =
|
|
219
|
+
property = lodash.find(model.properties, (e) => e.code === propertyName);
|
|
237
220
|
}
|
|
238
221
|
if (property && property.type === "json") {
|
|
239
222
|
params.push(JSON.stringify(entity[propertyName]));
|
|
@@ -268,7 +251,7 @@ class QueryBuilder {
|
|
|
268
251
|
}
|
|
269
252
|
let property = null;
|
|
270
253
|
if (model) {
|
|
271
|
-
property =
|
|
254
|
+
property = lodash.find(model.properties, (e) => (e.columnName || e.code) === propertyName);
|
|
272
255
|
}
|
|
273
256
|
if (property && property.type === "json") {
|
|
274
257
|
params.push(JSON.stringify(entity[propertyName]));
|
|
@@ -554,6 +537,14 @@ class PluginManager {
|
|
|
554
537
|
}
|
|
555
538
|
}
|
|
556
539
|
}
|
|
540
|
+
/** 在接收到HTTP请求,执行 actions 前调用。 */
|
|
541
|
+
async beforeRunRouteActions(handlerContext) {
|
|
542
|
+
for (const plugin of this.#plugins) {
|
|
543
|
+
if (plugin.beforeRunRouteActions) {
|
|
544
|
+
await plugin.beforeRunRouteActions(this.#server, handlerContext);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
557
548
|
}
|
|
558
549
|
|
|
559
550
|
class EventManager {
|
|
@@ -580,6 +571,7 @@ function isNullOrUndefined(val) {
|
|
|
580
571
|
}
|
|
581
572
|
|
|
582
573
|
async function buildRoutes(server, applicationConfig) {
|
|
574
|
+
const logger = server.getLogger();
|
|
583
575
|
const router = new Router__default["default"]();
|
|
584
576
|
let baseUrl = server.config.baseUrl;
|
|
585
577
|
if (baseUrl) {
|
|
@@ -596,6 +588,7 @@ async function buildRoutes(server, applicationConfig) {
|
|
|
596
588
|
}
|
|
597
589
|
const routePath = baseUrl + routeConfig.endpoint;
|
|
598
590
|
router[routeConfig.method.toLowerCase()](routePath, async (routerContext, next) => {
|
|
591
|
+
routerContext.routeConfig = lodash.cloneDeep(routeConfig);
|
|
599
592
|
const { request, params } = routerContext;
|
|
600
593
|
let search = request.url.search;
|
|
601
594
|
if (search && search.startsWith("?")) {
|
|
@@ -612,21 +605,27 @@ async function buildRoutes(server, applicationConfig) {
|
|
|
612
605
|
}
|
|
613
606
|
}
|
|
614
607
|
// Normalize input value
|
|
615
|
-
|
|
616
|
-
|
|
608
|
+
logger.debug("Processing rapid request.", {
|
|
609
|
+
method: requestMethod,
|
|
610
|
+
url: request.url.toString(),
|
|
611
|
+
input
|
|
612
|
+
});
|
|
617
613
|
let handlerContext = {
|
|
614
|
+
logger,
|
|
618
615
|
routerContext,
|
|
619
616
|
next,
|
|
620
617
|
server,
|
|
621
618
|
applicationConfig,
|
|
622
619
|
input,
|
|
623
620
|
};
|
|
624
|
-
|
|
625
|
-
|
|
621
|
+
await server.beforeRunRouteActions(handlerContext);
|
|
622
|
+
for (const actionConfig of routeConfig.actions) {
|
|
623
|
+
const actionCode = actionConfig.code;
|
|
624
|
+
const handler = server.getActionHandlerByCode(actionCode);
|
|
626
625
|
if (!handler) {
|
|
627
|
-
throw new Error("Unknown handler: " +
|
|
626
|
+
throw new Error("Unknown handler: " + actionCode);
|
|
628
627
|
}
|
|
629
|
-
const result = handler(handlerContext,
|
|
628
|
+
const result = handler(handlerContext, actionConfig.config);
|
|
630
629
|
if (result instanceof Promise) {
|
|
631
630
|
await result;
|
|
632
631
|
}
|
|
@@ -645,12 +644,12 @@ function mergeHeaders(target, source) {
|
|
|
645
644
|
target.set(keyValuePair[0], keyValuePair[1]);
|
|
646
645
|
}
|
|
647
646
|
}
|
|
648
|
-
else if (
|
|
647
|
+
else if (lodash.isArray(source)) {
|
|
649
648
|
for (const keyValuePair of source) {
|
|
650
649
|
target.set(keyValuePair[0], keyValuePair[1]);
|
|
651
650
|
}
|
|
652
651
|
}
|
|
653
|
-
else if (
|
|
652
|
+
else if (lodash.isObject(source)) {
|
|
654
653
|
Object.entries(source).forEach(([key, value]) => target.set(key, value));
|
|
655
654
|
}
|
|
656
655
|
return target;
|
|
@@ -698,13 +697,16 @@ class RapidResponse {
|
|
|
698
697
|
}
|
|
699
698
|
|
|
700
699
|
class RouteContext {
|
|
700
|
+
#logger;
|
|
701
701
|
request;
|
|
702
702
|
response;
|
|
703
703
|
state;
|
|
704
704
|
method;
|
|
705
705
|
path;
|
|
706
706
|
params;
|
|
707
|
-
|
|
707
|
+
routeConfig;
|
|
708
|
+
constructor(server, request) {
|
|
709
|
+
this.#logger = server.getLogger();
|
|
708
710
|
this.request = request;
|
|
709
711
|
this.state = {};
|
|
710
712
|
this.response = new RapidResponse();
|
|
@@ -1016,6 +1018,7 @@ function setCookie(headers, cookie) {
|
|
|
1016
1018
|
|
|
1017
1019
|
const GlobalRequest = global.Request;
|
|
1018
1020
|
class RapidRequest {
|
|
1021
|
+
#logger;
|
|
1019
1022
|
#raw;
|
|
1020
1023
|
#bodyParsed;
|
|
1021
1024
|
#body;
|
|
@@ -1023,7 +1026,8 @@ class RapidRequest {
|
|
|
1023
1026
|
#parsedCookies;
|
|
1024
1027
|
method;
|
|
1025
1028
|
url;
|
|
1026
|
-
constructor(req) {
|
|
1029
|
+
constructor(server, req) {
|
|
1030
|
+
this.#logger = server.getLogger();
|
|
1027
1031
|
this.#raw = req;
|
|
1028
1032
|
this.method = req.method;
|
|
1029
1033
|
this.url = new URL(req.url);
|
|
@@ -1031,7 +1035,7 @@ class RapidRequest {
|
|
|
1031
1035
|
}
|
|
1032
1036
|
async parseBody() {
|
|
1033
1037
|
if (this.#bodyParsed) {
|
|
1034
|
-
|
|
1038
|
+
this.#logger.warn("Request body has been parsed. 'parseBody()' method should not be called more than once.");
|
|
1035
1039
|
return;
|
|
1036
1040
|
}
|
|
1037
1041
|
const requestMethod = this.method;
|
|
@@ -1739,7 +1743,7 @@ async function findEntities(server, dataAccessor, options) {
|
|
|
1739
1743
|
const fieldsToSelect = [];
|
|
1740
1744
|
const relationPropertiesToSelect = [];
|
|
1741
1745
|
if (options.properties) {
|
|
1742
|
-
|
|
1746
|
+
lodash.forEach(options.properties, (propertyCode) => {
|
|
1743
1747
|
const property = model.properties.find((e) => e.code === propertyCode);
|
|
1744
1748
|
if (!property) {
|
|
1745
1749
|
throw new Error(`Collection '${model.namespace}.${model.singularCode}' does not have a property '${propertyCode}'.`);
|
|
@@ -1780,8 +1784,8 @@ async function findEntities(server, dataAccessor, options) {
|
|
|
1780
1784
|
}
|
|
1781
1785
|
if (isManyRelation) {
|
|
1782
1786
|
const relationLinks = await findManyRelationLinksViaLinkTable(server, targetModel, relationProperty, entityIds);
|
|
1783
|
-
|
|
1784
|
-
entity[relationProperty.code] =
|
|
1787
|
+
lodash.forEach(entities, (entity) => {
|
|
1788
|
+
entity[relationProperty.code] = lodash.filter(relationLinks, (link) => {
|
|
1785
1789
|
return link[relationProperty.selfIdColumnName] == entity["id"];
|
|
1786
1790
|
}).map(link => mapDbRowToEntity(targetModel, link.targetEntity, false));
|
|
1787
1791
|
});
|
|
@@ -1793,7 +1797,7 @@ async function findEntities(server, dataAccessor, options) {
|
|
|
1793
1797
|
relatedEntities = await findManyRelatedEntitiesViaIdPropertyCode(server, model, relationProperty, entityIds);
|
|
1794
1798
|
}
|
|
1795
1799
|
else {
|
|
1796
|
-
const targetEntityIds =
|
|
1800
|
+
const targetEntityIds = lodash.uniq(lodash.reject(lodash.map(entities, (entity) => entity[relationProperty.targetIdColumnName]), isNullOrUndefined));
|
|
1797
1801
|
relatedEntities = await findOneRelatedEntitiesViaIdPropertyCode(server, model, relationProperty, targetEntityIds);
|
|
1798
1802
|
}
|
|
1799
1803
|
const targetModel = server.getModel({
|
|
@@ -1801,12 +1805,12 @@ async function findEntities(server, dataAccessor, options) {
|
|
|
1801
1805
|
});
|
|
1802
1806
|
entities.forEach((entity) => {
|
|
1803
1807
|
if (isManyRelation) {
|
|
1804
|
-
entity[relationProperty.code] =
|
|
1808
|
+
entity[relationProperty.code] = lodash.filter(relatedEntities, (relatedEntity) => {
|
|
1805
1809
|
return relatedEntity[relationProperty.selfIdColumnName] == entity.id;
|
|
1806
1810
|
}).map(item => mapDbRowToEntity(targetModel, item, false));
|
|
1807
1811
|
}
|
|
1808
1812
|
else {
|
|
1809
|
-
entity[relationProperty.code] = mapDbRowToEntity(targetModel,
|
|
1813
|
+
entity[relationProperty.code] = mapDbRowToEntity(targetModel, lodash.find(relatedEntities, (relatedEntity) => {
|
|
1810
1814
|
// TODO: id property code should be configurable.
|
|
1811
1815
|
return relatedEntity["id"] == entity[relationProperty.targetIdColumnName];
|
|
1812
1816
|
}), false);
|
|
@@ -1819,7 +1823,7 @@ async function findEntities(server, dataAccessor, options) {
|
|
|
1819
1823
|
}
|
|
1820
1824
|
async function findEntity(server, dataAccessor, options) {
|
|
1821
1825
|
const entities = await findEntities(server, dataAccessor, options);
|
|
1822
|
-
return
|
|
1826
|
+
return lodash.first(entities);
|
|
1823
1827
|
}
|
|
1824
1828
|
async function findById(server, dataAccessor, id, keepNonPropertyFields = false) {
|
|
1825
1829
|
return await findEntity(server, dataAccessor, {
|
|
@@ -1845,7 +1849,7 @@ async function replaceFiltersWithFiltersOperator(server, model, filters) {
|
|
|
1845
1849
|
replacedFilters.push(filter);
|
|
1846
1850
|
}
|
|
1847
1851
|
else if (operator === "exists" || operator === "notExists") {
|
|
1848
|
-
const relationProperty =
|
|
1852
|
+
const relationProperty = lodash.find(model.properties, (property) => property.code === filter.field);
|
|
1849
1853
|
if (!relationProperty) {
|
|
1850
1854
|
throw new Error(`Invalid filters. Property '${filter.field}' was not found in model '${model.namespace}.${model.singularCode}'`);
|
|
1851
1855
|
}
|
|
@@ -1890,7 +1894,7 @@ async function replaceFiltersWithFiltersOperator(server, model, filters) {
|
|
|
1890
1894
|
filters: filter.filters,
|
|
1891
1895
|
properties: ["id"],
|
|
1892
1896
|
});
|
|
1893
|
-
const entityIds =
|
|
1897
|
+
const entityIds = lodash.map(entities, (entity) => entity["id"]);
|
|
1894
1898
|
replacedFilters.push({
|
|
1895
1899
|
field: relationProperty.targetIdColumnName,
|
|
1896
1900
|
operator: operator === "exists" ? "in" : "notIn",
|
|
@@ -1909,7 +1913,7 @@ async function replaceFiltersWithFiltersOperator(server, model, filters) {
|
|
|
1909
1913
|
filters: filter.filters,
|
|
1910
1914
|
properties: [relationProperty.selfIdColumnName],
|
|
1911
1915
|
});
|
|
1912
|
-
const selfEntityIds =
|
|
1916
|
+
const selfEntityIds = lodash.map(targetEntities, (entity) => entity[relationProperty.selfIdColumnName]);
|
|
1913
1917
|
replacedFilters.push({
|
|
1914
1918
|
field: "id",
|
|
1915
1919
|
operator: operator === "exists" ? "in" : "notIn",
|
|
@@ -1934,7 +1938,7 @@ async function replaceFiltersWithFiltersOperator(server, model, filters) {
|
|
|
1934
1938
|
filters: filter.filters,
|
|
1935
1939
|
properties: ['id'],
|
|
1936
1940
|
});
|
|
1937
|
-
const targetEntityIds =
|
|
1941
|
+
const targetEntityIds = lodash.map(targetEntities, (entity) => entity['id']);
|
|
1938
1942
|
const command = `SELECT * FROM ${server.queryBuilder.quoteTable({ schema: relationProperty.linkSchema, tableName: relationProperty.linkTableName })} WHERE ${server.queryBuilder.quoteObject(relationProperty.targetIdColumnName)} = ANY($1::int[])`;
|
|
1939
1943
|
const params = [targetEntityIds];
|
|
1940
1944
|
const links = await server.queryDatabaseObject(command, params);
|
|
@@ -1971,8 +1975,8 @@ async function findManyRelationLinksViaLinkTable(server, targetModel, relationPr
|
|
|
1971
1975
|
singularCode: targetModel.singularCode,
|
|
1972
1976
|
});
|
|
1973
1977
|
const targetEntities = await dataAccessor.find(findEntityOptions);
|
|
1974
|
-
|
|
1975
|
-
link.targetEntity =
|
|
1978
|
+
lodash.forEach(links, (link) => {
|
|
1979
|
+
link.targetEntity = lodash.find(targetEntities, (e) => e["id"] == link[relationProperty.targetIdColumnName]);
|
|
1976
1980
|
});
|
|
1977
1981
|
return links;
|
|
1978
1982
|
}
|
|
@@ -2011,7 +2015,7 @@ async function createEntity(server, dataAccessor, options) {
|
|
|
2011
2015
|
const { entity } = options;
|
|
2012
2016
|
const oneRelationPropertiesToCreate = [];
|
|
2013
2017
|
const manyRelationPropertiesToCreate = [];
|
|
2014
|
-
|
|
2018
|
+
lodash.keys(entity).forEach((propertyCode) => {
|
|
2015
2019
|
const property = model.properties.find((e) => e.code === propertyCode);
|
|
2016
2020
|
if (!property) {
|
|
2017
2021
|
// Unknown property
|
|
@@ -2030,7 +2034,7 @@ async function createEntity(server, dataAccessor, options) {
|
|
|
2030
2034
|
// save one-relation properties
|
|
2031
2035
|
for (const property of oneRelationPropertiesToCreate) {
|
|
2032
2036
|
const fieldValue = entity[property.code];
|
|
2033
|
-
if (
|
|
2037
|
+
if (lodash.isObject(fieldValue)) {
|
|
2034
2038
|
if (!fieldValue["id"]) {
|
|
2035
2039
|
const targetDataAccessor = server.getDataAccessor({
|
|
2036
2040
|
singularCode: property.targetSingularCode,
|
|
@@ -2059,12 +2063,12 @@ async function createEntity(server, dataAccessor, options) {
|
|
|
2059
2063
|
singularCode: property.targetSingularCode,
|
|
2060
2064
|
});
|
|
2061
2065
|
const relatedEntitiesToBeSaved = entity[property.code];
|
|
2062
|
-
if (!
|
|
2066
|
+
if (!lodash.isArray(relatedEntitiesToBeSaved)) {
|
|
2063
2067
|
throw new Error(`Value of field '${property.code}' should be an array.`);
|
|
2064
2068
|
}
|
|
2065
2069
|
for (const relatedEntityToBeSaved of relatedEntitiesToBeSaved) {
|
|
2066
2070
|
let relatedEntityId;
|
|
2067
|
-
if (
|
|
2071
|
+
if (lodash.isObject(relatedEntityToBeSaved)) {
|
|
2068
2072
|
relatedEntityId = relatedEntityToBeSaved["id"];
|
|
2069
2073
|
if (!relatedEntityId) {
|
|
2070
2074
|
// related entity is to be created
|
|
@@ -2138,7 +2142,7 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
|
|
|
2138
2142
|
}
|
|
2139
2143
|
const oneRelationPropertiesToUpdate = [];
|
|
2140
2144
|
const manyRelationPropertiesToUpdate = [];
|
|
2141
|
-
|
|
2145
|
+
lodash.keys(changes).forEach((propertyCode) => {
|
|
2142
2146
|
const property = model.properties.find((e) => e.code === propertyCode);
|
|
2143
2147
|
if (!property) {
|
|
2144
2148
|
// Unknown property
|
|
@@ -2156,7 +2160,7 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
|
|
|
2156
2160
|
const row = mapEntityToDbRow(model, changes);
|
|
2157
2161
|
oneRelationPropertiesToUpdate.forEach(property => {
|
|
2158
2162
|
const fieldValue = changes[property.code];
|
|
2159
|
-
if (
|
|
2163
|
+
if (lodash.isObject(fieldValue)) {
|
|
2160
2164
|
row[property.targetIdColumnName] = fieldValue["id"];
|
|
2161
2165
|
}
|
|
2162
2166
|
else {
|
|
@@ -2175,7 +2179,7 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
|
|
|
2175
2179
|
singularCode: property.targetSingularCode,
|
|
2176
2180
|
});
|
|
2177
2181
|
const relatedEntitiesToBeSaved = changes[property.code];
|
|
2178
|
-
if (!
|
|
2182
|
+
if (!lodash.isArray(relatedEntitiesToBeSaved)) {
|
|
2179
2183
|
throw new Error(`Value of field '${property.code}' should be an array.`);
|
|
2180
2184
|
}
|
|
2181
2185
|
if (property.linkTableName) {
|
|
@@ -2184,7 +2188,7 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
|
|
|
2184
2188
|
}
|
|
2185
2189
|
for (const relatedEntityToBeSaved of relatedEntitiesToBeSaved) {
|
|
2186
2190
|
let relatedEntityId;
|
|
2187
|
-
if (
|
|
2191
|
+
if (lodash.isObject(relatedEntityToBeSaved)) {
|
|
2188
2192
|
relatedEntityId = relatedEntityToBeSaved["id"];
|
|
2189
2193
|
if (!relatedEntityId) {
|
|
2190
2194
|
// related entity is to be created
|
|
@@ -2369,6 +2373,7 @@ class EntityManager {
|
|
|
2369
2373
|
}
|
|
2370
2374
|
|
|
2371
2375
|
class RapidServer {
|
|
2376
|
+
#logger;
|
|
2372
2377
|
#pluginManager;
|
|
2373
2378
|
#plugins;
|
|
2374
2379
|
#eventManager;
|
|
@@ -2384,6 +2389,7 @@ class RapidServer {
|
|
|
2384
2389
|
databaseConfig;
|
|
2385
2390
|
#buildedRoutes;
|
|
2386
2391
|
constructor(options) {
|
|
2392
|
+
this.#logger = options.logger;
|
|
2387
2393
|
this.#pluginManager = new PluginManager(this);
|
|
2388
2394
|
this.#eventManager = new EventManager();
|
|
2389
2395
|
this.#middlewares = [];
|
|
@@ -2400,6 +2406,9 @@ class RapidServer {
|
|
|
2400
2406
|
this.config = options.serverConfig;
|
|
2401
2407
|
this.#plugins = options.plugins || [];
|
|
2402
2408
|
}
|
|
2409
|
+
getLogger() {
|
|
2410
|
+
return this.#logger;
|
|
2411
|
+
}
|
|
2403
2412
|
getApplicationConfig() {
|
|
2404
2413
|
return this.#applicationConfig;
|
|
2405
2414
|
}
|
|
@@ -2407,12 +2416,13 @@ class RapidServer {
|
|
|
2407
2416
|
const { models, routes } = config;
|
|
2408
2417
|
if (models) {
|
|
2409
2418
|
for (const model of models) {
|
|
2410
|
-
const originalModel =
|
|
2419
|
+
const originalModel = lodash.find(this.#applicationConfig.models, (item) => item.singularCode == model.singularCode);
|
|
2411
2420
|
if (originalModel) {
|
|
2421
|
+
lodash.merge(originalModel, lodash.omit(model, ["id", "maintainedBy", "namespace", "singularCode", "pluralCode", "schema", "tableName", "properties", "extensions"]));
|
|
2412
2422
|
originalModel.name = model.name;
|
|
2413
2423
|
const originalProperties = originalModel.properties;
|
|
2414
2424
|
for (const property of model.properties) {
|
|
2415
|
-
const originalProperty =
|
|
2425
|
+
const originalProperty = lodash.find(originalProperties, (item) => item.code == property.code);
|
|
2416
2426
|
if (originalProperty) {
|
|
2417
2427
|
originalProperty.name = property.name;
|
|
2418
2428
|
}
|
|
@@ -2428,7 +2438,7 @@ class RapidServer {
|
|
|
2428
2438
|
}
|
|
2429
2439
|
if (routes) {
|
|
2430
2440
|
for (const route of routes) {
|
|
2431
|
-
const originalRoute =
|
|
2441
|
+
const originalRoute = lodash.find(this.#applicationConfig.routes, (item) => item.code == route.code);
|
|
2432
2442
|
if (originalRoute) {
|
|
2433
2443
|
originalRoute.name = route.name;
|
|
2434
2444
|
originalRoute.actions = route.actions;
|
|
@@ -2439,8 +2449,24 @@ class RapidServer {
|
|
|
2439
2449
|
}
|
|
2440
2450
|
}
|
|
2441
2451
|
}
|
|
2452
|
+
appendModelProperties(modelSingularCode, properties) {
|
|
2453
|
+
const originalModel = lodash.find(this.#applicationConfig.models, (item) => item.singularCode == modelSingularCode);
|
|
2454
|
+
if (!originalModel) {
|
|
2455
|
+
throw new Error(`Cannot append model properties. Model '${modelSingularCode}' was not found.`);
|
|
2456
|
+
}
|
|
2457
|
+
const originalProperties = originalModel.properties;
|
|
2458
|
+
for (const property of properties) {
|
|
2459
|
+
const originalProperty = lodash.find(originalProperties, (item) => item.code == property.code);
|
|
2460
|
+
if (originalProperty) {
|
|
2461
|
+
originalProperty.name = property.name;
|
|
2462
|
+
}
|
|
2463
|
+
else {
|
|
2464
|
+
originalProperties.push(property);
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2442
2468
|
registerActionHandler(plugin, options) {
|
|
2443
|
-
const handler =
|
|
2469
|
+
const handler = lodash.bind(options.handler, null, plugin);
|
|
2444
2470
|
this.#actionHandlersMapByCode.set(options.code, handler);
|
|
2445
2471
|
}
|
|
2446
2472
|
getActionHandlerByCode(code) {
|
|
@@ -2459,7 +2485,7 @@ class RapidServer {
|
|
|
2459
2485
|
if (!model) {
|
|
2460
2486
|
throw new Error(`Data model ${namespace}.${singularCode} not found.`);
|
|
2461
2487
|
}
|
|
2462
|
-
dataAccessor = new DataAccessor(this.#databaseAccessor, {
|
|
2488
|
+
dataAccessor = new DataAccessor(this, this.#databaseAccessor, {
|
|
2463
2489
|
model,
|
|
2464
2490
|
queryBuilder: this.queryBuilder,
|
|
2465
2491
|
});
|
|
@@ -2487,7 +2513,7 @@ class RapidServer {
|
|
|
2487
2513
|
return this;
|
|
2488
2514
|
}
|
|
2489
2515
|
async emitEvent(eventName, sender, payload) {
|
|
2490
|
-
|
|
2516
|
+
this.#logger.debug(`Emitting '${eventName}' event.`, { eventName, payload });
|
|
2491
2517
|
await this.#eventManager.emit(eventName, sender, payload);
|
|
2492
2518
|
// TODO: should move this logic into metaManager
|
|
2493
2519
|
// if (
|
|
@@ -2499,7 +2525,7 @@ class RapidServer {
|
|
|
2499
2525
|
// }
|
|
2500
2526
|
}
|
|
2501
2527
|
async start() {
|
|
2502
|
-
|
|
2528
|
+
this.#logger.info("Starting rapid server...");
|
|
2503
2529
|
const pluginManager = this.#pluginManager;
|
|
2504
2530
|
await pluginManager.loadPlugins(this.#plugins);
|
|
2505
2531
|
await pluginManager.initPlugins();
|
|
@@ -2509,11 +2535,11 @@ class RapidServer {
|
|
|
2509
2535
|
await pluginManager.registerMessageHandlers();
|
|
2510
2536
|
await pluginManager.registerTaskProcessors();
|
|
2511
2537
|
await this.configureApplication();
|
|
2512
|
-
|
|
2538
|
+
this.#logger.info(`Rapid server ready.`);
|
|
2513
2539
|
await pluginManager.onApplicationReady(this.#applicationConfig);
|
|
2514
2540
|
}
|
|
2515
2541
|
async configureApplication() {
|
|
2516
|
-
this.#applicationConfig =
|
|
2542
|
+
this.#applicationConfig = lodash.cloneDeep(this.#bootstrapApplicationConfig);
|
|
2517
2543
|
const pluginManager = this.#pluginManager;
|
|
2518
2544
|
await pluginManager.onLoadingApplication(this.#applicationConfig);
|
|
2519
2545
|
await pluginManager.configureModels(this.#applicationConfig);
|
|
@@ -2524,14 +2550,20 @@ class RapidServer {
|
|
|
2524
2550
|
this.#buildedRoutes = await buildRoutes(this, this.#applicationConfig);
|
|
2525
2551
|
}
|
|
2526
2552
|
async queryDatabaseObject(sql, params) {
|
|
2527
|
-
|
|
2553
|
+
try {
|
|
2554
|
+
return await this.#databaseAccessor.queryDatabaseObject(sql, params);
|
|
2555
|
+
}
|
|
2556
|
+
catch (err) {
|
|
2557
|
+
this.#logger.error("Failed to query database object.", { errorMessage: err.message, sql, params });
|
|
2558
|
+
throw err;
|
|
2559
|
+
}
|
|
2528
2560
|
}
|
|
2529
2561
|
async tryQueryDatabaseObject(sql, params) {
|
|
2530
2562
|
try {
|
|
2531
2563
|
return await this.queryDatabaseObject(sql, params);
|
|
2532
2564
|
}
|
|
2533
2565
|
catch (err) {
|
|
2534
|
-
|
|
2566
|
+
this.#logger.error("Failed to query database object.", { errorMessage: err.message, sql, params });
|
|
2535
2567
|
}
|
|
2536
2568
|
return [];
|
|
2537
2569
|
}
|
|
@@ -2539,13 +2571,16 @@ class RapidServer {
|
|
|
2539
2571
|
return this.#middlewares;
|
|
2540
2572
|
}
|
|
2541
2573
|
async handleRequest(request, next) {
|
|
2542
|
-
const rapidRequest = new RapidRequest(request);
|
|
2574
|
+
const rapidRequest = new RapidRequest(this, request);
|
|
2543
2575
|
await rapidRequest.parseBody();
|
|
2544
|
-
const routeContext = new RouteContext(rapidRequest);
|
|
2545
|
-
this.#pluginManager.onPrepareRouteContext(routeContext);
|
|
2576
|
+
const routeContext = new RouteContext(this, rapidRequest);
|
|
2577
|
+
await this.#pluginManager.onPrepareRouteContext(routeContext);
|
|
2546
2578
|
await this.#buildedRoutes(routeContext, next);
|
|
2547
2579
|
return routeContext.response.getResponse();
|
|
2548
2580
|
}
|
|
2581
|
+
async beforeRunRouteActions(handlerContext) {
|
|
2582
|
+
await this.#pluginManager.beforeRunRouteActions(handlerContext);
|
|
2583
|
+
}
|
|
2549
2584
|
}
|
|
2550
2585
|
|
|
2551
2586
|
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
|
@@ -2751,10 +2786,6 @@ class MetaManager {
|
|
|
2751
2786
|
get configurations() {
|
|
2752
2787
|
return [];
|
|
2753
2788
|
}
|
|
2754
|
-
async initPlugin(server) {
|
|
2755
|
-
}
|
|
2756
|
-
async registerMiddlewares(server) {
|
|
2757
|
-
}
|
|
2758
2789
|
async registerActionHandlers(server) {
|
|
2759
2790
|
server.registerActionHandler(this, listMetaModels);
|
|
2760
2791
|
server.registerActionHandler(this, listMetaRoutes);
|
|
@@ -2765,31 +2796,20 @@ class MetaManager {
|
|
|
2765
2796
|
server.registerEventHandler("entity.update", handleEntityUpdateEvent.bind(this, server));
|
|
2766
2797
|
server.registerEventHandler("entity.delete", handleEntityDeleteEvent.bind(this, server));
|
|
2767
2798
|
}
|
|
2768
|
-
async registerMessageHandlers(server) {
|
|
2769
|
-
}
|
|
2770
|
-
async registerTaskProcessors(server) {
|
|
2771
|
-
}
|
|
2772
|
-
async onLoadingApplication(server, applicationConfig) {
|
|
2773
|
-
}
|
|
2774
2799
|
async configureModels(server, applicationConfig) {
|
|
2800
|
+
const logger = server.getLogger();
|
|
2775
2801
|
try {
|
|
2802
|
+
logger.info("Loading meta of models...");
|
|
2776
2803
|
const models = await listCollections(server, applicationConfig);
|
|
2777
2804
|
server.appendApplicationConfig({ models });
|
|
2778
2805
|
}
|
|
2779
|
-
catch (
|
|
2780
|
-
|
|
2806
|
+
catch (error) {
|
|
2807
|
+
logger.crit("Failed to load meta of models.", { error });
|
|
2781
2808
|
}
|
|
2782
2809
|
}
|
|
2783
|
-
async configureModelProperties(server, applicationConfig) {
|
|
2784
|
-
}
|
|
2785
|
-
async configureRoutes(server, applicationConfig) {
|
|
2786
|
-
}
|
|
2787
2810
|
async onApplicationLoaded(server, applicationConfig) {
|
|
2788
|
-
console.log("metaManager.onApplicationLoaded");
|
|
2789
2811
|
await syncDatabaseSchema(server, applicationConfig);
|
|
2790
2812
|
}
|
|
2791
|
-
async onApplicationReady(server, applicationConfig) {
|
|
2792
|
-
}
|
|
2793
2813
|
}
|
|
2794
2814
|
async function handleEntityCreateEvent(server, sender, payload) {
|
|
2795
2815
|
if (sender === this) {
|
|
@@ -2849,15 +2869,16 @@ function listCollections(server, applicationConfig) {
|
|
|
2849
2869
|
});
|
|
2850
2870
|
}
|
|
2851
2871
|
async function syncDatabaseSchema(server, applicationConfig) {
|
|
2852
|
-
|
|
2872
|
+
const logger = server.getLogger();
|
|
2873
|
+
logger.info("Synchronizing database schema...");
|
|
2853
2874
|
const sqlQueryTableInformations = `SELECT table_schema, table_name FROM information_schema.tables`;
|
|
2854
2875
|
const tablesInDb = await server.queryDatabaseObject(sqlQueryTableInformations);
|
|
2855
2876
|
const { queryBuilder } = server;
|
|
2856
2877
|
for (const model of applicationConfig.models) {
|
|
2857
|
-
|
|
2878
|
+
logger.debug(`Checking data table for '${model.namespace}.${model.singularCode}'...`);
|
|
2858
2879
|
const expectedTableSchema = model.schema || server.databaseConfig.dbDefaultSchema;
|
|
2859
2880
|
const expectedTableName = model.tableName;
|
|
2860
|
-
const tableInDb =
|
|
2881
|
+
const tableInDb = lodash.find(tablesInDb, { table_schema: expectedTableSchema, table_name: expectedTableName });
|
|
2861
2882
|
if (!tableInDb) {
|
|
2862
2883
|
await server.queryDatabaseObject(`CREATE TABLE IF NOT EXISTS ${queryBuilder.quoteTable(model)} ()`, []);
|
|
2863
2884
|
}
|
|
@@ -2866,16 +2887,16 @@ async function syncDatabaseSchema(server, applicationConfig) {
|
|
|
2866
2887
|
FROM information_schema.columns;`;
|
|
2867
2888
|
const columnsInDb = await server.queryDatabaseObject(sqlQueryColumnInformations, []);
|
|
2868
2889
|
for (const model of applicationConfig.models) {
|
|
2869
|
-
|
|
2890
|
+
logger.debug(`Checking data columns for '${model.namespace}.${model.singularCode}'...`);
|
|
2870
2891
|
for (const property of model.properties) {
|
|
2871
2892
|
let columnDDL;
|
|
2872
2893
|
if (isRelationProperty(property)) {
|
|
2873
2894
|
if (property.relation === "one") {
|
|
2874
2895
|
const targetModel = applicationConfig.models.find(item => item.singularCode === property.targetSingularCode);
|
|
2875
2896
|
if (!targetModel) {
|
|
2876
|
-
|
|
2897
|
+
logger.warn(`Cannot find target model with singular code "${property.targetSingularCode}".`);
|
|
2877
2898
|
}
|
|
2878
|
-
const columnInDb =
|
|
2899
|
+
const columnInDb = lodash.find(columnsInDb, {
|
|
2879
2900
|
table_schema: model.schema || "public",
|
|
2880
2901
|
table_name: model.tableName,
|
|
2881
2902
|
column_name: property.targetIdColumnName,
|
|
@@ -2893,7 +2914,7 @@ async function syncDatabaseSchema(server, applicationConfig) {
|
|
|
2893
2914
|
}
|
|
2894
2915
|
else if (property.relation === "many") {
|
|
2895
2916
|
if (property.linkTableName) {
|
|
2896
|
-
const tableInDb =
|
|
2917
|
+
const tableInDb = lodash.find(tablesInDb, { table_schema: property.linkSchema || server.databaseConfig.dbDefaultSchema, table_name: property.linkTableName });
|
|
2897
2918
|
if (!tableInDb) {
|
|
2898
2919
|
columnDDL = generateLinkTableDDL(queryBuilder, {
|
|
2899
2920
|
linkSchema: property.linkSchema,
|
|
@@ -2906,10 +2927,10 @@ async function syncDatabaseSchema(server, applicationConfig) {
|
|
|
2906
2927
|
else {
|
|
2907
2928
|
const targetModel = applicationConfig.models.find(item => item.singularCode === property.targetSingularCode);
|
|
2908
2929
|
if (!targetModel) {
|
|
2909
|
-
|
|
2930
|
+
logger.warn(`Cannot find target model with singular code "${property.targetSingularCode}".`);
|
|
2910
2931
|
continue;
|
|
2911
2932
|
}
|
|
2912
|
-
const columnInDb =
|
|
2933
|
+
const columnInDb = lodash.find(columnsInDb, {
|
|
2913
2934
|
table_schema: targetModel.schema || "public",
|
|
2914
2935
|
table_name: targetModel.tableName,
|
|
2915
2936
|
column_name: property.selfIdColumnName,
|
|
@@ -2935,7 +2956,7 @@ async function syncDatabaseSchema(server, applicationConfig) {
|
|
|
2935
2956
|
}
|
|
2936
2957
|
else {
|
|
2937
2958
|
const columnName = property.columnName || property.code;
|
|
2938
|
-
const columnInDb =
|
|
2959
|
+
const columnInDb = lodash.find(columnsInDb, {
|
|
2939
2960
|
table_schema: model.schema || "public",
|
|
2940
2961
|
table_name: model.tableName,
|
|
2941
2962
|
column_name: columnName,
|
|
@@ -2997,7 +3018,6 @@ function generateCreateColumnDDL(queryBuilder, options) {
|
|
|
2997
3018
|
else {
|
|
2998
3019
|
const columnType = pgPropertyTypeColumnMap[options.type];
|
|
2999
3020
|
if (!columnType) {
|
|
3000
|
-
console.log('options', options);
|
|
3001
3021
|
throw new Error(`Property type "${options.type}" is not supported.`);
|
|
3002
3022
|
}
|
|
3003
3023
|
columnDDL += ` ${columnType}`;
|
|
@@ -3035,22 +3055,19 @@ const pgPropertyTypeColumnMap = {
|
|
|
3035
3055
|
};
|
|
3036
3056
|
|
|
3037
3057
|
function mergeInput(defaultInput, input, fixedInput) {
|
|
3038
|
-
return
|
|
3058
|
+
return lodash.mergeWith({}, defaultInput, input, fixedInput, doNotMergeArray);
|
|
3039
3059
|
}
|
|
3040
3060
|
function doNotMergeArray(objValue, srcValue) {
|
|
3041
|
-
if (
|
|
3061
|
+
if (lodash.isArray(srcValue)) {
|
|
3042
3062
|
return srcValue;
|
|
3043
3063
|
}
|
|
3044
3064
|
}
|
|
3045
3065
|
|
|
3046
3066
|
async function runCollectionEntityActionHandler(ctx, options, code, handleEntityAction) {
|
|
3047
|
-
const { server, input } = ctx;
|
|
3067
|
+
const { logger, server, input } = ctx;
|
|
3048
3068
|
const { defaultInput, fixedInput } = options;
|
|
3049
|
-
console.debug(`Running ${code} handler...`);
|
|
3050
|
-
console.debug(`defaultInput: ${JSON.stringify(defaultInput)}`);
|
|
3051
3069
|
const mergedInput = mergeInput(defaultInput, input, fixedInput);
|
|
3052
|
-
|
|
3053
|
-
console.debug(`mergedInput: ${JSON.stringify(mergedInput)}`);
|
|
3070
|
+
logger.debug(`Running ${code} handler...`, { defaultInput, fixedInput, mergedInput });
|
|
3054
3071
|
const entityManager = server.getEntityManager(options.singularCode);
|
|
3055
3072
|
const result = handleEntityAction(entityManager, mergedInput);
|
|
3056
3073
|
if (result instanceof Promise) {
|
|
@@ -3122,8 +3139,8 @@ var findCollectionEntities = /*#__PURE__*/Object.freeze({
|
|
|
3122
3139
|
|
|
3123
3140
|
const code$g = "findCollectionEntityById";
|
|
3124
3141
|
async function handler$g(plugin, ctx, options) {
|
|
3125
|
-
|
|
3126
|
-
|
|
3142
|
+
const { logger, server, input } = ctx;
|
|
3143
|
+
logger.debug(`Running ${code$g} handler...`, { input });
|
|
3127
3144
|
const { id } = input;
|
|
3128
3145
|
const entityManager = server.getEntityManager(options.singularCode);
|
|
3129
3146
|
const entity = await entityManager.findById(id);
|
|
@@ -3155,13 +3172,10 @@ var countCollectionEntities = /*#__PURE__*/Object.freeze({
|
|
|
3155
3172
|
|
|
3156
3173
|
const code$e = "createCollectionEntity";
|
|
3157
3174
|
async function handler$e(plugin, ctx, options) {
|
|
3158
|
-
const { server, input } = ctx;
|
|
3175
|
+
const { logger, server, input } = ctx;
|
|
3159
3176
|
const { defaultInput, fixedInput } = options;
|
|
3160
|
-
console.debug(`Running ${code$e} handler...`);
|
|
3161
|
-
console.debug(`defaultInput: ${JSON.stringify(defaultInput)}`);
|
|
3162
3177
|
const mergedInput = mergeInput(defaultInput, input, fixedInput);
|
|
3163
|
-
|
|
3164
|
-
console.debug(`mergedInput: ${JSON.stringify(mergedInput)}`);
|
|
3178
|
+
logger.debug(`Running ${code$e} handler...`, { defaultInput, fixedInput, mergedInput });
|
|
3165
3179
|
const userId = ctx.routerContext.state?.userId;
|
|
3166
3180
|
if (userId) {
|
|
3167
3181
|
input.createdBy = userId;
|
|
@@ -3181,19 +3195,16 @@ var createCollectionEntity = /*#__PURE__*/Object.freeze({
|
|
|
3181
3195
|
|
|
3182
3196
|
const code$d = "createCollectionEntitiesBatch";
|
|
3183
3197
|
async function handler$d(plugin, ctx, options) {
|
|
3184
|
-
const { server, input } = ctx;
|
|
3198
|
+
const { logger, server, input } = ctx;
|
|
3185
3199
|
const { defaultInput, fixedInput } = options;
|
|
3186
|
-
|
|
3200
|
+
logger.debug(`Running ${code$d} handler...`, { defaultInput, fixedInput, input });
|
|
3187
3201
|
const { entities } = input;
|
|
3188
|
-
if (!
|
|
3202
|
+
if (!lodash.isArray(entities)) {
|
|
3189
3203
|
throw new Error("input.entities should be an array.");
|
|
3190
3204
|
}
|
|
3191
|
-
console.debug(`defaultInput: ${JSON.stringify(defaultInput)}`);
|
|
3192
|
-
console.debug(`fixedInput: ${JSON.stringify(fixedInput)}`);
|
|
3193
3205
|
const output = [];
|
|
3194
3206
|
for (const entity of entities) {
|
|
3195
3207
|
const mergedEntity = mergeInput(defaultInput?.entity || {}, entity, fixedInput?.entity);
|
|
3196
|
-
console.debug(`mergedEntity: ${JSON.stringify(mergedEntity)}`);
|
|
3197
3208
|
const userId = ctx.routerContext.state?.userId;
|
|
3198
3209
|
if (userId) {
|
|
3199
3210
|
mergedEntity.createdBy = userId;
|
|
@@ -3215,13 +3226,10 @@ var createCollectionEntitiesBatch = /*#__PURE__*/Object.freeze({
|
|
|
3215
3226
|
|
|
3216
3227
|
const code$c = "updateCollectionEntityById";
|
|
3217
3228
|
async function handler$c(plugin, ctx, options) {
|
|
3218
|
-
const { server, input } = ctx;
|
|
3229
|
+
const { logger, server, input } = ctx;
|
|
3219
3230
|
const { defaultInput, fixedInput } = options;
|
|
3220
|
-
console.debug(`Running ${code$c} handler...`);
|
|
3221
|
-
console.debug(`defaultInput: ${JSON.stringify(defaultInput)}`);
|
|
3222
3231
|
const mergedInput = mergeInput(defaultInput, input, fixedInput);
|
|
3223
|
-
|
|
3224
|
-
console.debug(`mergedInput: ${JSON.stringify(mergedInput)}`);
|
|
3232
|
+
logger.debug(`Running ${code$c} handler...`, { defaultInput, fixedInput, mergedInput });
|
|
3225
3233
|
const entityManager = server.getEntityManager(options.singularCode);
|
|
3226
3234
|
const output = await entityManager.updateEntityById({ id: mergedInput.id, entityToSave: mergedInput }, plugin);
|
|
3227
3235
|
ctx.output = output;
|
|
@@ -3235,8 +3243,8 @@ var updateCollectionEntityById = /*#__PURE__*/Object.freeze({
|
|
|
3235
3243
|
|
|
3236
3244
|
const code$b = "deleteCollectionEntityById";
|
|
3237
3245
|
async function handler$b(plugin, ctx, options) {
|
|
3238
|
-
|
|
3239
|
-
|
|
3246
|
+
const { logger, server, input } = ctx;
|
|
3247
|
+
logger.debug(`Running ${code$b} handler...`);
|
|
3240
3248
|
const entityManager = server.getEntityManager(options.singularCode);
|
|
3241
3249
|
await entityManager.deleteById(input.id, plugin);
|
|
3242
3250
|
ctx.status = 200;
|
|
@@ -3251,13 +3259,10 @@ var deleteCollectionEntityById = /*#__PURE__*/Object.freeze({
|
|
|
3251
3259
|
|
|
3252
3260
|
const code$a = "addEntityRelations";
|
|
3253
3261
|
async function handler$a(plugin, ctx, options) {
|
|
3254
|
-
const { server, input } = ctx;
|
|
3262
|
+
const { logger, server, input } = ctx;
|
|
3255
3263
|
const { defaultInput, fixedInput } = options;
|
|
3256
|
-
console.debug(`Running ${code$a} handler...`);
|
|
3257
|
-
console.debug(`defaultInput: ${JSON.stringify(defaultInput)}`);
|
|
3258
3264
|
const mergedInput = mergeInput(defaultInput, input, fixedInput);
|
|
3259
|
-
|
|
3260
|
-
console.debug(`mergedInput: ${JSON.stringify(mergedInput)}`);
|
|
3265
|
+
logger.debug(`Running ${code$a} handler...`, { defaultInput, fixedInput, mergedInput });
|
|
3261
3266
|
const entityManager = server.getEntityManager(options.singularCode);
|
|
3262
3267
|
await entityManager.addRelations(mergedInput, plugin);
|
|
3263
3268
|
ctx.output = {};
|
|
@@ -3271,13 +3276,10 @@ var addEntityRelations = /*#__PURE__*/Object.freeze({
|
|
|
3271
3276
|
|
|
3272
3277
|
const code$9 = "removeEntityRelations";
|
|
3273
3278
|
async function handler$9(plugin, ctx, options) {
|
|
3274
|
-
const { server, input } = ctx;
|
|
3279
|
+
const { logger, server, input } = ctx;
|
|
3275
3280
|
const { defaultInput, fixedInput } = options;
|
|
3276
|
-
console.debug(`Running ${code$9} handler...`);
|
|
3277
|
-
console.debug(`defaultInput: ${JSON.stringify(defaultInput)}`);
|
|
3278
3281
|
const mergedInput = mergeInput(defaultInput, input, fixedInput);
|
|
3279
|
-
|
|
3280
|
-
console.debug(`mergedInput: ${JSON.stringify(mergedInput)}`);
|
|
3282
|
+
logger.debug(`Running ${code$9} handler...`, { defaultInput, fixedInput, mergedInput });
|
|
3281
3283
|
const entityManager = server.getEntityManager(options.singularCode);
|
|
3282
3284
|
await entityManager.removeRelations(mergedInput, plugin);
|
|
3283
3285
|
ctx.output = {};
|
|
@@ -3291,16 +3293,13 @@ var removeEntityRelations = /*#__PURE__*/Object.freeze({
|
|
|
3291
3293
|
|
|
3292
3294
|
const code$8 = "queryDatabase";
|
|
3293
3295
|
async function handler$8(plugin, ctx, options) {
|
|
3294
|
-
const { server, input } = ctx;
|
|
3296
|
+
const { logger, server, input } = ctx;
|
|
3295
3297
|
const { sql, querySingle, defaultInput, fixedInput } = options;
|
|
3296
|
-
console.debug(`Running ${code$8} handler...`);
|
|
3297
|
-
console.debug(`defaultInput: ${JSON.stringify(defaultInput)}`);
|
|
3298
3298
|
const mergedInput = mergeInput(defaultInput, input, fixedInput);
|
|
3299
|
-
|
|
3300
|
-
console.debug(`mergedInput: ${JSON.stringify(mergedInput)}`);
|
|
3299
|
+
logger.debug(`Running ${code$8} handler...`, { defaultInput, fixedInput, mergedInput });
|
|
3301
3300
|
const result = await server.queryDatabaseObject(sql, mergedInput);
|
|
3302
3301
|
if (querySingle) {
|
|
3303
|
-
ctx.output =
|
|
3302
|
+
ctx.output = lodash.first(result);
|
|
3304
3303
|
}
|
|
3305
3304
|
else {
|
|
3306
3305
|
ctx.output = result;
|
|
@@ -3390,10 +3389,6 @@ class DataManager {
|
|
|
3390
3389
|
get configurations() {
|
|
3391
3390
|
return [];
|
|
3392
3391
|
}
|
|
3393
|
-
async initPlugin(server) {
|
|
3394
|
-
}
|
|
3395
|
-
async registerMiddlewares(server) {
|
|
3396
|
-
}
|
|
3397
3392
|
async registerActionHandlers(server) {
|
|
3398
3393
|
server.registerActionHandler(this, findCollectionEntities);
|
|
3399
3394
|
server.registerActionHandler(this, findCollectionEntityById);
|
|
@@ -3406,18 +3401,6 @@ class DataManager {
|
|
|
3406
3401
|
server.registerActionHandler(this, deleteCollectionEntityById);
|
|
3407
3402
|
server.registerActionHandler(this, queryDatabase);
|
|
3408
3403
|
}
|
|
3409
|
-
async registerEventHandlers(server) {
|
|
3410
|
-
}
|
|
3411
|
-
async registerMessageHandlers(server) {
|
|
3412
|
-
}
|
|
3413
|
-
async registerTaskProcessors(server) {
|
|
3414
|
-
}
|
|
3415
|
-
async onLoadingApplication(server, applicationConfig) {
|
|
3416
|
-
}
|
|
3417
|
-
async configureModels(server, applicationConfig) {
|
|
3418
|
-
}
|
|
3419
|
-
async configureModelProperties(server, applicationConfig) {
|
|
3420
|
-
}
|
|
3421
3404
|
async configureRoutes(server, applicationConfig) {
|
|
3422
3405
|
const { models } = applicationConfig;
|
|
3423
3406
|
const routes = [];
|
|
@@ -3445,11 +3428,6 @@ class DataManager {
|
|
|
3445
3428
|
});
|
|
3446
3429
|
server.appendApplicationConfig({ routes });
|
|
3447
3430
|
}
|
|
3448
|
-
async onApplicationLoaded(server, applicationConfig) {
|
|
3449
|
-
console.log("[dataManager.onApplicationLoaded]");
|
|
3450
|
-
}
|
|
3451
|
-
async onApplicationReady(server, applicationConfig) {
|
|
3452
|
-
}
|
|
3453
3431
|
}
|
|
3454
3432
|
|
|
3455
3433
|
async function fetchWithTimeout(url, reqInit, timeout) {
|
|
@@ -3504,7 +3482,8 @@ async function sendSourceResponse(proxyCtx, targetRes) {
|
|
|
3504
3482
|
|
|
3505
3483
|
const code$7 = "httpProxy";
|
|
3506
3484
|
async function handler$7(plugin, ctx, options) {
|
|
3507
|
-
|
|
3485
|
+
const { logger } = ctx;
|
|
3486
|
+
logger.debug(`Running ${code$7} handler...`);
|
|
3508
3487
|
await doProxy(ctx.routerContext, options);
|
|
3509
3488
|
}
|
|
3510
3489
|
|
|
@@ -3533,10 +3512,6 @@ class RouteManager {
|
|
|
3533
3512
|
get configurations() {
|
|
3534
3513
|
return [];
|
|
3535
3514
|
}
|
|
3536
|
-
async initPlugin(server) {
|
|
3537
|
-
}
|
|
3538
|
-
async registerMiddlewares(server) {
|
|
3539
|
-
}
|
|
3540
3515
|
async registerActionHandlers(server) {
|
|
3541
3516
|
server.registerActionHandler(this, httpProxy);
|
|
3542
3517
|
}
|
|
@@ -3546,18 +3521,10 @@ class RouteManager {
|
|
|
3546
3521
|
// server.registerEventHandler("entity.update", handleEntityEvent.bind(null, server))
|
|
3547
3522
|
// server.registerEventHandler("entity.delete", handleEntityEvent.bind(null, server))
|
|
3548
3523
|
}
|
|
3549
|
-
async registerMessageHandlers(server) {
|
|
3550
|
-
}
|
|
3551
|
-
async registerTaskProcessors(server) {
|
|
3552
|
-
}
|
|
3553
|
-
async onLoadingApplication(server, applicationConfig) {
|
|
3554
|
-
}
|
|
3555
|
-
async configureModels(server, applicationConfig) {
|
|
3556
|
-
}
|
|
3557
|
-
async configureModelProperties(server, applicationConfig) {
|
|
3558
|
-
}
|
|
3559
3524
|
async configureRoutes(server, applicationConfig) {
|
|
3525
|
+
const logger = server.getLogger();
|
|
3560
3526
|
try {
|
|
3527
|
+
logger.info("Loading meta of routes...");
|
|
3561
3528
|
const entityManager = server.getEntityManager("route");
|
|
3562
3529
|
const routes = await entityManager.findEntities({
|
|
3563
3530
|
orderBy: [
|
|
@@ -3566,15 +3533,10 @@ class RouteManager {
|
|
|
3566
3533
|
});
|
|
3567
3534
|
applicationConfig.routes.push(...routes);
|
|
3568
3535
|
}
|
|
3569
|
-
catch (
|
|
3570
|
-
|
|
3536
|
+
catch (error) {
|
|
3537
|
+
logger.crit("Failed to load meta of routes.", { error });
|
|
3571
3538
|
}
|
|
3572
3539
|
}
|
|
3573
|
-
async onApplicationLoaded(server, applicationConfig) {
|
|
3574
|
-
console.log("[routeManager.onApplicationLoaded] onApplicationLoaded");
|
|
3575
|
-
}
|
|
3576
|
-
async onApplicationReady(server, applicationConfig) {
|
|
3577
|
-
}
|
|
3578
3540
|
}
|
|
3579
3541
|
|
|
3580
3542
|
var pluginConfig = {
|
|
@@ -3654,16 +3616,23 @@ var pluginConfig = {
|
|
|
3654
3616
|
* Webhooks plugin
|
|
3655
3617
|
*/
|
|
3656
3618
|
function listWebhooks(server) {
|
|
3657
|
-
const
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3619
|
+
const logger = server.getLogger();
|
|
3620
|
+
logger.info("Loading meta of webhooks...");
|
|
3621
|
+
try {
|
|
3622
|
+
const entityManager = server.getEntityManager("webhook");
|
|
3623
|
+
return entityManager.findEntities({
|
|
3624
|
+
filters: [
|
|
3625
|
+
{
|
|
3626
|
+
field: "enabled",
|
|
3627
|
+
operator: "eq",
|
|
3628
|
+
value: true,
|
|
3629
|
+
},
|
|
3630
|
+
],
|
|
3631
|
+
});
|
|
3632
|
+
}
|
|
3633
|
+
catch (error) {
|
|
3634
|
+
logger.crit("Failed to load meta of webhooks.", { error });
|
|
3635
|
+
}
|
|
3667
3636
|
}
|
|
3668
3637
|
class WebhooksPlugin {
|
|
3669
3638
|
#webhooks;
|
|
@@ -3685,12 +3654,6 @@ class WebhooksPlugin {
|
|
|
3685
3654
|
get configurations() {
|
|
3686
3655
|
return [];
|
|
3687
3656
|
}
|
|
3688
|
-
async initPlugin(server) {
|
|
3689
|
-
}
|
|
3690
|
-
async registerMiddlewares(server) {
|
|
3691
|
-
}
|
|
3692
|
-
async registerActionHandlers(server) {
|
|
3693
|
-
}
|
|
3694
3657
|
async registerEventHandlers(server) {
|
|
3695
3658
|
const events = [
|
|
3696
3659
|
"entity.create",
|
|
@@ -3701,12 +3664,6 @@ class WebhooksPlugin {
|
|
|
3701
3664
|
server.registerEventHandler(event, this.handleEntityEvent.bind(this, server, event));
|
|
3702
3665
|
}
|
|
3703
3666
|
}
|
|
3704
|
-
async registerMessageHandlers(server) {
|
|
3705
|
-
}
|
|
3706
|
-
async registerTaskProcessors(server) {
|
|
3707
|
-
}
|
|
3708
|
-
async onLoadingApplication(server, applicationConfig) {
|
|
3709
|
-
}
|
|
3710
3667
|
async configureModels(server, applicationConfig) {
|
|
3711
3668
|
server.appendApplicationConfig({
|
|
3712
3669
|
models: pluginConfig.models,
|
|
@@ -3717,7 +3674,6 @@ class WebhooksPlugin {
|
|
|
3717
3674
|
async configureRoutes(server, applicationConfig) {
|
|
3718
3675
|
}
|
|
3719
3676
|
async onApplicationLoaded(server, applicationConfig) {
|
|
3720
|
-
console.log("[webhooks.onApplicationLoaded] loading webhooks");
|
|
3721
3677
|
this.#webhooks = await listWebhooks(server);
|
|
3722
3678
|
}
|
|
3723
3679
|
async onApplicationReady(server, applicationConfig) {
|
|
@@ -3734,16 +3690,18 @@ class WebhooksPlugin {
|
|
|
3734
3690
|
if (payload.namespace === "meta" || payload.namespace === "sys") {
|
|
3735
3691
|
return;
|
|
3736
3692
|
}
|
|
3693
|
+
const logger = server.getLogger();
|
|
3737
3694
|
for (const webhook of this.#webhooks) {
|
|
3738
|
-
if (
|
|
3695
|
+
if (lodash.indexOf(webhook.events, event) === -1) {
|
|
3739
3696
|
continue;
|
|
3740
3697
|
}
|
|
3741
3698
|
if (webhook.namespace != payload.namespace ||
|
|
3742
3699
|
webhook.modelSingularCode !== payload.modelSingularCode) {
|
|
3743
3700
|
continue;
|
|
3744
3701
|
}
|
|
3745
|
-
|
|
3702
|
+
logger.debug(`Triggering webhook. ${webhook.url}`);
|
|
3746
3703
|
// TODO: It's better to trigger webhook through message queue.
|
|
3704
|
+
const requestBody = { event, payload };
|
|
3747
3705
|
try {
|
|
3748
3706
|
await fetchWithTimeout(webhook.url, {
|
|
3749
3707
|
method: "post",
|
|
@@ -3751,12 +3709,11 @@ class WebhooksPlugin {
|
|
|
3751
3709
|
"Content-Type": "application/json",
|
|
3752
3710
|
"x-webhook-secret": webhook.secret || "",
|
|
3753
3711
|
},
|
|
3754
|
-
body: JSON.stringify(
|
|
3712
|
+
body: JSON.stringify(requestBody),
|
|
3755
3713
|
});
|
|
3756
3714
|
}
|
|
3757
|
-
catch (
|
|
3758
|
-
|
|
3759
|
-
console.warn(err);
|
|
3715
|
+
catch (error) {
|
|
3716
|
+
logger.error("Failed to call webhook.", { error, webhookUrl: webhook.url, requestBody });
|
|
3760
3717
|
}
|
|
3761
3718
|
}
|
|
3762
3719
|
}
|
|
@@ -3991,36 +3948,17 @@ class AuthPlugin {
|
|
|
3991
3948
|
get configurations() {
|
|
3992
3949
|
return [];
|
|
3993
3950
|
}
|
|
3994
|
-
async initPlugin(server) {
|
|
3995
|
-
}
|
|
3996
|
-
async registerMiddlewares(server) {
|
|
3997
|
-
}
|
|
3998
3951
|
async registerActionHandlers(server) {
|
|
3999
3952
|
for (const actionHandler of pluginActionHandlers$1) {
|
|
4000
3953
|
server.registerActionHandler(this, actionHandler);
|
|
4001
3954
|
}
|
|
4002
3955
|
}
|
|
4003
|
-
async registerEventHandlers(server) {
|
|
4004
|
-
}
|
|
4005
|
-
async registerMessageHandlers(server) {
|
|
4006
|
-
}
|
|
4007
|
-
async registerTaskProcessors(server) {
|
|
4008
|
-
}
|
|
4009
|
-
async onLoadingApplication(server, applicationConfig) {
|
|
4010
|
-
}
|
|
4011
3956
|
async configureModels(server, applicationConfig) {
|
|
4012
3957
|
server.appendApplicationConfig({ models: pluginModels });
|
|
4013
3958
|
}
|
|
4014
|
-
async configureModelProperties(server, applicationConfig) {
|
|
4015
|
-
}
|
|
4016
3959
|
async configureRoutes(server, applicationConfig) {
|
|
4017
3960
|
server.appendApplicationConfig({ routes: pluginRoutes$1 });
|
|
4018
3961
|
}
|
|
4019
|
-
async onApplicationLoaded(server, applicationConfig) {
|
|
4020
|
-
console.log("authManager.onApplicationLoaded");
|
|
4021
|
-
}
|
|
4022
|
-
async onApplicationReady(server, applicationConfig) {
|
|
4023
|
-
}
|
|
4024
3962
|
async onPrepareRouteContext(server, routeContext) {
|
|
4025
3963
|
const request = routeContext.request;
|
|
4026
3964
|
let token;
|
|
@@ -4043,8 +3981,9 @@ class AuthPlugin {
|
|
|
4043
3981
|
routeContext.state.userId = tokenPayload.aud;
|
|
4044
3982
|
routeContext.state.userLogin = tokenPayload.act;
|
|
4045
3983
|
}
|
|
4046
|
-
catch (
|
|
4047
|
-
|
|
3984
|
+
catch (error) {
|
|
3985
|
+
const logger = server.getLogger();
|
|
3986
|
+
logger.debug("Verify JWT failed.", { error });
|
|
4048
3987
|
}
|
|
4049
3988
|
}
|
|
4050
3989
|
}
|
|
@@ -4136,7 +4075,7 @@ const code$1 = "uploadFile";
|
|
|
4136
4075
|
async function handler$1(plugin, ctx, options) {
|
|
4137
4076
|
const { server, applicationConfig, routerContext, input } = ctx;
|
|
4138
4077
|
let file = input.file || input.files;
|
|
4139
|
-
if (
|
|
4078
|
+
if (lodash.isArray(file)) {
|
|
4140
4079
|
file = file[0];
|
|
4141
4080
|
}
|
|
4142
4081
|
if (!file) {
|
|
@@ -4225,35 +4164,14 @@ class FileManager {
|
|
|
4225
4164
|
get configurations() {
|
|
4226
4165
|
return [];
|
|
4227
4166
|
}
|
|
4228
|
-
async initPlugin(server) {
|
|
4229
|
-
}
|
|
4230
|
-
async registerMiddlewares(server) {
|
|
4231
|
-
}
|
|
4232
4167
|
async registerActionHandlers(server) {
|
|
4233
4168
|
server.registerActionHandler(this, downloadDocumentActionHandler);
|
|
4234
4169
|
server.registerActionHandler(this, downloadFileActionHandler);
|
|
4235
4170
|
server.registerActionHandler(this, uploadFileActionHandler);
|
|
4236
4171
|
}
|
|
4237
|
-
async registerEventHandlers(server) {
|
|
4238
|
-
}
|
|
4239
|
-
async registerMessageHandlers(server) {
|
|
4240
|
-
}
|
|
4241
|
-
async registerTaskProcessors(server) {
|
|
4242
|
-
}
|
|
4243
|
-
async onLoadingApplication(server, applicationConfig) {
|
|
4244
|
-
}
|
|
4245
|
-
async configureModels(server, applicationConfig) {
|
|
4246
|
-
}
|
|
4247
|
-
async configureModelProperties(server, applicationConfig) {
|
|
4248
|
-
}
|
|
4249
4172
|
async configureRoutes(server, applicationConfig) {
|
|
4250
4173
|
server.appendApplicationConfig({ routes: pluginRoutes });
|
|
4251
4174
|
}
|
|
4252
|
-
async onApplicationLoaded(server, applicationConfig) {
|
|
4253
|
-
console.log("fileManager.onApplicationLoaded");
|
|
4254
|
-
}
|
|
4255
|
-
async onApplicationReady(server, applicationConfig) {
|
|
4256
|
-
}
|
|
4257
4175
|
}
|
|
4258
4176
|
|
|
4259
4177
|
const code = "runServerOperation";
|
|
@@ -4421,10 +4339,116 @@ class EntityWatchPlugin {
|
|
|
4421
4339
|
}
|
|
4422
4340
|
}
|
|
4423
4341
|
|
|
4342
|
+
function isAccessAllowed(policy, allowedActions) {
|
|
4343
|
+
let isAnyCheckPassed = true;
|
|
4344
|
+
let isAllCheckPassed = true;
|
|
4345
|
+
if (policy.any) {
|
|
4346
|
+
isAnyCheckPassed = false;
|
|
4347
|
+
for (const action of policy.any) {
|
|
4348
|
+
if (lodash.find(allowedActions, item => item === action) != null) {
|
|
4349
|
+
isAnyCheckPassed = true;
|
|
4350
|
+
break;
|
|
4351
|
+
}
|
|
4352
|
+
}
|
|
4353
|
+
}
|
|
4354
|
+
if (policy.all) {
|
|
4355
|
+
isAllCheckPassed = true;
|
|
4356
|
+
for (const action of policy.all) {
|
|
4357
|
+
if (lodash.find(allowedActions, item => item === action) == null) {
|
|
4358
|
+
isAnyCheckPassed = false;
|
|
4359
|
+
break;
|
|
4360
|
+
}
|
|
4361
|
+
}
|
|
4362
|
+
}
|
|
4363
|
+
return isAnyCheckPassed && isAllCheckPassed;
|
|
4364
|
+
}
|
|
4365
|
+
|
|
4366
|
+
class EntityAccessControlPlugin {
|
|
4367
|
+
constructor() {
|
|
4368
|
+
}
|
|
4369
|
+
get code() {
|
|
4370
|
+
return "entityAccessControl";
|
|
4371
|
+
}
|
|
4372
|
+
get description() {
|
|
4373
|
+
return "";
|
|
4374
|
+
}
|
|
4375
|
+
get extendingAbilities() {
|
|
4376
|
+
return [];
|
|
4377
|
+
}
|
|
4378
|
+
get configurableTargets() {
|
|
4379
|
+
return [];
|
|
4380
|
+
}
|
|
4381
|
+
get configurations() {
|
|
4382
|
+
return [];
|
|
4383
|
+
}
|
|
4384
|
+
async onLoadingApplication(server, applicationConfig) {
|
|
4385
|
+
const properties = [
|
|
4386
|
+
{
|
|
4387
|
+
name: "permissionPolicies",
|
|
4388
|
+
code: "permissionPolicies",
|
|
4389
|
+
columnName: "permission_policies",
|
|
4390
|
+
type: "json",
|
|
4391
|
+
},
|
|
4392
|
+
];
|
|
4393
|
+
server.appendModelProperties("model", properties);
|
|
4394
|
+
}
|
|
4395
|
+
async configureRoutes(server, applicationConfig) {
|
|
4396
|
+
const logger = server.getLogger();
|
|
4397
|
+
logger.info("Configuring entity access checking policies...");
|
|
4398
|
+
const model = lodash.find(applicationConfig.models, (item) => item.singularCode === "model");
|
|
4399
|
+
if (!model) {
|
|
4400
|
+
return;
|
|
4401
|
+
}
|
|
4402
|
+
const { permissionPolicies } = model;
|
|
4403
|
+
if (!permissionPolicies) {
|
|
4404
|
+
return;
|
|
4405
|
+
}
|
|
4406
|
+
const routes = applicationConfig.routes;
|
|
4407
|
+
for (const route of routes) {
|
|
4408
|
+
const { actions } = route;
|
|
4409
|
+
if (!actions) {
|
|
4410
|
+
continue;
|
|
4411
|
+
}
|
|
4412
|
+
for (const action of route.actions) {
|
|
4413
|
+
if (action.code === "findCollectionEntityById") {
|
|
4414
|
+
if (permissionPolicies.find) {
|
|
4415
|
+
lodash.set(action, "config.permissionPolicy", permissionPolicies.find);
|
|
4416
|
+
}
|
|
4417
|
+
}
|
|
4418
|
+
}
|
|
4419
|
+
}
|
|
4420
|
+
}
|
|
4421
|
+
async onPrepareRouteContext(server, routeContext) {
|
|
4422
|
+
const userId = routeContext.state.userId;
|
|
4423
|
+
if (!userId) {
|
|
4424
|
+
return;
|
|
4425
|
+
}
|
|
4426
|
+
const actions = await server.queryDatabaseObject(`select distinct a.* from sys_actions a
|
|
4427
|
+
inner join oc_role_sys_action_links ra on a.id = ra.action_id
|
|
4428
|
+
inner join oc_role_user_links ru on ru.role_id = ra.role_id
|
|
4429
|
+
where ru.user_id = $1;`, [userId]);
|
|
4430
|
+
routeContext.state.allowedActions = actions.map(item => item.code);
|
|
4431
|
+
}
|
|
4432
|
+
async beforeRunRouteActions(server, handlerContext) {
|
|
4433
|
+
// Check permission
|
|
4434
|
+
const { routerContext } = handlerContext;
|
|
4435
|
+
const { routeConfig } = routerContext;
|
|
4436
|
+
for (const actionConfig of routeConfig.actions) {
|
|
4437
|
+
const permissionPolicy = actionConfig.config?.permissionPolicy;
|
|
4438
|
+
if (permissionPolicy) {
|
|
4439
|
+
if (!isAccessAllowed(permissionPolicy, routerContext.state.allowedActions || [])) {
|
|
4440
|
+
throw new Error(`Your action of '${actionConfig.code}' is not permitted.`);
|
|
4441
|
+
}
|
|
4442
|
+
}
|
|
4443
|
+
}
|
|
4444
|
+
}
|
|
4445
|
+
}
|
|
4446
|
+
|
|
4424
4447
|
fixBigIntJSONSerialize();
|
|
4425
4448
|
|
|
4426
4449
|
exports.AuthPlugin = AuthPlugin;
|
|
4427
4450
|
exports.DataManagePlugin = DataManager;
|
|
4451
|
+
exports.EntityAccessControlPlugin = EntityAccessControlPlugin;
|
|
4428
4452
|
exports.EntityWatchPlugin = EntityWatchPlugin;
|
|
4429
4453
|
exports.FileManagePlugin = FileManager;
|
|
4430
4454
|
exports.GlobalRequest = GlobalRequest;
|