@forestadmin/agent 1.66.0 → 1.66.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/agent/services/chart.d.ts +102 -0
- package/dist/agent/services/chart.js +114 -0
- package/dist/routes/access/api-chart.d.ts +16 -0
- package/dist/routes/access/api-chart.js +47 -0
- package/dist/routes/modification/action.d.ts +16 -0
- package/dist/routes/modification/action.js +121 -0
- package/dist/services/authorization/internal/action-permission.d.ts +20 -0
- package/dist/services/authorization/internal/action-permission.js +98 -0
- package/dist/services/authorization/internal/generate-action-identifier.d.ts +12 -0
- package/dist/services/authorization/internal/generate-action-identifier.js +15 -0
- package/dist/services/authorization/internal/generate-actions-from-permissions.d.ts +12 -0
- package/dist/services/authorization/internal/generate-actions-from-permissions.js +139 -0
- package/dist/services/authorization/internal/generate-user-scope.d.ts +10 -0
- package/dist/services/authorization/internal/generate-user-scope.js +45 -0
- package/dist/services/authorization/internal/hash-chart.d.ts +5 -0
- package/dist/services/authorization/internal/hash-chart.js +58 -0
- package/dist/services/authorization/internal/rendering-permission.d.ts +39 -0
- package/dist/services/authorization/internal/rendering-permission.js +121 -0
- package/dist/services/authorization/internal/types.d.ts +255 -0
- package/dist/services/authorization/internal/types.js +54 -0
- package/dist/services/authorization/internal/user-permission.d.ts +16 -0
- package/dist/services/authorization/internal/user-permission.js +46 -0
- package/dist/services/permissions.d.ts +19 -0
- package/dist/services/permissions.js +85 -0
- package/dist/utils/forest-http-api.d.ts +37 -0
- package/dist/utils/forest-http-api.js +100 -0
- package/dist/utils/forest-schema/column-schema-validation.d.ts +5 -0
- package/dist/utils/forest-schema/column-schema-validation.js +14 -0
- package/dist/utils/forest-schema/emitter.d.ts +17 -0
- package/dist/utils/forest-schema/emitter.js +38 -0
- package/dist/utils/forest-schema/schema-generator.d.ts +6 -0
- package/dist/utils/forest-schema/schema-generator.js +13 -0
- package/dist/utils/forest-schema/schema-serializer.d.ts +12 -0
- package/dist/utils/forest-schema/schema-serializer.js +35 -0
- package/dist/utils/forest-schema/types.d.ts +85 -0
- package/dist/utils/forest-schema/types.js +16 -0
- package/package.json +4 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Collection, ConditionTree } from '@forestadmin/datasource-toolkit';
|
|
2
|
+
import { Context } from 'koa';
|
|
3
|
+
|
|
4
|
+
import { AgentOptionsWithDefaults } from '../types';
|
|
5
|
+
|
|
6
|
+
declare type RolesOptions = Pick<
|
|
7
|
+
AgentOptionsWithDefaults,
|
|
8
|
+
'forestServerUrl' | 'envSecret' | 'isProduction' | 'permissionsCacheDurationInSeconds'
|
|
9
|
+
>;
|
|
10
|
+
export interface FilterCondition {
|
|
11
|
+
value: boolean | number | string | string[];
|
|
12
|
+
fieldName: string | null;
|
|
13
|
+
subFieldName: string | null;
|
|
14
|
+
embeddedFieldName?: string | null;
|
|
15
|
+
operator: string;
|
|
16
|
+
}
|
|
17
|
+
export interface Filter {
|
|
18
|
+
type: 'and' | 'or';
|
|
19
|
+
conditions: FilterCondition[] | null;
|
|
20
|
+
}
|
|
21
|
+
export declare enum ChartType {
|
|
22
|
+
Pie = 'Pie',
|
|
23
|
+
Value = 'Value',
|
|
24
|
+
Leaderboard = 'Leaderboard',
|
|
25
|
+
Line = 'Line',
|
|
26
|
+
Objective = 'Objective',
|
|
27
|
+
Percentage = 'Percentage',
|
|
28
|
+
}
|
|
29
|
+
export interface BaseChart {
|
|
30
|
+
id: string;
|
|
31
|
+
type: ChartType;
|
|
32
|
+
}
|
|
33
|
+
export interface ApiRouteChart extends BaseChart {
|
|
34
|
+
type: ChartType;
|
|
35
|
+
apiRoute: string;
|
|
36
|
+
}
|
|
37
|
+
export interface QueryChart extends BaseChart {
|
|
38
|
+
type: ChartType;
|
|
39
|
+
query: string;
|
|
40
|
+
filter?: Record<string, any>;
|
|
41
|
+
}
|
|
42
|
+
export interface LeaderboardChart extends BaseChart {
|
|
43
|
+
type: ChartType.Leaderboard;
|
|
44
|
+
sourceCollectionName: string | number;
|
|
45
|
+
labelFieldName: string;
|
|
46
|
+
relationshipFieldName: string;
|
|
47
|
+
aggregateFieldName: string | null;
|
|
48
|
+
aggregator: 'Sum' | 'Count';
|
|
49
|
+
limit: number;
|
|
50
|
+
}
|
|
51
|
+
export interface LineChart extends BaseChart {
|
|
52
|
+
type: ChartType.Line;
|
|
53
|
+
sourceCollectionName: string | number;
|
|
54
|
+
groupByFieldName: string;
|
|
55
|
+
aggregateFieldName: string | null;
|
|
56
|
+
aggregator: 'Sum' | 'Count';
|
|
57
|
+
timeRange: 'Day' | 'Week' | 'Month' | 'Year';
|
|
58
|
+
filter: Filter | null;
|
|
59
|
+
}
|
|
60
|
+
export interface ObjectiveChart extends BaseChart {
|
|
61
|
+
type: ChartType.Objective;
|
|
62
|
+
sourceCollectionName: string | number;
|
|
63
|
+
aggregateFieldName: string;
|
|
64
|
+
aggregator: 'Sum' | 'Count';
|
|
65
|
+
objective: number;
|
|
66
|
+
filter: Filter | null;
|
|
67
|
+
}
|
|
68
|
+
export interface PercentageChart extends BaseChart {
|
|
69
|
+
type: ChartType.Percentage;
|
|
70
|
+
numeratorChartId: string;
|
|
71
|
+
denominatorChartId: string;
|
|
72
|
+
}
|
|
73
|
+
export interface PieChart extends BaseChart {
|
|
74
|
+
type: ChartType.Pie;
|
|
75
|
+
sourceCollectionName: string | number;
|
|
76
|
+
aggregateFieldName: string;
|
|
77
|
+
groupByFieldName: string;
|
|
78
|
+
aggregator: 'Sum' | 'Count';
|
|
79
|
+
filter: Filter | null;
|
|
80
|
+
}
|
|
81
|
+
export interface ValueChart extends BaseChart {
|
|
82
|
+
type: ChartType.Value;
|
|
83
|
+
sourceCollectionName: string | number;
|
|
84
|
+
aggregateFieldName: string;
|
|
85
|
+
aggregator: 'Sum' | 'Count';
|
|
86
|
+
filter: Filter | null;
|
|
87
|
+
}
|
|
88
|
+
export default class ChartService {
|
|
89
|
+
private options;
|
|
90
|
+
private cache;
|
|
91
|
+
constructor(options: RolesOptions);
|
|
92
|
+
invalidateCache(renderingId: number): void;
|
|
93
|
+
/** Checks that a charting query is in the list of allowed queries */
|
|
94
|
+
canChart(context: Context): Promise<void>;
|
|
95
|
+
/** Check if a user is allowed to perform a specific action */
|
|
96
|
+
can(context: Context, action: string, allowRefetch?: boolean): Promise<void>;
|
|
97
|
+
getScope(collection: Collection, context: Context): Promise<ConditionTree>;
|
|
98
|
+
/** Get cached version of "rendering permissions" */
|
|
99
|
+
private getRenderingPermissions;
|
|
100
|
+
}
|
|
101
|
+
export {};
|
|
102
|
+
// # sourceMappingURL=chart.d.ts.map
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
const __importDefault =
|
|
2
|
+
(this && this.__importDefault) ||
|
|
3
|
+
function (mod) {
|
|
4
|
+
return mod && mod.__esModule ? mod : { default: mod };
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
8
|
+
exports.ChartType = void 0;
|
|
9
|
+
const lru_cache_1 = __importDefault(require('lru-cache'));
|
|
10
|
+
const object_hash_1 = __importDefault(require('object-hash'));
|
|
11
|
+
const types_1 = require('../types');
|
|
12
|
+
const forest_http_api_1 = __importDefault(require('../utils/forest-http-api'));
|
|
13
|
+
|
|
14
|
+
let ChartType;
|
|
15
|
+
|
|
16
|
+
(function (ChartType) {
|
|
17
|
+
ChartType.Pie = 'Pie';
|
|
18
|
+
ChartType.Value = 'Value';
|
|
19
|
+
ChartType.Leaderboard = 'Leaderboard';
|
|
20
|
+
ChartType.Line = 'Line';
|
|
21
|
+
ChartType.Objective = 'Objective';
|
|
22
|
+
ChartType.Percentage = 'Percentage';
|
|
23
|
+
})((ChartType = exports.ChartType || (exports.ChartType = {})));
|
|
24
|
+
|
|
25
|
+
class ChartService {
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.options = options;
|
|
28
|
+
this.cache = new lru_cache_1.default({
|
|
29
|
+
max: 256,
|
|
30
|
+
ttl: this.options.permissionsCacheDurationInSeconds * 1000,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
invalidateCache(renderingId) {
|
|
35
|
+
this.cache.delete(renderingId);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Checks that a charting query is in the list of allowed queries */
|
|
39
|
+
async canChart(context) {
|
|
40
|
+
// If the permissions level already allow the chart, no need to check further
|
|
41
|
+
if (['admin', 'editor', 'developer'].includes(context.state.user.permissionLevel)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const chart = { ...context.request.body };
|
|
46
|
+
// When the server sends the data of the allowed charts, the target column is not specified
|
|
47
|
+
// for relations => allow them all.
|
|
48
|
+
if (chart?.group_by_field?.includes(':'))
|
|
49
|
+
chart.group_by_field = chart.group_by_field.substring(0, chart.group_by_field.indexOf(':'));
|
|
50
|
+
const chartHash = (0, object_hash_1.default)(chart, {
|
|
51
|
+
respectType: false,
|
|
52
|
+
excludeKeys: key => chart[key] === null,
|
|
53
|
+
});
|
|
54
|
+
await this.can(context, `chart:${chartHash}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Check if a user is allowed to perform a specific action */
|
|
58
|
+
async can(context, action, allowRefetch = true) {
|
|
59
|
+
const { id: userId, renderingId } = context.state.user;
|
|
60
|
+
const perms = await this.getRenderingPermissions(renderingId);
|
|
61
|
+
const isAllowed = perms.actions.has(action) || perms.actionsByUser[action]?.has(userId);
|
|
62
|
+
|
|
63
|
+
if (!isAllowed && allowRefetch) {
|
|
64
|
+
this.invalidateCache(renderingId);
|
|
65
|
+
|
|
66
|
+
return this.can(context, action, false);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!isAllowed) {
|
|
70
|
+
context.throw(types_1.HttpCode.Forbidden, 'Forbidden');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async getScope(collection, context) {
|
|
75
|
+
const { user } = context.state;
|
|
76
|
+
const perms = await this.getRenderingPermissions(user.renderingId);
|
|
77
|
+
const scopes = perms.scopes[collection.name];
|
|
78
|
+
if (!scopes) return null;
|
|
79
|
+
|
|
80
|
+
return scopes.conditionTree.replaceLeafs(leaf => {
|
|
81
|
+
const dynamicValues = scopes.dynamicScopeValues?.[user.id];
|
|
82
|
+
|
|
83
|
+
if (typeof leaf.value === 'string' && leaf.value.startsWith('$currentUser')) {
|
|
84
|
+
// Search replacement hash from forestadmin server
|
|
85
|
+
if (dynamicValues) {
|
|
86
|
+
return leaf.override({ value: dynamicValues[leaf.value] });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Search JWT token (new user)
|
|
90
|
+
return leaf.override({
|
|
91
|
+
value: leaf.value.startsWith('$currentUser.tags.')
|
|
92
|
+
? user.tags[leaf.value.substring(18)]
|
|
93
|
+
: user[leaf.value.substring(13)],
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return leaf;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Get cached version of "rendering permissions" */
|
|
102
|
+
getRenderingPermissions(renderingId) {
|
|
103
|
+
if (!this.cache.has(renderingId))
|
|
104
|
+
this.cache.set(
|
|
105
|
+
renderingId,
|
|
106
|
+
forest_http_api_1.default.getPermissions(this.options, renderingId),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// We already checked the entry is up-to-date with the .has() call => allowStale
|
|
110
|
+
return this.cache.get(renderingId, { allowStale: true });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
exports.default = ChartService;
|
|
114
|
+
// # sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYWdlbnQvc2VydmljZXMvY2hhcnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBRUEsMERBQWlDO0FBQ2pDLDhEQUFxQztBQUVyQyxvQ0FBOEQ7QUFDOUQsK0VBQStFO0FBcUIvRSxJQUFZLFNBT1g7QUFQRCxXQUFZLFNBQVM7SUFDbkIsd0JBQVcsQ0FBQTtJQUNYLDRCQUFlLENBQUE7SUFDZix3Q0FBMkIsQ0FBQTtJQUMzQiwwQkFBYSxDQUFBO0lBQ2Isb0NBQXVCLENBQUE7SUFDdkIsc0NBQXlCLENBQUE7QUFDM0IsQ0FBQyxFQVBXLFNBQVMsR0FBVCxpQkFBUyxLQUFULGlCQUFTLFFBT3BCO0FBc0VELE1BQXFCLFlBQVk7SUFJL0IsWUFBWSxPQUFxQjtRQUMvQixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUN2QixJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksbUJBQVEsQ0FBQztZQUN4QixHQUFHLEVBQUUsR0FBRztZQUNSLEdBQUcsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLGlDQUFpQyxHQUFHLElBQUk7U0FDM0QsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELGVBQWUsQ0FBQyxXQUFtQjtRQUNqQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBRUQscUVBQXFFO0lBQ3JFLEtBQUssQ0FBQyxRQUFRLENBQUMsT0FBZ0I7UUFDN0IsNkVBQTZFO1FBQzdFLElBQUksQ0FBQyxPQUFPLEVBQUUsUUFBUSxFQUFFLFdBQVcsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsRUFBRTtZQUNqRixPQUFPO1NBQ1I7UUFFRCxNQUFNLEtBQUssR0FBRyxFQUFFLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUUxQywyRkFBMkY7UUFDM0YsbUNBQW1DO1FBQ25DLElBQUksS0FBSyxFQUFFLGNBQWMsRUFBRSxRQUFRLENBQUMsR0FBRyxDQUFDO1lBQ3RDLEtBQUssQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFFOUYsTUFBTSxTQUFTLEdBQUcsSUFBQSxxQkFBVSxFQUFDLEtBQUssRUFBRTtZQUNsQyxXQUFXLEVBQUUsS0FBSztZQUNsQixXQUFXLEVBQUUsR0FBRyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEtBQUssSUFBSTtTQUN4QyxDQUFDLENBQUM7UUFFSCxNQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLFNBQVMsU0FBUyxFQUFFLENBQUMsQ0FBQztJQUNoRCxDQUFDO0lBRUQsOERBQThEO0lBQzlELEtBQUssQ0FBQyxHQUFHLENBQUMsT0FBZ0IsRUFBRSxNQUFjLEVBQUUsWUFBWSxHQUFHLElBQUk7UUFDN0QsTUFBTSxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUM7UUFDdkQsTUFBTSxLQUFLLEdBQUcsTUFBTSxJQUFJLENBQUMsdUJBQXVCLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDOUQsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFeEYsSUFBSSxDQUFDLFNBQVMsSUFBSSxZQUFZLEVBQUU7WUFDOUIsSUFBSSxDQUFDLGVBQWUsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUVsQyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQztTQUN6QztRQUVELElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDZCxPQUFPLENBQUMsS0FBSyxDQUFDLGdCQUFRLENBQUMsU0FBUyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1NBQ2hEO0lBQ0gsQ0FBQztJQUVELEtBQUssQ0FBQyxRQUFRLENBQUMsVUFBc0IsRUFBRSxPQUFnQjtRQUNyRCxNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQztRQUMvQixNQUFNLEtBQUssR0FBRyxNQUFNLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDbkUsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFN0MsSUFBSSxDQUFDLE1BQU07WUFBRSxPQUFPLElBQUksQ0FBQztRQUV6QixPQUFPLE1BQU0sQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQzlDLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxrQkFBa0IsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUUzRCxJQUFJLE9BQU8sSUFBSSxDQUFDLEtBQUssS0FBSyxRQUFRLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsY0FBYyxDQUFDLEVBQUU7Z0JBQzNFLGtEQUFrRDtnQkFDbEQsSUFBSSxhQUFhLEVBQUU7b0JBQ2pCLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLEtBQUssRUFBRSxhQUFhLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztpQkFDNUQ7Z0JBRUQsOEJBQThCO2dCQUM5QixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUM7b0JBQ25CLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxvQkFBb0IsQ0FBQzt3QkFDaEQsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUM7d0JBQ3JDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUM7aUJBQ25DLENBQUMsQ0FBQzthQUNKO1lBRUQsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxvREFBb0Q7SUFDNUMsdUJBQXVCLENBQUMsV0FBbUI7UUFDakQsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQztZQUM5QixJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUseUJBQWEsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDO1FBRXZGLGdGQUFnRjtRQUNoRixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQzNELENBQUM7Q0FDRjtBQTNGRCwrQkEyRkMifQ==
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/// <reference types="koa__router" />
|
|
2
|
+
import { DataSource } from '@forestadmin/datasource-toolkit';
|
|
3
|
+
import Router from '@koa/router';
|
|
4
|
+
import { AgentOptionsWithDefaults, RouteType } from '../../types';
|
|
5
|
+
import { ForestAdminHttpDriverServices } from '../../services';
|
|
6
|
+
import BaseRoute from '../base-route';
|
|
7
|
+
export default class ApiChartRoute extends BaseRoute {
|
|
8
|
+
readonly type = RouteType.PrivateRoute;
|
|
9
|
+
private dataSource;
|
|
10
|
+
private chartName;
|
|
11
|
+
constructor(services: ForestAdminHttpDriverServices, options: AgentOptionsWithDefaults, dataSource: DataSource, chartName: string);
|
|
12
|
+
setupRoutes(router: Router): void;
|
|
13
|
+
private handleApiChart;
|
|
14
|
+
private handleSmartChart;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=api-chart.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
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 uuid_1 = require("uuid");
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const types_1 = require("../../types");
|
|
9
|
+
const base_route_1 = __importDefault(require("../base-route"));
|
|
10
|
+
const query_string_1 = __importDefault(require("../../utils/query-string"));
|
|
11
|
+
class ApiChartRoute extends base_route_1.default {
|
|
12
|
+
constructor(services, options, dataSource, chartName) {
|
|
13
|
+
super(services, options);
|
|
14
|
+
this.type = types_1.RouteType.PrivateRoute;
|
|
15
|
+
this.dataSource = dataSource;
|
|
16
|
+
this.chartName = chartName;
|
|
17
|
+
}
|
|
18
|
+
setupRoutes(router) {
|
|
19
|
+
// Mount both GET and POST, respectively for smart and api charts.
|
|
20
|
+
const suffix = `/_charts/${this.chartName}`;
|
|
21
|
+
router.get(suffix, this.handleSmartChart.bind(this));
|
|
22
|
+
router.post(suffix, this.handleApiChart.bind(this));
|
|
23
|
+
// Log the route to help the customer fill the url in the frontend
|
|
24
|
+
if (!this.options.isProduction) {
|
|
25
|
+
const url = path_1.default.posix.join('/', this.options.prefix, 'forest', suffix);
|
|
26
|
+
this.options.logger('Info', `Chart '${this.chartName}' was mounted at '${url}'`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async handleApiChart(context) {
|
|
30
|
+
// Api Charts need the data to be formatted in JSON-API
|
|
31
|
+
context.response.body = {
|
|
32
|
+
data: {
|
|
33
|
+
id: (0, uuid_1.v1)(),
|
|
34
|
+
type: 'stats',
|
|
35
|
+
attributes: {
|
|
36
|
+
value: await this.dataSource.renderChart(query_string_1.default.parseCaller(context), this.chartName),
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async handleSmartChart(context) {
|
|
42
|
+
// Smart charts need the data to be unformatted
|
|
43
|
+
context.response.body = await this.dataSource.renderChart(query_string_1.default.parseCaller(context), this.chartName);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.default = ApiChartRoute;
|
|
47
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBpLWNoYXJ0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3JvdXRlcy9hY2Nlc3MvYXBpLWNoYXJ0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBRUEsK0JBQW9DO0FBRXBDLGdEQUF3QjtBQUV4Qix1Q0FBa0U7QUFFbEUsK0RBQXNDO0FBQ3RDLDRFQUF5RDtBQUV6RCxNQUFxQixhQUFjLFNBQVEsb0JBQVM7SUFNbEQsWUFDRSxRQUF1QyxFQUN2QyxPQUFpQyxFQUNqQyxVQUFzQixFQUN0QixTQUFpQjtRQUVqQixLQUFLLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBWGxCLFNBQUksR0FBRyxpQkFBUyxDQUFDLFlBQVksQ0FBQztRQWFyQyxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztRQUM3QixJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztJQUM3QixDQUFDO0lBRUQsV0FBVyxDQUFDLE1BQWM7UUFDeEIsa0VBQWtFO1FBQ2xFLE1BQU0sTUFBTSxHQUFHLFlBQVksSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQzVDLE1BQU0sQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNyRCxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBRXBELGtFQUFrRTtRQUNsRSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxZQUFZLEVBQUU7WUFDOUIsTUFBTSxHQUFHLEdBQUcsY0FBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUN4RSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsVUFBVSxJQUFJLENBQUMsU0FBUyxxQkFBcUIsR0FBRyxHQUFHLENBQUMsQ0FBQztTQUNsRjtJQUNILENBQUM7SUFFTyxLQUFLLENBQUMsY0FBYyxDQUFDLE9BQWdCO1FBQzNDLHVEQUF1RDtRQUN2RCxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksR0FBRztZQUN0QixJQUFJLEVBQUU7Z0JBQ0osRUFBRSxFQUFFLElBQUEsU0FBTSxHQUFFO2dCQUNaLElBQUksRUFBRSxPQUFPO2dCQUNiLFVBQVUsRUFBRTtvQkFDVixLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FDdEMsc0JBQWlCLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxFQUN0QyxJQUFJLENBQUMsU0FBUyxDQUNmO2lCQUNGO2FBQ0Y7U0FDRixDQUFDO0lBQ0osQ0FBQztJQUVPLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFnQjtRQUM3QywrQ0FBK0M7UUFDL0MsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FDdkQsc0JBQWlCLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxFQUN0QyxJQUFJLENBQUMsU0FBUyxDQUNmLENBQUM7SUFDSixDQUFDO0NBQ0Y7QUF0REQsZ0NBc0RDIn0=
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/// <reference types="koa__router" />
|
|
2
|
+
import { DataSource } from '@forestadmin/datasource-toolkit';
|
|
3
|
+
import Router from '@koa/router';
|
|
4
|
+
import { ForestAdminHttpDriverServices } from '../../services';
|
|
5
|
+
import { AgentOptionsWithDefaults } from '../../types';
|
|
6
|
+
import CollectionRoute from '../collection-route';
|
|
7
|
+
export default class ActionRoute extends CollectionRoute {
|
|
8
|
+
private readonly actionName;
|
|
9
|
+
constructor(services: ForestAdminHttpDriverServices, options: AgentOptionsWithDefaults, dataSource: DataSource, collectionName: string, actionName: string);
|
|
10
|
+
setupRoutes(router: Router): void;
|
|
11
|
+
private handleExecute;
|
|
12
|
+
private handleHook;
|
|
13
|
+
private middlewareCustomActionApprovalRequestData;
|
|
14
|
+
private getRecordSelection;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=action.d.ts.map
|
|
@@ -0,0 +1,121 @@
|
|
|
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 selectionIds = body_parser_1.default.parseSelectionIds(this.collection.schema, context);
|
|
104
|
+
let selectedIds = datasource_toolkit_1.ConditionTreeFactory.matchIds(this.collection.schema, selectionIds.ids);
|
|
105
|
+
if (selectionIds.areExcluded)
|
|
106
|
+
selectedIds = selectedIds.inverse();
|
|
107
|
+
const conditionTree = datasource_toolkit_1.ConditionTreeFactory.intersect(selectedIds, query_string_1.default.parseConditionTree(this.collection, context), await this.services.authorization.getScope(this.collection, context));
|
|
108
|
+
const caller = query_string_1.default.parseCaller(context);
|
|
109
|
+
const filter = context_filter_factory_1.default.build(this.collection, context, null, { conditionTree });
|
|
110
|
+
const attributes = context.request?.body?.data?.attributes;
|
|
111
|
+
if (attributes?.parent_association_name) {
|
|
112
|
+
const relation = attributes?.parent_association_name;
|
|
113
|
+
const parentCollection = this.dataSource.getCollection(attributes.parent_collection_name);
|
|
114
|
+
const parentId = id_1.default.unpackId(parentCollection.schema, attributes.parent_collection_id);
|
|
115
|
+
return datasource_toolkit_1.FilterFactory.makeForeignFilter(parentCollection, parentId, relation, caller, filter);
|
|
116
|
+
}
|
|
117
|
+
return filter;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
exports.default = ActionRoute;
|
|
121
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3JvdXRlcy9tb2RpZmljYXRpb24vYWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsd0VBS3lDO0FBU3pDLHVDQUFpRTtBQUNqRSwwRUFBaUQ7QUFDakQsZ0dBQXNFO0FBQ3RFLDRGQUEyRTtBQUMzRSxvR0FBaUY7QUFDakYsd0RBQXFDO0FBQ3JDLDRFQUF5RDtBQUN6RCwyRUFBa0Q7QUFFbEQsTUFBcUIsV0FBWSxTQUFRLDBCQUFlO0lBR3RELFlBQ0UsUUFBdUMsRUFDdkMsT0FBaUMsRUFDakMsVUFBc0IsRUFDdEIsY0FBc0IsRUFDdEIsVUFBa0I7UUFFbEIsS0FBSyxDQUFDLFFBQVEsRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLGNBQWMsQ0FBQyxDQUFDO1FBQ3JELElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO0lBQy9CLENBQUM7SUFFRCxXQUFXLENBQUMsTUFBYztRQUN4QixNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDekYsTUFBTSxJQUFJLEdBQUcsYUFBYSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksSUFBSSxXQUFXLEVBQUUsQ0FBQztRQUVoRSxNQUFNLENBQUMsSUFBSSxDQUNULEdBQUcsSUFBSSxRQUFRLEVBQ2YsSUFBSSxDQUFDLHlDQUF5QyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFDekQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQzlCLENBQUM7UUFDRixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxtQkFBbUIsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxD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
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AgentOptionsWithDefaults } from '../../../types';
|
|
2
|
+
|
|
3
|
+
export declare type ActionPermissionOptions = Pick<
|
|
4
|
+
AgentOptionsWithDefaults,
|
|
5
|
+
'forestServerUrl' | 'envSecret' | 'isProduction' | 'permissionsCacheDurationInSeconds' | 'logger'
|
|
6
|
+
>;
|
|
7
|
+
export default class ActionPermissionService {
|
|
8
|
+
private readonly options;
|
|
9
|
+
private permissionsPromise;
|
|
10
|
+
private permissionExpirationTimestamp;
|
|
11
|
+
constructor(options: ActionPermissionOptions);
|
|
12
|
+
canOneOf(userId: string, actionNames: string[]): Promise<boolean>;
|
|
13
|
+
can(userId: string, actionName: string): Promise<boolean>;
|
|
14
|
+
private hasPermissionOrRefetch;
|
|
15
|
+
private isAllowedOneOf;
|
|
16
|
+
private isAllowed;
|
|
17
|
+
private getPermissions;
|
|
18
|
+
private fetchEnvironmentPermissions;
|
|
19
|
+
}
|
|
20
|
+
// # sourceMappingURL=action-permission.d.ts.map
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const __importDefault =
|
|
2
|
+
(this && this.__importDefault) ||
|
|
3
|
+
function (mod) {
|
|
4
|
+
return mod && mod.__esModule ? mod : { default: mod };
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
8
|
+
const forest_http_api_1 = __importDefault(require('../../../utils/forest-http-api'));
|
|
9
|
+
const generate_actions_from_permissions_1 = __importDefault(
|
|
10
|
+
require('./generate-actions-from-permissions'),
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
class ActionPermissionService {
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.options = options;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
canOneOf(userId, actionNames) {
|
|
19
|
+
return this.hasPermissionOrRefetch({
|
|
20
|
+
userId,
|
|
21
|
+
actionNames,
|
|
22
|
+
allowRefetch: true,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
can(userId, actionName) {
|
|
27
|
+
return this.hasPermissionOrRefetch({
|
|
28
|
+
userId,
|
|
29
|
+
actionNames: [actionName],
|
|
30
|
+
allowRefetch: true,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async hasPermissionOrRefetch({ userId, actionNames, allowRefetch }) {
|
|
35
|
+
const permissions = await this.getPermissions();
|
|
36
|
+
const isAllowed = this.isAllowedOneOf({ permissions, actionNames, userId });
|
|
37
|
+
|
|
38
|
+
if (!isAllowed && allowRefetch) {
|
|
39
|
+
this.permissionsPromise = undefined;
|
|
40
|
+
this.permissionExpirationTimestamp = undefined;
|
|
41
|
+
|
|
42
|
+
return this.hasPermissionOrRefetch({
|
|
43
|
+
userId,
|
|
44
|
+
actionNames,
|
|
45
|
+
allowRefetch: false,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
this.options.logger(
|
|
50
|
+
'Debug',
|
|
51
|
+
`User ${userId} is ${isAllowed ? '' : 'not '}allowed to perform ${
|
|
52
|
+
actionNames.length > 1 ? ' one of ' : ''
|
|
53
|
+
}${actionNames.join(', ')}`,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
return isAllowed;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
isAllowedOneOf({ permissions, actionNames, userId }) {
|
|
60
|
+
return actionNames.some(actionName => this.isAllowed({ permissions, actionName, userId }));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
isAllowed({ permissions, actionName, userId }) {
|
|
64
|
+
return (
|
|
65
|
+
permissions.everythingAllowed ||
|
|
66
|
+
permissions.actionsGloballyAllowed.has(actionName) ||
|
|
67
|
+
permissions.actionsAllowedByUser.get(actionName)?.has(userId)
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async getPermissions() {
|
|
72
|
+
if (
|
|
73
|
+
this.permissionsPromise &&
|
|
74
|
+
this.permissionExpirationTimestamp &&
|
|
75
|
+
this.permissionExpirationTimestamp > Date.now()
|
|
76
|
+
) {
|
|
77
|
+
return this.permissionsPromise;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
this.permissionsPromise = this.fetchEnvironmentPermissions();
|
|
81
|
+
this.permissionExpirationTimestamp =
|
|
82
|
+
Date.now() + this.options.permissionsCacheDurationInSeconds * 1000;
|
|
83
|
+
|
|
84
|
+
return this.permissionsPromise;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async fetchEnvironmentPermissions() {
|
|
88
|
+
this.options.logger('Debug', 'Fetching environment permissions');
|
|
89
|
+
const [rawPermissions, users] = await Promise.all([
|
|
90
|
+
forest_http_api_1.default.getEnvironmentPermissions(this.options),
|
|
91
|
+
forest_http_api_1.default.getUsers(this.options),
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
return (0, generate_actions_from_permissions_1.default)(rawPermissions, users);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
exports.default = ActionPermissionService;
|
|
98
|
+
// # sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLXBlcm1pc3Npb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvc2VydmljZXMvYXV0aG9yaXphdGlvbi9pbnRlcm5hbC9hY3Rpb24tcGVybWlzc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUNBLHFGQUEyRDtBQUMzRCw0R0FFNkM7QUFPN0MsTUFBcUIsdUJBQXVCO0lBSTFDLFlBQTZCLE9BQWdDO1FBQWhDLFlBQU8sR0FBUCxPQUFPLENBQXlCO0lBQUcsQ0FBQztJQUUxRCxRQUFRLENBQUMsTUFBYyxFQUFFLFdBQXFCO1FBQ25ELE9BQU8sSUFBSSxDQUFDLHNCQUFzQixDQUFDO1lBQ2pDLE1BQU07WUFDTixXQUFXO1lBQ1gsWUFBWSxFQUFFLElBQUk7U0FDbkIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVNLEdBQUcsQ0FBQyxNQUFjLEVBQUUsVUFBa0I7UUFDM0MsT0FBTyxJQUFJLENBQUMsc0JBQXNCLENBQUM7WUFDakMsTUFBTTtZQUNOLFdBQVcsRUFBRSxDQUFDLFVBQVUsQ0FBQztZQUN6QixZQUFZLEVBQUUsSUFBSTtTQUNuQixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sS0FBSyxDQUFDLHNCQUFzQixDQUFDLEVBQ25DLE1BQU0sRUFDTixXQUFXLEVBQ1gsWUFBWSxHQUtiO1FBQ0MsTUFBTSxXQUFXLEdBQUcsTUFBTSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDaEQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxFQUFFLFdBQVcsRUFBRSxXQUFXLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUU1RSxJQUFJLENBQUMsU0FBUyxJQUFJLFlBQVksRUFBRTtZQUM5QixJQUFJLENBQUMsa0JBQWtCLEdBQUcsU0FBUyxDQUFDO1lBQ3BDLElBQUksQ0FBQyw2QkFBNkIsR0FBRyxTQUFTLENBQUM7WUFFL0MsT0FBTyxJQUFJLENBQUMsc0JBQXNCLENBQUM7Z0JBQ2pDLE1BQU07Z0JBQ04sV0FBVztnQkFDWCxZQUFZLEVBQUUsS0FBSzthQUNwQixDQUFDLENBQUM7U0FDSjtRQUVELElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUNqQixPQUFPLEVBQ1AsUUFBUSxNQUFNLE9BQU8sU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sc0JBQzFDLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEVBQ3hDLEdBQUcsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUM1QixDQUFDO1FBRUYsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUVPLGNBQWMsQ0FBQyxFQUNyQixXQUFXLEVBQ1gsV0FBVyxFQUNYLE1BQU0sR0FLUDtRQUNDLE9BQU8sV0FBVyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQztJQUM3RixDQUFDO0lBRU8sU0FBUyxDQUFDLEVBQ2hCLFdBQVcsRUFDWCxVQUFVLEVBQ1YsTUFBTSxHQUtQO1FBQ0MsT0FBTyxDQUNMLFdBQVcsQ0FBQyxpQkFBaUI7WUFDN0IsV0FBVyxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUM7WUFDbEQsV0FBVyxDQUFDLG9CQUFvQixDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLENBQzlELENBQUM7SUFDSixDQUFDO0lBRU8sS0FBSyxDQUFDLGNBQWM7UUFDMUIsSUFDRSxJQUFJLENBQUMsa0JBQWtCO1lBQ3ZCLElBQUksQ0FBQyw2QkFBNkI7WUFDbEMsSUFBSSxDQUFDLDZCQUE2QixHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsRUFDL0M7WUFDQSxPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQztTQUNoQztRQUVELElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMsMkJBQTJCLEVBQUUsQ0FBQztRQUM3RCxJQUFJLENBQUMsNkJBQTZCO1lBQ2hDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLGlDQUFpQyxHQUFHLElBQUksQ0FBQztRQUVyRSxPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQztJQUNqQyxDQUFDO0lBRU8sS0FBSyxDQUFDLDJCQUEyQjtRQUN2QyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsa0NBQWtDLENBQUMsQ0FBQztRQUVqRSxNQUFNLENBQUMsY0FBYyxFQUFFLEtBQUssQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUNoRCx5QkFBYSxDQUFDLHlCQUF5QixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7WUFDckQseUJBQWEsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztTQUNyQyxDQUFDLENBQUM7UUFFSCxPQUFPLElBQUEsMkNBQThCLEVBQUMsY0FBYyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQy9ELENBQUM7Q0FDRjtBQTdHRCwwQ0E2R0MifQ==
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CollectionActionEvent, CustomActionEvent } from './types';
|
|
2
|
+
|
|
3
|
+
export declare function generateCustomActionIdentifier(
|
|
4
|
+
actionEventName: CustomActionEvent,
|
|
5
|
+
customActionName: string,
|
|
6
|
+
collectionName: string,
|
|
7
|
+
): string;
|
|
8
|
+
export declare function generateCollectionActionIdentifier(
|
|
9
|
+
action: CollectionActionEvent,
|
|
10
|
+
collectionName: string,
|
|
11
|
+
): string;
|
|
12
|
+
// # sourceMappingURL=generate-action-identifier.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
exports.generateCollectionActionIdentifier = exports.generateCustomActionIdentifier = void 0;
|
|
3
|
+
|
|
4
|
+
function generateCustomActionIdentifier(actionEventName, customActionName, collectionName) {
|
|
5
|
+
return `custom:${collectionName}:${customActionName}:${actionEventName}`;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
exports.generateCustomActionIdentifier = generateCustomActionIdentifier;
|
|
9
|
+
|
|
10
|
+
function generateCollectionActionIdentifier(action, collectionName) {
|
|
11
|
+
return `collection:${collectionName}:${action}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
exports.generateCollectionActionIdentifier = generateCollectionActionIdentifier;
|
|
15
|
+
// # sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGUtYWN0aW9uLWlkZW50aWZpZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvc2VydmljZXMvYXV0aG9yaXphdGlvbi9pbnRlcm5hbC9nZW5lcmF0ZS1hY3Rpb24taWRlbnRpZmllci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFFQSxTQUFnQiw4QkFBOEIsQ0FDNUMsZUFBa0MsRUFDbEMsZ0JBQXdCLEVBQ3hCLGNBQXNCO0lBRXRCLE9BQU8sVUFBVSxjQUFjLElBQUksZ0JBQWdCLElBQUksZUFBZSxFQUFFLENBQUM7QUFDM0UsQ0FBQztBQU5ELHdFQU1DO0FBRUQsU0FBZ0Isa0NBQWtDLENBQ2hELE1BQTZCLEVBQzdCLGNBQXNCO0lBRXRCLE9BQU8sY0FBYyxjQUFjLElBQUksTUFBTSxFQUFFLENBQUM7QUFDbEQsQ0FBQztBQUxELGdGQUtDIn0=
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { EnvironmentPermissionsV4, UserPermissionV4 } from './types';
|
|
2
|
+
|
|
3
|
+
export declare type ActionPermissions = {
|
|
4
|
+
everythingAllowed: boolean;
|
|
5
|
+
actionsGloballyAllowed: Set<string>;
|
|
6
|
+
actionsAllowedByUser: Map<string, Set<string>>;
|
|
7
|
+
};
|
|
8
|
+
export default function generateActionsFromPermissions(
|
|
9
|
+
environmentPermissions: EnvironmentPermissionsV4,
|
|
10
|
+
users: UserPermissionV4[],
|
|
11
|
+
): ActionPermissions;
|
|
12
|
+
// # sourceMappingURL=generate-actions-from-permissions.d.ts.map
|