@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
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { RpdApplicationConfig, RpdDataModelProperty } from "~/types";
|
|
2
|
+
|
|
3
|
+
import { IRpdServer, RapidPlugin, RpdConfigurationItemOptions, RpdServerPluginConfigurableTargetOptions, RpdServerPluginExtendingAbilities } from "~/core/server";
|
|
4
|
+
import { find, set } from "lodash";
|
|
5
|
+
import { ActionHandlerContext } from "~/core/actionHandler";
|
|
6
|
+
import { isAccessAllowed } from "~/utilities/accessControlUtility";
|
|
7
|
+
import { RouteContext } from "~/core/routeContext";
|
|
8
|
+
|
|
9
|
+
class EntityAccessControlPlugin implements RapidPlugin {
|
|
10
|
+
constructor() {
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get code(): string {
|
|
14
|
+
return "entityAccessControl";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get description(): string {
|
|
18
|
+
return "";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get extendingAbilities(): RpdServerPluginExtendingAbilities[] {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get configurableTargets(): RpdServerPluginConfigurableTargetOptions[] {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get configurations(): RpdConfigurationItemOptions[] {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async onLoadingApplication(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
34
|
+
const properties: RpdDataModelProperty[] = [
|
|
35
|
+
{
|
|
36
|
+
name: "permissionPolicies",
|
|
37
|
+
code: "permissionPolicies",
|
|
38
|
+
columnName: "permission_policies",
|
|
39
|
+
type: "json",
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
server.appendModelProperties("model", properties);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async configureRoutes(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
46
|
+
const logger = server.getLogger();
|
|
47
|
+
logger.info("Configuring entity access checking policies...")
|
|
48
|
+
|
|
49
|
+
const model = find(applicationConfig.models, (item) => item.singularCode === "model");
|
|
50
|
+
if (!model) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const { permissionPolicies } = model;
|
|
55
|
+
if (!permissionPolicies) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const routes = applicationConfig.routes;
|
|
60
|
+
for (const route of routes) {
|
|
61
|
+
const { actions } = route;
|
|
62
|
+
if (!actions) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
for (const action of route.actions) {
|
|
67
|
+
if (action.code === "findCollectionEntityById") {
|
|
68
|
+
if (permissionPolicies.find) {
|
|
69
|
+
set(action, "config.permissionPolicy", permissionPolicies.find);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async onPrepareRouteContext(server: IRpdServer, routeContext: RouteContext) {
|
|
77
|
+
const userId = routeContext.state.userId;
|
|
78
|
+
if (!userId) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const actions = await server.queryDatabaseObject(
|
|
83
|
+
`select distinct a.* from sys_actions a
|
|
84
|
+
inner join oc_role_sys_action_links ra on a.id = ra.action_id
|
|
85
|
+
inner join oc_role_user_links ru on ru.role_id = ra.role_id
|
|
86
|
+
where ru.user_id = $1;`,
|
|
87
|
+
[userId]
|
|
88
|
+
);
|
|
89
|
+
routeContext.state.allowedActions = actions.map(item => item.code);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async beforeRunRouteActions(server: IRpdServer, handlerContext: ActionHandlerContext): Promise<any> {
|
|
93
|
+
// Check permission
|
|
94
|
+
const { routerContext } = handlerContext;
|
|
95
|
+
const { routeConfig } = routerContext;
|
|
96
|
+
for (const actionConfig of routeConfig.actions) {
|
|
97
|
+
const permissionPolicy = actionConfig.config?.permissionPolicy;
|
|
98
|
+
if (permissionPolicy) {
|
|
99
|
+
if (!isAccessAllowed(permissionPolicy, routerContext.state.allowedActions || [])) {
|
|
100
|
+
throw new Error(`Your action of '${actionConfig.code}' is not permitted.`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export default EntityAccessControlPlugin;
|
|
@@ -34,46 +34,15 @@ class FileManager implements RapidPlugin {
|
|
|
34
34
|
return [];
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
async initPlugin(server: IRpdServer): Promise<any> {
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async registerMiddlewares(server: IRpdServer): Promise<any> {
|
|
41
|
-
}
|
|
42
|
-
|
|
43
37
|
async registerActionHandlers(server: IRpdServer): Promise<any> {
|
|
44
38
|
server.registerActionHandler(this, downloadDocumentActionHandler);
|
|
45
39
|
server.registerActionHandler(this, downloadFileActionHandler);
|
|
46
40
|
server.registerActionHandler(this, uploadFileActionHandler);
|
|
47
41
|
}
|
|
48
42
|
|
|
49
|
-
async registerEventHandlers(server: IRpdServer): Promise<any> {
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async registerMessageHandlers(server: IRpdServer): Promise<any> {
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async registerTaskProcessors(server: IRpdServer): Promise<any> {
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async onLoadingApplication(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async configureModels(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async configureModelProperties(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
65
|
-
}
|
|
66
|
-
|
|
67
43
|
async configureRoutes(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
68
44
|
server.appendApplicationConfig({ routes: pluginRoutes });
|
|
69
45
|
}
|
|
70
|
-
|
|
71
|
-
async onApplicationLoaded(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
72
|
-
console.log("fileManager.onApplicationLoaded");
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async onApplicationReady(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
76
|
-
}
|
|
77
46
|
}
|
|
78
47
|
|
|
79
48
|
export default FileManager;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Meta manager plugin
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import * as _ from "lodash";
|
|
6
5
|
import {
|
|
7
6
|
IQueryBuilder,
|
|
8
7
|
QuoteTableOptions,
|
|
@@ -20,6 +19,7 @@ import * as listMetaModels from "./actionHandlers/listMetaModels";
|
|
|
20
19
|
import * as listMetaRoutes from "./actionHandlers/listMetaRoutes";
|
|
21
20
|
import * as getMetaModelDetail from "./actionHandlers/getMetaModelDetail";
|
|
22
21
|
import { isRelationProperty } from "~/utilities/rapidUtility";
|
|
22
|
+
import { find } from "lodash";
|
|
23
23
|
|
|
24
24
|
class MetaManager implements RapidPlugin {
|
|
25
25
|
get code(): string {
|
|
@@ -42,12 +42,6 @@ class MetaManager implements RapidPlugin {
|
|
|
42
42
|
return [];
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
async initPlugin(server: IRpdServer): Promise<any> {
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async registerMiddlewares(server: IRpdServer): Promise<any> {
|
|
49
|
-
}
|
|
50
|
-
|
|
51
45
|
async registerActionHandlers(server: IRpdServer): Promise<any> {
|
|
52
46
|
server.registerActionHandler(this, listMetaModels);
|
|
53
47
|
server.registerActionHandler(this, listMetaRoutes);
|
|
@@ -69,37 +63,20 @@ class MetaManager implements RapidPlugin {
|
|
|
69
63
|
);
|
|
70
64
|
}
|
|
71
65
|
|
|
72
|
-
async registerMessageHandlers(server: IRpdServer): Promise<any> {
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async registerTaskProcessors(server: IRpdServer): Promise<any> {
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async onLoadingApplication(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
79
|
-
}
|
|
80
|
-
|
|
81
66
|
async configureModels(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
67
|
+
const logger = server.getLogger();
|
|
82
68
|
try {
|
|
69
|
+
logger.info("Loading meta of models...");
|
|
83
70
|
const models: RpdDataModel[] = await listCollections(server, applicationConfig);
|
|
84
71
|
server.appendApplicationConfig({ models });
|
|
85
|
-
} catch (
|
|
86
|
-
|
|
72
|
+
} catch (error) {
|
|
73
|
+
logger.crit("Failed to load meta of models.", { error });
|
|
87
74
|
}
|
|
88
75
|
}
|
|
89
76
|
|
|
90
|
-
async configureModelProperties(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async configureRoutes(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
94
|
-
}
|
|
95
|
-
|
|
96
77
|
async onApplicationLoaded(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
97
|
-
console.log("metaManager.onApplicationLoaded");
|
|
98
78
|
await syncDatabaseSchema(server, applicationConfig);
|
|
99
79
|
}
|
|
100
|
-
|
|
101
|
-
async onApplicationReady(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
102
|
-
}
|
|
103
80
|
}
|
|
104
81
|
|
|
105
82
|
export default MetaManager;
|
|
@@ -236,17 +213,18 @@ async function syncDatabaseSchema(
|
|
|
236
213
|
server: IRpdServer,
|
|
237
214
|
applicationConfig: RpdApplicationConfig,
|
|
238
215
|
) {
|
|
239
|
-
|
|
216
|
+
const logger = server.getLogger();
|
|
217
|
+
logger.info("Synchronizing database schema...");
|
|
240
218
|
const sqlQueryTableInformations = `SELECT table_schema, table_name FROM information_schema.tables`;
|
|
241
219
|
const tablesInDb: TableInformation[] = await server.queryDatabaseObject(sqlQueryTableInformations);
|
|
242
220
|
const { queryBuilder } = server;
|
|
243
221
|
|
|
244
222
|
for (const model of applicationConfig.models) {
|
|
245
|
-
|
|
223
|
+
logger.debug(`Checking data table for '${model.namespace}.${model.singularCode}'...`);
|
|
246
224
|
|
|
247
225
|
const expectedTableSchema = model.schema || server.databaseConfig.dbDefaultSchema;
|
|
248
226
|
const expectedTableName = model.tableName;
|
|
249
|
-
const tableInDb =
|
|
227
|
+
const tableInDb = find(tablesInDb, { table_schema: expectedTableSchema, table_name: expectedTableName});
|
|
250
228
|
if (!tableInDb) {
|
|
251
229
|
await server.queryDatabaseObject(`CREATE TABLE IF NOT EXISTS ${queryBuilder.quoteTable(model)} ()`, []);
|
|
252
230
|
}
|
|
@@ -257,7 +235,7 @@ async function syncDatabaseSchema(
|
|
|
257
235
|
const columnsInDb: ColumnInformation[] = await server.queryDatabaseObject(sqlQueryColumnInformations, []);
|
|
258
236
|
|
|
259
237
|
for (const model of applicationConfig.models) {
|
|
260
|
-
|
|
238
|
+
logger.debug(`Checking data columns for '${model.namespace}.${model.singularCode}'...`);
|
|
261
239
|
|
|
262
240
|
for (const property of model.properties) {
|
|
263
241
|
let columnDDL;
|
|
@@ -265,10 +243,10 @@ async function syncDatabaseSchema(
|
|
|
265
243
|
if (property.relation === "one") {
|
|
266
244
|
const targetModel = applicationConfig.models.find(item => item.singularCode === property.targetSingularCode);
|
|
267
245
|
if (!targetModel) {
|
|
268
|
-
|
|
246
|
+
logger.warn(`Cannot find target model with singular code "${property.targetSingularCode}".`)
|
|
269
247
|
}
|
|
270
248
|
|
|
271
|
-
const columnInDb: ColumnInformation | undefined =
|
|
249
|
+
const columnInDb: ColumnInformation | undefined = find(columnsInDb, {
|
|
272
250
|
table_schema: model.schema || "public",
|
|
273
251
|
table_name: model.tableName,
|
|
274
252
|
column_name: property.targetIdColumnName!,
|
|
@@ -286,7 +264,7 @@ async function syncDatabaseSchema(
|
|
|
286
264
|
}
|
|
287
265
|
} else if (property.relation === "many") {
|
|
288
266
|
if (property.linkTableName) {
|
|
289
|
-
const tableInDb =
|
|
267
|
+
const tableInDb = find(tablesInDb, { table_schema: property.linkSchema || server.databaseConfig.dbDefaultSchema, table_name: property.linkTableName});
|
|
290
268
|
if (!tableInDb) {
|
|
291
269
|
columnDDL = generateLinkTableDDL(queryBuilder, {
|
|
292
270
|
linkSchema: property.linkSchema,
|
|
@@ -298,11 +276,11 @@ async function syncDatabaseSchema(
|
|
|
298
276
|
} else {
|
|
299
277
|
const targetModel = applicationConfig.models.find(item => item.singularCode === property.targetSingularCode);
|
|
300
278
|
if (!targetModel) {
|
|
301
|
-
|
|
279
|
+
logger.warn(`Cannot find target model with singular code "${property.targetSingularCode}".`)
|
|
302
280
|
continue;
|
|
303
281
|
}
|
|
304
282
|
|
|
305
|
-
const columnInDb: ColumnInformation | undefined =
|
|
283
|
+
const columnInDb: ColumnInformation | undefined = find(columnsInDb, {
|
|
306
284
|
table_schema: targetModel.schema || "public",
|
|
307
285
|
table_name: targetModel.tableName,
|
|
308
286
|
column_name: property.selfIdColumnName!,
|
|
@@ -328,7 +306,7 @@ async function syncDatabaseSchema(
|
|
|
328
306
|
}
|
|
329
307
|
} else {
|
|
330
308
|
const columnName = property.columnName || property.code;
|
|
331
|
-
const columnInDb: ColumnInformation | undefined =
|
|
309
|
+
const columnInDb: ColumnInformation | undefined = find(columnsInDb, {
|
|
332
310
|
table_schema: model.schema || "public",
|
|
333
311
|
table_name: model.tableName,
|
|
334
312
|
column_name: columnName,
|
|
@@ -398,7 +376,6 @@ function generateCreateColumnDDL(queryBuilder: IQueryBuilder, options: {
|
|
|
398
376
|
} else {
|
|
399
377
|
const columnType = pgPropertyTypeColumnMap[options.type];
|
|
400
378
|
if (!columnType) {
|
|
401
|
-
console.log('options', options);
|
|
402
379
|
throw new Error(`Property type "${options.type}" is not supported.`);
|
|
403
380
|
}
|
|
404
381
|
columnDDL += ` ${columnType}`;
|
|
@@ -30,12 +30,6 @@ class RouteManager implements RapidPlugin {
|
|
|
30
30
|
return [];
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
async initPlugin(server: IRpdServer): Promise<any> {
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async registerMiddlewares(server: IRpdServer): Promise<any> {
|
|
37
|
-
}
|
|
38
|
-
|
|
39
33
|
async registerActionHandlers(server: IRpdServer): Promise<any> {
|
|
40
34
|
server.registerActionHandler(this, httpProxy);
|
|
41
35
|
}
|
|
@@ -47,23 +41,10 @@ class RouteManager implements RapidPlugin {
|
|
|
47
41
|
// server.registerEventHandler("entity.delete", handleEntityEvent.bind(null, server))
|
|
48
42
|
}
|
|
49
43
|
|
|
50
|
-
async registerMessageHandlers(server: IRpdServer): Promise<any> {
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async registerTaskProcessors(server: IRpdServer): Promise<any> {
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async onLoadingApplication(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async configureModels(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async configureModelProperties(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
63
|
-
}
|
|
64
|
-
|
|
65
44
|
async configureRoutes(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
45
|
+
const logger = server.getLogger();
|
|
66
46
|
try {
|
|
47
|
+
logger.info("Loading meta of routes...");
|
|
67
48
|
const entityManager = server.getEntityManager("route");
|
|
68
49
|
const routes = await entityManager.findEntities({
|
|
69
50
|
orderBy: [
|
|
@@ -71,17 +52,10 @@ class RouteManager implements RapidPlugin {
|
|
|
71
52
|
],
|
|
72
53
|
});
|
|
73
54
|
applicationConfig.routes.push(...routes);
|
|
74
|
-
} catch (
|
|
75
|
-
|
|
55
|
+
} catch (error) {
|
|
56
|
+
logger.crit("Failed to load meta of routes.", { error });
|
|
76
57
|
}
|
|
77
58
|
}
|
|
78
|
-
|
|
79
|
-
async onApplicationLoaded(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
80
|
-
console.log("[routeManager.onApplicationLoaded] onApplicationLoaded");
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async onApplicationReady(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
84
|
-
}
|
|
85
59
|
}
|
|
86
60
|
|
|
87
61
|
export default RouteManager;
|
|
@@ -10,7 +10,8 @@ export async function handler(
|
|
|
10
10
|
ctx: ActionHandlerContext,
|
|
11
11
|
options: RunProxyHandlerOptions,
|
|
12
12
|
) {
|
|
13
|
-
|
|
13
|
+
const { logger } = ctx;
|
|
14
|
+
logger.debug(`Running ${code} handler...`);
|
|
14
15
|
|
|
15
16
|
await doProxy(ctx.routerContext, options);
|
|
16
17
|
}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Webhooks plugin
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import * as _ from "lodash";
|
|
6
5
|
import {
|
|
7
6
|
RpdApplicationConfig,
|
|
8
7
|
RpdEntityCreateEventPayload,
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
import { RpdServerPluginExtendingAbilities, RpdServerPluginConfigurableTargetOptions, RpdConfigurationItemOptions, IRpdServer, RapidPlugin } from "~/core/server";
|
|
14
13
|
import { fetchWithTimeout } from "~/utilities/httpUtility";
|
|
15
14
|
import pluginConfig from "./pluginConfig";
|
|
15
|
+
import { indexOf } from "lodash";
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
export interface Webhook {
|
|
@@ -30,16 +30,23 @@ export interface Webhook {
|
|
|
30
30
|
function listWebhooks(
|
|
31
31
|
server: IRpdServer,
|
|
32
32
|
) {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
const logger = server.getLogger();
|
|
34
|
+
logger.info("Loading meta of webhooks...");
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const entityManager = server.getEntityManager("webhook");
|
|
38
|
+
return entityManager.findEntities({
|
|
39
|
+
filters: [
|
|
40
|
+
{
|
|
41
|
+
field: "enabled",
|
|
42
|
+
operator: "eq",
|
|
43
|
+
value: true,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
});
|
|
47
|
+
} catch (error) {
|
|
48
|
+
logger.crit("Failed to load meta of webhooks.", { error });
|
|
49
|
+
}
|
|
43
50
|
}
|
|
44
51
|
|
|
45
52
|
|
|
@@ -70,15 +77,6 @@ class WebhooksPlugin implements RapidPlugin {
|
|
|
70
77
|
return [];
|
|
71
78
|
}
|
|
72
79
|
|
|
73
|
-
async initPlugin(server: IRpdServer): Promise<any> {
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async registerMiddlewares(server: IRpdServer): Promise<any> {
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async registerActionHandlers(server: IRpdServer): Promise<any> {
|
|
80
|
-
}
|
|
81
|
-
|
|
82
80
|
async registerEventHandlers(server: IRpdServer): Promise<any> {
|
|
83
81
|
const events: (keyof RpdServerEventTypes)[] = [
|
|
84
82
|
"entity.create",
|
|
@@ -93,15 +91,6 @@ class WebhooksPlugin implements RapidPlugin {
|
|
|
93
91
|
}
|
|
94
92
|
}
|
|
95
93
|
|
|
96
|
-
async registerMessageHandlers(server: IRpdServer): Promise<any> {
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async registerTaskProcessors(server: IRpdServer): Promise<any> {
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async onLoadingApplication(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
103
|
-
}
|
|
104
|
-
|
|
105
94
|
async configureModels(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
106
95
|
server.appendApplicationConfig({
|
|
107
96
|
models: pluginConfig.models,
|
|
@@ -115,7 +104,6 @@ class WebhooksPlugin implements RapidPlugin {
|
|
|
115
104
|
}
|
|
116
105
|
|
|
117
106
|
async onApplicationLoaded(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
118
|
-
console.log("[webhooks.onApplicationLoaded] loading webhooks");
|
|
119
107
|
this.#webhooks = await listWebhooks(server);
|
|
120
108
|
}
|
|
121
109
|
|
|
@@ -145,8 +133,10 @@ class WebhooksPlugin implements RapidPlugin {
|
|
|
145
133
|
return;
|
|
146
134
|
}
|
|
147
135
|
|
|
136
|
+
const logger = server.getLogger();
|
|
137
|
+
|
|
148
138
|
for (const webhook of this.#webhooks) {
|
|
149
|
-
if (
|
|
139
|
+
if (indexOf(webhook.events, event) === -1) {
|
|
150
140
|
continue;
|
|
151
141
|
}
|
|
152
142
|
|
|
@@ -157,8 +147,9 @@ class WebhooksPlugin implements RapidPlugin {
|
|
|
157
147
|
continue;
|
|
158
148
|
}
|
|
159
149
|
|
|
160
|
-
|
|
150
|
+
logger.debug(`Triggering webhook. ${webhook.url}`);
|
|
161
151
|
// TODO: It's better to trigger webhook through message queue.
|
|
152
|
+
const requestBody = { event, payload };
|
|
162
153
|
try {
|
|
163
154
|
await fetchWithTimeout(webhook.url, {
|
|
164
155
|
method: "post",
|
|
@@ -166,11 +157,10 @@ class WebhooksPlugin implements RapidPlugin {
|
|
|
166
157
|
"Content-Type": "application/json",
|
|
167
158
|
"x-webhook-secret": webhook.secret || "",
|
|
168
159
|
},
|
|
169
|
-
body: JSON.stringify(
|
|
160
|
+
body: JSON.stringify(requestBody),
|
|
170
161
|
});
|
|
171
|
-
} catch (
|
|
172
|
-
|
|
173
|
-
console.warn(err);
|
|
162
|
+
} catch (error) {
|
|
163
|
+
logger.error("Failed to call webhook.", { error, webhookUrl: webhook.url, requestBody });
|
|
174
164
|
}
|
|
175
165
|
}
|
|
176
166
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { find } from "lodash";
|
|
2
2
|
import {
|
|
3
3
|
CountEntityOptions,
|
|
4
4
|
DeleteEntityOptions,
|
|
@@ -148,7 +148,7 @@ export default class QueryBuilder {
|
|
|
148
148
|
|
|
149
149
|
let property: RpdDataModelProperty | null = null;
|
|
150
150
|
if (model) {
|
|
151
|
-
property =
|
|
151
|
+
property = find(
|
|
152
152
|
model.properties,
|
|
153
153
|
(e: RpdDataModelProperty) => e.code === propertyName,
|
|
154
154
|
);
|
|
@@ -192,7 +192,7 @@ export default class QueryBuilder {
|
|
|
192
192
|
|
|
193
193
|
let property: RpdDataModelProperty | null = null;
|
|
194
194
|
if (model) {
|
|
195
|
-
property =
|
|
195
|
+
property = find(
|
|
196
196
|
model.properties,
|
|
197
197
|
(e: RpdDataModelProperty) => (e.columnName || e.code) === propertyName,
|
|
198
198
|
);
|