aws-service-stack 0.18.372 β 0.18.374
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/README.md +150 -0
- package/dist/_examples/controller/property/property-crud.d.ts +4 -0
- package/dist/_examples/controller/property/property-crud.js +58 -0
- package/dist/_examples/controller/property/property-crud.js.map +1 -0
- package/dist/_examples/controller/property/property.config.d.ts +10 -0
- package/dist/_examples/controller/property/property.config.js +53 -0
- package/dist/_examples/controller/property/property.config.js.map +1 -0
- package/dist/_examples/controller/property/property.controller.d.ts +14 -0
- package/dist/_examples/controller/property/property.controller.js +72 -0
- package/dist/_examples/controller/property/property.controller.js.map +1 -0
- package/dist/_examples/controller/property/property.permissions.d.ts +2 -0
- package/dist/_examples/controller/property/property.permissions.js +19 -0
- package/dist/_examples/controller/property/property.permissions.js.map +1 -0
- package/dist/controller/controller-api.d.ts +5 -0
- package/dist/controller/controller-api.js +29 -1
- package/dist/controller/controller-api.js.map +1 -1
- package/dist/controller/controller-role.d.ts +53 -0
- package/dist/controller/controller-role.js +216 -0
- package/dist/controller/controller-role.js.map +1 -0
- package/dist/controller/index.d.ts +1 -0
- package/dist/controller/index.js +1 -0
- package/dist/controller/index.js.map +1 -1
- package/dist/function/cognito/cognito.function.d.ts +15 -0
- package/dist/function/cognito/cognito.function.js +45 -0
- package/dist/function/cognito/cognito.function.js.map +1 -1
- package/dist/function/cognito/index.d.ts +5 -1
- package/dist/function/cognito/index.js +4 -0
- package/dist/function/cognito/index.js.map +1 -1
- package/dist/function/index.d.ts +4 -0
- package/dist/model/base.config.d.ts +5 -1
- package/dist/model/base.config.js +7 -0
- package/dist/model/base.config.js.map +1 -1
- package/dist/model/base.model.d.ts +15 -0
- package/dist/model/base.model.js +4 -1
- package/dist/model/base.model.js.map +1 -1
- package/dist/model/index.d.ts +1 -0
- package/dist/model/index.js.map +1 -1
- package/dist/model/role.model.d.ts +20 -0
- package/dist/model/role.model.js +12 -0
- package/dist/model/role.model.js.map +1 -0
- package/dist/model/validation.model.d.ts +1 -1
- package/dist/model/validation.model.js.map +1 -1
- package/dist/service/index.d.ts +3 -0
- package/dist/service/index.js +3 -0
- package/dist/service/index.js.map +1 -1
- package/dist/service/permission.cache.d.ts +24 -0
- package/dist/service/permission.cache.js +61 -0
- package/dist/service/permission.cache.js.map +1 -0
- package/dist/service/permission.repo.d.ts +16 -0
- package/dist/service/permission.repo.js +63 -0
- package/dist/service/permission.repo.js.map +1 -0
- package/dist/service/permission.service.d.ts +39 -0
- package/dist/service/permission.service.js +151 -0
- package/dist/service/permission.service.js.map +1 -0
- package/dist/utils/date.util.d.ts +0 -13
- package/dist/utils/date.util.js +0 -35
- package/dist/utils/date.util.js.map +1 -1
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +31 -31
- package/dist/utils/data.util.d.ts +0 -20
- package/dist/utils/data.util.js +0 -73
- package/dist/utils/data.util.js.map +0 -1
package/README.md
CHANGED
|
@@ -420,6 +420,156 @@ new Function(this, "MyFunction", {
|
|
|
420
420
|
});
|
|
421
421
|
```
|
|
422
422
|
|
|
423
|
+
## π Role-Based Access Control (RBAC)
|
|
424
|
+
|
|
425
|
+
The framework provides a centralized RBAC system through `ControllerRole`, which manages Cognito user pool groups, DynamoDB-backed permissions, and scope-based data filtering β all integrated directly into `ControllerApi`.
|
|
426
|
+
|
|
427
|
+
### Architecture
|
|
428
|
+
|
|
429
|
+
```
|
|
430
|
+
ββββββββββββββββββββ
|
|
431
|
+
β ControllerApi β β Delegates RBAC check automatically
|
|
432
|
+
ββββββββββββββββββββ€
|
|
433
|
+
β ControllerRole β β Permission CRUD, Cognito groups, scope enforcement
|
|
434
|
+
ββββββββββββββββββββ€
|
|
435
|
+
βPermissionService β β Read-through cache (15-min TTL) + orchestration
|
|
436
|
+
ββββββββββββββββββββ€
|
|
437
|
+
β PermissionRepo β β DynamoDB via BaseRepoDBImpl
|
|
438
|
+
ββββββββββββββββββββ
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Permission Model
|
|
442
|
+
|
|
443
|
+
Each permission is stored in DynamoDB with the composite key `role#resource#scope`:
|
|
444
|
+
|
|
445
|
+
```typescript
|
|
446
|
+
interface Permission {
|
|
447
|
+
id: string;
|
|
448
|
+
role: string; // Cognito group name: "Manager", "Agent"
|
|
449
|
+
resource: string; // API resource: "property", "order"
|
|
450
|
+
scope: string; // Data scope: "Organization", "Branch", "Agent"
|
|
451
|
+
method: {
|
|
452
|
+
get?: boolean;
|
|
453
|
+
post?: boolean;
|
|
454
|
+
patch?: boolean;
|
|
455
|
+
put?: boolean;
|
|
456
|
+
delete?: boolean;
|
|
457
|
+
};
|
|
458
|
+
permissionKey: string; // "Manager#property#Branch"
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
### Configuration
|
|
463
|
+
|
|
464
|
+
Enable RBAC by adding `ROLE_TABLE`, `ROLE_PATH`, and `SCOPE_MAP` to your entity config:
|
|
465
|
+
|
|
466
|
+
```typescript
|
|
467
|
+
import { EntityConfigImpl, ScopeMap } from "@chinggis/core";
|
|
468
|
+
|
|
469
|
+
const scopeMap: ScopeMap = new Map([
|
|
470
|
+
["Organization", { filterField: "orgId", claimKey: "custom:orgId" }],
|
|
471
|
+
["Branch", { filterField: "branchId", claimKey: "custom:branch" }],
|
|
472
|
+
["Agent", { filterField: "agentId", claimKey: "custom:agent" }],
|
|
473
|
+
]);
|
|
474
|
+
|
|
475
|
+
export class PropertyConfig extends EntityConfigImpl {
|
|
476
|
+
constructor() {
|
|
477
|
+
super("/properties", ["adminUsers"]);
|
|
478
|
+
|
|
479
|
+
this.setDynamoDB("property-dev", "owner", indexMap)
|
|
480
|
+
.setOpenSearch(domain, "property")
|
|
481
|
+
.setPolicies(policyList)
|
|
482
|
+
.setScopes(scopeMap)
|
|
483
|
+
.setRoleTable("role-permissions-dev")
|
|
484
|
+
.setRolePath("/properties/role");
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
When both `ROLE_TABLE` and `SCOPE_MAP` are configured, `ControllerApi` automatically creates a `ControllerRole` instance and enforces RBAC on every request.
|
|
490
|
+
|
|
491
|
+
### How It Works
|
|
492
|
+
|
|
493
|
+
1. **Request arrives** at `ControllerApi.resolveCrudRequest()`
|
|
494
|
+
2. If RBAC is configured, `ControllerRole.checkRbacAccess()` is called
|
|
495
|
+
3. User's **role** is extracted from JWT `groups[0]`
|
|
496
|
+
4. **Scope** is read from `?scope=Branch` query parameter and validated against `ScopeMap`
|
|
497
|
+
5. Permission is checked via `PermissionService` (with in-memory cache)
|
|
498
|
+
6. On success, **scope filter** is applied (e.g., `filter.branchId = identity["custom:branch"]`)
|
|
499
|
+
7. On failure, `403 PermissionDenied` is thrown
|
|
500
|
+
|
|
501
|
+
### Permission CRUD Endpoints
|
|
502
|
+
|
|
503
|
+
When `ROLE_PATH` is configured, permission management endpoints are automatically available:
|
|
504
|
+
|
|
505
|
+
```
|
|
506
|
+
GET /properties/role # List all permissions
|
|
507
|
+
POST /properties/role # Create a permission
|
|
508
|
+
PATCH /properties/role # Update a permission
|
|
509
|
+
DELETE /properties/role # Delete a permission
|
|
510
|
+
POST /properties/role/add-role # Create a Cognito user pool group
|
|
511
|
+
POST /properties/role/add-user-role # Add a User to cognito group
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
#### Create a Permission
|
|
515
|
+
|
|
516
|
+
```json
|
|
517
|
+
POST /properties/role
|
|
518
|
+
{
|
|
519
|
+
"role": "Manager",
|
|
520
|
+
"resource": "property",
|
|
521
|
+
"scope": "Branch",
|
|
522
|
+
"method": { "get": true, "post": true, "patch": true, "delete": false }
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
#### Create a Cognito Group (Role)
|
|
527
|
+
|
|
528
|
+
```json
|
|
529
|
+
POST /properties/role/add-role
|
|
530
|
+
{
|
|
531
|
+
"groupName": "Manager",
|
|
532
|
+
"description": "Branch-level managers"
|
|
533
|
+
}
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Programmatic Usage
|
|
537
|
+
|
|
538
|
+
`ControllerRole` can also be used directly in custom controllers or services:
|
|
539
|
+
|
|
540
|
+
```typescript
|
|
541
|
+
import { ControllerRole } from "@chinggis/core";
|
|
542
|
+
|
|
543
|
+
const roleController = new ControllerRole("role-permissions-dev");
|
|
544
|
+
|
|
545
|
+
// Permission CRUD
|
|
546
|
+
await roleController.addPermission({
|
|
547
|
+
role: "Manager",
|
|
548
|
+
resource: "property",
|
|
549
|
+
scope: "Branch",
|
|
550
|
+
method: { get: true, post: true, patch: true },
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
await roleController.listPermissions();
|
|
554
|
+
await roleController.updatePermission("perm-id", { method: { delete: true } });
|
|
555
|
+
await roleController.deletePermission("perm-id");
|
|
556
|
+
|
|
557
|
+
// Permission check
|
|
558
|
+
const allowed = await roleController.hasPermission("Manager", "property", "Branch", "GET");
|
|
559
|
+
|
|
560
|
+
// Cognito group management
|
|
561
|
+
await roleController.addRole("us-east-1_PoolId", "Manager", "Branch-level managers");
|
|
562
|
+
await roleController.assignRole("us-east-1_PoolId", "john@example.com", "Manager");
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
### Caching
|
|
566
|
+
|
|
567
|
+
`PermissionService` uses a read-through cache with **15-minute TTL** optimized for Lambda warm invocations:
|
|
568
|
+
|
|
569
|
+
- Cache hits return instantly without DB calls
|
|
570
|
+
- Concurrent requests for the same key are deduplicated (single in-flight fetch)
|
|
571
|
+
- Cache is automatically invalidated on create, update, and delete operations
|
|
572
|
+
|
|
423
573
|
## π€ Contributing
|
|
424
574
|
|
|
425
575
|
1. Fork the repository
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
22
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
+
};
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.handler = void 0;
|
|
43
|
+
require("reflect-metadata");
|
|
44
|
+
const typedi_1 = __importStar(require("typedi"));
|
|
45
|
+
require("./property.controller");
|
|
46
|
+
const handler = (event) => typedi_1.default.get(HelperCDI).process(event);
|
|
47
|
+
exports.handler = handler;
|
|
48
|
+
let HelperCDI = class HelperCDI {
|
|
49
|
+
controller = typedi_1.default.get("PropertyController");
|
|
50
|
+
async process(event) {
|
|
51
|
+
console.log("example Processing...");
|
|
52
|
+
return this.controller.resolveCrudRequest(event);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
HelperCDI = __decorate([
|
|
56
|
+
(0, typedi_1.Service)()
|
|
57
|
+
], HelperCDI);
|
|
58
|
+
//# sourceMappingURL=property-crud.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property-crud.js","sourceRoot":"","sources":["../../../../src/_examples/controller/property/property-crud.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4BAA0B;AAC1B,iDAA4C;AAG5C,iCAA+B;AAExB,MAAM,OAAO,GAAG,CAAC,KAA2B,EAAE,EAAE,CAAC,gBAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAAnF,QAAA,OAAO,WAA4E;AAGhG,IAAM,SAAS,GAAf,MAAM,SAAS;IACL,UAAU,GAAuB,gBAAS,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAE7E,KAAK,CAAC,OAAO,CAAC,KAA2B;QACvC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACnD,CAAC;CACF,CAAA;AAPK,SAAS;IADd,IAAA,gBAAO,GAAE;GACJ,SAAS,CAOd","sourcesContent":["import \"reflect-metadata\";\nimport Container, { Service } from \"typedi\";\nimport { APIGatewayProxyEvent } from \"aws-lambda\";\nimport { PropertyController } from \"./property.controller\";\nimport \"./property.controller\";\n\nexport const handler = (event: APIGatewayProxyEvent) => Container.get(HelperCDI).process(event);\n\n@Service()\nclass HelperCDI {\n private controller: PropertyController = Container.get(\"PropertyController\");\n\n async process(event: APIGatewayProxyEvent) {\n console.log(\"example Processing...\");\n return this.controller.resolveCrudRequest(event);\n }\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { EntityConfigImpl } from "../../../model/base.config";
|
|
2
|
+
export declare const openSearch_order: {
|
|
3
|
+
domain: string;
|
|
4
|
+
index: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const path = "/property";
|
|
7
|
+
export declare class PropertyConfig extends EntityConfigImpl {
|
|
8
|
+
constructor();
|
|
9
|
+
}
|
|
10
|
+
export declare const CONFIG_PROPERTY: PropertyConfig;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CONFIG_PROPERTY = exports.PropertyConfig = exports.path = exports.openSearch_order = void 0;
|
|
4
|
+
const base_config_1 = require("../../../model/base.config");
|
|
5
|
+
const core_1 = require("../../../index.js");
|
|
6
|
+
const order_repo_db_interface_1 = require("../../repositories/order/order-repo-db.interface");
|
|
7
|
+
// OpenSearch configuration
|
|
8
|
+
exports.openSearch_order = {
|
|
9
|
+
domain: "https://search-amplify-opense-1ddfdekgbbpwe-kgxh6aum57h2wc4moozm2jcvom.ap-southeast-1.es.amazonaws.com",
|
|
10
|
+
index: "order",
|
|
11
|
+
};
|
|
12
|
+
exports.path = "/property"; // url path base
|
|
13
|
+
// Order configuration
|
|
14
|
+
class PropertyConfig extends base_config_1.EntityConfigImpl {
|
|
15
|
+
constructor() {
|
|
16
|
+
// DYNAMODB
|
|
17
|
+
const tableName = "Property-dev";
|
|
18
|
+
const ownerFieldName = "ownerId";
|
|
19
|
+
const indexMap = new core_1.DynamoIndexMap()
|
|
20
|
+
.setFields("ownerId")
|
|
21
|
+
.set("byAgent", { field: "agentId", rFields: ["agentId"] })
|
|
22
|
+
.set("propertyByBranch", { field: "branchId", rFields: ["branchId"] })
|
|
23
|
+
.set("byOrg", { field: "organizationId", rFields: ["organizationId"] });
|
|
24
|
+
// PERMISSIONS
|
|
25
|
+
const adminGroupNames = ["adminUsers"];
|
|
26
|
+
const policyList = [
|
|
27
|
+
{ method: core_1.HttpMethod.GET, path: `${exports.path}`, access: [core_1.Access.USER, core_1.Access.PUBLIC, core_1.Access.ADMIN] },
|
|
28
|
+
{ method: core_1.HttpMethod.GET, path: `${exports.path}/search`, access: [core_1.Access.USER], response: order_repo_db_interface_1.RESPONSE_FIELDS_LIST },
|
|
29
|
+
{ method: core_1.HttpMethod.GET, path: `${exports.path}/search/query`, access: [core_1.Access.USER], response: order_repo_db_interface_1.RESPONSE_FIELDS_LIST },
|
|
30
|
+
{ method: core_1.HttpMethod.GET, path: `${exports.path}/search/query/total-count`, access: [core_1.Access.USER] },
|
|
31
|
+
{ method: core_1.HttpMethod.GET, path: `${exports.path}/{id}`, access: [core_1.Access.USER], response: order_repo_db_interface_1.RESPONSE_FIELDS_DETAILS },
|
|
32
|
+
{ method: core_1.HttpMethod.POST, path: `${exports.path}`, access: [core_1.Access.USER], validator: order_repo_db_interface_1.CREATE, response: order_repo_db_interface_1.RESPONSE_FIELDS_DETAILS },
|
|
33
|
+
{ method: core_1.HttpMethod.PUT, path: `${exports.path}/{id}`, access: [core_1.Access.USER], validator: order_repo_db_interface_1.REPLACE, response: order_repo_db_interface_1.RESPONSE_FIELDS_DETAILS },
|
|
34
|
+
{ method: core_1.HttpMethod.PATCH, path: `${exports.path}/{id}`, access: [core_1.Access.USER], validator: order_repo_db_interface_1.UPDATE, response: order_repo_db_interface_1.RESPONSE_FIELDS_DETAILS },
|
|
35
|
+
{ method: core_1.HttpMethod.DELETE, path: `${exports.path}/{id}`, access: [core_1.Access.USER] },
|
|
36
|
+
];
|
|
37
|
+
// SCOPES
|
|
38
|
+
const scopeMap = new core_1.ScopeMap()
|
|
39
|
+
.set("branch", { filterField: "branchId", claimKey: "sub" })
|
|
40
|
+
.set("agent", { filterField: "agentId", claimKey: "custom:agent" })
|
|
41
|
+
.set("org", { filterField: "organizationId", claimKey: "custom:org" });
|
|
42
|
+
// INIT
|
|
43
|
+
super(exports.path, adminGroupNames);
|
|
44
|
+
this.setDynamoDB(tableName, ownerFieldName, indexMap)
|
|
45
|
+
.setOpenSearch(exports.openSearch_order.domain, exports.openSearch_order.index)
|
|
46
|
+
.setPolicies(policyList)
|
|
47
|
+
.setPermissionMap({ scopeMap, roleTable: "Permission-dev", rolePath: "/permission/plp" });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.PropertyConfig = PropertyConfig;
|
|
51
|
+
// Export default Order configuration
|
|
52
|
+
exports.CONFIG_PROPERTY = new PropertyConfig();
|
|
53
|
+
//# sourceMappingURL=property.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property.config.js","sourceRoot":"","sources":["../../../../src/_examples/controller/property/property.config.ts"],"names":[],"mappings":";;;AAAA,4DAA8D;AAC9D,yCAAwG;AACxG,8FAM0D;AAE1D,2BAA2B;AACd,QAAA,gBAAgB,GAAG;IAC9B,MAAM,EAAE,wGAAwG;IAChH,KAAK,EAAE,OAAO;CACf,CAAC;AACW,QAAA,IAAI,GAAG,WAAW,CAAC,CAAC,gBAAgB;AAEjD,sBAAsB;AACtB,MAAa,cAAe,SAAQ,8BAAgB;IAClD;QACE,WAAW;QACX,MAAM,SAAS,GAAG,cAAc,CAAC;QACjC,MAAM,cAAc,GAAG,SAAS,CAAC;QACjC,MAAM,QAAQ,GAAG,IAAI,qBAAc,EAAE;aAClC,SAAS,CAAC,SAAS,CAAC;aACpB,GAAG,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC;aAC1D,GAAG,CAAC,kBAAkB,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;aACrE,GAAG,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;QAE1E,cAAc;QACd,MAAM,eAAe,GAAG,CAAC,YAAY,CAAC,CAAC;QAEvC,MAAM,UAAU,GAAqB;YACnC,EAAE,MAAM,EAAE,iBAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,YAAI,EAAE,EAAE,MAAM,EAAE,CAAC,aAAC,CAAC,IAAI,EAAE,aAAC,CAAC,MAAM,EAAE,aAAC,CAAC,KAAK,CAAC,EAAE;YACvE,EAAE,MAAM,EAAE,iBAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,YAAI,SAAS,EAAE,MAAM,EAAE,CAAC,aAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,8CAAQ,EAAE;YAC/E,EAAE,MAAM,EAAE,iBAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,YAAI,eAAe,EAAE,MAAM,EAAE,CAAC,aAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,8CAAQ,EAAE;YACrF,EAAE,MAAM,EAAE,iBAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,YAAI,2BAA2B,EAAE,MAAM,EAAE,CAAC,aAAC,CAAC,IAAI,CAAC,EAAE;YAC7E,EAAE,MAAM,EAAE,iBAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,YAAI,OAAO,EAAE,MAAM,EAAE,CAAC,aAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,iDAAQ,EAAE;YAC7E,EAAE,MAAM,EAAE,iBAAC,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,YAAI,EAAE,EAAE,MAAM,EAAE,CAAC,aAAC,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,gCAAM,EAAE,QAAQ,EAAE,iDAAQ,EAAE;YAC5F,EAAE,MAAM,EAAE,iBAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,YAAI,OAAO,EAAE,MAAM,EAAE,CAAC,aAAC,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,iCAAO,EAAE,QAAQ,EAAE,iDAAQ,EAAE;YACjG,EAAE,MAAM,EAAE,iBAAC,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,YAAI,OAAO,EAAE,MAAM,EAAE,CAAC,aAAC,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,gCAAM,EAAE,QAAQ,EAAE,iDAAQ,EAAE;YAClG,EAAE,MAAM,EAAE,iBAAC,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,YAAI,OAAO,EAAE,MAAM,EAAE,CAAC,aAAC,CAAC,IAAI,CAAC,EAAE;SAC7D,CAAC;QAEF,SAAS;QACT,MAAM,QAAQ,GAAG,IAAI,eAAQ,EAAE;aAC5B,GAAG,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;aAC3D,GAAG,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;aAClE,GAAG,CAAC,KAAK,EAAE,EAAE,WAAW,EAAE,gBAAgB,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,CAAC;QAEzE,OAAO;QACP,KAAK,CAAC,YAAI,EAAE,eAAe,CAAC,CAAC;QAC7B,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,cAAc,EAAE,QAAQ,CAAC;aAClD,aAAa,CAAC,wBAAgB,CAAC,MAAM,EAAE,wBAAgB,CAAC,KAAK,CAAC;aAC9D,WAAW,CAAC,UAAU,CAAC;aACvB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC9F,CAAC;CACF;AAvCD,wCAuCC;AAED,qCAAqC;AACxB,QAAA,eAAe,GAAG,IAAI,cAAc,EAAE,CAAC","sourcesContent":["import { EntityConfigImpl } from \"../../../model/base.config\";\nimport { Access as a, DynamoIndexMap, EndpointPolicy, HttpMethod as m, ScopeMap } from \"@chinggis/core\";\nimport {\n CREATE,\n REPLACE,\n RESPONSE_FIELDS_DETAILS as FIELDS_D,\n RESPONSE_FIELDS_LIST as FIELDS_L,\n UPDATE,\n} from \"../../repositories/order/order-repo-db.interface\";\n\n// OpenSearch configuration\nexport const openSearch_order = {\n domain: \"https://search-amplify-opense-1ddfdekgbbpwe-kgxh6aum57h2wc4moozm2jcvom.ap-southeast-1.es.amazonaws.com\",\n index: \"order\",\n};\nexport const path = \"/property\"; // url path base\n\n// Order configuration\nexport class PropertyConfig extends EntityConfigImpl {\n constructor() {\n // DYNAMODB\n const tableName = \"Property-dev\";\n const ownerFieldName = \"ownerId\";\n const indexMap = new DynamoIndexMap()\n .setFields(\"ownerId\")\n .set(\"byAgent\", { field: \"agentId\", rFields: [\"agentId\"] })\n .set(\"propertyByBranch\", { field: \"branchId\", rFields: [\"branchId\"] })\n .set(\"byOrg\", { field: \"organizationId\", rFields: [\"organizationId\"] });\n\n // PERMISSIONS\n const adminGroupNames = [\"adminUsers\"];\n\n const policyList: EndpointPolicy[] = [\n { method: m.GET, path: `${path}`, access: [a.USER, a.PUBLIC, a.ADMIN] },\n { method: m.GET, path: `${path}/search`, access: [a.USER], response: FIELDS_L },\n { method: m.GET, path: `${path}/search/query`, access: [a.USER], response: FIELDS_L },\n { method: m.GET, path: `${path}/search/query/total-count`, access: [a.USER] },\n { method: m.GET, path: `${path}/{id}`, access: [a.USER], response: FIELDS_D },\n { method: m.POST, path: `${path}`, access: [a.USER], validator: CREATE, response: FIELDS_D },\n { method: m.PUT, path: `${path}/{id}`, access: [a.USER], validator: REPLACE, response: FIELDS_D },\n { method: m.PATCH, path: `${path}/{id}`, access: [a.USER], validator: UPDATE, response: FIELDS_D },\n { method: m.DELETE, path: `${path}/{id}`, access: [a.USER] },\n ];\n\n // SCOPES\n const scopeMap = new ScopeMap()\n .set(\"branch\", { filterField: \"branchId\", claimKey: \"sub\" })\n .set(\"agent\", { filterField: \"agentId\", claimKey: \"custom:agent\" })\n .set(\"org\", { filterField: \"organizationId\", claimKey: \"custom:org\" });\n\n // INIT\n super(path, adminGroupNames);\n this.setDynamoDB(tableName, ownerFieldName, indexMap)\n .setOpenSearch(openSearch_order.domain, openSearch_order.index)\n .setPolicies(policyList)\n .setPermissionMap({ scopeMap, roleTable: \"Permission-dev\", rolePath: \"/permission/plp\" });\n }\n}\n\n// Export default Order configuration\nexport const CONFIG_PROPERTY = new PropertyConfig();\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { OrderService } from "../../service/order-service.interface";
|
|
2
|
+
import "../../service/order-service";
|
|
3
|
+
import { Order } from "src/_examples/model-shared/example.model";
|
|
4
|
+
import { HttpRequest } from "src/utils";
|
|
5
|
+
import { ControllerApi } from "src/controller";
|
|
6
|
+
/**
|
|
7
|
+
* Example Controller for Profile: Validator (Zod) is set centrally.
|
|
8
|
+
* Scopes are configured in PropertyConfig via ScopeMap.
|
|
9
|
+
*/
|
|
10
|
+
export declare class PropertyController extends ControllerApi<Order, OrderService> {
|
|
11
|
+
protected processCrudRequest(event: HttpRequest): Promise<any>;
|
|
12
|
+
constructor();
|
|
13
|
+
getPermission(permission: string): Promise<boolean>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
22
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
+
};
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
42
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
43
|
+
};
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.PropertyController = void 0;
|
|
46
|
+
const typedi_1 = __importStar(require("typedi"));
|
|
47
|
+
const property_config_1 = require("./property.config");
|
|
48
|
+
require("../../service/order-service");
|
|
49
|
+
const controller_1 = require("src/controller");
|
|
50
|
+
const property_permissions_1 = require("./property.permissions");
|
|
51
|
+
/**
|
|
52
|
+
* Example Controller for Profile: Validator (Zod) is set centrally.
|
|
53
|
+
* Scopes are configured in PropertyConfig via ScopeMap.
|
|
54
|
+
*/
|
|
55
|
+
let PropertyController = class PropertyController extends controller_1.ControllerApi {
|
|
56
|
+
processCrudRequest(event) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
constructor() {
|
|
60
|
+
const service = typedi_1.default.get("OrderService");
|
|
61
|
+
super(service, property_config_1.CONFIG_PROPERTY.toObject());
|
|
62
|
+
}
|
|
63
|
+
async getPermission(permission) {
|
|
64
|
+
return (0, property_permissions_1.hasPropertyPermission)(permission);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
exports.PropertyController = PropertyController;
|
|
68
|
+
exports.PropertyController = PropertyController = __decorate([
|
|
69
|
+
(0, typedi_1.Service)("PropertyController"),
|
|
70
|
+
__metadata("design:paramtypes", [])
|
|
71
|
+
], PropertyController);
|
|
72
|
+
//# sourceMappingURL=property.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property.controller.js","sourceRoot":"","sources":["../../../../src/_examples/controller/property/property.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAA4C;AAG5C,uDAAoD;AAEpD,uCAAqC;AAGrC,+CAA+C;AAC/C,iEAA+D;AAE/D;;;GAGG;AAEI,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,0BAAkC;IAC9D,kBAAkB,CAAC,KAAkB;QAC7C,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;QACE,MAAM,OAAO,GAAiB,gBAAS,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC5D,KAAK,CAAC,OAAO,EAAE,iCAAe,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,UAAkB;QACpC,OAAO,IAAA,4CAAqB,EAAC,UAAU,CAAC,CAAC;IAC3C,CAAC;CACF,CAAA;AAbY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,gBAAO,EAAC,oBAAoB,CAAC;;GACjB,kBAAkB,CAa9B","sourcesContent":["import Container, { Service } from \"typedi\";\nimport {} from \"../../../controller/base-controller\";\n\nimport { CONFIG_PROPERTY } from \"./property.config\";\nimport { OrderService } from \"../../service/order-service.interface\";\nimport \"../../service/order-service\";\nimport { Order } from \"src/_examples/model-shared/example.model\";\nimport { HttpRequest } from \"src/utils\";\nimport { ControllerApi } from \"src/controller\";\nimport { hasPropertyPermission } from \"./property.permissions\";\n\n/**\n * Example Controller for Profile: Validator (Zod) is set centrally.\n * Scopes are configured in PropertyConfig via ScopeMap.\n */\n@Service(\"PropertyController\")\nexport class PropertyController extends ControllerApi<Order, OrderService> {\n protected processCrudRequest(event: HttpRequest): Promise<any> {\n return undefined;\n }\n\n constructor() {\n const service: OrderService = Container.get(\"OrderService\");\n super(service, CONFIG_PROPERTY.toObject());\n }\n\n async getPermission(permission: string): Promise<boolean> {\n return hasPropertyPermission(permission);\n }\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROPERTY_PERMISSION_KEYS = void 0;
|
|
4
|
+
exports.hasPropertyPermission = hasPropertyPermission;
|
|
5
|
+
exports.PROPERTY_PERMISSION_KEYS = new Set([
|
|
6
|
+
"adminusers.property.branch.GET",
|
|
7
|
+
"adminusers.property.branch.POST",
|
|
8
|
+
"user.property.branch.GET",
|
|
9
|
+
"user.property.agent.GET",
|
|
10
|
+
"user.property.agent.POST",
|
|
11
|
+
"owner.property.branch.GET",
|
|
12
|
+
"owner.property.branch.POST",
|
|
13
|
+
"owner.property.agent.GET",
|
|
14
|
+
"owner.property.agent.POST",
|
|
15
|
+
]);
|
|
16
|
+
function hasPropertyPermission(permission) {
|
|
17
|
+
return exports.PROPERTY_PERMISSION_KEYS.has(permission);
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=property.permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property.permissions.js","sourceRoot":"","sources":["../../../../src/_examples/controller/property/property.permissions.ts"],"names":[],"mappings":";;;AAYA,sDAEC;AAdY,QAAA,wBAAwB,GAAG,IAAI,GAAG,CAAS;IACtD,gCAAgC;IAChC,iCAAiC;IACjC,0BAA0B;IAC1B,yBAAyB;IACzB,0BAA0B;IAC1B,2BAA2B;IAC3B,4BAA4B;IAC5B,0BAA0B;IAC1B,2BAA2B;CAC5B,CAAC,CAAC;AAEH,SAAgB,qBAAqB,CAAC,UAAkB;IACtD,OAAO,gCAAwB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AAClD,CAAC","sourcesContent":["export const PROPERTY_PERMISSION_KEYS = new Set<string>([\n \"adminusers.property.branch.GET\",\n \"adminusers.property.branch.POST\",\n \"user.property.branch.GET\",\n \"user.property.agent.GET\",\n \"user.property.agent.POST\",\n \"owner.property.branch.GET\",\n \"owner.property.branch.POST\",\n \"owner.property.agent.GET\",\n \"owner.property.agent.POST\",\n]);\n\nexport function hasPropertyPermission(permission: string): boolean {\n return PROPERTY_PERMISSION_KEYS.has(permission);\n}\n"]}
|
|
@@ -6,18 +6,23 @@ export declare abstract class ControllerApi<R extends BaseEntity, T extends Crud
|
|
|
6
6
|
protected readonly service: T;
|
|
7
7
|
protected config: EntityConfig;
|
|
8
8
|
protected adminGroupNames: string[];
|
|
9
|
+
private roleController;
|
|
9
10
|
protected constructor(baseService: T, config: EntityConfig);
|
|
11
|
+
/** Return constructor-defined resource name */
|
|
12
|
+
protected getResource(): string;
|
|
10
13
|
resolveCrudRequest(event: APIGatewayProxyEvent): Promise<APIResponse>;
|
|
11
14
|
setConfig(config: EntityConfig): void;
|
|
12
15
|
processCrudRequestPre(req: HttpRequest): Promise<HttpRequest>;
|
|
13
16
|
processCrudRequestPost(request: HttpRequest, response: R | List<R>): Promise<R | List<R>>;
|
|
14
17
|
protected handleList(methode: HttpMethod, path: string, request: HttpRequest): Promise<any>;
|
|
18
|
+
protected handlePermission(req: HttpRequest, path: string): Promise<any>;
|
|
15
19
|
protected handleUpdate(entityId: string, requestBody: any, requestedUser?: CognitoUser): Promise<R>;
|
|
16
20
|
protected handleDelete(entityId: string, requestedUser?: CognitoUser): Promise<boolean>;
|
|
17
21
|
protected handleFetch(entityId: string, requestedUser?: CognitoUser): Promise<R>;
|
|
18
22
|
protected handleReplace(entityId: string, entity: any, requestedUser?: CognitoUser): Promise<R>;
|
|
19
23
|
protected handlePostCreate(entity: R, cognitoUser: CognitoUser): Promise<R>;
|
|
20
24
|
protected abstract processCrudRequest(event: HttpRequest): Promise<any>;
|
|
25
|
+
protected isPermissionRequest(path: string): boolean;
|
|
21
26
|
protected isListRequest(methode: HttpMethod, path: string): boolean;
|
|
22
27
|
protected isUpdateRequest(methode: HttpMethod, path: string): boolean;
|
|
23
28
|
protected isDeleteRequest(methode: HttpMethod, path: string): boolean;
|
|
@@ -4,10 +4,12 @@ exports.ControllerApi = void 0;
|
|
|
4
4
|
const index_1 = require("../index");
|
|
5
5
|
const exception_1 = require("../exception");
|
|
6
6
|
const string_util_1 = require("../utils/string.util");
|
|
7
|
+
const controller_role_1 = require("./controller-role");
|
|
7
8
|
class ControllerApi {
|
|
8
9
|
service;
|
|
9
10
|
config;
|
|
10
11
|
adminGroupNames;
|
|
12
|
+
roleController;
|
|
11
13
|
constructor(baseService, config) {
|
|
12
14
|
this.service = baseService;
|
|
13
15
|
if (!config)
|
|
@@ -16,13 +18,26 @@ class ControllerApi {
|
|
|
16
18
|
if (config.ADMIN_GROUP_NAME) {
|
|
17
19
|
this.adminGroupNames = config.ADMIN_GROUP_NAME;
|
|
18
20
|
}
|
|
21
|
+
if (config.PERMISSION_MAP) {
|
|
22
|
+
this.roleController = new controller_role_1.ControllerRole(config.PERMISSION_MAP.roleTable);
|
|
23
|
+
}
|
|
19
24
|
this.service.setConfig(config);
|
|
20
25
|
}
|
|
26
|
+
/** Return constructor-defined resource name */
|
|
27
|
+
getResource() {
|
|
28
|
+
return this.config.BASE_PATH.replace("/", "");
|
|
29
|
+
}
|
|
21
30
|
async resolveCrudRequest(event) {
|
|
22
31
|
try {
|
|
23
32
|
let req = (0, index_1.parseHttpRequest)(event, this.adminGroupNames);
|
|
24
33
|
const policy = (0, index_1.findMatchedPolicy)(req.methode, event?.requestContext?.resourcePath, this.config.ENDPOINT_POLICY);
|
|
25
|
-
this.
|
|
34
|
+
if (this.config.PERMISSION_MAP && this.roleController) {
|
|
35
|
+
const resource = this.getResource();
|
|
36
|
+
await this.roleController.checkRbacAccess(req, resource, this.config.PERMISSION_MAP.scopeMap, this.adminGroupNames);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
this.checkPermission(policy?.access, req.requestType);
|
|
40
|
+
}
|
|
26
41
|
this.validateRequest(policy?.validator, req.body);
|
|
27
42
|
if (req.identity) {
|
|
28
43
|
log.debug("groups: " + JSON.stringify(req.identity.groups, null, 2));
|
|
@@ -78,6 +93,9 @@ class ControllerApi {
|
|
|
78
93
|
return await this.service.scan(request?.filter || {});
|
|
79
94
|
}
|
|
80
95
|
}
|
|
96
|
+
async handlePermission(req, path) {
|
|
97
|
+
return this.roleController.handlePermissionRequest(req, path, this.config.PERMISSION_MAP, this.adminGroupNames);
|
|
98
|
+
}
|
|
81
99
|
async handleUpdate(entityId, requestBody, requestedUser) {
|
|
82
100
|
if (!entityId)
|
|
83
101
|
throw new exception_1.ErrorHttp({ code: 400, error: "BadRequest" }, "[CORE] Cannot PATCH resource without id field");
|
|
@@ -149,6 +167,14 @@ class ControllerApi {
|
|
|
149
167
|
// Save entity
|
|
150
168
|
return this.service.save(entity, profileId, parentId, cognitoUser);
|
|
151
169
|
}
|
|
170
|
+
isPermissionRequest(path) {
|
|
171
|
+
if (this.config.PERMISSION_MAP && this.roleController) {
|
|
172
|
+
const rolePath = (0, string_util_1.trimSpecialChar)(this.config.PERMISSION_MAP.rolePath);
|
|
173
|
+
const normalizedPath = (0, string_util_1.trimSpecialChar)(path);
|
|
174
|
+
return normalizedPath.includes(rolePath);
|
|
175
|
+
}
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
152
178
|
isListRequest(methode, path) {
|
|
153
179
|
const basePath = (0, string_util_1.trimSpecialChar)(this.config.BASE_PATH);
|
|
154
180
|
const allowedPaths = [
|
|
@@ -195,6 +221,8 @@ class ControllerApi {
|
|
|
195
221
|
async handleCrudByMethod(req) {
|
|
196
222
|
const path = req.event?.requestContext?.resourcePath;
|
|
197
223
|
const entity = this.parseEntity(req.body);
|
|
224
|
+
if (this.isPermissionRequest(path))
|
|
225
|
+
return this.handlePermission(req, path);
|
|
198
226
|
if (this.isUpdateRequest(req.methode, path))
|
|
199
227
|
return this.handleUpdate(req.entityId, entity, req.identity);
|
|
200
228
|
if (this.isDeleteRequest(req.methode, path))
|