@forestadmin/agent 1.0.0-alpha.2 → 1.0.0-alpha.4
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/access/chart.js +2 -2
- package/dist/routes/security/scope-invalidation.js +2 -2
- package/dist/services/authorization/authorization.d.ts +2 -0
- package/dist/services/authorization/authorization.js +15 -1
- package/dist/services/authorization/internal/action-permission.d.ts +1 -1
- package/dist/services/authorization/internal/action-permission.js +3 -1
- package/dist/services/authorization/internal/hash-chart.d.ts +4 -0
- package/dist/services/authorization/internal/hash-chart.js +48 -0
- package/dist/services/authorization/internal/rendering-permission.d.ts +9 -1
- package/dist/services/authorization/internal/rendering-permission.js +45 -3
- package/dist/services/authorization/internal/types.d.ts +54 -18
- package/dist/services/authorization/internal/types.js +2 -1
- package/dist/services/authorization/internal/user-permission.d.ts +2 -1
- package/dist/services/authorization/internal/user-permission.js +7 -1
- package/dist/services/index.d.ts +0 -2
- package/dist/services/index.js +1 -3
- package/dist/utils/forest-http-api.d.ts +0 -28
- package/dist/utils/forest-http-api.js +1 -81
- package/package.json +1 -1
- package/dist/services/permissions.d.ts +0 -17
- package/dist/services/permissions.js +0 -60
|
@@ -22,7 +22,7 @@ class Chart extends collection_route_1.default {
|
|
|
22
22
|
router.post(`/stats/${this.collection.name}`, this.handleChart.bind(this));
|
|
23
23
|
}
|
|
24
24
|
async handleChart(context) {
|
|
25
|
-
await this.services.
|
|
25
|
+
await this.services.authorization.assertCanRetrieveChart(context);
|
|
26
26
|
context.response.body = {
|
|
27
27
|
data: {
|
|
28
28
|
id: (0, uuid_1.v1)(),
|
|
@@ -159,4 +159,4 @@ Chart.formats = {
|
|
|
159
159
|
Month: 'MMM yy',
|
|
160
160
|
Year: 'yyyy',
|
|
161
161
|
};
|
|
162
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
162
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcm91dGVzL2FjY2Vzcy9jaGFydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHdFQVN5QztBQUV6QyxpQ0FBaUM7QUFDakMsK0JBQW9DO0FBR3BDLDJFQUFrRDtBQUNsRCxnR0FBc0U7QUFDdEUsNEVBQXlEO0FBRXpELElBQUssU0FNSjtBQU5ELFdBQUssU0FBUztJQUNaLDRCQUFlLENBQUE7SUFDZixvQ0FBdUIsQ0FBQTtJQUN2Qix3QkFBVyxDQUFBO0lBQ1gsMEJBQWEsQ0FBQTtJQUNiLHdDQUEyQixDQUFBO0FBQzdCLENBQUMsRUFOSSxTQUFTLEtBQVQsU0FBUyxRQU1iO0FBRUQsTUFBcUIsS0FBTSxTQUFRLDBCQUFlO0lBUWhELFdBQVcsQ0FBQyxNQUFjO1FBQ3hCLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDN0UsQ0FBQztJQUVELEtBQUssQ0FBQyxXQUFXLENBQUMsT0FBZ0I7UUFDaEMsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxzQkFBc0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUVsRSxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksR0FBRztZQUN0QixJQUFJLEVBQUU7Z0JBQ0osRUFBRSxFQUFFLElBQUEsU0FBTSxHQUFFO2dCQUNaLElBQUksRUFBRSxPQUFPO2dCQUNiLFVBQVUsRUFBRSxFQUFFLEtBQUssRUFBRSxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQUU7YUFDckQ7U0FDRixDQUFDO0lBQ0osQ0FBQztJQUVPLEtBQUssQ0FBQyxTQUFTLENBQUMsT0FBZ0I7UUFDdEMsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUM7UUFFakMsUUFBUSxJQUFJLENBQUMsSUFBSSxFQUFFO1lBQ2pCLEtBQUssU0FBUyxDQUFDLEtBQUs7Z0JBQ2xCLE9BQU8sSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUN0QyxLQUFLLFNBQVMsQ0FBQyxXQUFXO2dCQUN4QixPQUFPLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUM1QyxLQUFLLFNBQVMsQ0FBQyxTQUFTO2dCQUN0QixPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUMxQyxLQUFLLFNBQVMsQ0FBQyxHQUFHO2dCQUNoQixPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDcEMsS0FBSyxTQUFTLENBQUMsSUFBSTtnQkFDakIsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ3JDO2dCQUNFLE1BQU0sSUFBSSxvQ0FBZSxDQUFDLHVCQUF1QixJQUFJLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQztTQUNsRTtJQUNILENBQUM7SUFFTyxLQUFLLENBQUMsY0FBYyxDQUMxQixPQUFnQjtRQUVoQixNQUFNLE1BQU0sR0FBRyxzQkFBaUIsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDdEQsTUFBTSxhQUFhLEdBQUcsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3BELE1BQU0sTUFBTSxHQUFHO1lBQ2IsWUFBWSxFQUFFLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDO1lBQzdELGFBQWEsRUFBRSxTQUFTO1NBQ3pCLENBQUM7UUFFRixNQUFNLGVBQWUsR0FDbEIsYUFBYSxDQUFDLGFBQXFDLEVBQUUsVUFBVSxLQUFLLEtBQUssQ0FBQztRQUM3RSxNQUFNLGlCQUFpQixHQUFHLGFBQWEsQ0FBQyxhQUFhLEVBQUUsUUFBUSxDQUM3RCxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FDakMsQ0FBQztRQUVGLElBQUksaUJBQWlCLElBQUksQ0FBQyxlQUFlLEVBQUU7WUFDekMsTUFBTSxDQUFDLGFBQWEsR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQzVDLE9BQU8sRUFDUCxrQ0FBYSxDQUFDLHVCQUF1QixDQUFDLGFBQWEsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLENBQ3RFLENBQUM7U0FDSDtRQUVELE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUM7SUFFTyxLQUFLLENBQUMsa0JBQWtCLENBQUMsT0FBZ0I7UUFDL0MsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFDcEYsQ0FBQztJQUVPLEtBQUssQ0FBQyxZQUFZLENBQUMsT0FBZ0I7UUFDekMsTUFBTSxFQUNKLGNBQWMsRUFBRSxZQUFZLEVBQzVCLFNBQVMsRUFDVCxlQUFlLEVBQUUsY0FBYyxHQUNoQyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDO1FBRXpCLE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQzFDLHNCQUFpQixDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsRUFDdEMsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxFQUM3QixJQUFJLGdDQUFXLENBQUM7WUFDZCxTQUFTLEVBQUUsU0FBUztZQUNwQixLQUFLLEVBQUUsY0FBYztZQUNyQixNQUFNLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsQ0FBQztTQUNsQyxDQUFDLENBQ0gsQ0FBQztRQUVGLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDdEIsR0FBRyxFQUFFLEdBQUcsQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFXO1lBQ3RDLEtBQUssRUFBRSxHQUFHLENBQUMsS0FBZTtTQUMzQixDQUFDLENBQUMsQ0FBQztJQUNOLENBQUM7SUFFTyxLQUFLLENBQUMsYUFBYSxDQUFDLE9BQWdCO1FBQzFDLE1BQU0sRUFDSixTQUFTLEVBQ1QsZUFBZSxFQUFFLGNBQWMsRUFDL0IsbUJBQW1CLEVBQUUsZ0JBQWdCLEVBQ3JDLFVBQVUsRUFBRSxTQUFTLEdBQ3RCLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUM7UUFFekIsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FDMUMsc0JBQWlCLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxFQUN0QyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQzdCLElBQUksZ0NBQVcsQ0FBQztZQUNkLFNBQVMsRUFBRSxTQUFTO1lBQ3BCLEtBQUssRUFBRSxjQUFjO1lBQ3JCLE1BQU0sRUFBRSxDQUFDLEVBQUUsS0FBSyxFQUFFLGdCQUFnQixFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsQ0FBQztTQUM1RCxDQUFDLENBQ0gsQ0FBQztRQUVGLE1BQU0sTUFBTSxHQUFHLEVBQUUsQ0FBQztRQUNsQixJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQ2pCLE1BQU0sQ0FBQyxnQkFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLGdCQUFnQixDQUFXLENBQUMsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FDbEYsR0FBRyxDQUFDLEtBQUssQ0FDVixDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7UUFFSCxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUNyRixNQUFNLElBQUksR0FBRyxnQkFBUSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRXZELE1BQU0sVUFBVSxHQUFHLEVBQUUsQ0FBQztRQUN0QixNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRXhDLEtBQ0UsSUFBSSxPQUFPLEdBQUcsZ0JBQVEsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQ3hDLE9BQU8sSUFBSSxJQUFJLEVBQ2YsT0FBTyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQzFDO1lBQ0EsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUN2QyxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQy9DLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1NBQy9DO1FBRUQsT0FBTyxVQUFVLENBQUM7SUFDcEIsQ0FBQztJQUVPLEtBQUssQ0FBQyxvQkFBb0IsQ0FDaEMsT0FBZ0I7UUFFaEIsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUM7UUFDakMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBbUIsQ0FBQztRQUV2RixJQUFJLFVBQWtCLENBQUM7UUFDdkIsSUFBSSxNQUFjLENBQUM7UUFDbkIsSUFBSSxXQUF3QixDQUFDO1FBRTdCLElBQUksS0FBSyxFQUFFLElBQUksS0FBSyxXQUFXLEVBQUU7WUFDL0IsTUFBTSxPQUFPLEdBQUcsb0NBQWUsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1lBRTdGLElBQUksT0FBTyxFQUFFO2dCQUNYLFVBQVUsR0FBRyxLQUFLLENBQUMsaUJBQWlCLENBQUM7Z0JBQ3JDLE1BQU0sR0FBRyxDQUFDLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDdkQsV0FBVyxHQUFHLElBQUksZ0NBQVcsQ0FBQztvQkFDNUIsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTO29CQUN6QixLQUFLLEVBQUUsSUFBSSxDQUFDLGVBQWU7b0JBQzNCLE1BQU0sRUFBRSxDQUFDLEVBQUUsS0FBSyxFQUFFLEdBQUcsT0FBTyxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDO2lCQUN0RCxDQUFDLENBQUM7YUFDSjtTQUNGO1FBRUQsSUFBSSxLQUFLLEVBQUUsSUFBSSxLQUFLLFlBQVksRUFBRTtZQUNoQyxNQUFNLE1BQU0sR0FBRyxvQ0FBZSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLENBQUM7WUFDMUYsTUFBTSxNQUFNLEdBQUcsb0NBQWUsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1lBRTFGLElBQUksTUFBTSxJQUFJLE1BQU0sRUFBRTtnQkFDcEIsVUFBVSxHQUFHLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQztnQkFDckMsTUFBTSxHQUFHLENBQUMsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUN0RCxXQUFXLEdBQUcsSUFBSSxnQ0FBVyxDQUFDO29CQUM1QixTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7b0JBQ3pCLEtBQUssRUFBRSxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sSUFBSSxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUk7b0JBQ3hFLE1BQU0sRUFBRSxDQUFDLEVBQUUsS0FBSyxFQUFFLEdBQUcsTUFBTSxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDO2lCQUNyRCxDQUFDLENBQUM7YUFDSjtTQUNGO1FBRUQsSUFBSSxVQUFVLElBQUksTUFBTSxJQUFJLFdBQVcsRUFBRTtZQUN2QyxNQUFNLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxVQUFVO2lCQUMvQixhQUFhLENBQUMsVUFBVSxDQUFDO2lCQUN6QixTQUFTLENBQUMsc0JBQWlCLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBRTlGLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7Z0JBQ3RCLEdBQUcsRUFBRSxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFXO2dCQUNyRCxLQUFLLEVBQUUsR0FBRyxDQUFDLEtBQWU7YUFDM0IsQ0FBQyxDQUFDLENBQUM7U0FDTDtRQUVELE1BQU0sSUFBSSxvQ0FBZSxDQUN2Qiw4RUFBOEUsQ0FDL0UsQ0FBQztJQUNKLENBQUM7SUFFTyxLQUFLLENBQUMsWUFBWSxDQUFDLE9BQWdCLEVBQUUsTUFBYztRQUN6RCxNQUFNLEVBQUUsU0FBUyxFQUFFLGVBQWUsRUFBRSxjQUFjLEVBQUUsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQztRQUM1RSxNQUFNLFdBQVcsR0FBRyxJQUFJLGdDQUFXLENBQUMsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxjQUFjLEVBQUUsQ0FBQyxDQUFDO1FBRXJGLE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQzFDLHNCQUFpQixDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsRUFDdEMsTUFBTSxFQUNOLFdBQVcsQ0FDWixDQUFDO1FBRUYsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3JELENBQUM7SUFFTyxLQUFLLENBQUMsU0FBUyxDQUFDLE9BQWdCO1FBQ3RDLE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFbkYsT0FBTyxnQ0FBb0IsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDckUsQ0FBQzs7QUFwTkgsd0JBcU5DO0FBcE55QixhQUFPLEdBQWtDO0lBQy9ELEdBQUcsRUFBRSxZQUFZO0lBQ2pCLElBQUksRUFBRSxXQUFXO0lBQ2pCLEtBQUssRUFBRSxRQUFRO0lBQ2YsSUFBSSxFQUFFLE1BQU07Q0FDYixDQUFDIn0=
|
|
@@ -20,9 +20,9 @@ class ScopeInvalidation extends base_route_1.default {
|
|
|
20
20
|
if (Number.isNaN(renderingId)) {
|
|
21
21
|
throw new datasource_toolkit_1.ValidationError('Malformed body');
|
|
22
22
|
}
|
|
23
|
-
this.services.
|
|
23
|
+
this.services.authorization.invalidateScopeCache(renderingId);
|
|
24
24
|
context.response.status = types_1.HttpCode.NoContent;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
exports.default = ScopeInvalidation;
|
|
28
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
28
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NvcGUtaW52YWxpZGF0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3JvdXRlcy9zZWN1cml0eS9zY29wZS1pbnZhbGlkYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFDQSx3RUFBa0U7QUFHbEUsdUNBQWtEO0FBQ2xELCtEQUFzQztBQUV0QyxNQUFxQixpQkFBa0IsU0FBUSxvQkFBUztJQUF4RDs7UUFDVyxTQUFJLEdBQUcsaUJBQVMsQ0FBQyxZQUFZLENBQUM7SUFrQnpDLENBQUM7SUFoQkMsV0FBVyxDQUFDLE1BQWM7UUFDeEIsTUFBTSxDQUFDLElBQUksQ0FBQywyQkFBMkIsRUFBRSxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQzVFLENBQUM7SUFFRCwwRkFBMEY7SUFDbEYsS0FBSyxDQUFDLGVBQWUsQ0FBQyxPQUFnQjtRQUM1QyxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFFOUQsSUFBSSxNQUFNLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFO1lBQzdCLE1BQU0sSUFBSSxvQ0FBZSxDQUFDLGdCQUFnQixDQUFDLENBQUM7U0FDN0M7UUFFRCxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxvQkFBb0IsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUU5RCxPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxnQkFBUSxDQUFDLFNBQVMsQ0FBQztJQUMvQyxDQUFDO0NBQ0Y7QUFuQkQsb0NBbUJDIn0=
|
|
@@ -15,5 +15,7 @@ export default class AuthorizationService {
|
|
|
15
15
|
private assertCanOnCollection;
|
|
16
16
|
assertCanExecuteCustomAction(context: Context, customActionName: string, collectionName: string): Promise<void>;
|
|
17
17
|
getScope(collection: Collection, context: Context): Promise<ConditionTree>;
|
|
18
|
+
assertCanRetrieveChart(context: Context): Promise<void>;
|
|
19
|
+
invalidateScopeCache(renderingId: number): void;
|
|
18
20
|
}
|
|
19
21
|
//# sourceMappingURL=authorization.d.ts.map
|
|
@@ -53,6 +53,20 @@ class AuthorizationService {
|
|
|
53
53
|
return null;
|
|
54
54
|
return datasource_toolkit_1.ConditionTreeFactory.fromPlainObject(scope);
|
|
55
55
|
}
|
|
56
|
+
async assertCanRetrieveChart(context) {
|
|
57
|
+
const { renderingId, id: userId } = context.state.user;
|
|
58
|
+
const { body: chartRequest } = context.request;
|
|
59
|
+
if (!(await this.renderingPermissionService.canRetrieveChart({
|
|
60
|
+
renderingId,
|
|
61
|
+
userId,
|
|
62
|
+
chartRequest,
|
|
63
|
+
}))) {
|
|
64
|
+
context.throw(403, 'Forbidden');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
invalidateScopeCache(renderingId) {
|
|
68
|
+
this.renderingPermissionService.invalidateCache(renderingId);
|
|
69
|
+
}
|
|
56
70
|
}
|
|
57
71
|
exports.default = AuthorizationService;
|
|
58
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
72
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aG9yaXphdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zZXJ2aWNlcy9hdXRob3JpemF0aW9uL2F1dGhvcml6YXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFFQSx3RUFBa0c7QUFDbEcsNENBQTRFO0FBQzVFLHNGQUcrQztBQUkvQyxNQUFxQixvQkFBb0I7SUFDdkMsWUFDbUIsdUJBQWdELEVBQ2hELDBCQUFzRDtRQUR0RCw0QkFBdUIsR0FBdkIsdUJBQXVCLENBQXlCO1FBQ2hELCtCQUEwQixHQUExQiwwQkFBMEIsQ0FBNEI7SUFDdEUsQ0FBQztJQUVHLEtBQUssQ0FBQyxlQUFlLENBQUMsT0FBZ0IsRUFBRSxjQUFzQjtRQUNuRSxNQUFNLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxPQUFPLEVBQUUsNkJBQXFCLENBQUMsTUFBTSxFQUFFLGNBQWMsQ0FBQyxDQUFDO0lBQzFGLENBQUM7SUFFTSxLQUFLLENBQUMsYUFBYSxDQUFDLE9BQWdCLEVBQUUsY0FBc0I7UUFDakUsTUFBTSxJQUFJLENBQUMscUJBQXFCLENBQUMsT0FBTyxFQUFFLDZCQUFxQixDQUFDLElBQUksRUFBRSxjQUFjLENBQUMsQ0FBQztJQUN4RixDQUFDO0lBRU0sS0FBSyxDQUFDLFlBQVksQ0FBQyxPQUFnQixFQUFFLGNBQXNCO1FBQ2hFLE1BQU0sSUFBSSxDQUFDLHFCQUFxQixDQUFDLE9BQU8sRUFBRSw2QkFBcUIsQ0FBQyxHQUFHLEVBQUUsY0FBYyxDQUFDLENBQUM7SUFDdkYsQ0FBQztJQUVNLEtBQUssQ0FBQyxhQUFhLENBQUMsT0FBZ0IsRUFBRSxjQUFzQjtRQUNqRSxNQUFNLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxPQUFPLEVBQUUsNkJBQXFCLENBQUMsSUFBSSxFQUFFLGNBQWMsQ0FBQyxDQUFDO0lBQ3hGLENBQUM7SUFFTSxLQUFLLENBQUMsZUFBZSxDQUFDLE9BQWdCLEVBQUUsY0FBc0I7UUFDbkUsTUFBTSxJQUFJ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
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AgentOptionsWithDefaults } from '../../../types';
|
|
2
|
-
export declare type ActionPermissionOptions = Pick<AgentOptionsWithDefaults, 'forestServerUrl' | 'envSecret' | 'isProduction' | 'permissionsCacheDurationInSeconds'>;
|
|
2
|
+
export declare type ActionPermissionOptions = Pick<AgentOptionsWithDefaults, 'forestServerUrl' | 'envSecret' | 'isProduction' | 'permissionsCacheDurationInSeconds' | 'logger'>;
|
|
3
3
|
export default class ActionPermissionService {
|
|
4
4
|
private readonly options;
|
|
5
5
|
private permissionsPromise;
|
|
@@ -35,6 +35,7 @@ class ActionPermissionService {
|
|
|
35
35
|
allowRefetch: false,
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
|
+
this.options.logger('Debug', `User ${userId} is ${isAllowed ? '' : 'not '}allowed to perform ${actionNames.length > 1 ? ' one of ' : ''}${actionNames.join(', ')}`);
|
|
38
39
|
return isAllowed;
|
|
39
40
|
}
|
|
40
41
|
isAllowedOneOf({ permissions, actionNames, userId, }) {
|
|
@@ -57,6 +58,7 @@ class ActionPermissionService {
|
|
|
57
58
|
return this.permissionsPromise;
|
|
58
59
|
}
|
|
59
60
|
async fetchEnvironmentPermissions() {
|
|
61
|
+
this.options.logger('Debug', 'Fetching environment permissions');
|
|
60
62
|
const [rawPermissions, users] = await Promise.all([
|
|
61
63
|
forest_http_api_1.default.getEnvironmentPermissions(this.options),
|
|
62
64
|
forest_http_api_1.default.getUsers(this.options),
|
|
@@ -65,4 +67,4 @@ class ActionPermissionService {
|
|
|
65
67
|
}
|
|
66
68
|
}
|
|
67
69
|
exports.default = ActionPermissionService;
|
|
68
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
70
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLXBlcm1pc3Npb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvc2VydmljZXMvYXV0aG9yaXphdGlvbi9pbnRlcm5hbC9hY3Rpb24tcGVybWlzc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUNBLHFGQUEyRDtBQUMzRCw0R0FFNkM7QUFPN0MsTUFBcUIsdUJBQXVCO0lBSTFDLFlBQTZCLE9BQWdDO1FBQWhDLFlBQU8sR0FBUCxPQUFPLENBQXlCO0lBQUcsQ0FBQztJQUUxRCxRQUFRLENBQUMsTUFBYyxFQUFFLFdBQXFCO1FBQ25ELE9BQU8sSUFBSSxDQUFDLHNCQUFzQixDQUFDO1lBQ2pDLE1BQU07WUFDTixXQUFXO1lBQ1gsWUFBWSxFQUFFLElBQUk7U0FDbkIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVNLEdBQUcsQ0FBQyxNQUFjLEVBQUUsVUFBa0I7UUFDM0MsT0FBTyxJQUFJLENBQUMsc0JBQXNCLENBQUM7WUFDakMsTUFBTTtZQUNOLFdBQVcsRUFBRSxDQUFDLFVBQVUsQ0FBQztZQUN6QixZQUFZLEVBQUUsSUFBSTtTQUNuQixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sS0FBSyxDQUFDLHNCQUFzQixDQUFDLEVBQ25DLE1BQU0sRUFDTixXQUFXLEVBQ1gsWUFBWSxHQUtiO1FBQ0MsTUFBTSxXQUFXLEdBQUcsTUFBTSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDaEQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxFQUFFLFdBQVcsRUFBRSxXQUFXLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUU1RSxJQUFJLENBQUMsU0FBUyxJQUFJLFlBQVksRUFBRTtZQUM5QixJQUFJLENBQUMsa0JBQWtCLEdBQUcsU0FBUyxDQUFDO1lBQ3BDLElBQUksQ0FBQyw2QkFBNkIsR0FBRyxTQUFTLENBQUM7WUFFL0MsT0FBTyxJQUFJLENBQUMsc0JBQXNCLENBQUM7Z0JBQ2pDLE1BQU07Z0JBQ04sV0FBVztnQkFDWCxZQUFZLEVBQUUsS0FBSzthQUNwQixDQUFDLENBQUM7U0FDSjtRQUVELElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUNqQixPQUFPLEVBQ1AsUUFBUSxNQUFNLE9BQU8sU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sc0JBQzFDLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEVBQ3hDLEdBQUcsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUM1QixDQUFDO1FBRUYsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUVPLGNBQWMsQ0FBQyxFQUNyQixXQUFXLEVBQ1gsV0FBVyxFQUNYLE1BQU0sR0FLUDtRQUNDLE9BQU8sV0FBVyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQztJQUM3RixDQUFDO0lBRU8sU0FBUyxDQUFDLEVBQ2hCLFdBQVcsRUFDWCxVQUFVLEVBQ1YsTUFBTSxHQUtQO1FBQ0MsT0FBTyxDQUNMLFdBQVcsQ0FBQyxpQkFBaUI7WUFDN0IsV0FBVyxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUM7WUFDbEQsV0FBVyxDQUFDLG9CQUFvQixDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLENBQzlELENBQUM7SUFDSixDQUFDO0lBRU8sS0FBSyxDQUFDLGNBQWM7UUFDMUIsSUFDRSxJQUFJLENBQUMsa0JBQWtCO1lBQ3ZCLElBQUksQ0FBQyw2QkFBNkI7WUFDbEMsSUFBSSxDQUFDLDZCQUE2QixHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsRUFDL0M7WUFDQSxPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQztTQUNoQztRQUVELElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMsMkJBQTJCLEVBQUUsQ0FBQztRQUM3RCxJQUFJLENBQUMsNkJBQTZCO1lBQ2hDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLGlDQUFpQyxHQUFHLElBQUksQ0FBQztRQUVyRSxPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQztJQUNqQyxDQUFDO0lBRU8sS0FBSyxDQUFDLDJCQUEyQjtRQUN2QyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsa0NBQWtDLENBQUMsQ0FBQztRQUVqRSxNQUFNLENBQUMsY0FBYyxFQUFFLEtBQUssQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUNoRCx5QkFBYSxDQUFDLHlCQUF5QixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7WUFDckQseUJBQWEsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztTQUNyQyxDQUFDLENBQUM7UUFFSCxPQUFPLElBQUEsMkNBQThCLEVBQUMsY0FBYyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQy9ELENBQUM7Q0FDRjtBQTdHRCwwQ0E2R0MifQ==
|
|
@@ -0,0 +1,48 @@
|
|
|
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
|
+
exports.hashChartRequest = exports.hashServerCharts = void 0;
|
|
7
|
+
const object_hash_1 = __importDefault(require("object-hash"));
|
|
8
|
+
function hashServerCharts(chartsByType) {
|
|
9
|
+
const serverCharts = Object.entries(chartsByType)
|
|
10
|
+
.filter(([key]) => key !== 'queries')
|
|
11
|
+
.map(([, value]) => value)
|
|
12
|
+
.flat();
|
|
13
|
+
const frontendCharts = serverCharts.map(chart => ({
|
|
14
|
+
type: chart.type,
|
|
15
|
+
filters: chart.filter,
|
|
16
|
+
aggregate: chart.aggregator,
|
|
17
|
+
aggregate_field: chart.aggregateFieldName,
|
|
18
|
+
collection: chart.sourceCollectionId,
|
|
19
|
+
time_range: chart.timeRange,
|
|
20
|
+
group_by_date_field: (chart.type === 'Line' && chart.groupByFieldName) || null,
|
|
21
|
+
group_by_field: (chart.type !== 'Line' && chart.groupByFieldName) || null,
|
|
22
|
+
limit: chart.limit,
|
|
23
|
+
label_field: chart.labelFieldName,
|
|
24
|
+
relationship_field: chart.relationshipFieldName,
|
|
25
|
+
}));
|
|
26
|
+
const hashes = frontendCharts.map(chart => (0, object_hash_1.default)(chart, {
|
|
27
|
+
respectType: false,
|
|
28
|
+
excludeKeys: key => chart[key] === null || chart[key] === undefined,
|
|
29
|
+
}));
|
|
30
|
+
return new Set(hashes);
|
|
31
|
+
}
|
|
32
|
+
exports.hashServerCharts = hashServerCharts;
|
|
33
|
+
function hashChartRequest(chart) {
|
|
34
|
+
const hashed = {
|
|
35
|
+
...chart,
|
|
36
|
+
// When the server sends the data of the allowed charts, the target column is not specified
|
|
37
|
+
// for relations => allow them all.
|
|
38
|
+
...(chart?.group_by_field?.includes(':')
|
|
39
|
+
? { group_by_field: chart.group_by_field.substring(0, chart.group_by_field.indexOf(':')) }
|
|
40
|
+
: {}),
|
|
41
|
+
};
|
|
42
|
+
return (0, object_hash_1.default)(hashed, {
|
|
43
|
+
respectType: false,
|
|
44
|
+
excludeKeys: key => chart[key] === null,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
exports.hashChartRequest = hashChartRequest;
|
|
48
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFzaC1jaGFydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zZXJ2aWNlcy9hdXRob3JpemF0aW9uL2ludGVybmFsL2hhc2gtY2hhcnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsOERBQXFDO0FBSXJDLFNBQWdCLGdCQUFnQixDQUFDLFlBQXVDO0lBQ3RFLE1BQU0sWUFBWSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDO1NBQzlDLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsS0FBSyxTQUFTLENBQUM7U0FDcEMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUM7U0FDekIsSUFBSSxFQUFFLENBQUM7SUFFVixNQUFNLGNBQWMsR0FBRyxZQUFZLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNoRCxJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUk7UUFDaEIsT0FBTyxFQUFFLEtBQUssQ0FBQyxNQUFNO1FBQ3JCLFNBQVMsRUFBRSxLQUFLLENBQUMsVUFBVTtRQUMzQixlQUFlLEVBQUUsS0FBSyxDQUFDLGtCQUFrQjtRQUN6QyxVQUFVLEVBQUUsS0FBSyxDQUFDLGtCQUFrQjtRQUNwQyxVQUFVLEVBQUUsS0FBSyxDQUFDLFNBQVM7UUFDM0IsbUJBQW1CLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxLQUFLLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxJQUFJO1FBQzlFLGNBQWMsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssTUFBTSxJQUFJLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLElBQUk7UUFDekUsS0FBSyxFQUFFLEtBQUssQ0FBQyxLQUFLO1FBQ2xCLFdBQVcsRUFBRSxLQUFLLENBQUMsY0FBYztRQUNqQyxrQkFBa0IsRUFBRSxLQUFLLENBQUMscUJBQXFCO0tBQ2hELENBQUMsQ0FBQyxDQUFDO0lBRUosTUFBTSxNQUFNLEdBQUcsY0FBYyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUN4QyxJQUFBLHFCQUFVLEVBQUMsS0FBSyxFQUFFO1FBQ2hCLFdBQVcsRUFBRSxLQUFLO1FBQ2xCLFdBQVcsRUFBRSxHQUFHLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxJQUFJLElBQUksS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLFNBQVM7S0FDcEUsQ0FBQyxDQUNILENBQUM7SUFFRixPQUFPLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0FBQ3pCLENBQUM7QUE1QkQsNENBNEJDO0FBRUQsU0FBZ0IsZ0JBQWdCLENBQUMsS0FBVTtJQUN6QyxNQUFNLE1BQU0sR0FBRztRQUNiLEdBQUcsS0FBSztRQUNSLDJGQUEyRjtRQUMzRixtQ0FBbUM7UUFDbkMsR0FBRyxDQUFDLEtBQUssRUFBRSxjQUFjLEVBQUUsUUFBUSxDQUFDLEdBQUcsQ0FBQztZQUN0QyxDQUFDLENBQUMsRUFBRSxjQUFjLEVBQUUsS0FBSyxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUU7WUFDMUYsQ0FBQyxDQUFDLEVBQUUsQ0FBQztLQUNSLENBQUM7SUFFRixPQUFPLElBQUEscUJBQVUsRUFBQyxNQUFNLEVBQUU7UUFDeEIsV0FBVyxFQUFFLEtBQUs7UUFDbEIsV0FBVyxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLElBQUk7S0FDeEMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQWRELDRDQWNDIn0=
|
|
@@ -2,7 +2,7 @@ import { GenericTree } from '@forestadmin/datasource-toolkit';
|
|
|
2
2
|
import { AgentOptionsWithDefaults } from '../../../types';
|
|
3
3
|
import { User } from './types';
|
|
4
4
|
import UserPermissionService from './user-permission';
|
|
5
|
-
export declare type RenderingPermissionOptions = Pick<AgentOptionsWithDefaults, 'forestServerUrl' | 'envSecret' | 'isProduction' | 'permissionsCacheDurationInSeconds'>;
|
|
5
|
+
export declare type RenderingPermissionOptions = Pick<AgentOptionsWithDefaults, 'forestServerUrl' | 'envSecret' | 'isProduction' | 'permissionsCacheDurationInSeconds' | 'logger'>;
|
|
6
6
|
export default class RenderingPermissionService {
|
|
7
7
|
private readonly options;
|
|
8
8
|
private readonly userPermissions;
|
|
@@ -14,5 +14,13 @@ export default class RenderingPermissionService {
|
|
|
14
14
|
user: User;
|
|
15
15
|
}): Promise<GenericTree>;
|
|
16
16
|
private getScopeOrRetry;
|
|
17
|
+
private loadPermissions;
|
|
18
|
+
canRetrieveChart({ renderingId, chartRequest, userId, }: {
|
|
19
|
+
renderingId: number;
|
|
20
|
+
chartRequest: any;
|
|
21
|
+
userId: number;
|
|
22
|
+
}): Promise<boolean>;
|
|
23
|
+
private canRetrieveChartHashOrRetry;
|
|
24
|
+
invalidateCache(renderingId: any): void;
|
|
17
25
|
}
|
|
18
26
|
//# sourceMappingURL=rendering-permission.d.ts.map
|
|
@@ -4,6 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const lru_cache_1 = __importDefault(require("lru-cache"));
|
|
7
|
+
const types_1 = require("./types");
|
|
8
|
+
const hash_chart_1 = require("./hash-chart");
|
|
7
9
|
const forest_http_api_1 = __importDefault(require("../../../utils/forest-http-api"));
|
|
8
10
|
const generate_user_scope_1 = __importDefault(require("./generate-user-scope"));
|
|
9
11
|
class RenderingPermissionService {
|
|
@@ -13,7 +15,7 @@ class RenderingPermissionService {
|
|
|
13
15
|
this.permissionsByRendering = new lru_cache_1.default({
|
|
14
16
|
max: 256,
|
|
15
17
|
ttl: this.options.permissionsCacheDurationInSeconds * 1000,
|
|
16
|
-
fetchMethod: renderingId =>
|
|
18
|
+
fetchMethod: renderingId => this.loadPermissions(renderingId),
|
|
17
19
|
});
|
|
18
20
|
}
|
|
19
21
|
async getScope({ renderingId, collectionName, user, }) {
|
|
@@ -27,13 +29,53 @@ class RenderingPermissionService {
|
|
|
27
29
|
const collectionPermissions = permissions?.collections?.[collectionName];
|
|
28
30
|
if (!collectionPermissions) {
|
|
29
31
|
if (allowRetry) {
|
|
30
|
-
this.
|
|
32
|
+
this.invalidateCache(renderingId);
|
|
31
33
|
return this.getScopeOrRetry({ renderingId, collectionName, user, allowRetry: false });
|
|
32
34
|
}
|
|
33
35
|
return null;
|
|
34
36
|
}
|
|
35
37
|
return (0, generate_user_scope_1.default)(collectionPermissions.scope, permissions.team, userInfo);
|
|
36
38
|
}
|
|
39
|
+
async loadPermissions(renderingId) {
|
|
40
|
+
this.options.logger('Debug', `Loading rendering permissions for rendering ${renderingId}`);
|
|
41
|
+
const rawPermissions = await forest_http_api_1.default.getRenderingPermissions(renderingId, this.options);
|
|
42
|
+
return {
|
|
43
|
+
team: rawPermissions.team,
|
|
44
|
+
collections: rawPermissions.collections,
|
|
45
|
+
charts: (0, hash_chart_1.hashServerCharts)(rawPermissions.stats),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async canRetrieveChart({ renderingId, chartRequest, userId, }) {
|
|
49
|
+
const chartHash = (0, hash_chart_1.hashChartRequest)(chartRequest);
|
|
50
|
+
return this.canRetrieveChartHashOrRetry({ renderingId, chartHash, userId, allowRetry: true });
|
|
51
|
+
}
|
|
52
|
+
async canRetrieveChartHashOrRetry({ renderingId, userId, chartHash, allowRetry, }) {
|
|
53
|
+
const [userInfo, permissions] = await Promise.all([
|
|
54
|
+
this.userPermissions.getUserInfo(userId),
|
|
55
|
+
this.permissionsByRendering.fetch(renderingId),
|
|
56
|
+
]);
|
|
57
|
+
if ([types_1.PermissionLevel.Admin, types_1.PermissionLevel.Developer, types_1.PermissionLevel.Editor].includes(userInfo?.permissionLevel) ||
|
|
58
|
+
permissions.charts.has(chartHash)) {
|
|
59
|
+
this.options.logger('Debug', `User ${userId} can retrieve chart on rendering ${renderingId}`);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
if (allowRetry) {
|
|
63
|
+
this.invalidateCache(renderingId);
|
|
64
|
+
this.userPermissions.clearCache();
|
|
65
|
+
return this.canRetrieveChartHashOrRetry({
|
|
66
|
+
renderingId,
|
|
67
|
+
userId,
|
|
68
|
+
chartHash,
|
|
69
|
+
allowRetry: false,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
this.options.logger('Debug', `User ${userId} cannot retrieve chart on rendering ${renderingId}`);
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
invalidateCache(renderingId) {
|
|
76
|
+
this.options.logger('Debug', `Invalidating rendering permissions cache for rendering ${renderingId}`);
|
|
77
|
+
this.permissionsByRendering.del(renderingId);
|
|
78
|
+
}
|
|
37
79
|
}
|
|
38
80
|
exports.default = RenderingPermissionService;
|
|
39
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
81
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVuZGVyaW5nLXBlcm1pc3Npb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvc2VydmljZXMvYXV0aG9yaXphdGlvbi9pbnRlcm5hbC9yZW5kZXJpbmctcGVybWlzc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUNBLDBEQUFpQztBQUdqQyxtQ0FPaUI7QUFDakIsNkNBQWtFO0FBQ2xFLHFGQUEyRDtBQUUzRCxnRkFBc0Q7QUFhdEQsTUFBcUIsMEJBQTBCO0lBRzdDLFlBQ21CLE9BQW1DLEVBQ25DLGVBQXNDO1FBRHRDLFlBQU8sR0FBUCxPQUFPLENBQTRCO1FBQ25DLG9CQUFlLEdBQWYsZUFBZSxDQUF1QjtRQUV2RCxJQUFJLENBQUMsc0JBQXNCLEdBQUcsSUFBSSxtQkFBUSxDQUFDO1lBQ3pDLEdBQUcsRUFBRSxHQUFHO1lBQ1IsR0FBRyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsaUNBQWlDLEdBQUcsSUFBSTtZQUMxRCxXQUFXLEVBQUUsV0FBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLFdBQVcsQ0FBQztTQUM5RCxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU0sS0FBSyxDQUFDLFFBQVEsQ0FBQyxFQUNwQixXQUFXLEVBQ1gsY0FBYyxFQUNkLElBQUksR0FLTDtRQUNDLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxFQUFFLFdBQVcsRUFBRSxjQUFjLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZGLENBQUM7SUFFTyxLQUFLLENBQUMsZUFBZSxDQUFDLEVBQzVCLFdBQVcsRUFDWCxjQUFjLEVBQ2QsSUFBSSxFQUNKLFVBQVUsR0FNWDtRQUNDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsUUFBUSxDQUFDLEdBQThDLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUMzRixJQUFJLENBQUMsc0JBQXNCLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQztZQUM5QyxJQUFJLENBQUMsZUFBZSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1NBQzFDLENBQUMsQ0FBQztRQUVILE1BQU0scUJBQXFCLEdBQUcsV0FBVyxFQUFFLFdBQVcsRUFBRSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBRXpFLElBQUksQ0FBQyxxQkFBcUIsRUFBRTtZQUMxQixJQUFJLFVBQVUsRUFBRTtnQkFDZCxJQUFJLENBQUMsZUFBZSxDQUFDLFdBQVcsQ0FBQyxDQUFDO2dCQUVsQyxPQUFPLElBQUksQ0FBQyxlQUFlLENBQUMsRUFBRSxXQUFXLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQzthQUN2RjtZQUVELE9BQU8sSUFBSSxDQUFDO1NBQ2I7UUFFRCxPQUFPLElBQUEsNkJBQWlCLEVBQUMscUJBQXFCLENBQUMsS0FBSyxFQUFFLFdBQVcsQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDcEYsQ0FBQztJQUVPLEtBQUssQ0FBQyxlQUFlLENBQUMsV0FBbUI7UUFDL0MsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLCtDQUErQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO1FBRTNGLE1BQU0sY0FBYyxHQUFHLE1BQU0seUJBQWEsQ0FBQyx1QkFBdUIsQ0FBQyxXQUFXLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRTlGLE9BQU87WUFDTCxJQUFJLEVBQUUsY0FBYyxDQUFDLElBQUk7WUFDekIsV0FBVyxFQUFFLGNBQWMsQ0FBQyxXQUFXO1lBQ3ZDLE1BQU0sRUFBRSxJQUFBLDZCQUFnQixFQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUM7U0FDL0MsQ0FBQztJQUNKLENBQUM7SUFFTSxLQUFLLENBQUMsZ0JBQWdCLENBQUMsRUFDNUIsV0FBVyxFQUNYLFlBQVksRUFDWixNQUFNLEdBS1A7UUFDQyxNQUFNLFNBQVMsR0FBRyxJQUFBLDZCQUFnQixFQUFDLFlBQVksQ0FBQyxDQUFDO1FBRWpELE9BQU8sSUFBSSxDQUFDLDJCQUEyQixDQUFDLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDaEcsQ0FBQztJQUVPLEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxFQUN4QyxXQUFXLEVBQ1gsTUFBTSxFQUNOLFNBQVMsRUFDVCxVQUFVLEdBTVg7UUFDQyxNQUFNLENBQUMsUUFBUSxFQUFFLFdBQVcsQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUNoRCxJQUFJLENBQUMsZUFBZSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUM7WUFDeEMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUM7U0FDL0MsQ0FBQyxDQUFDO1FBRUgsSUFDRSxDQUFDLHVCQUFlLENBQUMsS0FBSyxFQUFFLHVCQUFlLENBQUMsU0FBUyxFQUFFLHVCQUFlLENBQUMsTUFBTSxDQUFDLENBQUMsUUFBUSxDQUNqRixRQUFRLEVBQUUsZUFBZSxDQUMxQjtZQUNELFdBQVcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxFQUNqQztZQUNBLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxRQUFRLE1BQU0sb0NBQW9DLFdBQVcsRUFBRSxDQUFDLENBQUM7WUFFOUYsT0FBTyxJQUFJLENBQUM7U0FDYjtRQUVELElBQUksVUFBVSxFQUFFO1lBQ2QsSUFBSSxDQUFDLGVBQWUsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUNsQyxJQUFJLENBQUMsZUFBZSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBRWxDLE9BQU8sSUFBSSxDQUFDLDJCQUEyQixDQUFDO2dCQUN0QyxXQUFXO2dCQUNYLE1BQU07Z0JBQ04sU0FBUztnQkFDVCxVQUFVLEVBQUUsS0FBSzthQUNsQixDQUFDLENBQUM7U0FDSjtRQUVELElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUNqQixPQUFPLEVBQ1AsUUFBUSxNQUFNLHVDQUF1QyxXQUFXLEVBQUUsQ0FDbkUsQ0FBQztRQUVGLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVNLGVBQWUsQ0FBQyxXQUFXO1FBQ2hDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUNqQixPQUFPLEVBQ1AsMERBQTBELFdBQVcsRUFBRSxDQUN4RSxDQUFDO1FBRUYsSUFBSSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUMvQyxDQUFDO0NBQ0Y7QUExSUQsNkNBMElDIn0=
|
|
@@ -34,6 +34,7 @@ export interface EnvironmentPermissionsV4Remote {
|
|
|
34
34
|
export declare enum PermissionLevel {
|
|
35
35
|
Admin = "admin",
|
|
36
36
|
Developer = "developer",
|
|
37
|
+
Editor = "editor",
|
|
37
38
|
User = "user"
|
|
38
39
|
}
|
|
39
40
|
export declare type UserPermissionV4 = {
|
|
@@ -75,10 +76,7 @@ export interface DisplaySettings {
|
|
|
75
76
|
height: number;
|
|
76
77
|
}
|
|
77
78
|
export interface BaseChart {
|
|
78
|
-
name: string;
|
|
79
|
-
description: string;
|
|
80
79
|
type: ChartType;
|
|
81
|
-
displaySettings: DisplaySettings;
|
|
82
80
|
}
|
|
83
81
|
export interface SmartRouteChart extends BaseChart {
|
|
84
82
|
type: Exclude<ChartType, ChartType.Smart>;
|
|
@@ -104,23 +102,61 @@ export interface SmartChart extends BaseChart {
|
|
|
104
102
|
};
|
|
105
103
|
id: string;
|
|
106
104
|
}
|
|
107
|
-
export
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
105
|
+
export interface LeaderboardChart extends BaseChart {
|
|
106
|
+
type: ChartType.Leaderboard;
|
|
107
|
+
sourceCollectionId: string | number;
|
|
108
|
+
labelFieldName: string;
|
|
109
|
+
relationshipFieldName: string;
|
|
110
|
+
aggregateFieldName: string | null;
|
|
111
|
+
aggregator: 'Sum' | 'Count';
|
|
112
|
+
limit: any;
|
|
113
|
+
}
|
|
114
|
+
export interface LineChart extends BaseChart {
|
|
115
|
+
type: ChartType.Line;
|
|
116
|
+
sourceCollectionId: string | number;
|
|
117
|
+
groupByFieldName: string;
|
|
118
|
+
aggregateFieldName: string | null;
|
|
119
|
+
aggregator: 'Sum' | 'Count';
|
|
120
|
+
timeRange: 'Day' | 'Week' | 'Month' | 'Year';
|
|
121
|
+
filter: Filter | null;
|
|
122
|
+
}
|
|
123
|
+
export interface ObjectiveChart extends BaseChart {
|
|
124
|
+
type: ChartType.Objective;
|
|
125
|
+
sourceCollectionId: string | number;
|
|
126
|
+
aggregateFieldName: string;
|
|
127
|
+
aggregator: 'Sum' | 'Count';
|
|
128
|
+
objective: number;
|
|
129
|
+
filter: Filter | null;
|
|
130
|
+
}
|
|
131
|
+
export interface PercentageChart extends BaseChart {
|
|
132
|
+
type: ChartType.Percentage;
|
|
133
|
+
numeratorChartId: string;
|
|
134
|
+
denominatorChartId: string;
|
|
135
|
+
}
|
|
136
|
+
export interface PieChart extends BaseChart {
|
|
137
|
+
type: ChartType.Pie;
|
|
138
|
+
sourceCollectionId: string | number;
|
|
139
|
+
aggregateFieldName: string;
|
|
140
|
+
groupByFieldName: string;
|
|
141
|
+
aggregator: 'Sum' | 'Count';
|
|
142
|
+
filter: Filter | null;
|
|
143
|
+
}
|
|
144
|
+
export interface ValueChart extends BaseChart {
|
|
145
|
+
type: ChartType.Value;
|
|
146
|
+
sourceCollectionId: string | number;
|
|
147
|
+
aggregateFieldName: string;
|
|
148
|
+
aggregator: 'Sum' | 'Count';
|
|
149
|
+
filter: Filter | null;
|
|
150
|
+
}
|
|
151
|
+
export declare type Chart = SmartChart | ApiRouteChart | QueryChart | SmartRouteChart | LeaderboardChart | LineChart | ObjectiveChart | PercentageChart | PieChart | ValueChart;
|
|
116
152
|
export interface RenderingChartDefinitions {
|
|
117
153
|
queries: string[];
|
|
118
|
-
leaderboards:
|
|
119
|
-
lines:
|
|
120
|
-
objectives:
|
|
121
|
-
percentages:
|
|
122
|
-
pies:
|
|
123
|
-
values:
|
|
154
|
+
leaderboards: LeaderboardChart[];
|
|
155
|
+
lines: LineChart[];
|
|
156
|
+
objectives: ObjectiveChart[];
|
|
157
|
+
percentages: PercentageChart[];
|
|
158
|
+
pies: PieChart[];
|
|
159
|
+
values: ValueChart[];
|
|
124
160
|
}
|
|
125
161
|
export interface CollectionColumn {
|
|
126
162
|
id: string | number;
|
|
@@ -5,6 +5,7 @@ var PermissionLevel;
|
|
|
5
5
|
(function (PermissionLevel) {
|
|
6
6
|
PermissionLevel["Admin"] = "admin";
|
|
7
7
|
PermissionLevel["Developer"] = "developer";
|
|
8
|
+
PermissionLevel["Editor"] = "editor";
|
|
8
9
|
PermissionLevel["User"] = "user";
|
|
9
10
|
})(PermissionLevel = exports.PermissionLevel || (exports.PermissionLevel = {}));
|
|
10
11
|
var CollectionActionEvent;
|
|
@@ -33,4 +34,4 @@ var ChartType;
|
|
|
33
34
|
ChartType["Percentage"] = "Percentage";
|
|
34
35
|
ChartType["Smart"] = "Smart";
|
|
35
36
|
})(ChartType = exports.ChartType || (exports.ChartType = {}));
|
|
36
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
37
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvc2VydmljZXMvYXV0aG9yaXphdGlvbi9pbnRlcm5hbC90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUF3Q0EsSUFBWSxlQUtYO0FBTEQsV0FBWSxlQUFlO0lBQ3pCLGtDQUFlLENBQUE7SUFDZiwwQ0FBdUIsQ0FBQTtJQUN2QixvQ0FBaUIsQ0FBQTtJQUNqQixnQ0FBYSxDQUFBO0FBQ2YsQ0FBQyxFQUxXLGVBQWUsR0FBZix1QkFBZSxLQUFmLHVCQUFlLFFBSzFCO0FBWUQsSUFBWSxxQkFPWDtBQVBELFdBQVkscUJBQXFCO0lBQy9CLDBDQUFpQixDQUFBO0lBQ2pCLDBDQUFpQixDQUFBO0lBQ2pCLHNDQUFhLENBQUE7SUFDYixzQ0FBYSxDQUFBO0lBQ2IsMENBQWlCLENBQUE7SUFDakIsb0NBQVcsQ0FBQTtBQUNiLENBQUMsRUFQVyxxQkFBcUIsR0FBckIsNkJBQXFCLEtBQXJCLDZCQUFxQixRQU9oQztBQUVELElBQVksaUJBS1g7QUFMRCxXQUFZLGlCQUFpQjtJQUMzQix3Q0FBbUIsQ0FBQTtJQUNuQix3Q0FBbUIsQ0FBQTtJQUNuQixpREFBNEIsQ0FBQTtJQUM1Qix5REFBb0MsQ0FBQTtBQUN0QyxDQUFDLEVBTFcsaUJBQWlCLEdBQWpCLHlCQUFpQixLQUFqQix5QkFBaUIsUUFLNUI7QUFFRCxJQUFZLFNBUVg7QUFSRCxXQUFZLFNBQVM7SUFDbkIsd0JBQVcsQ0FBQTtJQUNYLDRCQUFlLENBQUE7SUFDZix3Q0FBMkIsQ0FBQTtJQUMzQiwwQkFBYSxDQUFBO0lBQ2Isb0NBQXVCLENBQUE7SUFDdkIsc0NBQXlCLENBQUE7SUFDekIsNEJBQWUsQ0FBQTtBQUNqQixDQUFDLEVBUlcsU0FBUyxHQUFULGlCQUFTLEtBQVQsaUJBQVMsUUFRcEIifQ==
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { AgentOptionsWithDefaults } from '../../../types';
|
|
2
2
|
import { UserPermissionV4 } from './types';
|
|
3
|
-
export declare type UserPermissionOptions = Pick<AgentOptionsWithDefaults, 'forestServerUrl' | 'envSecret' | 'isProduction' | 'permissionsCacheDurationInSeconds'>;
|
|
3
|
+
export declare type UserPermissionOptions = Pick<AgentOptionsWithDefaults, 'forestServerUrl' | 'envSecret' | 'isProduction' | 'permissionsCacheDurationInSeconds' | 'logger'>;
|
|
4
4
|
export default class UserPermissionService {
|
|
5
5
|
private readonly options;
|
|
6
6
|
private cacheExpirationTimestamp;
|
|
7
7
|
private userInfoById;
|
|
8
8
|
constructor(options: UserPermissionOptions);
|
|
9
9
|
getUserInfo(userId: number): Promise<UserPermissionV4 | undefined>;
|
|
10
|
+
clearCache(): void;
|
|
10
11
|
}
|
|
11
12
|
//# sourceMappingURL=user-permission.d.ts.map
|
|
@@ -7,6 +7,7 @@ const forest_http_api_1 = __importDefault(require("../../../utils/forest-http-ap
|
|
|
7
7
|
class UserPermissionService {
|
|
8
8
|
constructor(options) {
|
|
9
9
|
this.options = options;
|
|
10
|
+
this.cacheExpirationTimestamp = 0;
|
|
10
11
|
// The trick here is to keep the cache as a Promise and not a Map
|
|
11
12
|
// in order to avoid doing the same HTTP request twice when
|
|
12
13
|
// 2 calls are made to getUserInfo at the same time.
|
|
@@ -18,6 +19,7 @@ class UserPermissionService {
|
|
|
18
19
|
!(await this.userInfoById).has(userId)) {
|
|
19
20
|
this.cacheExpirationTimestamp =
|
|
20
21
|
Date.now() + this.options.permissionsCacheDurationInSeconds * 1000;
|
|
22
|
+
this.options.logger('Debug', `Refreshing user permissions cache`);
|
|
21
23
|
// The response here is not awaited in order to be set in the cache
|
|
22
24
|
// allowing subsequent calls to getUserInfo to use the cache even if
|
|
23
25
|
// the response is not yet available.
|
|
@@ -25,6 +27,10 @@ class UserPermissionService {
|
|
|
25
27
|
}
|
|
26
28
|
return (await this.userInfoById).get(userId);
|
|
27
29
|
}
|
|
30
|
+
clearCache() {
|
|
31
|
+
this.userInfoById = null;
|
|
32
|
+
this.cacheExpirationTimestamp = Number.NEGATIVE_INFINITY;
|
|
33
|
+
}
|
|
28
34
|
}
|
|
29
35
|
exports.default = UserPermissionService;
|
|
30
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
36
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlci1wZXJtaXNzaW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3NlcnZpY2VzL2F1dGhvcml6YXRpb24vaW50ZXJuYWwvdXNlci1wZXJtaXNzaW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBRUEscUZBQTJEO0FBTzNELE1BQXFCLHFCQUFxQjtJQVF4QyxZQUE2QixPQUE4QjtRQUE5QixZQUFPLEdBQVAsT0FBTyxDQUF1QjtRQVBuRCw2QkFBd0IsR0FBRyxDQUFDLENBQUM7UUFFckMsaUVBQWlFO1FBQ2pFLDJEQUEyRDtRQUMzRCxvREFBb0Q7UUFDNUMsaUJBQVksR0FBMkMsSUFBSSxDQUFDO0lBRU4sQ0FBQztJQUV4RCxLQUFLLENBQUMsV0FBVyxDQUFDLE1BQWM7UUFDckMsSUFDRSxDQUFDLElBQUksQ0FBQyx3QkFBd0I7WUFDOUIsSUFBSSxDQUFDLHdCQUF3QixHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUU7WUFDMUMsQ0FBQyxDQUFDLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFDdEM7WUFDQSxJQUFJLENBQUMsd0JBQXdCO2dCQUMzQixJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQ0FBaUMsR0FBRyxJQUFJLENBQUM7WUFFckUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLG1DQUFtQyxDQUFDLENBQUM7WUFFbEUsbUVBQW1FO1lBQ25FLG9FQUFvRTtZQUNwRSxxQ0FBcUM7WUFDckMsSUFBSSxDQUFDLFlBQVksR0FBRyx5QkFBYSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUMzRCxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUNyRCxDQUFDO1NBQ0g7UUFFRCxPQUFPLENBQUMsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQy9DLENBQUM7SUFFTSxVQUFVO1FBQ2YsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUM7UUFDekIsSUFBSSxDQUFDLHdCQUF3QixHQUFHLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQztJQUMzRCxDQUFDO0NBQ0Y7QUFwQ0Qsd0NBb0NDIn0=
|
package/dist/services/index.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { AgentOptionsWithDefaults } from '../types';
|
|
2
2
|
import AuthorizationService from './authorization/authorization';
|
|
3
|
-
import PermissionService from './permissions';
|
|
4
3
|
import Serializer from './serializer';
|
|
5
4
|
export declare type ForestAdminHttpDriverServices = {
|
|
6
|
-
permissions: PermissionService;
|
|
7
5
|
serializer: Serializer;
|
|
8
6
|
authorization: AuthorizationService;
|
|
9
7
|
};
|
package/dist/services/index.js
CHANGED
|
@@ -3,14 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const permissions_1 = __importDefault(require("./permissions"));
|
|
7
6
|
const serializer_1 = __importDefault(require("./serializer"));
|
|
8
7
|
const authorization_1 = __importDefault(require("./authorization"));
|
|
9
8
|
exports.default = (options) => {
|
|
10
9
|
return {
|
|
11
|
-
permissions: new permissions_1.default(options),
|
|
12
10
|
authorization: (0, authorization_1.default)(options),
|
|
13
11
|
serializer: new serializer_1.default(),
|
|
14
12
|
};
|
|
15
13
|
};
|
|
16
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFFQSw4REFBc0M7QUFDdEMsb0VBQTBEO0FBTzFELGtCQUFlLENBQUMsT0FBaUMsRUFBaUMsRUFBRTtJQUNsRixPQUFPO1FBQ0wsYUFBYSxFQUFFLElBQUEsdUJBQTJCLEVBQUMsT0FBTyxDQUFDO1FBQ25ELFVBQVUsRUFBRSxJQUFJLG9CQUFVLEVBQUU7S0FDN0IsQ0FBQztBQUNKLENBQUMsQ0FBQyJ9
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { IssuerMetadata } from 'openid-client';
|
|
2
2
|
import { JSONAPIDocument } from 'json-api-serializer';
|
|
3
|
-
import { PlainConditionTree } from '@forestadmin/datasource-toolkit';
|
|
4
3
|
import { AgentOptions } from '../types';
|
|
5
4
|
import { EnvironmentPermissionsV4, UserPermissionV4 } from '../services/authorization';
|
|
6
5
|
import { RenderingPermissionV4 } from '../services/authorization/internal/types';
|
|
@@ -27,22 +26,6 @@ export declare type UserInfo = {
|
|
|
27
26
|
};
|
|
28
27
|
permissionLevel: string;
|
|
29
28
|
};
|
|
30
|
-
export declare type RenderingPermissions = {
|
|
31
|
-
actions: Set<string>;
|
|
32
|
-
actionsByUser: {
|
|
33
|
-
[actionName: string]: Set<number>;
|
|
34
|
-
};
|
|
35
|
-
scopes: {
|
|
36
|
-
[collectionName: string]: {
|
|
37
|
-
conditionTree: PlainConditionTree;
|
|
38
|
-
dynamicScopeValues: {
|
|
39
|
-
[userId: number]: {
|
|
40
|
-
[replacementKey: string]: unknown;
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
};
|
|
46
29
|
declare type HttpOptions = Pick<AgentOptions, 'envSecret' | 'forestServerUrl' | 'isProduction'>;
|
|
47
30
|
export default class ForestHttpApi {
|
|
48
31
|
static getIpWhitelistConfiguration(options: HttpOptions): Promise<IpWhitelistConfiguration>;
|
|
@@ -50,20 +33,9 @@ export default class ForestHttpApi {
|
|
|
50
33
|
static getUserInformation(options: HttpOptions, renderingId: number, accessToken: string): Promise<UserInfo>;
|
|
51
34
|
static hasSchema(options: HttpOptions, hash: string): Promise<boolean>;
|
|
52
35
|
static uploadSchema(options: HttpOptions, apimap: JSONAPIDocument): Promise<void>;
|
|
53
|
-
static getPermissions(options: HttpOptions, renderingId: number): Promise<RenderingPermissions>;
|
|
54
36
|
static getEnvironmentPermissions(options: HttpOptions): Promise<EnvironmentPermissionsV4>;
|
|
55
37
|
static getUsers(options: HttpOptions): Promise<UserPermissionV4[]>;
|
|
56
38
|
static getRenderingPermissions(renderingId: number, options: HttpOptions): Promise<RenderingPermissionV4>;
|
|
57
|
-
/** Helper to format permissions into something easy to validate against */
|
|
58
|
-
private static decodeChartPermissions;
|
|
59
|
-
/**
|
|
60
|
-
* Helper to format permissions into something easy to validate against
|
|
61
|
-
* Note that the format the server is sending varies depending on if we're using a remote or
|
|
62
|
-
* local environment.
|
|
63
|
-
*/
|
|
64
|
-
private static decodeActionPermissions;
|
|
65
|
-
/** Helper to format permissions into something easy to validate against */
|
|
66
|
-
private static decodeScopePermissions;
|
|
67
39
|
private static handleResponseError;
|
|
68
40
|
}
|
|
69
41
|
export {};
|
|
@@ -3,7 +3,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const object_hash_1 = __importDefault(require("object-hash"));
|
|
7
6
|
const superagent_1 = __importDefault(require("superagent"));
|
|
8
7
|
class ForestHttpApi {
|
|
9
8
|
static async getIpWhitelistConfiguration(options) {
|
|
@@ -76,29 +75,6 @@ class ForestHttpApi {
|
|
|
76
75
|
this.handleResponseError(e);
|
|
77
76
|
}
|
|
78
77
|
}
|
|
79
|
-
static async getPermissions(options, renderingId) {
|
|
80
|
-
try {
|
|
81
|
-
const { body } = await superagent_1.default
|
|
82
|
-
.get(`${options.forestServerUrl}/liana/v3/permissions`)
|
|
83
|
-
.set('forest-secret-key', options.envSecret)
|
|
84
|
-
.query(`renderingId=${renderingId}`);
|
|
85
|
-
if (!body.meta?.rolesACLActivated) {
|
|
86
|
-
throw new Error('Roles V2 are unsupported');
|
|
87
|
-
}
|
|
88
|
-
const actions = new Set();
|
|
89
|
-
const actionsByUser = {};
|
|
90
|
-
ForestHttpApi.decodeChartPermissions(body?.stats ?? {}, actions);
|
|
91
|
-
ForestHttpApi.decodeActionPermissions(body?.data?.collections ?? {}, actions, actionsByUser);
|
|
92
|
-
return {
|
|
93
|
-
actions,
|
|
94
|
-
actionsByUser,
|
|
95
|
-
scopes: ForestHttpApi.decodeScopePermissions(body?.data?.renderings?.[renderingId] ?? {}),
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
catch (e) {
|
|
99
|
-
this.handleResponseError(e);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
78
|
static async getEnvironmentPermissions(options) {
|
|
103
79
|
try {
|
|
104
80
|
const { body } = await superagent_1.default
|
|
@@ -132,62 +108,6 @@ class ForestHttpApi {
|
|
|
132
108
|
this.handleResponseError(e);
|
|
133
109
|
}
|
|
134
110
|
}
|
|
135
|
-
/** Helper to format permissions into something easy to validate against */
|
|
136
|
-
static decodeChartPermissions(chartsByType, actions) {
|
|
137
|
-
const serverCharts = Object.values(chartsByType).flat();
|
|
138
|
-
const frontendCharts = serverCharts.map(chart => ({
|
|
139
|
-
type: chart.type,
|
|
140
|
-
filters: chart.filter,
|
|
141
|
-
aggregate: chart.aggregator,
|
|
142
|
-
aggregate_field: chart.aggregateFieldName,
|
|
143
|
-
collection: chart.sourceCollectionId,
|
|
144
|
-
time_range: chart.timeRange,
|
|
145
|
-
group_by_date_field: (chart.type === 'Line' && chart.groupByFieldName) || null,
|
|
146
|
-
group_by_field: (chart.type !== 'Line' && chart.groupByFieldName) || null,
|
|
147
|
-
limit: chart.limit,
|
|
148
|
-
label_field: chart.labelFieldName,
|
|
149
|
-
relationship_field: chart.relationshipFieldName,
|
|
150
|
-
}));
|
|
151
|
-
const hashes = frontendCharts.map(chart => (0, object_hash_1.default)(chart, {
|
|
152
|
-
respectType: false,
|
|
153
|
-
excludeKeys: key => chart[key] === null || chart[key] === undefined,
|
|
154
|
-
}));
|
|
155
|
-
hashes.forEach(hash => actions.add(`chart:${hash}`));
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Helper to format permissions into something easy to validate against
|
|
159
|
-
* Note that the format the server is sending varies depending on if we're using a remote or
|
|
160
|
-
* local environment.
|
|
161
|
-
*/
|
|
162
|
-
static decodeActionPermissions(collections, actions, actionsByUser) {
|
|
163
|
-
for (const [name, settings] of Object.entries(collections)) {
|
|
164
|
-
for (const [actionName, userIds] of Object.entries(settings.collection ?? {})) {
|
|
165
|
-
const shortName = actionName.substring(0, actionName.length - 'Enabled'.length);
|
|
166
|
-
if (typeof userIds === 'boolean')
|
|
167
|
-
actions.add(`${shortName}:${name}`);
|
|
168
|
-
else
|
|
169
|
-
actionsByUser[`${shortName}:${name}`] = new Set(userIds);
|
|
170
|
-
}
|
|
171
|
-
for (const [actionName, actionPerms] of Object.entries(settings.actions ?? {})) {
|
|
172
|
-
const userIds = actionPerms.triggerEnabled;
|
|
173
|
-
if (typeof userIds === 'boolean')
|
|
174
|
-
actions.add(`custom:${actionName}:${name}`);
|
|
175
|
-
else
|
|
176
|
-
actionsByUser[`custom:${actionName}:${name}`] = new Set(userIds);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
/** Helper to format permissions into something easy to validate against */
|
|
181
|
-
static decodeScopePermissions(rendering) {
|
|
182
|
-
const scopes = {};
|
|
183
|
-
for (const [name, { scope }] of Object.entries(rendering)) {
|
|
184
|
-
scopes[name] = scope && {
|
|
185
|
-
conditionTree: scope.filter,
|
|
186
|
-
dynamicScopeValues: scope.dynamicScopesValues?.users ?? {},
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
return scopes;
|
|
190
|
-
}
|
|
191
111
|
static handleResponseError(e) {
|
|
192
112
|
if (/certificate/i.test(e.message))
|
|
193
113
|
throw new Error('ForestAdmin server TLS certificate cannot be verified. ' +
|
|
@@ -210,4 +130,4 @@ class ForestHttpApi {
|
|
|
210
130
|
}
|
|
211
131
|
}
|
|
212
132
|
exports.default = ForestHttpApi;
|
|
213
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
133
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yZXN0LWh0dHAtYXBpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL2ZvcmVzdC1odHRwLWFwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUdBLDREQUFpRTtBQStCakUsTUFBcUIsYUFBYTtJQUNoQyxNQUFNLENBQUMsS0FBSyxDQUFDLDJCQUEyQixDQUN0QyxPQUFvQjtRQUVwQixJQUFJO1lBQ0YsTUFBTSxRQUFRLEdBQWEsTUFBTSxvQkFBVTtpQkFDeEMsR0FBRyxDQUFDLElBQUksR0FBRyxDQUFDLDhCQUE4QixFQUFFLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztpQkFDaEYsR0FBRyxDQUFDLG1CQUFtQixFQUFFLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUUvQyxNQUFNLEVBQUUsVUFBVSxFQUFFLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7WUFFMUMsT0FBTyxFQUFFLGdCQUFnQixFQUFFLFVBQVUsQ0FBQyxnQkFBZ0IsRUFBRSxPQUFPLEVBQUUsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDO1NBQ3JGO1FBQUMsT0FBTyxDQUFDLEVBQUU7WUFDVixJQUFJLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDN0I7SUFDSCxDQUFDO0lBRUQsTUFBTSxDQUFDLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxPQUFvQjtRQUN2RCxJQUFJO1lBQ0YsTUFBTSxRQUFRLEdBQWEsTUFBTSxvQkFBVTtpQkFDeEMsR0FBRyxDQUFDLElBQUksR0FBRyxDQUFDLHdDQUF3QyxFQUFFLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztpQkFDMUYsR0FBRyxDQUFDLG1CQUFtQixFQUFFLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUUvQyxPQUFPLFFBQVEsQ0FBQyxJQUFJLENBQUM7U0FDdEI7UUFBQyxPQUFPLENBQUMsRUFBRTtZ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
|
package/package.json
CHANGED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { Context } from 'koa';
|
|
2
|
-
import { AgentOptionsWithDefaults } from '../types';
|
|
3
|
-
declare type RolesOptions = Pick<AgentOptionsWithDefaults, 'forestServerUrl' | 'envSecret' | 'isProduction' | 'permissionsCacheDurationInSeconds'>;
|
|
4
|
-
export default class PermissionService {
|
|
5
|
-
private options;
|
|
6
|
-
private cache;
|
|
7
|
-
constructor(options: RolesOptions);
|
|
8
|
-
invalidateCache(renderingId: number): void;
|
|
9
|
-
/** Checks that a charting query is in the list of allowed queries */
|
|
10
|
-
canChart(context: Context): Promise<void>;
|
|
11
|
-
/** Check if a user is allowed to perform a specific action */
|
|
12
|
-
can(context: Context, action: string, allowRefetch?: boolean): Promise<void>;
|
|
13
|
-
/** Get cached version of "rendering permissions" */
|
|
14
|
-
private getRenderingPermissions;
|
|
15
|
-
}
|
|
16
|
-
export {};
|
|
17
|
-
//# sourceMappingURL=permissions.d.ts.map
|
|
@@ -1,60 +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 lru_cache_1 = __importDefault(require("lru-cache"));
|
|
7
|
-
const object_hash_1 = __importDefault(require("object-hash"));
|
|
8
|
-
const types_1 = require("../types");
|
|
9
|
-
const forest_http_api_1 = __importDefault(require("../utils/forest-http-api"));
|
|
10
|
-
class PermissionService {
|
|
11
|
-
constructor(options) {
|
|
12
|
-
this.options = options;
|
|
13
|
-
this.cache = new lru_cache_1.default({
|
|
14
|
-
max: 256,
|
|
15
|
-
ttl: this.options.permissionsCacheDurationInSeconds * 1000,
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
invalidateCache(renderingId) {
|
|
19
|
-
this.cache.delete(renderingId);
|
|
20
|
-
}
|
|
21
|
-
/** Checks that a charting query is in the list of allowed queries */
|
|
22
|
-
async canChart(context) {
|
|
23
|
-
// If the permissions level already allow the chart, no need to check further
|
|
24
|
-
if (['admin', 'editor', 'developer'].includes(context.state.user.permissionLevel)) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
const chart = { ...context.request.body };
|
|
28
|
-
// When the server sends the data of the allowed charts, the target column is not specified
|
|
29
|
-
// for relations => allow them all.
|
|
30
|
-
if (chart?.group_by_field?.includes(':'))
|
|
31
|
-
chart.group_by_field = chart.group_by_field.substring(0, chart.group_by_field.indexOf(':'));
|
|
32
|
-
const chartHash = (0, object_hash_1.default)(chart, {
|
|
33
|
-
respectType: false,
|
|
34
|
-
excludeKeys: key => chart[key] === null,
|
|
35
|
-
});
|
|
36
|
-
await this.can(context, `chart:${chartHash}`);
|
|
37
|
-
}
|
|
38
|
-
/** Check if a user is allowed to perform a specific action */
|
|
39
|
-
async can(context, action, allowRefetch = true) {
|
|
40
|
-
const { id: userId, renderingId } = context.state.user;
|
|
41
|
-
const perms = await this.getRenderingPermissions(renderingId);
|
|
42
|
-
const isAllowed = perms.actions.has(action) || perms.actionsByUser[action]?.has(userId);
|
|
43
|
-
if (!isAllowed && allowRefetch) {
|
|
44
|
-
this.invalidateCache(renderingId);
|
|
45
|
-
return this.can(context, action, false);
|
|
46
|
-
}
|
|
47
|
-
if (!isAllowed) {
|
|
48
|
-
context.throw(types_1.HttpCode.Forbidden, 'Forbidden');
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
/** Get cached version of "rendering permissions" */
|
|
52
|
-
getRenderingPermissions(renderingId) {
|
|
53
|
-
if (!this.cache.has(renderingId))
|
|
54
|
-
this.cache.set(renderingId, forest_http_api_1.default.getPermissions(this.options, renderingId));
|
|
55
|
-
// We already checked the entry is up-to-date with the .has() call => allowStale
|
|
56
|
-
return this.cache.get(renderingId, { allowStale: true });
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
exports.default = PermissionService;
|
|
60
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVybWlzc2lvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvcGVybWlzc2lvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFDQSwwREFBaUM7QUFDakMsOERBQXFDO0FBRXJDLG9DQUE4RDtBQUM5RCwrRUFBK0U7QUFPL0UsTUFBcUIsaUJBQWlCO0lBSXBDLFlBQVksT0FBcUI7UUFDL0IsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFDdkIsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLG1CQUFRLENBQUM7WUFDeEIsR0FBRyxFQUFFLEdBQUc7WUFDUixHQUFHLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQ0FBaUMsR0FBRyxJQUFJO1NBQzNELENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxlQUFlLENBQUMsV0FBbUI7UUFDakMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDakMsQ0FBQztJQUVELHFFQUFxRTtJQUNyRSxLQUFLLENBQUMsUUFBUSxDQUFDLE9BQWdCO1FBQzdCLDZFQUE2RTtRQUM3RSxJQUFJLENBQUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxXQUFXLENBQUMsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLEVBQUU7WUFDakYsT0FBTztTQUNSO1FBRUQsTUFBTSxLQUFLLEdBQUcsRUFBRSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7UUFFMUMsMkZBQTJGO1FBQzNGLG1DQUFtQztRQUNuQyxJQUFJLEtBQUssRUFBRSxjQUFjLEVBQUUsUUFBUSxDQUFDLEdBQUcsQ0FBQztZQUN0QyxLQUFLLENBQUMsY0FBYyxHQUFHLEtBQUssQ0FBQyxjQUFjLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBRTlGLE1BQU0sU0FBUyxHQUFHLElBQUEscUJBQVUsRUFBQyxLQUFLLEVBQUU7WUFDbEMsV0FBVyxFQUFFLEtBQUs7WUFDbEIsV0FBVyxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLElBQUk7U0FDeEMsQ0FBQyxDQUFDO1FBRUgsTUFBTSxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxTQUFTLFNBQVMsRUFBRSxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVELDhEQUE4RDtJQUM5RCxLQUFLLENBQUMsR0FBRyxDQUFDLE9BQWdCLEVBQUUsTUFBYyxFQUFFLFlBQVksR0FBRyxJQUFJO1FBQzdELE1BQU0sRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO1FBQ3ZELE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLHVCQUF1QixDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQzlELE1BQU0sU0FBUyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRXhGLElBQUksQ0FBQyxTQUFTLElBQUksWUFBWSxFQUFFO1lBQzlCLElBQUksQ0FBQyxlQUFlLENBQUMsV0FBVyxDQUFDLENBQUM7WUFFbEMsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUM7U0FDekM7UUFFRCxJQUFJLENBQUMsU0FBUyxFQUFFO1lBQ2QsT0FBTyxDQUFDLEtBQUssQ0FBQyxnQkFBUSxDQUFDLFNBQVMsRUFBRSxXQUFXLENBQUMsQ0FBQztTQUNoRDtJQUNILENBQUM7SUFFRCxvREFBb0Q7SUFDNUMsdUJBQXVCLENBQUMsV0FBbUI7UUFDakQsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQztZQUM5QixJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUseUJBQWEsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDO1FBRXZGLGdGQUFnRjtRQUNoRixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQzNELENBQUM7Q0FDRjtBQS9ERCxvQ0ErREMifQ==
|