@ruiapp/rapid-core 0.1.59 → 0.1.61
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/index.js +86 -23
- package/dist/plugins/serverOperation/ServerOperationPluginTypes.d.ts +2 -0
- package/dist/utilities/timeUtility.d.ts +2 -0
- package/package.json +1 -1
- package/src/dataAccess/entityManager.ts +31 -5
- package/src/plugins/dataManage/actionHandlers/createCollectionEntity.ts +0 -5
- package/src/plugins/entityAccessControl/EntityAccessControlPlugin.ts +56 -16
- package/src/plugins/serverOperation/ServerOperationPlugin.ts +8 -1
- package/src/plugins/serverOperation/ServerOperationPluginTypes.ts +2 -0
- package/src/utilities/timeUtility.ts +9 -0
package/dist/index.js
CHANGED
|
@@ -6,9 +6,9 @@ var lodash = require('lodash');
|
|
|
6
6
|
var events = require('events');
|
|
7
7
|
var Router = require('koa-tree-router');
|
|
8
8
|
var qs = require('qs');
|
|
9
|
+
var dayjs = require('dayjs');
|
|
9
10
|
var jsonwebtoken = require('jsonwebtoken');
|
|
10
11
|
var crypto = require('crypto');
|
|
11
|
-
var dayjs = require('dayjs');
|
|
12
12
|
var bcrypt = require('bcrypt');
|
|
13
13
|
var path = require('path');
|
|
14
14
|
var fs = require('fs');
|
|
@@ -38,8 +38,8 @@ function _interopNamespace(e) {
|
|
|
38
38
|
|
|
39
39
|
var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router);
|
|
40
40
|
var qs__default = /*#__PURE__*/_interopDefaultLegacy(qs);
|
|
41
|
-
var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
|
|
42
41
|
var dayjs__default = /*#__PURE__*/_interopDefaultLegacy(dayjs);
|
|
42
|
+
var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
|
|
43
43
|
var bcrypt__default = /*#__PURE__*/_interopDefaultLegacy(bcrypt);
|
|
44
44
|
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
45
45
|
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
@@ -1965,6 +1965,10 @@ function getEntityPartChanges(before, after) {
|
|
|
1965
1965
|
return changed;
|
|
1966
1966
|
}
|
|
1967
1967
|
|
|
1968
|
+
function getNowStringWithTimezone() {
|
|
1969
|
+
return dayjs__default["default"]().format("YYYY-MM-DD HH:mm:ss.SSSZ");
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1968
1972
|
function convertEntityOrderByToRowOrderBy(server, model, baseModel, orderByList) {
|
|
1969
1973
|
if (!orderByList) {
|
|
1970
1974
|
return null;
|
|
@@ -2413,6 +2417,17 @@ async function createEntity(server, dataAccessor, options, plugin) {
|
|
|
2413
2417
|
throw newEntityOperationError("Create base entity directly is not allowed.");
|
|
2414
2418
|
}
|
|
2415
2419
|
const { entity, routeContext } = options;
|
|
2420
|
+
const userId = options.routeContext.state?.userId;
|
|
2421
|
+
if (userId) {
|
|
2422
|
+
const createdByProperty = getEntityPropertyByCode(server, model, "createdBy");
|
|
2423
|
+
if (createdByProperty) {
|
|
2424
|
+
entity.createdBy = userId;
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
const createdAtProperty = getEntityPropertyByCode(server, model, "createdAt");
|
|
2428
|
+
if (createdAtProperty) {
|
|
2429
|
+
entity.createdAt = getNowStringWithTimezone();
|
|
2430
|
+
}
|
|
2416
2431
|
await server.beforeCreateEntity(model, options);
|
|
2417
2432
|
await server.emitEvent({
|
|
2418
2433
|
eventName: "entity.beforeCreate",
|
|
@@ -2580,7 +2595,7 @@ async function createEntity(server, dataAccessor, options, plugin) {
|
|
|
2580
2595
|
}
|
|
2581
2596
|
async function updateEntityById(server, dataAccessor, options, plugin) {
|
|
2582
2597
|
const model = dataAccessor.getModel();
|
|
2583
|
-
const { id,
|
|
2598
|
+
const { id, routeContext } = options;
|
|
2584
2599
|
if (!id) {
|
|
2585
2600
|
throw new Error("Id is required when updating an entity.");
|
|
2586
2601
|
}
|
|
@@ -2591,11 +2606,23 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
|
|
|
2591
2606
|
if (!entity) {
|
|
2592
2607
|
throw new Error(`${model.namespace}.${model.singularCode} with id "${id}" was not found.`);
|
|
2593
2608
|
}
|
|
2609
|
+
let { entityToSave } = options;
|
|
2594
2610
|
let changes = getEntityPartChanges(entity, entityToSave);
|
|
2595
2611
|
if (!changes && !options.operation) {
|
|
2596
2612
|
return entity;
|
|
2597
2613
|
}
|
|
2598
|
-
|
|
2614
|
+
entityToSave = changes || {};
|
|
2615
|
+
const userId = options.routeContext.state?.userId;
|
|
2616
|
+
if (userId) {
|
|
2617
|
+
const updatedByProperty = getEntityPropertyByCode(server, model, "updatedBy");
|
|
2618
|
+
if (updatedByProperty) {
|
|
2619
|
+
entityToSave.updatedBy = userId;
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
const updatedAtProperty = getEntityPropertyByCode(server, model, "updatedAt");
|
|
2623
|
+
if (updatedAtProperty) {
|
|
2624
|
+
entityToSave.updatedAt = getNowStringWithTimezone();
|
|
2625
|
+
}
|
|
2599
2626
|
await server.beforeUpdateEntity(model, options, entity);
|
|
2600
2627
|
await server.emitEvent({
|
|
2601
2628
|
eventName: "entity.beforeUpdate",
|
|
@@ -2603,14 +2630,14 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
|
|
|
2603
2630
|
namespace: model.namespace,
|
|
2604
2631
|
modelSingularCode: model.singularCode,
|
|
2605
2632
|
before: entity,
|
|
2606
|
-
changes:
|
|
2633
|
+
changes: entityToSave,
|
|
2607
2634
|
operation: options.operation,
|
|
2608
2635
|
stateProperties: options.stateProperties,
|
|
2609
2636
|
},
|
|
2610
2637
|
sender: plugin,
|
|
2611
2638
|
routeContext: options.routeContext,
|
|
2612
2639
|
});
|
|
2613
|
-
changes = getEntityPartChanges(entity,
|
|
2640
|
+
changes = getEntityPartChanges(entity, entityToSave);
|
|
2614
2641
|
const oneRelationPropertiesToUpdate = [];
|
|
2615
2642
|
const manyRelationPropertiesToUpdate = [];
|
|
2616
2643
|
lodash.keys(changes).forEach((propertyCode) => {
|
|
@@ -3934,10 +3961,6 @@ async function handler$j(plugin, ctx, options) {
|
|
|
3934
3961
|
const { defaultInput, fixedInput } = options;
|
|
3935
3962
|
const mergedInput = mergeInput(defaultInput, input, fixedInput);
|
|
3936
3963
|
logger.debug(`Running ${code$j} handler...`, { defaultInput, fixedInput, mergedInput });
|
|
3937
|
-
const userId = ctx.routerContext.state?.userId;
|
|
3938
|
-
if (userId) {
|
|
3939
|
-
input.createdBy = userId;
|
|
3940
|
-
}
|
|
3941
3964
|
const entityManager = server.getEntityManager(options.singularCode);
|
|
3942
3965
|
const output = await entityManager.createEntity({
|
|
3943
3966
|
entity: input,
|
|
@@ -5530,6 +5553,7 @@ class ServerOperationPlugin {
|
|
|
5530
5553
|
code: "runServerOperation",
|
|
5531
5554
|
config: {
|
|
5532
5555
|
operation: operation.handler,
|
|
5556
|
+
permissionCheck: operation.permissionCheck,
|
|
5533
5557
|
},
|
|
5534
5558
|
},
|
|
5535
5559
|
],
|
|
@@ -5980,14 +6004,6 @@ class EntityAccessControlPlugin {
|
|
|
5980
6004
|
async configureRoutes(server, applicationConfig) {
|
|
5981
6005
|
const logger = server.getLogger();
|
|
5982
6006
|
logger.info("Configuring entity access checking policies...");
|
|
5983
|
-
const model = lodash.find(applicationConfig.models, (item) => item.singularCode === "model");
|
|
5984
|
-
if (!model) {
|
|
5985
|
-
return;
|
|
5986
|
-
}
|
|
5987
|
-
const { permissionPolicies } = model;
|
|
5988
|
-
if (!permissionPolicies) {
|
|
5989
|
-
return;
|
|
5990
|
-
}
|
|
5991
6007
|
const routes = applicationConfig.routes;
|
|
5992
6008
|
for (const route of routes) {
|
|
5993
6009
|
const { actions } = route;
|
|
@@ -5995,9 +6011,56 @@ class EntityAccessControlPlugin {
|
|
|
5995
6011
|
continue;
|
|
5996
6012
|
}
|
|
5997
6013
|
for (const action of route.actions) {
|
|
5998
|
-
if (action.code === "findCollectionEntityById") {
|
|
6014
|
+
if (action.code === "findCollectionEntityById" || action.code === "findCollectionEntities" || action.code === "countCollectionEntities") {
|
|
6015
|
+
const model = lodash.find(applicationConfig.models, (item) => item.singularCode === action.config.singularCode);
|
|
6016
|
+
if (!model) {
|
|
6017
|
+
continue;
|
|
6018
|
+
}
|
|
6019
|
+
const { permissionPolicies } = model;
|
|
6020
|
+
if (!permissionPolicies) {
|
|
6021
|
+
continue;
|
|
6022
|
+
}
|
|
5999
6023
|
if (permissionPolicies.find) {
|
|
6000
|
-
lodash.set(action, "config.
|
|
6024
|
+
lodash.set(action, "config.permissionCheck", permissionPolicies.find);
|
|
6025
|
+
}
|
|
6026
|
+
}
|
|
6027
|
+
else if (action.code === "createCollectionEntity" || action.code === "createCollectionEntitiesBatch") {
|
|
6028
|
+
const model = lodash.find(applicationConfig.models, (item) => item.singularCode === action.config.singularCode);
|
|
6029
|
+
if (!model) {
|
|
6030
|
+
continue;
|
|
6031
|
+
}
|
|
6032
|
+
const { permissionPolicies } = model;
|
|
6033
|
+
if (!permissionPolicies) {
|
|
6034
|
+
continue;
|
|
6035
|
+
}
|
|
6036
|
+
if (permissionPolicies.create) {
|
|
6037
|
+
lodash.set(action, "config.permissionCheck", permissionPolicies.create);
|
|
6038
|
+
}
|
|
6039
|
+
}
|
|
6040
|
+
else if (action.code === "updateCollectionEntityById" || action.code === "addEntityRelations" || action.code === "removeEntityRelations") {
|
|
6041
|
+
const model = lodash.find(applicationConfig.models, (item) => item.singularCode === action.config.singularCode);
|
|
6042
|
+
if (!model) {
|
|
6043
|
+
continue;
|
|
6044
|
+
}
|
|
6045
|
+
const { permissionPolicies } = model;
|
|
6046
|
+
if (!permissionPolicies) {
|
|
6047
|
+
continue;
|
|
6048
|
+
}
|
|
6049
|
+
if (permissionPolicies.update) {
|
|
6050
|
+
lodash.set(action, "config.permissionCheck", permissionPolicies.update);
|
|
6051
|
+
}
|
|
6052
|
+
}
|
|
6053
|
+
else if (action.code === "deleteCollectionEntityById") {
|
|
6054
|
+
const model = lodash.find(applicationConfig.models, (item) => item.singularCode === action.config.singularCode);
|
|
6055
|
+
if (!model) {
|
|
6056
|
+
continue;
|
|
6057
|
+
}
|
|
6058
|
+
const { permissionPolicies } = model;
|
|
6059
|
+
if (!permissionPolicies) {
|
|
6060
|
+
continue;
|
|
6061
|
+
}
|
|
6062
|
+
if (permissionPolicies.delete) {
|
|
6063
|
+
lodash.set(action, "config.permissionCheck", permissionPolicies.delete);
|
|
6001
6064
|
}
|
|
6002
6065
|
}
|
|
6003
6066
|
}
|
|
@@ -6019,9 +6082,9 @@ class EntityAccessControlPlugin {
|
|
|
6019
6082
|
const { routerContext } = handlerContext;
|
|
6020
6083
|
const { routeConfig } = routerContext;
|
|
6021
6084
|
for (const actionConfig of routeConfig.actions) {
|
|
6022
|
-
const
|
|
6023
|
-
if (
|
|
6024
|
-
if (!isAccessAllowed(
|
|
6085
|
+
const permissionCheck = actionConfig.config?.permissionCheck;
|
|
6086
|
+
if (permissionCheck) {
|
|
6087
|
+
if (!isAccessAllowed(permissionCheck, routerContext.state.allowedActions || [])) {
|
|
6025
6088
|
throw new Error(`Your action of '${actionConfig.code}' is not permitted.`);
|
|
6026
6089
|
}
|
|
6027
6090
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ActionHandlerContext } from "../../core/actionHandler";
|
|
2
2
|
import { RpdHttpMethod } from "../../types";
|
|
3
|
+
import { PermissionCheckPolicy } from "../../utilities/accessControlUtility";
|
|
3
4
|
export interface ServerOperation {
|
|
4
5
|
code: string;
|
|
5
6
|
description?: string;
|
|
6
7
|
method: RpdHttpMethod;
|
|
8
|
+
permissionCheck?: PermissionCheckPolicy;
|
|
7
9
|
handler: (ctx: ActionHandlerContext) => Promise<void>;
|
|
8
10
|
}
|
|
9
11
|
export interface ServerOperationPluginInitOptions {
|
package/package.json
CHANGED
|
@@ -26,7 +26,7 @@ import { filter, find, first, forEach, isArray, isObject, keys, map, reject, uni
|
|
|
26
26
|
import { getEntityPropertiesIncludingBase, getEntityProperty, getEntityPropertyByCode } from "./metaHelper";
|
|
27
27
|
import { ColumnQueryOptions, CountRowOptions, FindRowOptions, FindRowOrderByOptions, RowFilterOptions } from "./dataAccessTypes";
|
|
28
28
|
import { newEntityOperationError } from "~/utilities/errorUtility";
|
|
29
|
-
import {
|
|
29
|
+
import { getNowStringWithTimezone } from "~/utilities/timeUtility";
|
|
30
30
|
|
|
31
31
|
function convertEntityOrderByToRowOrderBy(server: IRpdServer, model: RpdDataModel, baseModel?: RpdDataModel, orderByList?: FindEntityOrderByOptions[]) {
|
|
32
32
|
if (!orderByList) {
|
|
@@ -514,6 +514,18 @@ async function createEntity(server: IRpdServer, dataAccessor: IRpdDataAccessor,
|
|
|
514
514
|
|
|
515
515
|
const { entity, routeContext } = options;
|
|
516
516
|
|
|
517
|
+
const userId = options.routeContext.state?.userId;
|
|
518
|
+
if (userId) {
|
|
519
|
+
const createdByProperty = getEntityPropertyByCode(server, model, "createdBy");
|
|
520
|
+
if (createdByProperty) {
|
|
521
|
+
entity.createdBy = userId;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
const createdAtProperty = getEntityPropertyByCode(server, model, "createdAt");
|
|
525
|
+
if (createdAtProperty) {
|
|
526
|
+
entity.createdAt = getNowStringWithTimezone();
|
|
527
|
+
}
|
|
528
|
+
|
|
517
529
|
await server.beforeCreateEntity(model, options);
|
|
518
530
|
|
|
519
531
|
await server.emitEvent({
|
|
@@ -693,7 +705,7 @@ async function createEntity(server: IRpdServer, dataAccessor: IRpdDataAccessor,
|
|
|
693
705
|
|
|
694
706
|
async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccessor, options: UpdateEntityByIdOptions, plugin?: RapidPlugin) {
|
|
695
707
|
const model = dataAccessor.getModel();
|
|
696
|
-
const { id,
|
|
708
|
+
const { id, routeContext } = options;
|
|
697
709
|
if (!id) {
|
|
698
710
|
throw new Error("Id is required when updating an entity.");
|
|
699
711
|
}
|
|
@@ -706,12 +718,26 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
|
|
|
706
718
|
throw new Error(`${model.namespace}.${model.singularCode} with id "${id}" was not found.`);
|
|
707
719
|
}
|
|
708
720
|
|
|
721
|
+
let { entityToSave } = options;
|
|
709
722
|
let changes = getEntityPartChanges(entity, entityToSave);
|
|
710
723
|
if (!changes && !options.operation) {
|
|
711
724
|
return entity;
|
|
712
725
|
}
|
|
713
726
|
|
|
714
|
-
|
|
727
|
+
entityToSave = changes || {};
|
|
728
|
+
|
|
729
|
+
const userId = options.routeContext.state?.userId;
|
|
730
|
+
if (userId) {
|
|
731
|
+
const updatedByProperty = getEntityPropertyByCode(server, model, "updatedBy");
|
|
732
|
+
if (updatedByProperty) {
|
|
733
|
+
entityToSave.updatedBy = userId;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
const updatedAtProperty = getEntityPropertyByCode(server, model, "updatedAt");
|
|
737
|
+
if (updatedAtProperty) {
|
|
738
|
+
entityToSave.updatedAt = getNowStringWithTimezone();
|
|
739
|
+
}
|
|
740
|
+
|
|
715
741
|
await server.beforeUpdateEntity(model, options, entity);
|
|
716
742
|
|
|
717
743
|
await server.emitEvent({
|
|
@@ -720,7 +746,7 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
|
|
|
720
746
|
namespace: model.namespace,
|
|
721
747
|
modelSingularCode: model.singularCode,
|
|
722
748
|
before: entity,
|
|
723
|
-
changes:
|
|
749
|
+
changes: entityToSave,
|
|
724
750
|
operation: options.operation,
|
|
725
751
|
stateProperties: options.stateProperties,
|
|
726
752
|
},
|
|
@@ -728,7 +754,7 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
|
|
|
728
754
|
routeContext: options.routeContext,
|
|
729
755
|
});
|
|
730
756
|
|
|
731
|
-
changes = getEntityPartChanges(entity,
|
|
757
|
+
changes = getEntityPartChanges(entity, entityToSave);
|
|
732
758
|
|
|
733
759
|
const oneRelationPropertiesToUpdate: RpdDataModelProperty[] = [];
|
|
734
760
|
const manyRelationPropertiesToUpdate: RpdDataModelProperty[] = [];
|
|
@@ -12,11 +12,6 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
|
|
|
12
12
|
const mergedInput = mergeInput(defaultInput, input, fixedInput);
|
|
13
13
|
logger.debug(`Running ${code} handler...`, { defaultInput, fixedInput, mergedInput });
|
|
14
14
|
|
|
15
|
-
const userId = ctx.routerContext.state?.userId;
|
|
16
|
-
if (userId) {
|
|
17
|
-
input.createdBy = userId;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
15
|
const entityManager = server.getEntityManager(options.singularCode);
|
|
21
16
|
const output = await entityManager.createEntity(
|
|
22
17
|
{
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { RpdApplicationConfig, RpdDataModelProperty } from "~/types";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
IRpdServer,
|
|
5
|
+
RapidPlugin,
|
|
6
|
+
RpdConfigurationItemOptions,
|
|
7
|
+
RpdServerPluginConfigurableTargetOptions,
|
|
8
|
+
RpdServerPluginExtendingAbilities,
|
|
9
|
+
} from "~/core/server";
|
|
4
10
|
import { find, set } from "lodash";
|
|
5
11
|
import { ActionHandlerContext } from "~/core/actionHandler";
|
|
6
12
|
import { isAccessAllowed } from "~/utilities/accessControlUtility";
|
|
@@ -45,16 +51,6 @@ class EntityAccessControlPlugin implements RapidPlugin {
|
|
|
45
51
|
const logger = server.getLogger();
|
|
46
52
|
logger.info("Configuring entity access checking policies...");
|
|
47
53
|
|
|
48
|
-
const model = find(applicationConfig.models, (item) => item.singularCode === "model");
|
|
49
|
-
if (!model) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const { permissionPolicies } = model;
|
|
54
|
-
if (!permissionPolicies) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
54
|
const routes = applicationConfig.routes;
|
|
59
55
|
for (const route of routes) {
|
|
60
56
|
const { actions } = route;
|
|
@@ -63,9 +59,53 @@ class EntityAccessControlPlugin implements RapidPlugin {
|
|
|
63
59
|
}
|
|
64
60
|
|
|
65
61
|
for (const action of route.actions) {
|
|
66
|
-
if (action.code === "findCollectionEntityById") {
|
|
62
|
+
if (action.code === "findCollectionEntityById" || action.code === "findCollectionEntities" || action.code === "countCollectionEntities") {
|
|
63
|
+
const model = find(applicationConfig.models, (item) => item.singularCode === action.config.singularCode);
|
|
64
|
+
if (!model) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const { permissionPolicies } = model;
|
|
68
|
+
if (!permissionPolicies) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
67
71
|
if (permissionPolicies.find) {
|
|
68
|
-
set(action, "config.
|
|
72
|
+
set(action, "config.permissionCheck", permissionPolicies.find);
|
|
73
|
+
}
|
|
74
|
+
} else if (action.code === "createCollectionEntity" || action.code === "createCollectionEntitiesBatch") {
|
|
75
|
+
const model = find(applicationConfig.models, (item) => item.singularCode === action.config.singularCode);
|
|
76
|
+
if (!model) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const { permissionPolicies } = model;
|
|
80
|
+
if (!permissionPolicies) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (permissionPolicies.create) {
|
|
84
|
+
set(action, "config.permissionCheck", permissionPolicies.create);
|
|
85
|
+
}
|
|
86
|
+
} else if (action.code === "updateCollectionEntityById" || action.code === "addEntityRelations" || action.code === "removeEntityRelations") {
|
|
87
|
+
const model = find(applicationConfig.models, (item) => item.singularCode === action.config.singularCode);
|
|
88
|
+
if (!model) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const { permissionPolicies } = model;
|
|
92
|
+
if (!permissionPolicies) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (permissionPolicies.update) {
|
|
96
|
+
set(action, "config.permissionCheck", permissionPolicies.update);
|
|
97
|
+
}
|
|
98
|
+
} else if (action.code === "deleteCollectionEntityById") {
|
|
99
|
+
const model = find(applicationConfig.models, (item) => item.singularCode === action.config.singularCode);
|
|
100
|
+
if (!model) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const { permissionPolicies } = model;
|
|
104
|
+
if (!permissionPolicies) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (permissionPolicies.delete) {
|
|
108
|
+
set(action, "config.permissionCheck", permissionPolicies.delete);
|
|
69
109
|
}
|
|
70
110
|
}
|
|
71
111
|
}
|
|
@@ -93,9 +133,9 @@ class EntityAccessControlPlugin implements RapidPlugin {
|
|
|
93
133
|
const { routerContext } = handlerContext;
|
|
94
134
|
const { routeConfig } = routerContext;
|
|
95
135
|
for (const actionConfig of routeConfig.actions) {
|
|
96
|
-
const
|
|
97
|
-
if (
|
|
98
|
-
if (!isAccessAllowed(
|
|
136
|
+
const permissionCheck = actionConfig.config?.permissionCheck;
|
|
137
|
+
if (permissionCheck) {
|
|
138
|
+
if (!isAccessAllowed(permissionCheck, routerContext.state.allowedActions || [])) {
|
|
99
139
|
throw new Error(`Your action of '${actionConfig.code}' is not permitted.`);
|
|
100
140
|
}
|
|
101
141
|
}
|
|
@@ -2,7 +2,13 @@ import type { RpdApplicationConfig, RpdRoute } from "~/types";
|
|
|
2
2
|
|
|
3
3
|
import pluginActionHandlers from "./actionHandlers";
|
|
4
4
|
import { ServerOperation, ServerOperationPluginInitOptions } from "./ServerOperationPluginTypes";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
IRpdServer,
|
|
7
|
+
RapidPlugin,
|
|
8
|
+
RpdConfigurationItemOptions,
|
|
9
|
+
RpdServerPluginConfigurableTargetOptions,
|
|
10
|
+
RpdServerPluginExtendingAbilities,
|
|
11
|
+
} from "~/core/server";
|
|
6
12
|
|
|
7
13
|
class ServerOperationPlugin implements RapidPlugin {
|
|
8
14
|
#operations: ServerOperation[];
|
|
@@ -68,6 +74,7 @@ class ServerOperationPlugin implements RapidPlugin {
|
|
|
68
74
|
code: "runServerOperation",
|
|
69
75
|
config: {
|
|
70
76
|
operation: operation.handler,
|
|
77
|
+
permissionCheck: operation.permissionCheck,
|
|
71
78
|
},
|
|
72
79
|
},
|
|
73
80
|
],
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { ActionHandlerContext } from "~/core/actionHandler";
|
|
2
2
|
import { RpdHttpMethod } from "~/types";
|
|
3
|
+
import { PermissionCheckPolicy } from "~/utilities/accessControlUtility";
|
|
3
4
|
|
|
4
5
|
export interface ServerOperation {
|
|
5
6
|
code: string;
|
|
6
7
|
description?: string;
|
|
7
8
|
method: RpdHttpMethod;
|
|
9
|
+
permissionCheck?: PermissionCheckPolicy;
|
|
8
10
|
handler: (ctx: ActionHandlerContext) => Promise<void>;
|
|
9
11
|
}
|
|
10
12
|
|