@forestadmin/agent 1.4.15 → 1.5.1
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/routes/index.js +2 -2
- package/dist/routes/modification/action/action-authorization.d.ts +30 -0
- package/dist/routes/modification/action/action-authorization.js +183 -0
- package/dist/routes/modification/{action.d.ts → action/action.d.ts} +4 -3
- package/dist/routes/modification/action/action.js +146 -0
- package/dist/routes/modification/action/errors/approvalNotAllowedError.d.ts +5 -0
- package/dist/routes/modification/action/errors/approvalNotAllowedError.js +12 -0
- package/dist/routes/modification/action/errors/customActionRequiresApprovalError.d.ts +5 -0
- package/dist/routes/modification/action/errors/customActionRequiresApprovalError.js +12 -0
- package/dist/routes/modification/action/errors/customActionTriggerForbiddenError.d.ts +5 -0
- package/dist/routes/modification/action/errors/customActionTriggerForbiddenError.js +10 -0
- package/dist/routes/modification/action/errors/invalidActionConditionError.d.ts +5 -0
- package/dist/routes/modification/action/errors/invalidActionConditionError.js +10 -0
- package/dist/routes/system/error-handling.js +4 -10
- package/dist/services/authorization/authorization.d.ts +0 -13
- package/dist/services/authorization/authorization.js +1 -38
- package/package.json +4 -4
- package/dist/routes/modification/action.js +0 -129
package/dist/routes/index.js
CHANGED
|
@@ -14,7 +14,7 @@ const csv_related_1 = __importDefault(require("./access/csv-related"));
|
|
|
14
14
|
const get_1 = __importDefault(require("./access/get"));
|
|
15
15
|
const list_1 = __importDefault(require("./access/list"));
|
|
16
16
|
const list_related_1 = __importDefault(require("./access/list-related"));
|
|
17
|
-
const action_1 = __importDefault(require("./modification/action"));
|
|
17
|
+
const action_1 = __importDefault(require("./modification/action/action"));
|
|
18
18
|
const associate_related_1 = __importDefault(require("./modification/associate-related"));
|
|
19
19
|
const create_1 = __importDefault(require("./modification/create"));
|
|
20
20
|
const delete_1 = __importDefault(require("./modification/delete"));
|
|
@@ -107,4 +107,4 @@ function makeRoutes(dataSource, options, services) {
|
|
|
107
107
|
return routes.sort((a, b) => a.type - b.type);
|
|
108
108
|
}
|
|
109
109
|
exports.default = makeRoutes;
|
|
110
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
110
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcm91dGVzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUlBLHlGQUFvRTtBQUNwRSx5RkFBb0U7QUFDcEUsMkRBQW1DO0FBQ25DLDJEQUFtQztBQUNuQywyRUFBa0Q7QUFDbEQsdURBQStCO0FBQy9CLHVFQUE4QztBQUM5Qyx1REFBK0I7QUFDL0IseURBQWlDO0FBQ2pDLHlFQUFnRDtBQUVoRCwwRUFBdUQ7QUFDdkQseUZBQWdFO0FBQ2hFLG1FQUEyQztBQUMzQyxtRUFBMkM7QUFDM0MseUdBQStFO0FBQy9FLG1FQUEyQztBQUMzQywrRUFBc0Q7QUFDdEQscUZBQTREO0FBQzVELCtFQUF1RDtBQUN2RCwyRUFBa0Q7QUFDbEQsdUZBQThEO0FBQzlELDZFQUFvRDtBQUNwRCx1RUFBK0M7QUFDL0MsNkRBQXFDO0FBRXhCLFFBQUEsZ0JBQWdCLEdBQUc7SUFDOUIsd0JBQWM7SUFDZCx3QkFBYTtJQUNiLHFCQUFXO0lBQ1gsc0JBQVc7SUFDWCxnQkFBTTtJQUNOLDRCQUFpQjtDQUNsQixDQUFDO0FBQ1csUUFBQSxzQkFBc0IsR0FBRztJQUNwQyxlQUFLO0lBQ0wsZUFBSztJQUNMLGdCQUFNO0lBQ04sYUFBRztJQUNILGdCQUFNO0lBQ04sYUFBRztJQUNILGNBQUk7SUFDSixnQkFBTTtJQUNOLHNCQUFXO0NBQ1osQ0FBQztBQUNXLFFBQUEsbUJBQW1CLEdBQUc7SUFDakMsMkJBQWdCO0lBQ2hCLHVCQUFZO0lBQ1oscUJBQVU7SUFDVixtQ0FBdUI7SUFDdkIsc0JBQVc7Q0FDWixDQUFDO0FBQ1csUUFBQSw0QkFBNEIsR0FBRyxDQUFDLHlCQUFjLENBQUMsQ0FBQztBQUU3RCxTQUFTLGFBQWEsQ0FBQyxPQUFnQixFQUFFLFFBQWtCO0lBQ3pELE9BQU8sd0JBQWdCLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxLQUFLLENBQUMsUUFB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
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Caller, Collection, Filter } from '@forestadmin/datasource-toolkit';
|
|
2
|
+
import { ForestAdminClient } from '@forestadmin/forestadmin-client';
|
|
3
|
+
declare type CanPerformCustomActionParams = {
|
|
4
|
+
caller: Caller;
|
|
5
|
+
customActionName: string;
|
|
6
|
+
collection: Collection;
|
|
7
|
+
filterForCaller: Filter;
|
|
8
|
+
filterForAllCaller: Filter;
|
|
9
|
+
};
|
|
10
|
+
export default class ActionAuthorizationService {
|
|
11
|
+
private readonly forestAdminClient;
|
|
12
|
+
constructor(forestAdminClient: ForestAdminClient);
|
|
13
|
+
assertCanTriggerCustomAction({ customActionName, collection, filterForCaller, filterForAllCaller, caller, }: CanPerformCustomActionParams): Promise<void>;
|
|
14
|
+
assertCanApproveCustomAction({ customActionName, requesterId, collection, filterForCaller, filterForAllCaller, caller, }: CanPerformCustomActionParams & {
|
|
15
|
+
requesterId: number | string;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
assertCanRequestCustomActionParameters(caller: Caller, customActionName: string, collectionName: string): Promise<void>;
|
|
18
|
+
private canTriggerCustomAction;
|
|
19
|
+
private doesTriggerCustomActionRequiresApproval;
|
|
20
|
+
private canApproveCustomAction;
|
|
21
|
+
private getRoleIdsAllowedToApprove;
|
|
22
|
+
private static canPerformConditionalCustomAction;
|
|
23
|
+
private static aggregateCountConditionIntersection;
|
|
24
|
+
/**
|
|
25
|
+
* Given a map it groups keys based on their hash values
|
|
26
|
+
*/
|
|
27
|
+
private static transformToRolesIdsGroupByConditions;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=action-authorization.d.ts.map
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
7
|
+
const object_hash_1 = __importDefault(require("object-hash"));
|
|
8
|
+
const condition_tree_parser_1 = __importDefault(require("../../../utils/condition-tree-parser"));
|
|
9
|
+
const approvalNotAllowedError_1 = __importDefault(require("./errors/approvalNotAllowedError"));
|
|
10
|
+
const customActionRequiresApprovalError_1 = __importDefault(require("./errors/customActionRequiresApprovalError"));
|
|
11
|
+
const customActionTriggerForbiddenError_1 = __importDefault(require("./errors/customActionTriggerForbiddenError"));
|
|
12
|
+
const invalidActionConditionError_1 = __importDefault(require("./errors/invalidActionConditionError"));
|
|
13
|
+
class ActionAuthorizationService {
|
|
14
|
+
constructor(forestAdminClient) {
|
|
15
|
+
this.forestAdminClient = forestAdminClient;
|
|
16
|
+
}
|
|
17
|
+
async assertCanTriggerCustomAction({ customActionName, collection, filterForCaller, filterForAllCaller, caller, }) {
|
|
18
|
+
const canTrigger = await this.canTriggerCustomAction(caller, customActionName, collection, filterForCaller);
|
|
19
|
+
if (!canTrigger) {
|
|
20
|
+
throw new customActionTriggerForbiddenError_1.default();
|
|
21
|
+
}
|
|
22
|
+
const triggerRequiresApproval = await this.doesTriggerCustomActionRequiresApproval(caller, customActionName, collection, filterForCaller);
|
|
23
|
+
if (triggerRequiresApproval) {
|
|
24
|
+
const roleIdsAllowedToApprove = await this.getRoleIdsAllowedToApprove(caller, customActionName, collection, filterForAllCaller);
|
|
25
|
+
throw new customActionRequiresApprovalError_1.default(roleIdsAllowedToApprove);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async assertCanApproveCustomAction({ customActionName, requesterId, collection, filterForCaller, filterForAllCaller, caller, }) {
|
|
29
|
+
const canApprove = await this.canApproveCustomAction(caller, customActionName, collection, filterForCaller, requesterId);
|
|
30
|
+
if (!canApprove) {
|
|
31
|
+
const roleIdsAllowedToApprove = await this.getRoleIdsAllowedToApprove(caller, customActionName, collection, filterForAllCaller);
|
|
32
|
+
throw new approvalNotAllowedError_1.default(roleIdsAllowedToApprove);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async assertCanRequestCustomActionParameters(caller, customActionName, collectionName) {
|
|
36
|
+
const canRequest = await this.forestAdminClient.permissionService.canRequestCustomActionParameters({
|
|
37
|
+
userId: caller.id,
|
|
38
|
+
customActionName,
|
|
39
|
+
collectionName,
|
|
40
|
+
});
|
|
41
|
+
if (!canRequest) {
|
|
42
|
+
throw new datasource_toolkit_1.ForbiddenError();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async canTriggerCustomAction(caller, customActionName, collection, filterForCaller) {
|
|
46
|
+
const canTrigger = await this.forestAdminClient.permissionService.canTriggerCustomAction({
|
|
47
|
+
userId: caller.id,
|
|
48
|
+
customActionName,
|
|
49
|
+
collectionName: collection.name,
|
|
50
|
+
});
|
|
51
|
+
if (!canTrigger) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const conditionalTriggerRawCondition = await this.forestAdminClient.permissionService.getConditionalTriggerCondition({
|
|
55
|
+
userId: caller.id,
|
|
56
|
+
customActionName,
|
|
57
|
+
collectionName: collection.name,
|
|
58
|
+
});
|
|
59
|
+
return ActionAuthorizationService.canPerformConditionalCustomAction(caller, collection, filterForCaller, conditionalTriggerRawCondition);
|
|
60
|
+
}
|
|
61
|
+
async doesTriggerCustomActionRequiresApproval(caller, customActionName, collection, filterForCaller) {
|
|
62
|
+
const doesTriggerRequiresApproval = await this.forestAdminClient.permissionService.doesTriggerCustomActionRequiresApproval({
|
|
63
|
+
userId: caller.id,
|
|
64
|
+
customActionName,
|
|
65
|
+
collectionName: collection.name,
|
|
66
|
+
});
|
|
67
|
+
if (!doesTriggerRequiresApproval) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
const conditionalRequiresApprovalRawCondition = await this.forestAdminClient.permissionService.getConditionalRequiresApprovalCondition({
|
|
71
|
+
userId: caller.id,
|
|
72
|
+
customActionName,
|
|
73
|
+
collectionName: collection.name,
|
|
74
|
+
});
|
|
75
|
+
if (conditionalRequiresApprovalRawCondition) {
|
|
76
|
+
const matchingRecordsCount = await ActionAuthorizationService.aggregateCountConditionIntersection(caller, collection, filterForCaller, conditionalRequiresApprovalRawCondition);
|
|
77
|
+
// No records match the condition, trigger does not require approval
|
|
78
|
+
if (matchingRecordsCount === 0) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
async canApproveCustomAction(caller, customActionName, collection, filterForCaller, requesterId) {
|
|
85
|
+
const canApprove = await this.forestAdminClient.permissionService.canApproveCustomAction({
|
|
86
|
+
userId: caller.id,
|
|
87
|
+
requesterId,
|
|
88
|
+
customActionName,
|
|
89
|
+
collectionName: collection.name,
|
|
90
|
+
});
|
|
91
|
+
if (!canApprove) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
const conditionalApproveRawCondition = await this.forestAdminClient.permissionService.getConditionalApproveCondition({
|
|
95
|
+
userId: caller.id,
|
|
96
|
+
customActionName,
|
|
97
|
+
collectionName: collection.name,
|
|
98
|
+
});
|
|
99
|
+
return ActionAuthorizationService.canPerformConditionalCustomAction(caller, collection, filterForCaller, conditionalApproveRawCondition);
|
|
100
|
+
}
|
|
101
|
+
async getRoleIdsAllowedToApprove(caller, customActionName, collection, filterForAllCaller) {
|
|
102
|
+
const actionConditionsByRoleId = await this.forestAdminClient.permissionService.getConditionalApproveConditions({
|
|
103
|
+
customActionName,
|
|
104
|
+
collectionName: collection.name,
|
|
105
|
+
});
|
|
106
|
+
const roleIdsAllowedToApproveWithoutConditions = await this.forestAdminClient.permissionService.getRoleIdsAllowedToApproveWithoutConditions({
|
|
107
|
+
customActionName,
|
|
108
|
+
collectionName: collection.name,
|
|
109
|
+
});
|
|
110
|
+
// Optimization - We groupBy conditions to only make the aggregate count once when possible
|
|
111
|
+
const rolesIdsGroupByConditions = ActionAuthorizationService.transformToRolesIdsGroupByConditions(actionConditionsByRoleId);
|
|
112
|
+
if (!rolesIdsGroupByConditions.length) {
|
|
113
|
+
return roleIdsAllowedToApproveWithoutConditions;
|
|
114
|
+
}
|
|
115
|
+
const [requestRecordsCount, ...conditionRecordsCounts] = await Promise.all([
|
|
116
|
+
ActionAuthorizationService.aggregateCountConditionIntersection(caller, collection, filterForAllCaller),
|
|
117
|
+
...rolesIdsGroupByConditions.map(({ condition }) => ActionAuthorizationService.aggregateCountConditionIntersection(caller, collection, filterForAllCaller, condition)),
|
|
118
|
+
]);
|
|
119
|
+
return rolesIdsGroupByConditions.reduce((roleIdsAllowedToApprove, { roleIds }, currentIndex) => {
|
|
120
|
+
if (requestRecordsCount === conditionRecordsCounts[currentIndex]) {
|
|
121
|
+
roleIdsAllowedToApprove.push(...roleIds);
|
|
122
|
+
}
|
|
123
|
+
return roleIdsAllowedToApprove;
|
|
124
|
+
},
|
|
125
|
+
// Roles with userApprovalEnabled excluding the one with conditions
|
|
126
|
+
// are allowed to approve by default
|
|
127
|
+
roleIdsAllowedToApproveWithoutConditions);
|
|
128
|
+
}
|
|
129
|
+
static async canPerformConditionalCustomAction(caller, collection, requestFilter, condition) {
|
|
130
|
+
if (condition) {
|
|
131
|
+
const [requestRecordsCount, matchingRecordsCount] = await Promise.all([
|
|
132
|
+
ActionAuthorizationService.aggregateCountConditionIntersection(caller, collection, requestFilter),
|
|
133
|
+
ActionAuthorizationService.aggregateCountConditionIntersection(caller, collection, requestFilter, condition),
|
|
134
|
+
]);
|
|
135
|
+
// If all records condition the condition everything is ok
|
|
136
|
+
// Otherwise when some records don't match the condition then the user
|
|
137
|
+
// is not allow to perform the conditional action
|
|
138
|
+
return matchingRecordsCount === requestRecordsCount;
|
|
139
|
+
}
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
static async aggregateCountConditionIntersection(caller, collection, requestFilter, condition) {
|
|
143
|
+
try {
|
|
144
|
+
// Override request filter with condition if any
|
|
145
|
+
const conditionalFilter = requestFilter.override({
|
|
146
|
+
conditionTree: condition
|
|
147
|
+
? datasource_toolkit_1.ConditionTreeFactory.intersect(condition_tree_parser_1.default.fromPlainObject(collection, condition), requestFilter.conditionTree)
|
|
148
|
+
: requestFilter.conditionTree,
|
|
149
|
+
});
|
|
150
|
+
const rows = await collection.aggregate(caller, conditionalFilter, new datasource_toolkit_1.Aggregation({
|
|
151
|
+
operation: 'Count',
|
|
152
|
+
}));
|
|
153
|
+
return rows?.[0]?.value ?? 0;
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
throw new invalidActionConditionError_1.default();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Given a map it groups keys based on their hash values
|
|
161
|
+
*/
|
|
162
|
+
static transformToRolesIdsGroupByConditions(actionConditionsByRoleId) {
|
|
163
|
+
const rolesIdsGroupByConditions = Array.from(actionConditionsByRoleId, ([roleId, condition]) => {
|
|
164
|
+
return {
|
|
165
|
+
roleId,
|
|
166
|
+
condition,
|
|
167
|
+
conditionHash: (0, object_hash_1.default)(condition, { respectType: false }),
|
|
168
|
+
};
|
|
169
|
+
}).reduce((acc, current) => {
|
|
170
|
+
const { roleId, condition, conditionHash } = current;
|
|
171
|
+
if (acc.has(conditionHash)) {
|
|
172
|
+
acc.get(conditionHash).roleIds.push(roleId);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
acc.set(conditionHash, { roleIds: [roleId], condition });
|
|
176
|
+
}
|
|
177
|
+
return acc;
|
|
178
|
+
}, new Map());
|
|
179
|
+
return Array.from(rolesIdsGroupByConditions.values());
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
exports.default = ActionAuthorizationService;
|
|
183
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLWF1dGhvcml6YXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvcm91dGVzL21vZGlmaWNhdGlvbi9hY3Rpb24vYWN0aW9uLWF1dGhvcml6YXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSx3RUFPeUM7QUFFekMsOERBQXFDO0FBRXJDLGlHQUF1RTtBQUN2RSwrRkFBdUU7QUFDdkUsbUhBQTJGO0FBQzNGLG1IQUEyRjtBQUMzRix1R0FBK0U7QUFVL0UsTUFBcUIsMEJBQTBCO0lBQzdDLFlBQTZCLGlCQUFvQztRQUFwQyxzQkFBaUIsR0FBakIsaUJBQWlCLENBQW1CO0lBQUcsQ0FBQztJQUU5RCxLQUFLLENBQUMsNEJBQTRCLENBQUMsRUFDeEMsZ0JBQWdCLEVBQ2hCLFVBQVUsRUFDVixlQUFlLEVBQ2Ysa0JBQWtCLEVBQ2xCLE1BQU0sR0FDdUI7UUFDN0IsTUFBTSxVQUFVLEdBQUcsTUFBTSxJQUFJLENBQUMsc0JBQXNCLENBQ2xELE1BQU0sRUFDTixnQkFBZ0IsRUFDaEIsVUFBVSxFQUNWLGVBQWUsQ0FDaEIsQ0FBQztRQUVGLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDZixNQUFNLElBQUksMkNBQWlDLEVBQUUsQ0FBQztTQUMvQztRQUVELE1BQU0sdUJBQXVCLEdBQUcsTUFBTSxJQUFJLENBQUMsdUNBQXVDLENBQ2hGLE1BQU0sRUFDTixnQkFBZ0IsRUFDaEIsVUFBVSxFQUNWLGVBQWUsQ0FDaEIsQ0FBQztRQUVGLElBQUksdUJBQXVCLEVBQUU7WUFDM0IsTUFBTSx1QkFBdUIsR0FBRyxNQUFNLElBQUksQ0FBQywwQkFBMEIsQ0FDbkUsTUFBTSxFQUNOLGdCQUFnQixFQUNoQixVQUFVLEVBQ1Ysa0JBQWtCLENBQ25CLENBQUM7WUFFRixNQUFNLElBQUksMkNBQWlDLENBQUMsdUJBQXVCLENBQUMsQ0FBQztTQUN0RTtJQUNILENBQUM7SUFFTSxLQUFLLENBQUMsNEJBQTRCLENB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
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/// <reference types="koa__router" />
|
|
2
2
|
import { DataSource } from '@forestadmin/datasource-toolkit';
|
|
3
3
|
import Router from '@koa/router';
|
|
4
|
-
import { ForestAdminHttpDriverServices } from '
|
|
5
|
-
import { AgentOptionsWithDefaults } from '
|
|
6
|
-
import CollectionRoute from '
|
|
4
|
+
import { ForestAdminHttpDriverServices } from '../../../services';
|
|
5
|
+
import { AgentOptionsWithDefaults } from '../../../types';
|
|
6
|
+
import CollectionRoute from '../../collection-route';
|
|
7
7
|
export default class ActionRoute extends CollectionRoute {
|
|
8
8
|
private readonly actionName;
|
|
9
|
+
private actionAuthorizationService;
|
|
9
10
|
constructor(services: ForestAdminHttpDriverServices, options: AgentOptionsWithDefaults, dataSource: DataSource, collectionName: string, actionName: string);
|
|
10
11
|
setupRoutes(router: Router): void;
|
|
11
12
|
private handleExecute;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
7
|
+
const types_1 = require("../../../types");
|
|
8
|
+
const body_parser_1 = __importDefault(require("../../../utils/body-parser"));
|
|
9
|
+
const context_filter_factory_1 = __importDefault(require("../../../utils/context-filter-factory"));
|
|
10
|
+
const action_values_1 = __importDefault(require("../../../utils/forest-schema/action-values"));
|
|
11
|
+
const generator_actions_1 = __importDefault(require("../../../utils/forest-schema/generator-actions"));
|
|
12
|
+
const id_1 = __importDefault(require("../../../utils/id"));
|
|
13
|
+
const query_string_1 = __importDefault(require("../../../utils/query-string"));
|
|
14
|
+
const collection_route_1 = __importDefault(require("../../collection-route"));
|
|
15
|
+
const action_authorization_1 = __importDefault(require("./action-authorization"));
|
|
16
|
+
class ActionRoute extends collection_route_1.default {
|
|
17
|
+
constructor(services, options, dataSource, collectionName, actionName) {
|
|
18
|
+
super(services, options, dataSource, collectionName);
|
|
19
|
+
this.actionName = actionName;
|
|
20
|
+
this.actionAuthorizationService = new action_authorization_1.default(options.forestAdminClient);
|
|
21
|
+
}
|
|
22
|
+
setupRoutes(router) {
|
|
23
|
+
const actionIndex = Object.keys(this.collection.schema.actions).indexOf(this.actionName);
|
|
24
|
+
const path = `/_actions/${this.collection.name}/${actionIndex}`;
|
|
25
|
+
router.post(`${path}/:slug`, this.middlewareCustomActionApprovalRequestData.bind(this), this.handleExecute.bind(this));
|
|
26
|
+
router.post(`${path}/:slug/hooks/load`, this.handleHook.bind(this));
|
|
27
|
+
router.post(`${path}/:slug/hooks/change`, this.handleHook.bind(this));
|
|
28
|
+
}
|
|
29
|
+
async handleExecute(context) {
|
|
30
|
+
const { dataSource } = this.collection;
|
|
31
|
+
const caller = query_string_1.default.parseCaller(context);
|
|
32
|
+
const [filterForCaller, filterForAllCaller] = await Promise.all([
|
|
33
|
+
this.getRecordSelection(context),
|
|
34
|
+
this.getRecordSelection(context, false),
|
|
35
|
+
]);
|
|
36
|
+
const requestBody = context.request.body;
|
|
37
|
+
const canPerformCustomActionParams = {
|
|
38
|
+
caller,
|
|
39
|
+
customActionName: this.actionName,
|
|
40
|
+
collection: this.collection,
|
|
41
|
+
filterForCaller,
|
|
42
|
+
filterForAllCaller,
|
|
43
|
+
};
|
|
44
|
+
if (requestBody?.data?.attributes?.requester_id) {
|
|
45
|
+
await this.actionAuthorizationService.assertCanApproveCustomAction({
|
|
46
|
+
...canPerformCustomActionParams,
|
|
47
|
+
requesterId: requestBody.data.attributes.requester_id,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
await this.actionAuthorizationService.assertCanTriggerCustomAction(canPerformCustomActionParams);
|
|
52
|
+
}
|
|
53
|
+
const rawData = context.request.body.data.attributes.values;
|
|
54
|
+
// As forms are dynamic, we don't have any way to ensure that we're parsing the data correctly
|
|
55
|
+
// => better send invalid data to the getForm() customer handler than to the execute() one.
|
|
56
|
+
const unsafeData = action_values_1.default.makeFormDataUnsafe(rawData);
|
|
57
|
+
const fields = await this.collection.getForm(caller, this.actionName, unsafeData, filterForCaller);
|
|
58
|
+
// Now that we have the field list, we can parse the data again.
|
|
59
|
+
const data = action_values_1.default.makeFormData(dataSource, rawData, fields);
|
|
60
|
+
const result = await this.collection.execute(caller, this.actionName, data, filterForCaller);
|
|
61
|
+
if (result?.type === 'Error') {
|
|
62
|
+
context.response.status = types_1.HttpCode.BadRequest;
|
|
63
|
+
context.response.body = { error: result.message, html: result.html };
|
|
64
|
+
}
|
|
65
|
+
else if (result?.type === 'Success') {
|
|
66
|
+
context.response.body = {
|
|
67
|
+
success: result.message,
|
|
68
|
+
html: result.html,
|
|
69
|
+
refresh: { relationships: [...result.invalidated] },
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
else if (result?.type === 'Webhook') {
|
|
73
|
+
const { url, method, headers, body } = result;
|
|
74
|
+
context.response.body = { webhook: { url, method, headers, body } };
|
|
75
|
+
}
|
|
76
|
+
else if (result?.type === 'Redirect') {
|
|
77
|
+
context.response.body = { redirectTo: result.path };
|
|
78
|
+
}
|
|
79
|
+
else if (result?.type === 'File') {
|
|
80
|
+
context.response.attachment(result.name);
|
|
81
|
+
context.response.set('Access-Control-Expose-Headers', 'Content-Disposition');
|
|
82
|
+
context.response.type = result.mimeType;
|
|
83
|
+
context.response.body = result.stream;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
throw new Error('Unexpected Action result.');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async handleHook(context) {
|
|
90
|
+
const { id: userId } = context.state.user;
|
|
91
|
+
await this.actionAuthorizationService.assertCanRequestCustomActionParameters(userId, this.actionName, this.collection.name);
|
|
92
|
+
const { dataSource } = this.collection;
|
|
93
|
+
const forestFields = context.request.body?.data?.attributes?.fields;
|
|
94
|
+
const data = forestFields
|
|
95
|
+
? action_values_1.default.makeFormDataFromFields(dataSource, forestFields)
|
|
96
|
+
: null;
|
|
97
|
+
const caller = query_string_1.default.parseCaller(context);
|
|
98
|
+
const filter = await this.getRecordSelection(context);
|
|
99
|
+
const fields = await this.collection.getForm(caller, this.actionName, data, filter);
|
|
100
|
+
context.response.body = {
|
|
101
|
+
fields: fields.map(field => generator_actions_1.default.buildFieldSchema(this.collection.dataSource, field)),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
async middlewareCustomActionApprovalRequestData(context, next) {
|
|
105
|
+
const requestBody = context.request.body;
|
|
106
|
+
// We forbid requester_id from default request as it's only retrieved from
|
|
107
|
+
// signed_approval_request
|
|
108
|
+
if (requestBody?.data?.attributes?.requester_id) {
|
|
109
|
+
throw new datasource_toolkit_1.UnprocessableError();
|
|
110
|
+
}
|
|
111
|
+
if (requestBody?.data?.attributes?.signed_approval_request) {
|
|
112
|
+
const signedParameters = this.options.forestAdminClient.verifySignedActionParameters(requestBody.data.attributes.signed_approval_request);
|
|
113
|
+
context.request.body = signedParameters;
|
|
114
|
+
}
|
|
115
|
+
return next();
|
|
116
|
+
}
|
|
117
|
+
async getRecordSelection(context, includeUserScope = true) {
|
|
118
|
+
const attributes = context.request?.body?.data?.attributes;
|
|
119
|
+
// Match user filter + search + scope? + segment.
|
|
120
|
+
const scope = includeUserScope
|
|
121
|
+
? await this.services.authorization.getScope(this.collection, context)
|
|
122
|
+
: null;
|
|
123
|
+
let filter = context_filter_factory_1.default.build(this.collection, context, scope);
|
|
124
|
+
// Restrict the filter to the selected records for single or bulk actions.
|
|
125
|
+
if (this.collection.schema.actions[this.actionName].scope !== 'Global') {
|
|
126
|
+
const selectionIds = body_parser_1.default.parseSelectionIds(this.collection.schema, context);
|
|
127
|
+
let selectedIds = datasource_toolkit_1.ConditionTreeFactory.matchIds(this.collection.schema, selectionIds.ids);
|
|
128
|
+
if (selectionIds.areExcluded)
|
|
129
|
+
selectedIds = selectedIds.inverse();
|
|
130
|
+
filter = filter.override({
|
|
131
|
+
conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(filter.conditionTree, selectedIds),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
// Restrict the filter further for the "related data" page.
|
|
135
|
+
if (attributes?.parent_association_name) {
|
|
136
|
+
const caller = query_string_1.default.parseCaller(context);
|
|
137
|
+
const relation = attributes?.parent_association_name;
|
|
138
|
+
const parent = this.dataSource.getCollection(attributes.parent_collection_name);
|
|
139
|
+
const parentId = id_1.default.unpackId(parent.schema, attributes.parent_collection_id);
|
|
140
|
+
filter = await datasource_toolkit_1.FilterFactory.makeForeignFilter(parent, parentId, relation, caller, filter);
|
|
141
|
+
}
|
|
142
|
+
return filter;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.default = ActionRoute;
|
|
146
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3JvdXRlcy9tb2RpZmljYXRpb24vYWN0aW9uL2FjdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHdFQU15QztBQVN6QywwQ0FBb0U7QUFDcEUsNkVBQW9EO0FBQ3BELG1HQUF5RTtBQUN6RSwrRkFBOEU7QUFDOUUsdUdBQW9GO0FBQ3BGLDJEQUF3QztBQUN4QywrRUFBNEQ7QUFDNUQsOEVBQXFEO0FBQ3JELGtGQUFnRTtBQUVoRSxNQUFxQixXQUFZLFNBQVEsMEJBQWU7SUFLdEQsWUFDRSxRQUF1QyxFQUN2QyxPQUFpQyxFQUNqQyxVQUFzQixFQUN0QixjQUFzQixFQUN0QixVQUFrQjtRQUVsQixLQUFLLENBQUMsUUFBUSxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDckQsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7UUFFN0IsSUFBSSxDQUFDLDBCQUEwQixHQUFHLElBQUksOEJBQTBCLENBQUMsT0FBTyxDQUFDLGlCQUFpQixDQUFDLENBQUM7SUFDOUYsQ0FBQztJQUVELFdBQVcsQ0FBQyxNQUFjO1FBQ3hCLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUN6RixNQUFNLElBQUksR0FBRyxhQUFhLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxJQUFJLFdBQVcsRUFBRSxDQUFDO1FBRWhFLE1BQU0sQ0FBQyxJQUFJLENBQ1QsR0FBRyxJQUFJLFFBQVEsRUFDZixJQUFJLENBQUMseUNBQXlDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUN6RCxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FDOUIsQ0FB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
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
4
|
+
class ApprovalNotAllowedError extends datasource_toolkit_1.ForbiddenError {
|
|
5
|
+
constructor(roleIdsAllowedToApprove) {
|
|
6
|
+
super("You don't have permission to approve this action.", {
|
|
7
|
+
roleIdsAllowedToApprove,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.default = ApprovalNotAllowedError;
|
|
12
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwcm92YWxOb3RBbGxvd2VkRXJyb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvcm91dGVzL21vZGlmaWNhdGlvbi9hY3Rpb24vZXJyb3JzL2FwcHJvdmFsTm90QWxsb3dlZEVycm9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsd0VBQWlFO0FBRWpFLE1BQXFCLHVCQUF3QixTQUFRLG1DQUFjO0lBQ2pFLFlBQVksdUJBQWlDO1FBQzNDLEtBQUssQ0FBQyxtREFBbUQsRUFBRTtZQUN6RCx1QkFBdUI7U0FDeEIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBTkQsMENBTUMifQ==
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
4
|
+
class CustomActionRequiresApprovalError extends datasource_toolkit_1.ForbiddenError {
|
|
5
|
+
constructor(roleIdsAllowedToApprove) {
|
|
6
|
+
super('This action requires to be approved.', {
|
|
7
|
+
roleIdsAllowedToApprove,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.default = CustomActionRequiresApprovalError;
|
|
12
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VzdG9tQWN0aW9uUmVxdWlyZXNBcHByb3ZhbEVycm9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3JvdXRlcy9tb2RpZmljYXRpb24vYWN0aW9uL2Vycm9ycy9jdXN0b21BY3Rpb25SZXF1aXJlc0FwcHJvdmFsRXJyb3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSx3RUFBaUU7QUFFakUsTUFBcUIsaUNBQWtDLFNBQVEsbUNBQWM7SUFDM0UsWUFBWSx1QkFBaUM7UUFDM0MsS0FBSyxDQUFDLHNDQUFzQyxFQUFFO1lBQzVDLHVCQUF1QjtTQUN4QixDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0Y7QUFORCxvREFNQyJ9
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
4
|
+
class CustomActionTriggerForbiddenError extends datasource_toolkit_1.ForbiddenError {
|
|
5
|
+
constructor() {
|
|
6
|
+
super("You don't have permission to trigger this action.");
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
exports.default = CustomActionTriggerForbiddenError;
|
|
10
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VzdG9tQWN0aW9uVHJpZ2dlckZvcmJpZGRlbkVycm9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3JvdXRlcy9tb2RpZmljYXRpb24vYWN0aW9uL2Vycm9ycy9jdXN0b21BY3Rpb25UcmlnZ2VyRm9yYmlkZGVuRXJyb3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSx3RUFBaUU7QUFFakUsTUFBcUIsaUNBQWtDLFNBQVEsbUNBQWM7SUFDM0U7UUFDRSxLQUFLLENBQUMsbURBQW1ELENBQUMsQ0FBQztJQUM3RCxDQUFDO0NBQ0Y7QUFKRCxvREFJQyJ9
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
4
|
+
class InvalidActionConditionError extends datasource_toolkit_1.UnprocessableError {
|
|
5
|
+
constructor() {
|
|
6
|
+
super('The conditions to trigger this action cannot be verified. Please contact an administrator.');
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
exports.default = InvalidActionConditionError;
|
|
10
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW52YWxpZEFjdGlvbkNvbmRpdGlvbkVycm9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3JvdXRlcy9tb2RpZmljYXRpb24vYWN0aW9uL2Vycm9ycy9pbnZhbGlkQWN0aW9uQ29uZGl0aW9uRXJyb3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSx3RUFBcUU7QUFFckUsTUFBcUIsMkJBQTRCLFNBQVEsdUNBQWtCO0lBQ3pFO1FBQ0UsS0FBSyxDQUNILDRGQUE0RixDQUM3RixDQUFDO0lBQ0osQ0FBQztDQUNGO0FBTkQsOENBTUMifQ==
|
|
@@ -51,10 +51,7 @@ class ErrorHandling extends base_route_1.default {
|
|
|
51
51
|
return types_1.HttpCode.InternalServerError;
|
|
52
52
|
}
|
|
53
53
|
getErrorMessage(error) {
|
|
54
|
-
if (error instanceof koa_1.HttpError ||
|
|
55
|
-
error instanceof datasource_toolkit_1.ValidationError ||
|
|
56
|
-
error instanceof datasource_toolkit_1.UnprocessableError ||
|
|
57
|
-
error instanceof datasource_toolkit_1.ForbiddenError) {
|
|
54
|
+
if (error instanceof koa_1.HttpError || error instanceof datasource_toolkit_1.BusinessError) {
|
|
58
55
|
return error.message;
|
|
59
56
|
}
|
|
60
57
|
if (this.options.customizeErrorMessage) {
|
|
@@ -65,13 +62,10 @@ class ErrorHandling extends base_route_1.default {
|
|
|
65
62
|
return 'Unexpected error';
|
|
66
63
|
}
|
|
67
64
|
getErrorName(error) {
|
|
68
|
-
return error.constructor.name;
|
|
65
|
+
return error.name || error.constructor.name;
|
|
69
66
|
}
|
|
70
67
|
getErrorPayload(error) {
|
|
71
|
-
if (error instanceof
|
|
72
|
-
error instanceof datasource_toolkit_1.ValidationError ||
|
|
73
|
-
error instanceof datasource_toolkit_1.UnprocessableError ||
|
|
74
|
-
error instanceof datasource_toolkit_1.ForbiddenError) {
|
|
68
|
+
if (error instanceof datasource_toolkit_1.BusinessError) {
|
|
75
69
|
return error.data;
|
|
76
70
|
}
|
|
77
71
|
return null;
|
|
@@ -96,4 +90,4 @@ class ErrorHandling extends base_route_1.default {
|
|
|
96
90
|
}
|
|
97
91
|
}
|
|
98
92
|
exports.default = ErrorHandling;
|
|
99
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
93
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3ItaGFuZGxpbmcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcm91dGVzL3N5c3RlbS9lcnJvci1oYW5kbGluZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHdFQUt5QztBQUV6Qyw2QkFBK0M7QUFFL0MsdUNBQWtEO0FBQ2xELCtEQUFzQztBQUV0QyxNQUFxQixhQUFjLFNBQVEsb0JBQVM7SUFBcEQ7O1FBQ0UsU0FBSSxHQUFHLGlCQUFTLENBQUMsWUFBWSxDQUFDO0lBdUZoQyxDQUFDO0lBckZDLFdBQVcsQ0FBQyxNQUFjO1FBQ3hCLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUMzQyxDQUFDO0lBRU8sS0FBSyxDQUFDLFlBQVksQ0FBQyxPQUFnQixFQUFFLElBQVU7UUFDckQsSUFBSTtZQUNGLE1BQU0sSUFBSSxFQUFFLENBQUM7U0FDZDtRQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ1YsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUN0QyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRXJDLE9BQU8sQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztZQUNqQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksR0FBRztnQkFDdEIsTUFBTSxFQUFFO29CQUNOO3dCQUNFLElBQUksRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQzt3QkFDMUIsTUFBTSxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDO3dCQUMvQixrRkFBa0Y7d0JBQ2xGLE1BQU07d0JBQ04sR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO3FC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
|
|
@@ -11,21 +11,8 @@ export default class AuthorizationService {
|
|
|
11
11
|
assertCanDelete(context: Context, collectionName: string): Promise<void>;
|
|
12
12
|
assertCanExport(context: Context, collectionName: string): Promise<void>;
|
|
13
13
|
private assertCanOnCollection;
|
|
14
|
-
assertCanTriggerCustomAction({ context, customActionName, collectionName, }: {
|
|
15
|
-
context: Context;
|
|
16
|
-
customActionName: string;
|
|
17
|
-
collectionName: string;
|
|
18
|
-
}): Promise<void>;
|
|
19
|
-
assertCanApproveCustomAction({ context, customActionName, collectionName, requesterId, }: {
|
|
20
|
-
context: Context;
|
|
21
|
-
customActionName: string;
|
|
22
|
-
collectionName: string;
|
|
23
|
-
requesterId: number | string;
|
|
24
|
-
}): Promise<void>;
|
|
25
|
-
assertCanRequestCustomActionParameters(context: Context, customActionName: string, collectionName: string): Promise<void>;
|
|
26
14
|
assertCanExecuteChart(context: Context): Promise<void>;
|
|
27
15
|
getScope(collection: Collection, context: Context): Promise<ConditionTree>;
|
|
28
16
|
invalidateScopeCache(renderingId: number | string): void;
|
|
29
|
-
verifySignedActionParameters<TSignedParameters>(signedToken: string): TSignedParameters;
|
|
30
17
|
}
|
|
31
18
|
//# sourceMappingURL=authorization.d.ts.map
|
|
@@ -40,40 +40,6 @@ class AuthorizationService {
|
|
|
40
40
|
context.throw(types_1.HttpCode.Forbidden, 'Forbidden');
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
async assertCanTriggerCustomAction({ context, customActionName, collectionName, }) {
|
|
44
|
-
const { id: userId } = context.state.user;
|
|
45
|
-
const canTrigger = await this.forestAdminClient.permissionService.canTriggerCustomAction({
|
|
46
|
-
userId,
|
|
47
|
-
customActionName,
|
|
48
|
-
collectionName,
|
|
49
|
-
});
|
|
50
|
-
if (!canTrigger) {
|
|
51
|
-
context.throw(types_1.HttpCode.Forbidden, 'Forbidden');
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
async assertCanApproveCustomAction({ context, customActionName, collectionName, requesterId, }) {
|
|
55
|
-
const { id: userId } = context.state.user;
|
|
56
|
-
const canApprove = await this.forestAdminClient.permissionService.canApproveCustomAction({
|
|
57
|
-
userId,
|
|
58
|
-
customActionName,
|
|
59
|
-
collectionName,
|
|
60
|
-
requesterId,
|
|
61
|
-
});
|
|
62
|
-
if (!canApprove) {
|
|
63
|
-
context.throw(types_1.HttpCode.Forbidden, 'Forbidden');
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
async assertCanRequestCustomActionParameters(context, customActionName, collectionName) {
|
|
67
|
-
const { id: userId } = context.state.user;
|
|
68
|
-
const canRequest = await this.forestAdminClient.permissionService.canRequestCustomActionParameters({
|
|
69
|
-
userId,
|
|
70
|
-
customActionName,
|
|
71
|
-
collectionName,
|
|
72
|
-
});
|
|
73
|
-
if (!canRequest) {
|
|
74
|
-
context.throw(types_1.HttpCode.Forbidden, 'Forbidden');
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
43
|
async assertCanExecuteChart(context) {
|
|
78
44
|
const { renderingId, id: userId } = context.state.user;
|
|
79
45
|
const { body: chartRequest } = context.request;
|
|
@@ -110,9 +76,6 @@ class AuthorizationService {
|
|
|
110
76
|
invalidateScopeCache(renderingId) {
|
|
111
77
|
this.forestAdminClient.markScopesAsUpdated(renderingId);
|
|
112
78
|
}
|
|
113
|
-
verifySignedActionParameters(signedToken) {
|
|
114
|
-
return this.forestAdminClient.verifySignedActionParameters(signedToken);
|
|
115
|
-
}
|
|
116
79
|
}
|
|
117
80
|
exports.default = AuthorizationService;
|
|
118
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
81
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aG9yaXphdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zZXJ2aWNlcy9hdXRob3JpemF0aW9uL2F1dGhvcml6YXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSx3RUFBZ0c7QUFDaEcsd0VBTXlDO0FBR3pDLHVDQUF1QztBQUN2Qyw4RkFBb0U7QUFFcEUsTUFBcUIsb0JBQW9CO0lBQ3ZDLFlBQTZCLGlCQUFvQztRQUFwQyxzQkFBaUIsR0FBakIsaUJBQWlCLENBQW1CO0lBQUcsQ0FBQztJQUU5RCxLQUFLLENBQUMsZUFBZSxDQUFDLE9BQWdCLEVBQUUsY0FBc0I7UUFDbkUsTUFBTSxJQUFJLENBQUMscUJBQXFCLENBQUMsMENBQXFCLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxjQUFjLENBQUMsQ0FBQztJQUMxRixDQUFDO0lBRU0sS0FBSyxDQUFDLGFBQWEsQ0FBQyxPQUFnQixFQUFFLGNBQXNCO1FBQ2pFLE1BQU0sSUFBSSxDQUFDLHFCQUFxQixDQUFDLDBDQUFxQixDQUFDLElBQUksRUFBRSxPQUFPLEVBQUUsY0FBYyxDQUFDLENBQUM7SUFDeEYsQ0FBQztJQUVNLEtBQUssQ0FBQyxZQUFZLENBQUMsT0FBZ0IsRUFBRSxjQUFzQjtRQUNoRSxNQUFNLElBQUksQ0FBQyxxQkFBcUIsQ0FBQywwQ0FBcUIsQ0FBQyxHQUFHLEVBQUUsT0FBTyxFQUFFLGNBQWMsQ0FBQyxDQUFDO0lBQ3ZGLENBQUM7SUFFTSxLQUFLLENBQUMsYUFBYSxDQUFDLE9BQWdCLEVBQUUsY0FBc0I7UUFDakUsTUFBTSxJQUFJLENBQUMscUJBQXFCLENBQUMsMENBQXFCLENBQUMsSUFBSSxFQUFFLE9BQU8sRUFBRSxjQUFjLENBQUMsQ0FBQztJQUN4RixDQUFDO0lBRU0sS0FBSyxDQUFDLGVBQWUsQ0FBQyxPQUFnQixFQUFFLGNBQXNCO1FBQ25FLE1BQU0sSUFBSSxDQUFDLHFCQUFxQixDQUFDLDBDQUFxQixDQUFD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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forestadmin/agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@fast-csv/format": "^4.3.5",
|
|
16
16
|
"@fastify/express": "^1.1.0",
|
|
17
|
-
"@forestadmin/datasource-customizer": "1.5.
|
|
18
|
-
"@forestadmin/datasource-toolkit": "1.
|
|
19
|
-
"@forestadmin/forestadmin-client": "1.
|
|
17
|
+
"@forestadmin/datasource-customizer": "1.5.6",
|
|
18
|
+
"@forestadmin/datasource-toolkit": "1.2.0",
|
|
19
|
+
"@forestadmin/forestadmin-client": "1.1.1",
|
|
20
20
|
"@koa/cors": "^3.3.0",
|
|
21
21
|
"@koa/router": "^10.1.1",
|
|
22
22
|
"forest-ip-utils": "^1.0.1",
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
7
|
-
const types_1 = require("../../types");
|
|
8
|
-
const body_parser_1 = __importDefault(require("../../utils/body-parser"));
|
|
9
|
-
const context_filter_factory_1 = __importDefault(require("../../utils/context-filter-factory"));
|
|
10
|
-
const action_values_1 = __importDefault(require("../../utils/forest-schema/action-values"));
|
|
11
|
-
const generator_actions_1 = __importDefault(require("../../utils/forest-schema/generator-actions"));
|
|
12
|
-
const id_1 = __importDefault(require("../../utils/id"));
|
|
13
|
-
const query_string_1 = __importDefault(require("../../utils/query-string"));
|
|
14
|
-
const collection_route_1 = __importDefault(require("../collection-route"));
|
|
15
|
-
class ActionRoute extends collection_route_1.default {
|
|
16
|
-
constructor(services, options, dataSource, collectionName, actionName) {
|
|
17
|
-
super(services, options, dataSource, collectionName);
|
|
18
|
-
this.actionName = actionName;
|
|
19
|
-
}
|
|
20
|
-
setupRoutes(router) {
|
|
21
|
-
const actionIndex = Object.keys(this.collection.schema.actions).indexOf(this.actionName);
|
|
22
|
-
const path = `/_actions/${this.collection.name}/${actionIndex}`;
|
|
23
|
-
router.post(`${path}/:slug`, this.middlewareCustomActionApprovalRequestData.bind(this), this.handleExecute.bind(this));
|
|
24
|
-
router.post(`${path}/:slug/hooks/load`, this.handleHook.bind(this));
|
|
25
|
-
router.post(`${path}/:slug/hooks/change`, this.handleHook.bind(this));
|
|
26
|
-
}
|
|
27
|
-
async handleExecute(context) {
|
|
28
|
-
const { dataSource } = this.collection;
|
|
29
|
-
const caller = query_string_1.default.parseCaller(context);
|
|
30
|
-
const filter = await this.getRecordSelection(context);
|
|
31
|
-
const rawData = context.request.body.data.attributes.values;
|
|
32
|
-
// As forms are dynamic, we don't have any way to ensure that we're parsing the data correctly
|
|
33
|
-
// => better send invalid data to the getForm() customer handler than to the execute() one.
|
|
34
|
-
const unsafeData = action_values_1.default.makeFormDataUnsafe(rawData);
|
|
35
|
-
const fields = await this.collection.getForm(caller, this.actionName, unsafeData, filter);
|
|
36
|
-
// Now that we have the field list, we can parse the data again.
|
|
37
|
-
const data = action_values_1.default.makeFormData(dataSource, rawData, fields);
|
|
38
|
-
const result = await this.collection.execute(caller, this.actionName, data, filter);
|
|
39
|
-
if (result?.type === 'Error') {
|
|
40
|
-
context.response.status = types_1.HttpCode.BadRequest;
|
|
41
|
-
context.response.body = { error: result.message, html: result.html };
|
|
42
|
-
}
|
|
43
|
-
else if (result?.type === 'Success') {
|
|
44
|
-
context.response.body = {
|
|
45
|
-
success: result.message,
|
|
46
|
-
html: result.html,
|
|
47
|
-
refresh: { relationships: [...result.invalidated] },
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
else if (result?.type === 'Webhook') {
|
|
51
|
-
const { url, method, headers, body } = result;
|
|
52
|
-
context.response.body = { webhook: { url, method, headers, body } };
|
|
53
|
-
}
|
|
54
|
-
else if (result?.type === 'Redirect') {
|
|
55
|
-
context.response.body = { redirectTo: result.path };
|
|
56
|
-
}
|
|
57
|
-
else if (result?.type === 'File') {
|
|
58
|
-
context.response.attachment(result.name);
|
|
59
|
-
context.response.set('Access-Control-Expose-Headers', 'Content-Disposition');
|
|
60
|
-
context.response.type = result.mimeType;
|
|
61
|
-
context.response.body = result.stream;
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
throw new Error('Unexpected Action result.');
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
async handleHook(context) {
|
|
68
|
-
await this.services.authorization.assertCanRequestCustomActionParameters(context, this.actionName, this.collection.name);
|
|
69
|
-
const { dataSource } = this.collection;
|
|
70
|
-
const forestFields = context.request.body?.data?.attributes?.fields;
|
|
71
|
-
const data = forestFields
|
|
72
|
-
? action_values_1.default.makeFormDataFromFields(dataSource, forestFields)
|
|
73
|
-
: null;
|
|
74
|
-
const caller = query_string_1.default.parseCaller(context);
|
|
75
|
-
const filter = await this.getRecordSelection(context);
|
|
76
|
-
const fields = await this.collection.getForm(caller, this.actionName, data, filter);
|
|
77
|
-
context.response.body = {
|
|
78
|
-
fields: fields.map(field => generator_actions_1.default.buildFieldSchema(this.collection.dataSource, field)),
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
async middlewareCustomActionApprovalRequestData(context, next) {
|
|
82
|
-
const requestBody = context.request.body;
|
|
83
|
-
if (requestBody?.data?.attributes?.signed_approval_request) {
|
|
84
|
-
const signedParameters = this.services.authorization.verifySignedActionParameters(requestBody.data.attributes.signed_approval_request);
|
|
85
|
-
await this.services.authorization.assertCanApproveCustomAction({
|
|
86
|
-
context,
|
|
87
|
-
customActionName: this.actionName,
|
|
88
|
-
collectionName: this.collection.name,
|
|
89
|
-
requesterId: signedParameters?.data?.attributes?.requester_id,
|
|
90
|
-
});
|
|
91
|
-
context.request.body = signedParameters;
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
await this.services.authorization.assertCanTriggerCustomAction({
|
|
95
|
-
context,
|
|
96
|
-
customActionName: this.actionName,
|
|
97
|
-
collectionName: this.collection.name,
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
return next();
|
|
101
|
-
}
|
|
102
|
-
async getRecordSelection(context) {
|
|
103
|
-
const attributes = context.request?.body?.data?.attributes;
|
|
104
|
-
// Match user filter + search + scope + segment.
|
|
105
|
-
const scope = await this.services.authorization.getScope(this.collection, context);
|
|
106
|
-
let filter = context_filter_factory_1.default.build(this.collection, context, scope);
|
|
107
|
-
// Restrict the filter to the selected records for single or bulk actions.
|
|
108
|
-
if (this.collection.schema.actions[this.actionName].scope !== 'Global') {
|
|
109
|
-
const selectionIds = body_parser_1.default.parseSelectionIds(this.collection.schema, context);
|
|
110
|
-
let selectedIds = datasource_toolkit_1.ConditionTreeFactory.matchIds(this.collection.schema, selectionIds.ids);
|
|
111
|
-
if (selectionIds.areExcluded)
|
|
112
|
-
selectedIds = selectedIds.inverse();
|
|
113
|
-
filter = filter.override({
|
|
114
|
-
conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(filter.conditionTree, selectedIds),
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
// Restrict the filter further for the "related data" page.
|
|
118
|
-
if (attributes?.parent_association_name) {
|
|
119
|
-
const caller = query_string_1.default.parseCaller(context);
|
|
120
|
-
const relation = attributes?.parent_association_name;
|
|
121
|
-
const parent = this.dataSource.getCollection(attributes.parent_collection_name);
|
|
122
|
-
const parentId = id_1.default.unpackId(parent.schema, attributes.parent_collection_id);
|
|
123
|
-
filter = await datasource_toolkit_1.FilterFactory.makeForeignFilter(parent, parentId, relation, caller, filter);
|
|
124
|
-
}
|
|
125
|
-
return filter;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
exports.default = ActionRoute;
|
|
129
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3JvdXRlcy9tb2RpZmljYXRpb24vYWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsd0VBS3lDO0FBU3pDLHVDQUFpRTtBQUNqRSwwRUFBaUQ7QUFDakQsZ0dBQXNFO0FBQ3RFLDRGQUEyRTtBQUMzRSxvR0FBaUY7QUFDakYsd0RBQXFDO0FBQ3JDLDRFQUF5RDtBQUN6RCwyRUFBa0Q7QUFFbEQsTUFBcUIsV0FBWSxTQUFRLDBCQUFlO0lBR3RELFlBQ0UsUUFBdUMsRUFDdkMsT0FBaUMsRUFDakMsVUFBc0IsRUFDdEIsY0FBc0IsRUFDdEIsVUFBa0I7UUFFbEIsS0FBSyxDQUFDLFFBQVEsRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLGNBQWMsQ0FBQyxDQUFDO1FBQ3JELElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO0lBQy9CLENBQUM7SUFFRCxXQUFXLENBQUMsTUFBYztRQUN4QixNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDekYsTUFBTSxJQUFJLEdBQUcsYUFBYSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksSUFBSSxXQUFXLEVBQUUsQ0FBQztRQUVoRSxNQUFNLENBQUMsSUFBSSxDQUNULEdBQUcsSUFBSSxRQUFRLEVBQ2YsSUFBSSxDQUFDLHlDQUF5QyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFDekQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQzlCLENBQUM7UUFDRixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxtQkFBbUIsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxD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
|