aws-service-stack 0.18.377 → 0.18.379
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/_examples/controller/{property/property-crud.js → properties/properties-crud.js} +1 -1
- package/dist/_examples/controller/properties/properties-crud.js.map +1 -0
- package/dist/_examples/controller/{property → properties}/property.config.d.ts +1 -1
- package/dist/_examples/controller/{property → properties}/property.config.js +17 -20
- package/dist/_examples/controller/properties/property.config.js.map +1 -0
- package/dist/_examples/controller/{property → properties}/property.controller.d.ts +0 -1
- package/dist/_examples/controller/{property → properties}/property.controller.js +0 -4
- package/dist/_examples/controller/properties/property.controller.js.map +1 -0
- package/dist/controller/controller-api.js +5 -2
- package/dist/controller/controller-api.js.map +1 -1
- package/dist/controller/controller-role.d.ts +13 -6
- package/dist/controller/controller-role.js +92 -61
- package/dist/controller/controller-role.js.map +1 -1
- package/dist/model/base.model.d.ts +1 -0
- package/dist/model/base.model.js.map +1 -1
- package/dist/service/permission.repo.d.ts +2 -0
- package/dist/service/permission.repo.js +3 -0
- package/dist/service/permission.repo.js.map +1 -1
- package/dist/service/permission.service.d.ts +2 -1
- package/dist/service/permission.service.js +2 -3
- package/dist/service/permission.service.js.map +1 -1
- package/package.json +1 -1
- package/dist/_examples/controller/property/property-crud.js.map +0 -1
- package/dist/_examples/controller/property/property.config.js.map +0 -1
- package/dist/_examples/controller/property/property.controller.js.map +0 -1
- package/dist/_examples/controller/property/property.permissions.d.ts +0 -2
- package/dist/_examples/controller/property/property.permissions.js +0 -19
- package/dist/_examples/controller/property/property.permissions.js.map +0 -1
- /package/dist/_examples/controller/{property/property-crud.d.ts → properties/properties-crud.d.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"properties-crud.js","sourceRoot":"","sources":["../../../../src/_examples/controller/properties/properties-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"]}
|
|
@@ -3,13 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.CONFIG_PROPERTY = exports.PropertyConfig = exports.path = exports.openSearch_order = void 0;
|
|
4
4
|
const base_config_1 = require("../../../model/base.config");
|
|
5
5
|
const core_1 = require("../../../index.js");
|
|
6
|
-
const order_repo_db_interface_1 = require("../../repositories/order/order-repo-db.interface");
|
|
7
6
|
// OpenSearch configuration
|
|
8
7
|
exports.openSearch_order = {
|
|
9
|
-
domain: "https://search-
|
|
8
|
+
domain: "https://search-plp-2sf54r2u5ip4cijraklbfwgyti.ap-southeast-1.es.amazonaws.com",
|
|
10
9
|
index: "order",
|
|
11
10
|
};
|
|
12
|
-
exports.path = "/
|
|
11
|
+
exports.path = "/properties"; // url path base
|
|
13
12
|
// Order configuration
|
|
14
13
|
class PropertyConfig extends base_config_1.EntityConfigImpl {
|
|
15
14
|
constructor() {
|
|
@@ -17,34 +16,32 @@ class PropertyConfig extends base_config_1.EntityConfigImpl {
|
|
|
17
16
|
const tableName = "Property-dev";
|
|
18
17
|
const ownerFieldName = "ownerId";
|
|
19
18
|
const indexMap = new core_1.DynamoIndexMap()
|
|
20
|
-
.setFields("
|
|
19
|
+
.setFields("id")
|
|
21
20
|
.set("byAgent", { field: "agentId", rFields: ["agentId"] })
|
|
22
|
-
.set("
|
|
21
|
+
.set("byBranch", { field: "branchId", rFields: ["branchId"] })
|
|
23
22
|
.set("byOrg", { field: "organizationId", rFields: ["organizationId"] });
|
|
24
23
|
// PERMISSIONS
|
|
25
|
-
const adminGroupNames = ["
|
|
24
|
+
const adminGroupNames = ["admin"];
|
|
26
25
|
const policyList = [
|
|
27
|
-
{ method: core_1.HttpMethod.GET, path: `${exports.path}
|
|
28
|
-
{ method: core_1.HttpMethod.GET, path: `${exports.path}/search
|
|
29
|
-
{ method: core_1.HttpMethod.GET, path: `${exports.path}/
|
|
30
|
-
{ method: core_1.HttpMethod.
|
|
31
|
-
{ method: core_1.HttpMethod.
|
|
32
|
-
{ method: core_1.HttpMethod.
|
|
33
|
-
{ method: core_1.HttpMethod.
|
|
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] },
|
|
26
|
+
{ method: core_1.HttpMethod.GET, path: `${exports.path}` },
|
|
27
|
+
{ method: core_1.HttpMethod.GET, path: `${exports.path}/search/query` },
|
|
28
|
+
{ method: core_1.HttpMethod.GET, path: `${exports.path}/{id}` },
|
|
29
|
+
{ method: core_1.HttpMethod.POST, path: `${exports.path}` },
|
|
30
|
+
{ method: core_1.HttpMethod.PUT, path: `${exports.path}/{id}` },
|
|
31
|
+
{ method: core_1.HttpMethod.PATCH, path: `${exports.path}/{id}` },
|
|
32
|
+
{ method: core_1.HttpMethod.DELETE, path: `${exports.path}/{id}` },
|
|
36
33
|
];
|
|
37
34
|
// SCOPES
|
|
38
35
|
const scopeMap = new core_1.ScopeMap()
|
|
39
|
-
.set("
|
|
40
|
-
.set("
|
|
41
|
-
.set("
|
|
36
|
+
.set("org", { filterField: "organizationId", claimKey: "custom:org", level: 1 })
|
|
37
|
+
.set("branch", { filterField: "branchId", claimKey: "custom:branch", level: 2 })
|
|
38
|
+
.set("agent", { filterField: "agentId", claimKey: "sub", level: 3 });
|
|
42
39
|
// INIT
|
|
43
40
|
super(exports.path, adminGroupNames);
|
|
44
41
|
this.setDynamoDB(tableName, ownerFieldName, indexMap)
|
|
45
|
-
.setOpenSearch(exports.openSearch_order.domain,
|
|
42
|
+
.setOpenSearch(exports.openSearch_order.domain, tableName.toLowerCase())
|
|
46
43
|
.setPolicies(policyList)
|
|
47
|
-
.setPermissionMap({ scopeMap, roleTable: "Permission-dev", rolePath: "/permission
|
|
44
|
+
.setPermissionMap({ scopeMap, roleTable: "Permission-dev", rolePath: "/permission" });
|
|
48
45
|
}
|
|
49
46
|
}
|
|
50
47
|
exports.PropertyConfig = PropertyConfig;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property.config.js","sourceRoot":"","sources":["../../../../src/_examples/controller/properties/property.config.ts"],"names":[],"mappings":";;;AAAA,4DAA8D;AAC9D,yCAA2F;AAE3F,2BAA2B;AACd,QAAA,gBAAgB,GAAG;IAC9B,MAAM,EAAE,+EAA+E;IACvF,KAAK,EAAE,OAAO;CACf,CAAC;AACW,QAAA,IAAI,GAAG,aAAa,CAAC,CAAC,gBAAgB;AAEnD,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,IAAI,CAAC;aACf,GAAG,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC;aAC1D,GAAG,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;aAC7D,GAAG,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;QAE1E,cAAc;QACd,MAAM,eAAe,GAAG,CAAC,OAAO,CAAC,CAAC;QAElC,MAAM,UAAU,GAAqB;YACnC,EAAE,MAAM,EAAE,iBAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,YAAI,EAAE,EAAE;YAClC,EAAE,MAAM,EAAE,iBAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,YAAI,eAAe,EAAE;YAC/C,EAAE,MAAM,EAAE,iBAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,YAAI,OAAO,EAAE;YACvC,EAAE,MAAM,EAAE,iBAAC,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,YAAI,EAAE,EAAE;YACnC,EAAE,MAAM,EAAE,iBAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,YAAI,OAAO,EAAE;YACvC,EAAE,MAAM,EAAE,iBAAC,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,YAAI,OAAO,EAAE;YACzC,EAAE,MAAM,EAAE,iBAAC,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,YAAI,OAAO,EAAE;SAC3C,CAAC;QAEF,SAAS;QACT,MAAM,QAAQ,GAAG,IAAI,eAAQ,EAAE;aAC5B,GAAG,CAAC,KAAK,EAAE,EAAE,WAAW,EAAE,gBAAgB,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;aAC/E,GAAG,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;aAC/E,GAAG,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QAEvE,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,SAAS,CAAC,WAAW,EAAE,CAAC;aAC/D,WAAW,CAAC,UAAU,CAAC;aACvB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC,CAAC;IAC1F,CAAC;CACF;AArCD,wCAqCC;AAED,qCAAqC;AACxB,QAAA,eAAe,GAAG,IAAI,cAAc,EAAE,CAAC","sourcesContent":["import { EntityConfigImpl } from \"../../../model/base.config\";\nimport { DynamoIndexMap, EndpointPolicy, HttpMethod as m, ScopeMap } from \"@chinggis/core\";\n\n// OpenSearch configuration\nexport const openSearch_order = {\n domain: \"https://search-plp-2sf54r2u5ip4cijraklbfwgyti.ap-southeast-1.es.amazonaws.com\",\n index: \"order\",\n};\nexport const path = \"/properties\"; // 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(\"id\")\n .set(\"byAgent\", { field: \"agentId\", rFields: [\"agentId\"] })\n .set(\"byBranch\", { field: \"branchId\", rFields: [\"branchId\"] })\n .set(\"byOrg\", { field: \"organizationId\", rFields: [\"organizationId\"] });\n\n // PERMISSIONS\n const adminGroupNames = [\"admin\"];\n\n const policyList: EndpointPolicy[] = [\n { method: m.GET, path: `${path}` },\n { method: m.GET, path: `${path}/search/query` },\n { method: m.GET, path: `${path}/{id}` },\n { method: m.POST, path: `${path}` },\n { method: m.PUT, path: `${path}/{id}` },\n { method: m.PATCH, path: `${path}/{id}` },\n { method: m.DELETE, path: `${path}/{id}` },\n ];\n\n // SCOPES\n const scopeMap = new ScopeMap()\n .set(\"org\", { filterField: \"organizationId\", claimKey: \"custom:org\", level: 1 })\n .set(\"branch\", { filterField: \"branchId\", claimKey: \"custom:branch\", level: 2 })\n .set(\"agent\", { filterField: \"agentId\", claimKey: \"sub\", level: 3 });\n\n // INIT\n super(path, adminGroupNames);\n this.setDynamoDB(tableName, ownerFieldName, indexMap)\n .setOpenSearch(openSearch_order.domain, tableName.toLowerCase())\n .setPolicies(policyList)\n .setPermissionMap({ scopeMap, roleTable: \"Permission-dev\", rolePath: \"/permission\" });\n }\n}\n\n// Export default Order configuration\nexport const CONFIG_PROPERTY = new PropertyConfig();\n"]}
|
|
@@ -10,5 +10,4 @@ import { ControllerApi } from "src/controller";
|
|
|
10
10
|
export declare class PropertyController extends ControllerApi<Order, OrderService> {
|
|
11
11
|
protected processCrudRequest(event: HttpRequest): Promise<any>;
|
|
12
12
|
constructor();
|
|
13
|
-
getPermission(permission: string): Promise<boolean>;
|
|
14
13
|
}
|
|
@@ -47,7 +47,6 @@ const typedi_1 = __importStar(require("typedi"));
|
|
|
47
47
|
const property_config_1 = require("./property.config");
|
|
48
48
|
require("../../service/order-service");
|
|
49
49
|
const controller_1 = require("src/controller");
|
|
50
|
-
const property_permissions_1 = require("./property.permissions");
|
|
51
50
|
/**
|
|
52
51
|
* Example Controller for Profile: Validator (Zod) is set centrally.
|
|
53
52
|
* Scopes are configured in PropertyConfig via ScopeMap.
|
|
@@ -60,9 +59,6 @@ let PropertyController = class PropertyController extends controller_1.Controlle
|
|
|
60
59
|
const service = typedi_1.default.get("OrderService");
|
|
61
60
|
super(service, property_config_1.CONFIG_PROPERTY.toObject());
|
|
62
61
|
}
|
|
63
|
-
async getPermission(permission) {
|
|
64
|
-
return (0, property_permissions_1.hasPropertyPermission)(permission);
|
|
65
|
-
}
|
|
66
62
|
};
|
|
67
63
|
exports.PropertyController = PropertyController;
|
|
68
64
|
exports.PropertyController = PropertyController = __decorate([
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property.controller.js","sourceRoot":"","sources":["../../../../src/_examples/controller/properties/property.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAA4C;AAG5C,uDAAoD;AAEpD,uCAAqC;AAGrC,+CAA+C;AAE/C;;;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;CACF,CAAA;AATY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,gBAAO,EAAC,oBAAoB,CAAC;;GACjB,kBAAkB,CAS9B","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\";\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"]}
|
|
@@ -31,12 +31,15 @@ class ControllerApi {
|
|
|
31
31
|
try {
|
|
32
32
|
let req = (0, index_1.parseHttpRequest)(event, this.adminGroupNames);
|
|
33
33
|
const policy = (0, index_1.findMatchedPolicy)(req.methode, event?.requestContext?.resourcePath, this.config.ENDPOINT_POLICY);
|
|
34
|
-
if (policy
|
|
34
|
+
if (policy?.access?.length) {
|
|
35
35
|
this.checkPermission(policy?.access, req.requestType);
|
|
36
36
|
}
|
|
37
37
|
else if (this.config.PERMISSION_MAP && this.roleController) {
|
|
38
38
|
const resource = this.getResource();
|
|
39
|
-
await this.roleController.
|
|
39
|
+
await this.roleController.checkAccess(req, resource, this.config.PERMISSION_MAP.scopeMap, this.adminGroupNames);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
throw new exception_1.ErrorHttp({ code: 403, error: "PermissionDenied" }, "Access denied");
|
|
40
43
|
}
|
|
41
44
|
this.validateRequest(policy?.validator, req.body);
|
|
42
45
|
if (req.identity) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller-api.js","sourceRoot":"","sources":["../../src/controller/controller-api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Access,\n APIResponse,\n BaseEntity,\n createApiResponse,\n EndpointPolicy,\n findMatchedPolicy,\n formatErrors,\n HttpMethod,\n HttpRequest,\n List,\n parseHttpRequest,\n removeFields,\n RequestType,\n ResponseFields,\n validateWithSchema,\n} from \"../index\";\nimport { APIGatewayProxyEvent } from \"aws-lambda\";\nimport { errorHandlerHttp, ErrorHttp } from \"../exception\";\nimport { CognitoUser, EntityConfig } from \"@chinggis/types\";\nimport { trimSpecialChar } from \"../utils/string.util\";\nimport { CrudService } from \"../service\";\nimport { ControllerRole } from \"./controller-role\";\n\nexport abstract class ControllerApi<R extends BaseEntity, T extends CrudService<R>> {\n protected readonly service: T;\n protected config: EntityConfig;\n protected adminGroupNames: string[];\n\n private roleController: ControllerRole;\n\n protected constructor(baseService: T, config: EntityConfig) {\n this.service = baseService;\n\n if (!config) return;\n\n this.config = config;\n\n if (config.ADMIN_GROUP_NAME) {\n this.adminGroupNames = config.ADMIN_GROUP_NAME;\n }\n\n if (config.PERMISSION_MAP) {\n this.roleController = new ControllerRole(config.PERMISSION_MAP.roleTable);\n }\n\n this.service.setConfig(config);\n }\n\n /** Return constructor-defined resource name */\n protected getResource(): string {\n return this.config.BASE_PATH.replace(\"/\", \"\");\n }\n\n async resolveCrudRequest(event: APIGatewayProxyEvent): Promise<APIResponse> {\n try {\n let req = parseHttpRequest(event, this.adminGroupNames);\n\n const policy: EndpointPolicy | undefined = findMatchedPolicy(\n req.methode,\n event?.requestContext?.resourcePath,\n this.config.ENDPOINT_POLICY,\n );\n\n if (policy.access?.length) {\n this.checkPermission(policy?.access, req.requestType);\n } else if (this.config.PERMISSION_MAP && this.roleController) {\n const resource = this.getResource();\n await this.roleController.checkRbacAccess(\n req,\n resource,\n this.config.PERMISSION_MAP.scopeMap,\n this.adminGroupNames,\n );\n }\n\n this.validateRequest(policy?.validator, req.body);\n\n if (req.identity) {\n log.debug(\"groups: \" + JSON.stringify(req.identity.groups, null, 2));\n log.debug(`claims:${JSON.stringify(req.identity, null, 2)}`);\n log.debug(\n `groups:${req.identity.groups}, isAdmin:${req.identity.isAdmin}, userId:${req.identity.sub}, profileId:${req.identity.profile}, username:${req.identity.username}, requestType:${req.requestType}`,\n );\n }\n\n // if (req.isAdmin) {\n // delete req.filter[\"profileId\"];\n // delete req.filter[\"ownerParentId\"];\n // }\n\n req = await this.processCrudRequestPre(req);\n\n let response: any = await this.handleCrudByMethod(req);\n\n if (response) response = await this.processCrudRequestPost(req, response);\n else response = await this.processCrudRequest(req); // Custom Endpoints\n\n if (!policy?.response) {\n return createApiResponse(200, response);\n }\n\n const filteredResponse = this.filterResponse(response, policy.response);\n\n return createApiResponse(200, filteredResponse);\n } catch (err) {\n const error = errorHandlerHttp(err);\n log.error(error);\n return createApiResponse(error.statusCode, error.content);\n }\n }\n\n setConfig(config: EntityConfig): void {\n this.config = config;\n }\n\n async processCrudRequestPre(req: HttpRequest): Promise<HttpRequest> {\n return req;\n }\n\n async processCrudRequestPost(request: HttpRequest, response: R | List<R>): Promise<R | List<R>> {\n return response;\n }\n\n protected async handleList(methode: HttpMethod, path: string, request: HttpRequest): Promise<any> {\n if (methode === \"GET\" && trimSpecialChar(path) === trimSpecialChar(this.config.BASE_PATH)) {\n return await this.service.find(request?.filter || {});\n }\n\n if (methode === \"GET\" && trimSpecialChar(path) === trimSpecialChar(this.config.BASE_PATH) + \"/search\") {\n return this.service.search(request?.filter || {});\n }\n\n if (methode === \"GET\" && trimSpecialChar(path) === trimSpecialChar(this.config.BASE_PATH) + \"/search/query\") {\n return this.service.searchQuery(request?.filter);\n }\n\n if (\n methode === \"GET\" &&\n trimSpecialChar(path) === trimSpecialChar(this.config.BASE_PATH) + \"/search/query/total-count\"\n ) {\n return this.service.searchQueryTotalCount(request?.filter);\n }\n\n if (methode === \"GET\" && trimSpecialChar(path) === trimSpecialChar(this.config.BASE_PATH) + \"/scan\") {\n return await this.service.scan(request?.filter || {});\n }\n }\n\n protected async handlePermission(req: HttpRequest, path: string) {\n return this.roleController.handlePermissionRequest(req, path, this.config.PERMISSION_MAP, this.adminGroupNames);\n }\n\n protected async handleUpdate(entityId: string, requestBody: any, requestedUser?: CognitoUser): Promise<R> {\n if (!entityId)\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] Cannot PATCH resource without id field\");\n\n const entity = this.parseEntity(requestBody);\n\n if (Object.keys(entity).length === 0) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] No fields to update\");\n }\n\n const fieldName = this.config.DYNAMO_DB?.MAP?.partitionKey ?? \"id\";\n\n // id change is forbidden\n if (entity[fieldName]) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] Cannot modify the id field\");\n }\n\n entity[fieldName] = entityId;\n return this.service.update(entity, requestedUser);\n }\n\n protected async handleDelete(entityId: string, requestedUser?: CognitoUser): Promise<boolean> {\n if (!entityId)\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] Cannot delete resource without id field\");\n\n return this.service.remove(entityId, requestedUser);\n }\n\n protected async handleFetch(entityId: string, requestedUser?: CognitoUser): Promise<R> {\n if (!entityId)\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] Cannot fetch resource without id field\");\n\n const result = await this.service.findById(entityId, requestedUser);\n\n if (result) return result;\n\n throw new ErrorHttp({ code: 404, error: \"NotFound\" }, `[CORE] Resource with ID ${entityId} not found`);\n }\n\n protected async handleReplace(entityId: string, entity: any, requestedUser?: CognitoUser) {\n if (!entityId)\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] Cannot PUT resource without id field\");\n\n if (!Object.keys(entity).length) {\n throw new ErrorHttp({ code: 400, error: \"Bad Request\" }, \"[CORE] No entity provided for PUT update\");\n }\n\n if (!entityId) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] Cannot PUT resource without id field\");\n }\n\n entity.id = entityId;\n\n return this.service.update(entity, requestedUser);\n }\n\n protected async handlePostCreate(entity: R, cognitoUser: CognitoUser) {\n if (!entity || Object.keys(entity).length === 0) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] No entity payload provided\");\n }\n\n if (!entity.ownerId) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] No ownerId provided\");\n }\n\n // Initialize IDs\n const { ownerId, ownerParentId: inputParentId } = entity;\n let profileId = ownerId;\n let parentId: string;\n\n // Determine parentId and profileId\n if (cognitoUser.isAdmin && inputParentId) {\n parentId = inputParentId;\n } else if (cognitoUser.isParent) {\n console.log(\"is parent becomming true\");\n\n parentId = cognitoUser.profile;\n } else {\n console.log(\"is parent not becomming true\");\n console.log(\"the value of isParent: \", cognitoUser.isParent, typeof cognitoUser.isParent);\n\n parentId = cognitoUser.parentId;\n profileId = cognitoUser.profile;\n }\n\n // Remove fields that shouldn't be saved directly\n delete entity.ownerParentId;\n delete entity.ownerId;\n\n // Save entity\n return this.service.save(entity, profileId, parentId, cognitoUser);\n }\n\n protected abstract processCrudRequest(event: HttpRequest): Promise<any>;\n\n protected isPermissionRequest(path: string): boolean {\n if (this.config.PERMISSION_MAP && this.roleController) {\n const rolePath = trimSpecialChar(this.config.PERMISSION_MAP.rolePath);\n const normalizedPath = trimSpecialChar(path);\n return normalizedPath.includes(rolePath);\n }\n\n return false;\n }\n\n protected isListRequest(methode: HttpMethod, path: string): boolean {\n const basePath = trimSpecialChar(this.config.BASE_PATH);\n\n const allowedPaths = [\n basePath,\n `${basePath}/search`,\n `${basePath}/scan`,\n `${basePath}/search/query`,\n `${basePath}/search/query/total-count`,\n ];\n\n const isMethodGet = methode === \"GET\";\n const isAllowedPath = allowedPaths.includes(trimSpecialChar(path));\n\n return isMethodGet && isAllowedPath;\n }\n\n protected isUpdateRequest(methode: HttpMethod, path: string): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}/{id}`;\n const isMethodPatch = methode === \"PATCH\";\n const isExpectedPath = trimSpecialChar(path) === expectedPath;\n\n return isMethodPatch && isExpectedPath;\n }\n\n protected isDeleteRequest(methode: HttpMethod, path: string): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}/{id}`;\n const isMethodDelete = methode === \"DELETE\";\n const isExpectedPath = trimSpecialChar(path) === expectedPath;\n\n return isMethodDelete && isExpectedPath;\n }\n\n protected isFetchRequest(methode: HttpMethod, path: string): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}/{id}`;\n const isMethodGet = methode === \"GET\";\n const isExpectedPath = trimSpecialChar(path) === expectedPath;\n\n return isMethodGet && isExpectedPath;\n }\n\n protected isPostRequest(methode: HttpMethod, path: string): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}`;\n const isMethodGet = methode === \"POST\";\n const isExpectedPath = trimSpecialChar(path) === expectedPath;\n\n return isMethodGet && isExpectedPath;\n }\n\n protected isPutRequest(methode: HttpMethod, path: string): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}/{id}`;\n const isMethodGet = methode === \"PUT\";\n const isExpectedPath = trimSpecialChar(path) === expectedPath;\n\n return isMethodGet && isExpectedPath;\n }\n\n private async handleCrudByMethod(req: HttpRequest): Promise<any> {\n const path = req.event?.requestContext?.resourcePath;\n\n const entity = this.parseEntity(req.body);\n\n if (this.isPermissionRequest(path)) return this.handlePermission(req, path);\n if (this.isUpdateRequest(req.methode, path)) return this.handleUpdate(req.entityId, entity, req.identity);\n if (this.isDeleteRequest(req.methode, path)) return this.handleDelete(req.entityId, req.identity);\n if (this.isFetchRequest(req.methode, path)) return this.handleFetch(req.entityId, req.identity);\n if (this.isPutRequest(req.methode, path)) return this.handleReplace(req.entityId, entity, req.identity);\n if (this.isPostRequest(req.methode, path)) return this.handlePostCreate(entity, req.identity);\n if (this.isListRequest(req.methode, path)) return this.handleList(req.methode, path, req);\n\n return null;\n }\n\n private filterResponse(response: any, responsePolicy: ResponseFields): any {\n if (Array.isArray(response)) {\n return removeFields(response, responsePolicy.include, responsePolicy.exclude);\n }\n\n if (response?.items && Array.isArray(response.items)) {\n response.items = removeFields(response.items, responsePolicy.include, responsePolicy.exclude);\n return response;\n }\n\n return removeFields([response], responsePolicy.include, responsePolicy.exclude)[0];\n }\n\n /** Map RequestType to Access for permission checking */\n private getUserAccessLevel(requestType: RequestType): Access {\n switch (requestType) {\n case RequestType.ADMIN:\n return Access.ADMIN;\n case RequestType.USER:\n return Access.USER;\n case RequestType.GUEST:\n return Access.PUBLIC;\n case RequestType.SYSTEM:\n return Access.SYSTEM;\n default:\n return Access.PUBLIC;\n }\n }\n\n /** Check if the user has permission for the current operation */\n private checkPermission(allowedAccess: Access[], requestType: RequestType) {\n const currentAccessLevel = this.getUserAccessLevel(requestType);\n\n // This means USER can access OWNER-level permissions, but the service will verify actual ownership\n const hasPermission =\n allowedAccess.includes(currentAccessLevel) ||\n (requestType === RequestType.USER && allowedAccess.includes(Access.OWNER));\n\n if (hasPermission) return;\n\n throw new ErrorHttp(\n { code: 403, error: \"PermissionDenied\" },\n `Access denied. Required: ${allowedAccess.join(\", \")}, Current: ${currentAccessLevel}`,\n );\n }\n\n private setUserFilter(request: any, isAdmin: boolean, profileId: string) {\n if (isAdmin && !profileId) return;\n const ownerIdFieldName = this.config.OWNER_ID_FIELD_NAME || \"ownerId\";\n request.filterAndSort[ownerIdFieldName] = profileId;\n return request.filterAndSort;\n }\n\n private parseEntity(requestBody: any): R {\n if (!requestBody) return {} as R;\n return typeof requestBody === \"string\" ? JSON.parse(requestBody) : requestBody;\n }\n\n private validateRequest(schema: any, requestBody: any) {\n if (!schema) return;\n\n try {\n validateWithSchema(schema, requestBody);\n } catch (error) {\n const formattedErrors = formatErrors(error);\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, formattedErrors);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"controller-api.js","sourceRoot":"","sources":["../../src/controller/controller-api.ts"],"names":[],"mappings":";;;AAAA,oCAgBkB;AAElB,4CAA2D;AAE3D,sDAAuD;AAEvD,uDAAmD;AAEnD,MAAsB,aAAa;IACd,OAAO,CAAI;IACpB,MAAM,CAAe;IACrB,eAAe,CAAW;IAE5B,cAAc,CAAiB;IAEvC,YAAsB,WAAc,EAAE,MAAoB;QACxD,IAAI,CAAC,OAAO,GAAG,WAAW,CAAC;QAE3B,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;YAC5B,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,gBAAgB,CAAC;QACjD,CAAC;QAED,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;YAC1B,IAAI,CAAC,cAAc,GAAG,IAAI,gCAAc,CAAC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QAC5E,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAED,+CAA+C;IACrC,WAAW;QACnB,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,KAA2B;QAClD,IAAI,CAAC;YACH,IAAI,GAAG,GAAG,IAAA,wBAAgB,EAAC,KAAK,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;YAExD,MAAM,MAAM,GAA+B,IAAA,yBAAiB,EAC1D,GAAG,CAAC,OAAO,EACX,KAAK,EAAE,cAAc,EAAE,YAAY,EACnC,IAAI,CAAC,MAAM,CAAC,eAAe,CAC5B,CAAC;YAEF,IAAI,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;gBAC3B,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;YACxD,CAAC;iBAAM,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;gBACpC,MAAM,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;YAClH,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAAE,eAAe,CAAC,CAAC;YACjF,CAAC;YAED,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;YAElD,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;gBACjB,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBACrE,GAAG,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC7D,GAAG,CAAC,KAAK,CACP,UAAU,GAAG,CAAC,QAAQ,CAAC,MAAM,aAAa,GAAG,CAAC,QAAQ,CAAC,OAAO,YAAY,GAAG,CAAC,QAAQ,CAAC,GAAG,eAAe,GAAG,CAAC,QAAQ,CAAC,OAAO,cAAc,GAAG,CAAC,QAAQ,CAAC,QAAQ,iBAAiB,GAAG,CAAC,WAAW,EAAE,CACnM,CAAC;YACJ,CAAC;YAED,0BAA0B;YAC1B,yCAAyC;YACzC,6CAA6C;YAC7C,SAAS;YAET,GAAG,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;YAE5C,IAAI,QAAQ,GAAQ,MAAM,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;YAEvD,IAAI,QAAQ;gBAAE,QAAQ,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;;gBACrE,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,mBAAmB;YAEvE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC;gBACtB,OAAO,IAAA,yBAAiB,EAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAC1C,CAAC;YAED,MAAM,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YAExE,OAAO,IAAA,yBAAiB,EAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,IAAA,4BAAgB,EAAC,GAAG,CAAC,CAAC;YACpC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACjB,OAAO,IAAA,yBAAiB,EAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,SAAS,CAAC,MAAoB;QAC5B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,GAAgB;QAC1C,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAC,OAAoB,EAAE,QAAqB;QACtE,OAAO,QAAQ,CAAC;IAClB,CAAC;IAES,KAAK,CAAC,UAAU,CAAC,OAAmB,EAAE,IAAY,EAAE,OAAoB;QAChF,IAAI,OAAO,KAAK,KAAK,IAAI,IAAA,6BAAe,EAAC,IAAI,CAAC,KAAK,IAAA,6BAAe,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1F,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,IAAI,OAAO,KAAK,KAAK,IAAI,IAAA,6BAAe,EAAC,IAAI,CAAC,KAAK,IAAA,6BAAe,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,SAAS,EAAE,CAAC;YACtG,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC;QACpD,CAAC;QAED,IAAI,OAAO,KAAK,KAAK,IAAI,IAAA,6BAAe,EAAC,IAAI,CAAC,KAAK,IAAA,6BAAe,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,eAAe,EAAE,CAAC;YAC5G,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACnD,CAAC;QAED,IACE,OAAO,KAAK,KAAK;YACjB,IAAA,6BAAe,EAAC,IAAI,CAAC,KAAK,IAAA,6BAAe,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,2BAA2B,EAC9F,CAAC;YACD,OAAO,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,OAAO,KAAK,KAAK,IAAI,IAAA,6BAAe,EAAC,IAAI,CAAC,KAAK,IAAA,6BAAe,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,OAAO,EAAE,CAAC;YACpG,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAES,KAAK,CAAC,gBAAgB,CAAC,GAAgB,EAAE,IAAY;QAC7D,OAAO,IAAI,CAAC,cAAc,CAAC,uBAAuB,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;IAClH,CAAC;IAES,KAAK,CAAC,YAAY,CAAC,QAAgB,EAAE,WAAgB,EAAE,aAA2B;QAC1F,IAAI,CAAC,QAAQ;YACX,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,+CAA+C,CAAC,CAAC;QAE3G,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAE7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,4BAA4B,CAAC,CAAC;QACxF,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,YAAY,IAAI,IAAI,CAAC;QAEnE,yBAAyB;QACzB,IAAI,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,mCAAmC,CAAC,CAAC;QAC/F,CAAC;QAED,MAAM,CAAC,SAAS,CAAC,GAAG,QAAQ,CAAC;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACpD,CAAC;IAES,KAAK,CAAC,YAAY,CAAC,QAAgB,EAAE,aAA2B;QACxE,IAAI,CAAC,QAAQ;YACX,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,gDAAgD,CAAC,CAAC;QAE5G,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IACtD,CAAC;IAES,KAAK,CAAC,WAAW,CAAC,QAAgB,EAAE,aAA2B;QACvE,IAAI,CAAC,QAAQ;YACX,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,+CAA+C,CAAC,CAAC;QAE3G,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAEpE,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC;QAE1B,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,2BAA2B,QAAQ,YAAY,CAAC,CAAC;IACzG,CAAC;IAES,KAAK,CAAC,aAAa,CAAC,QAAgB,EAAE,MAAW,EAAE,aAA2B;QACtF,IAAI,CAAC,QAAQ;YACX,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,6CAA6C,CAAC,CAAC;QAEzG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;YAChC,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,0CAA0C,CAAC,CAAC;QACvG,CAAC;QAED,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,6CAA6C,CAAC,CAAC;QACzG,CAAC;QAED,MAAM,CAAC,EAAE,GAAG,QAAQ,CAAC;QAErB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACpD,CAAC;IAES,KAAK,CAAC,gBAAgB,CAAC,MAAS,EAAE,WAAwB;QAClE,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChD,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,mCAAmC,CAAC,CAAC;QAC/F,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,4BAA4B,CAAC,CAAC;QACxF,CAAC;QAED,iBAAiB;QACjB,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC;QACzD,IAAI,SAAS,GAAG,OAAO,CAAC;QACxB,IAAI,QAAgB,CAAC;QAErB,mCAAmC;QACnC,IAAI,WAAW,CAAC,OAAO,IAAI,aAAa,EAAE,CAAC;YACzC,QAAQ,GAAG,aAAa,CAAC;QAC3B,CAAC;aAAM,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;YAExC,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;YAC5C,OAAO,CAAC,GAAG,CAAC,yBAAyB,EAAE,WAAW,CAAC,QAAQ,EAAE,OAAO,WAAW,CAAC,QAAQ,CAAC,CAAC;YAE1F,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC;YAChC,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC;QAClC,CAAC;QAED,iDAAiD;QACjD,OAAO,MAAM,CAAC,aAAa,CAAC;QAC5B,OAAO,MAAM,CAAC,OAAO,CAAC;QAEtB,cAAc;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;IACrE,CAAC;IAIS,mBAAmB,CAAC,IAAY;QACxC,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACtD,MAAM,QAAQ,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;YACtE,MAAM,cAAc,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,CAAC;YAC7C,OAAO,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC3C,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAES,aAAa,CAAC,OAAmB,EAAE,IAAY;QACvD,MAAM,QAAQ,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAExD,MAAM,YAAY,GAAG;YACnB,QAAQ;YACR,GAAG,QAAQ,SAAS;YACpB,GAAG,QAAQ,OAAO;YAClB,GAAG,QAAQ,eAAe;YAC1B,GAAG,QAAQ,2BAA2B;SACvC,CAAC;QAEF,MAAM,WAAW,GAAG,OAAO,KAAK,KAAK,CAAC;QACtC,MAAM,aAAa,GAAG,YAAY,CAAC,QAAQ,CAAC,IAAA,6BAAe,EAAC,IAAI,CAAC,CAAC,CAAC;QAEnE,OAAO,WAAW,IAAI,aAAa,CAAC;IACtC,CAAC;IAES,eAAe,CAAC,OAAmB,EAAE,IAAY;QACzD,MAAM,YAAY,GAAG,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC;QACtE,MAAM,aAAa,GAAG,OAAO,KAAK,OAAO,CAAC;QAC1C,MAAM,cAAc,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,KAAK,YAAY,CAAC;QAE9D,OAAO,aAAa,IAAI,cAAc,CAAC;IACzC,CAAC;IAES,eAAe,CAAC,OAAmB,EAAE,IAAY;QACzD,MAAM,YAAY,GAAG,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC;QACtE,MAAM,cAAc,GAAG,OAAO,KAAK,QAAQ,CAAC;QAC5C,MAAM,cAAc,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,KAAK,YAAY,CAAC;QAE9D,OAAO,cAAc,IAAI,cAAc,CAAC;IAC1C,CAAC;IAES,cAAc,CAAC,OAAmB,EAAE,IAAY;QACxD,MAAM,YAAY,GAAG,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC;QACtE,MAAM,WAAW,GAAG,OAAO,KAAK,KAAK,CAAC;QACtC,MAAM,cAAc,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,KAAK,YAAY,CAAC;QAE9D,OAAO,WAAW,IAAI,cAAc,CAAC;IACvC,CAAC;IAES,aAAa,CAAC,OAAmB,EAAE,IAAY;QACvD,MAAM,YAAY,GAAG,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;QACjE,MAAM,WAAW,GAAG,OAAO,KAAK,MAAM,CAAC;QACvC,MAAM,cAAc,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,KAAK,YAAY,CAAC;QAE9D,OAAO,WAAW,IAAI,cAAc,CAAC;IACvC,CAAC;IAES,YAAY,CAAC,OAAmB,EAAE,IAAY;QACtD,MAAM,YAAY,GAAG,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC;QACtE,MAAM,WAAW,GAAG,OAAO,KAAK,KAAK,CAAC;QACtC,MAAM,cAAc,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,KAAK,YAAY,CAAC;QAE9D,OAAO,WAAW,IAAI,cAAc,CAAC;IACvC,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAAC,GAAgB;QAC/C,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,EAAE,cAAc,EAAE,YAAY,CAAC;QAErD,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAE1C,IAAI,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC5E,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC1G,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClG,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChG,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxG,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9F,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QAE1F,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,cAAc,CAAC,QAAa,EAAE,cAA8B;QAClE,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,OAAO,IAAA,oBAAY,EAAC,QAAQ,EAAE,cAAc,CAAC,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;QAChF,CAAC;QAED,IAAI,QAAQ,EAAE,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACrD,QAAQ,CAAC,KAAK,GAAG,IAAA,oBAAY,EAAC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;YAC9F,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,OAAO,IAAA,oBAAY,EAAC,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,CAAC;IAED,yDAAyD;IACjD,kBAAkB,CAAC,WAAwB;QACjD,QAAQ,WAAW,EAAE,CAAC;YACpB,KAAK,mBAAW,CAAC,KAAK;gBACpB,OAAO,cAAM,CAAC,KAAK,CAAC;YACtB,KAAK,mBAAW,CAAC,IAAI;gBACnB,OAAO,cAAM,CAAC,IAAI,CAAC;YACrB,KAAK,mBAAW,CAAC,KAAK;gBACpB,OAAO,cAAM,CAAC,MAAM,CAAC;YACvB,KAAK,mBAAW,CAAC,MAAM;gBACrB,OAAO,cAAM,CAAC,MAAM,CAAC;YACvB;gBACE,OAAO,cAAM,CAAC,MAAM,CAAC;QACzB,CAAC;IACH,CAAC;IAED,iEAAiE;IACzD,eAAe,CAAC,aAAuB,EAAE,WAAwB;QACvE,MAAM,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;QAEhE,mGAAmG;QACnG,MAAM,aAAa,GACjB,aAAa,CAAC,QAAQ,CAAC,kBAAkB,CAAC;YAC1C,CAAC,WAAW,KAAK,mBAAW,CAAC,IAAI,IAAI,aAAa,CAAC,QAAQ,CAAC,cAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAE7E,IAAI,aAAa;YAAE,OAAO;QAE1B,MAAM,IAAI,qBAAS,CACjB,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,kBAAkB,EAAE,EACxC,4BAA4B,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,kBAAkB,EAAE,CACvF,CAAC;IACJ,CAAC;IAEO,aAAa,CAAC,OAAY,EAAE,OAAgB,EAAE,SAAiB;QACrE,IAAI,OAAO,IAAI,CAAC,SAAS;YAAE,OAAO;QAClC,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC,mBAAmB,IAAI,SAAS,CAAC;QACtE,OAAO,CAAC,aAAa,CAAC,gBAAgB,CAAC,GAAG,SAAS,CAAC;QACpD,OAAO,OAAO,CAAC,aAAa,CAAC;IAC/B,CAAC;IAEO,WAAW,CAAC,WAAgB;QAClC,IAAI,CAAC,WAAW;YAAE,OAAO,EAAO,CAAC;QACjC,OAAO,OAAO,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IACjF,CAAC;IAEO,eAAe,CAAC,MAAW,EAAE,WAAgB;QACnD,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,IAAI,CAAC;YACH,IAAA,0BAAkB,EAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,eAAe,GAAG,IAAA,oBAAY,EAAC,KAAK,CAAC,CAAC;YAC5C,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,eAAe,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;CACF;AApXD,sCAoXC","sourcesContent":["import {\n Access,\n APIResponse,\n BaseEntity,\n createApiResponse,\n EndpointPolicy,\n findMatchedPolicy,\n formatErrors,\n HttpMethod,\n HttpRequest,\n List,\n parseHttpRequest,\n removeFields,\n RequestType,\n ResponseFields,\n validateWithSchema,\n} from \"../index\";\nimport { APIGatewayProxyEvent } from \"aws-lambda\";\nimport { errorHandlerHttp, ErrorHttp } from \"../exception\";\nimport { CognitoUser, EntityConfig } from \"@chinggis/types\";\nimport { trimSpecialChar } from \"../utils/string.util\";\nimport { CrudService } from \"../service\";\nimport { ControllerRole } from \"./controller-role\";\n\nexport abstract class ControllerApi<R extends BaseEntity, T extends CrudService<R>> {\n protected readonly service: T;\n protected config: EntityConfig;\n protected adminGroupNames: string[];\n\n private roleController: ControllerRole;\n\n protected constructor(baseService: T, config: EntityConfig) {\n this.service = baseService;\n\n if (!config) return;\n\n this.config = config;\n\n if (config.ADMIN_GROUP_NAME) {\n this.adminGroupNames = config.ADMIN_GROUP_NAME;\n }\n\n if (config.PERMISSION_MAP) {\n this.roleController = new ControllerRole(config.PERMISSION_MAP.roleTable);\n }\n\n this.service.setConfig(config);\n }\n\n /** Return constructor-defined resource name */\n protected getResource(): string {\n return this.config.BASE_PATH.replace(\"/\", \"\");\n }\n\n async resolveCrudRequest(event: APIGatewayProxyEvent): Promise<APIResponse> {\n try {\n let req = parseHttpRequest(event, this.adminGroupNames);\n\n const policy: EndpointPolicy | undefined = findMatchedPolicy(\n req.methode,\n event?.requestContext?.resourcePath,\n this.config.ENDPOINT_POLICY,\n );\n\n if (policy?.access?.length) {\n this.checkPermission(policy?.access, req.requestType);\n } else if (this.config.PERMISSION_MAP && this.roleController) {\n const resource = this.getResource();\n await this.roleController.checkAccess(req, resource, this.config.PERMISSION_MAP.scopeMap, this.adminGroupNames);\n } else {\n throw new ErrorHttp({ code: 403, error: \"PermissionDenied\" }, \"Access denied\");\n }\n\n this.validateRequest(policy?.validator, req.body);\n\n if (req.identity) {\n log.debug(\"groups: \" + JSON.stringify(req.identity.groups, null, 2));\n log.debug(`claims:${JSON.stringify(req.identity, null, 2)}`);\n log.debug(\n `groups:${req.identity.groups}, isAdmin:${req.identity.isAdmin}, userId:${req.identity.sub}, profileId:${req.identity.profile}, username:${req.identity.username}, requestType:${req.requestType}`,\n );\n }\n\n // if (req.isAdmin) {\n // delete req.filter[\"profileId\"];\n // delete req.filter[\"ownerParentId\"];\n // }\n\n req = await this.processCrudRequestPre(req);\n\n let response: any = await this.handleCrudByMethod(req);\n\n if (response) response = await this.processCrudRequestPost(req, response);\n else response = await this.processCrudRequest(req); // Custom Endpoints\n\n if (!policy?.response) {\n return createApiResponse(200, response);\n }\n\n const filteredResponse = this.filterResponse(response, policy.response);\n\n return createApiResponse(200, filteredResponse);\n } catch (err) {\n const error = errorHandlerHttp(err);\n log.error(error);\n return createApiResponse(error.statusCode, error.content);\n }\n }\n\n setConfig(config: EntityConfig): void {\n this.config = config;\n }\n\n async processCrudRequestPre(req: HttpRequest): Promise<HttpRequest> {\n return req;\n }\n\n async processCrudRequestPost(request: HttpRequest, response: R | List<R>): Promise<R | List<R>> {\n return response;\n }\n\n protected async handleList(methode: HttpMethod, path: string, request: HttpRequest): Promise<any> {\n if (methode === \"GET\" && trimSpecialChar(path) === trimSpecialChar(this.config.BASE_PATH)) {\n return await this.service.find(request?.filter || {});\n }\n\n if (methode === \"GET\" && trimSpecialChar(path) === trimSpecialChar(this.config.BASE_PATH) + \"/search\") {\n return this.service.search(request?.filter || {});\n }\n\n if (methode === \"GET\" && trimSpecialChar(path) === trimSpecialChar(this.config.BASE_PATH) + \"/search/query\") {\n return this.service.searchQuery(request?.filter);\n }\n\n if (\n methode === \"GET\" &&\n trimSpecialChar(path) === trimSpecialChar(this.config.BASE_PATH) + \"/search/query/total-count\"\n ) {\n return this.service.searchQueryTotalCount(request?.filter);\n }\n\n if (methode === \"GET\" && trimSpecialChar(path) === trimSpecialChar(this.config.BASE_PATH) + \"/scan\") {\n return await this.service.scan(request?.filter || {});\n }\n }\n\n protected async handlePermission(req: HttpRequest, path: string) {\n return this.roleController.handlePermissionRequest(req, path, this.config.PERMISSION_MAP, this.adminGroupNames);\n }\n\n protected async handleUpdate(entityId: string, requestBody: any, requestedUser?: CognitoUser): Promise<R> {\n if (!entityId)\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] Cannot PATCH resource without id field\");\n\n const entity = this.parseEntity(requestBody);\n\n if (Object.keys(entity).length === 0) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] No fields to update\");\n }\n\n const fieldName = this.config.DYNAMO_DB?.MAP?.partitionKey ?? \"id\";\n\n // id change is forbidden\n if (entity[fieldName]) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] Cannot modify the id field\");\n }\n\n entity[fieldName] = entityId;\n return this.service.update(entity, requestedUser);\n }\n\n protected async handleDelete(entityId: string, requestedUser?: CognitoUser): Promise<boolean> {\n if (!entityId)\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] Cannot delete resource without id field\");\n\n return this.service.remove(entityId, requestedUser);\n }\n\n protected async handleFetch(entityId: string, requestedUser?: CognitoUser): Promise<R> {\n if (!entityId)\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] Cannot fetch resource without id field\");\n\n const result = await this.service.findById(entityId, requestedUser);\n\n if (result) return result;\n\n throw new ErrorHttp({ code: 404, error: \"NotFound\" }, `[CORE] Resource with ID ${entityId} not found`);\n }\n\n protected async handleReplace(entityId: string, entity: any, requestedUser?: CognitoUser) {\n if (!entityId)\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] Cannot PUT resource without id field\");\n\n if (!Object.keys(entity).length) {\n throw new ErrorHttp({ code: 400, error: \"Bad Request\" }, \"[CORE] No entity provided for PUT update\");\n }\n\n if (!entityId) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] Cannot PUT resource without id field\");\n }\n\n entity.id = entityId;\n\n return this.service.update(entity, requestedUser);\n }\n\n protected async handlePostCreate(entity: R, cognitoUser: CognitoUser) {\n if (!entity || Object.keys(entity).length === 0) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] No entity payload provided\");\n }\n\n if (!entity.ownerId) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] No ownerId provided\");\n }\n\n // Initialize IDs\n const { ownerId, ownerParentId: inputParentId } = entity;\n let profileId = ownerId;\n let parentId: string;\n\n // Determine parentId and profileId\n if (cognitoUser.isAdmin && inputParentId) {\n parentId = inputParentId;\n } else if (cognitoUser.isParent) {\n console.log(\"is parent becomming true\");\n\n parentId = cognitoUser.profile;\n } else {\n console.log(\"is parent not becomming true\");\n console.log(\"the value of isParent: \", cognitoUser.isParent, typeof cognitoUser.isParent);\n\n parentId = cognitoUser.parentId;\n profileId = cognitoUser.profile;\n }\n\n // Remove fields that shouldn't be saved directly\n delete entity.ownerParentId;\n delete entity.ownerId;\n\n // Save entity\n return this.service.save(entity, profileId, parentId, cognitoUser);\n }\n\n protected abstract processCrudRequest(event: HttpRequest): Promise<any>;\n\n protected isPermissionRequest(path: string): boolean {\n if (this.config.PERMISSION_MAP && this.roleController) {\n const rolePath = trimSpecialChar(this.config.PERMISSION_MAP.rolePath);\n const normalizedPath = trimSpecialChar(path);\n return normalizedPath.includes(rolePath);\n }\n\n return false;\n }\n\n protected isListRequest(methode: HttpMethod, path: string): boolean {\n const basePath = trimSpecialChar(this.config.BASE_PATH);\n\n const allowedPaths = [\n basePath,\n `${basePath}/search`,\n `${basePath}/scan`,\n `${basePath}/search/query`,\n `${basePath}/search/query/total-count`,\n ];\n\n const isMethodGet = methode === \"GET\";\n const isAllowedPath = allowedPaths.includes(trimSpecialChar(path));\n\n return isMethodGet && isAllowedPath;\n }\n\n protected isUpdateRequest(methode: HttpMethod, path: string): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}/{id}`;\n const isMethodPatch = methode === \"PATCH\";\n const isExpectedPath = trimSpecialChar(path) === expectedPath;\n\n return isMethodPatch && isExpectedPath;\n }\n\n protected isDeleteRequest(methode: HttpMethod, path: string): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}/{id}`;\n const isMethodDelete = methode === \"DELETE\";\n const isExpectedPath = trimSpecialChar(path) === expectedPath;\n\n return isMethodDelete && isExpectedPath;\n }\n\n protected isFetchRequest(methode: HttpMethod, path: string): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}/{id}`;\n const isMethodGet = methode === \"GET\";\n const isExpectedPath = trimSpecialChar(path) === expectedPath;\n\n return isMethodGet && isExpectedPath;\n }\n\n protected isPostRequest(methode: HttpMethod, path: string): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}`;\n const isMethodGet = methode === \"POST\";\n const isExpectedPath = trimSpecialChar(path) === expectedPath;\n\n return isMethodGet && isExpectedPath;\n }\n\n protected isPutRequest(methode: HttpMethod, path: string): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}/{id}`;\n const isMethodGet = methode === \"PUT\";\n const isExpectedPath = trimSpecialChar(path) === expectedPath;\n\n return isMethodGet && isExpectedPath;\n }\n\n private async handleCrudByMethod(req: HttpRequest): Promise<any> {\n const path = req.event?.requestContext?.resourcePath;\n\n const entity = this.parseEntity(req.body);\n\n if (this.isPermissionRequest(path)) return this.handlePermission(req, path);\n if (this.isUpdateRequest(req.methode, path)) return this.handleUpdate(req.entityId, entity, req.identity);\n if (this.isDeleteRequest(req.methode, path)) return this.handleDelete(req.entityId, req.identity);\n if (this.isFetchRequest(req.methode, path)) return this.handleFetch(req.entityId, req.identity);\n if (this.isPutRequest(req.methode, path)) return this.handleReplace(req.entityId, entity, req.identity);\n if (this.isPostRequest(req.methode, path)) return this.handlePostCreate(entity, req.identity);\n if (this.isListRequest(req.methode, path)) return this.handleList(req.methode, path, req);\n\n return null;\n }\n\n private filterResponse(response: any, responsePolicy: ResponseFields): any {\n if (Array.isArray(response)) {\n return removeFields(response, responsePolicy.include, responsePolicy.exclude);\n }\n\n if (response?.items && Array.isArray(response.items)) {\n response.items = removeFields(response.items, responsePolicy.include, responsePolicy.exclude);\n return response;\n }\n\n return removeFields([response], responsePolicy.include, responsePolicy.exclude)[0];\n }\n\n /** Map RequestType to Access for permission checking */\n private getUserAccessLevel(requestType: RequestType): Access {\n switch (requestType) {\n case RequestType.ADMIN:\n return Access.ADMIN;\n case RequestType.USER:\n return Access.USER;\n case RequestType.GUEST:\n return Access.PUBLIC;\n case RequestType.SYSTEM:\n return Access.SYSTEM;\n default:\n return Access.PUBLIC;\n }\n }\n\n /** Check if the user has permission for the current operation */\n private checkPermission(allowedAccess: Access[], requestType: RequestType) {\n const currentAccessLevel = this.getUserAccessLevel(requestType);\n\n // This means USER can access OWNER-level permissions, but the service will verify actual ownership\n const hasPermission =\n allowedAccess.includes(currentAccessLevel) ||\n (requestType === RequestType.USER && allowedAccess.includes(Access.OWNER));\n\n if (hasPermission) return;\n\n throw new ErrorHttp(\n { code: 403, error: \"PermissionDenied\" },\n `Access denied. Required: ${allowedAccess.join(\", \")}, Current: ${currentAccessLevel}`,\n );\n }\n\n private setUserFilter(request: any, isAdmin: boolean, profileId: string) {\n if (isAdmin && !profileId) return;\n const ownerIdFieldName = this.config.OWNER_ID_FIELD_NAME || \"ownerId\";\n request.filterAndSort[ownerIdFieldName] = profileId;\n return request.filterAndSort;\n }\n\n private parseEntity(requestBody: any): R {\n if (!requestBody) return {} as R;\n return typeof requestBody === \"string\" ? JSON.parse(requestBody) : requestBody;\n }\n\n private validateRequest(schema: any, requestBody: any) {\n if (!schema) return;\n\n try {\n validateWithSchema(schema, requestBody);\n } catch (error) {\n const formattedErrors = formatErrors(error);\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, formattedErrors);\n }\n }\n}\n"]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Permission } from "../model/role.model";
|
|
2
|
-
import { PermissionMap, ScopeMap } from "../model/base.model";
|
|
2
|
+
import { List, PermissionMap, ScopeMap } from "../model/base.model";
|
|
3
3
|
import { HttpRequest } from "../utils/http/http.util";
|
|
4
4
|
import { PermissionService } from "../service/permission.service";
|
|
5
|
+
import { Filter } from "../model/index.js";
|
|
5
6
|
/**
|
|
6
7
|
* ControllerRole — centralized Permission CRUD + RBAC access enforcement.
|
|
7
8
|
*
|
|
@@ -23,7 +24,7 @@ export declare class ControllerRole {
|
|
|
23
24
|
updatePermission(id: string, updates: Partial<Pick<Permission, "role" | "resource" | "scope" | "method">>): Promise<Permission>;
|
|
24
25
|
deletePermission(id: string): Promise<boolean>;
|
|
25
26
|
getPermission(id: string): Promise<Permission | null>;
|
|
26
|
-
listPermissions(): Promise<Permission
|
|
27
|
+
listPermissions(filter?: Filter): Promise<List<Partial<Permission>>>;
|
|
27
28
|
addRole(userPoolId: string, groupName: string, description?: string): Promise<{
|
|
28
29
|
groupName: string;
|
|
29
30
|
description?: string;
|
|
@@ -42,15 +43,21 @@ export declare class ControllerRole {
|
|
|
42
43
|
hasPermission(role: string, resource: string, scope: string, method: string): Promise<boolean>;
|
|
43
44
|
getPermissionByKey(permissionKey: string): Promise<Permission | null>;
|
|
44
45
|
handlePermissionRequest(req: HttpRequest, path: string, permissionMap: PermissionMap, adminGroups: string[]): Promise<any>;
|
|
45
|
-
|
|
46
|
+
private permissionDenied;
|
|
47
|
+
checkAccess(req: HttpRequest, resource: string, scopeMap: ScopeMap, adminGroups?: string[]): Promise<boolean>;
|
|
46
48
|
checkAdminPermission(cognitoGroups: string[], adminGroups: string[]): boolean;
|
|
47
49
|
private isAdmin;
|
|
48
50
|
private validate;
|
|
49
|
-
private
|
|
51
|
+
private isOpenSearchPath;
|
|
50
52
|
private extractRoles;
|
|
51
|
-
private
|
|
53
|
+
private getScope;
|
|
54
|
+
private hasAnyRolePermission;
|
|
52
55
|
private applyScopeFilter;
|
|
53
|
-
private
|
|
56
|
+
private setDefaultIndexFields;
|
|
57
|
+
private setDefaultFilters;
|
|
58
|
+
private getRequestedScopeForDefaultFilters;
|
|
59
|
+
private getScopeLevelLimit;
|
|
54
60
|
private applyAllScopeValues;
|
|
61
|
+
private isUnset;
|
|
55
62
|
private clearScopeFilters;
|
|
56
63
|
}
|
|
@@ -79,8 +79,8 @@ class ControllerRole {
|
|
|
79
79
|
this.validate(IdParamDto, id);
|
|
80
80
|
return this.permissionService.getPermissionById(id);
|
|
81
81
|
}
|
|
82
|
-
async listPermissions() {
|
|
83
|
-
return this.permissionService.listPermissions();
|
|
82
|
+
async listPermissions(filter) {
|
|
83
|
+
return this.permissionService.listPermissions(filter);
|
|
84
84
|
}
|
|
85
85
|
// ---------------------------------------------------------------------------
|
|
86
86
|
// Role (Cognito group)
|
|
@@ -127,7 +127,7 @@ class ControllerRole {
|
|
|
127
127
|
}
|
|
128
128
|
switch (req.methode) {
|
|
129
129
|
case "GET":
|
|
130
|
-
return this.listPermissions();
|
|
130
|
+
return this.listPermissions(req.filter);
|
|
131
131
|
case "PATCH":
|
|
132
132
|
return this.updatePermission(req.entityId, req.body);
|
|
133
133
|
case "DELETE":
|
|
@@ -139,39 +139,36 @@ class ControllerRole {
|
|
|
139
139
|
// ---------------------------------------------------------------------------
|
|
140
140
|
// RBAC access enforcement (used by ControllerApi)
|
|
141
141
|
// ---------------------------------------------------------------------------
|
|
142
|
-
|
|
142
|
+
permissionDenied(message = "Permission denied: no role accessible") {
|
|
143
|
+
throw new exception_1.ErrorHttp({ code: 403, error: "PermissionDenied" }, message);
|
|
144
|
+
}
|
|
145
|
+
async checkAccess(req, resource, scopeMap, adminGroups) {
|
|
143
146
|
const roles = this.extractRoles(req);
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
this.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
else {
|
|
156
|
-
this.applyScopeFilter(req, scope, scopeMap);
|
|
157
|
-
}
|
|
158
|
-
if (adminGroups?.length && this.isAdmin(roles, adminGroups)) {
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
for (const role of roles) {
|
|
162
|
-
const allowed = await this.permissionService.hasPermission(role, resource, scope, method);
|
|
163
|
-
if (allowed) {
|
|
164
|
-
return;
|
|
147
|
+
if (roles?.length) {
|
|
148
|
+
const method = req.methode.toUpperCase();
|
|
149
|
+
const scope = this.getScope(req, scopeMap);
|
|
150
|
+
if (method === "POST") {
|
|
151
|
+
this.setDefaultIndexFields(req, scopeMap);
|
|
152
|
+
}
|
|
153
|
+
if (method === "GET" && this.isOpenSearchPath(req)) {
|
|
154
|
+
this.setDefaultFilters(req, scopeMap);
|
|
155
|
+
}
|
|
156
|
+
else if (method === "GET") {
|
|
157
|
+
this.applyScopeFilter(req, scope, scopeMap);
|
|
165
158
|
}
|
|
159
|
+
if (adminGroups?.length && this.isAdmin(roles, adminGroups))
|
|
160
|
+
return true;
|
|
161
|
+
const hasPermission = await this.hasAnyRolePermission(roles, resource, scope, method);
|
|
162
|
+
if (hasPermission)
|
|
163
|
+
return true;
|
|
164
|
+
this.permissionDenied(`Permission denied: ${roles.join(",")}: "${resource}#${scope}.${method}"`);
|
|
166
165
|
}
|
|
167
|
-
|
|
168
|
-
throw new exception_1.ErrorHttp({ code: 403, error: "PermissionDenied" }, `Permission denied: roles=${roles.join(",")} "${key}.${method}"`);
|
|
166
|
+
this.permissionDenied();
|
|
169
167
|
}
|
|
170
168
|
checkAdminPermission(cognitoGroups, adminGroups) {
|
|
171
|
-
if (
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
return true;
|
|
169
|
+
if (this.isAdmin(cognitoGroups, adminGroups))
|
|
170
|
+
return true;
|
|
171
|
+
this.permissionDenied("Permission Denied");
|
|
175
172
|
}
|
|
176
173
|
// ---------------------------------------------------------------------------
|
|
177
174
|
// Private helpers
|
|
@@ -188,22 +185,23 @@ class ControllerRole {
|
|
|
188
185
|
throw new exception_1.ErrorHttp({ code: 400, error: "BadRequest" }, formattedErrors);
|
|
189
186
|
}
|
|
190
187
|
}
|
|
191
|
-
|
|
192
|
-
const path = req.event?.requestContext?.resourcePath ?? req.resourcePath ?? "";
|
|
193
|
-
return
|
|
188
|
+
isOpenSearchPath(req) {
|
|
189
|
+
const path = (0, string_util_1.trimSpecialChar)(req.event?.requestContext?.resourcePath ?? req.resourcePath ?? "");
|
|
190
|
+
return path.endsWith("search/query");
|
|
194
191
|
}
|
|
195
192
|
extractRoles(req) {
|
|
196
193
|
return req.identity?.groups ?? [];
|
|
197
194
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const allowed =
|
|
204
|
-
|
|
195
|
+
getScope(req, scopeMap) {
|
|
196
|
+
return req.queryStringParameters?.scope || req.customQueryParameters?.scope || scopeMap.keys().next().value;
|
|
197
|
+
}
|
|
198
|
+
async hasAnyRolePermission(roles, resource, scope, method) {
|
|
199
|
+
for (const role of roles) {
|
|
200
|
+
const allowed = await this.permissionService.hasPermission(role, resource, scope, method);
|
|
201
|
+
if (allowed)
|
|
202
|
+
return true;
|
|
205
203
|
}
|
|
206
|
-
return
|
|
204
|
+
return false;
|
|
207
205
|
}
|
|
208
206
|
applyScopeFilter(req, scope, scopeMap) {
|
|
209
207
|
if (!req.filter)
|
|
@@ -212,36 +210,69 @@ class ControllerRole {
|
|
|
212
210
|
const mapping = scopeMap.get(scope);
|
|
213
211
|
if (!mapping)
|
|
214
212
|
return;
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
213
|
+
let claimValue = req.identity?.[mapping.claimKey] || req.identity?.attributes?.[mapping.claimKey];
|
|
214
|
+
if (!claimValue && req?.filter[mapping.filterField]) {
|
|
215
|
+
claimValue = req.filter[mapping.filterField];
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
req.filter[mapping.filterField] = claimValue;
|
|
219
219
|
}
|
|
220
|
-
req.filter[mapping.filterField] = claimValue;
|
|
221
220
|
delete req.filter?.scope;
|
|
222
221
|
}
|
|
223
|
-
|
|
222
|
+
setDefaultIndexFields(req, scopeMap) {
|
|
224
223
|
if (!req.body)
|
|
225
224
|
req.body = {};
|
|
226
|
-
req.body.ownerId
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
225
|
+
if (this.isUnset(req.body.ownerId))
|
|
226
|
+
req.body.ownerId = req.identity?.sub;
|
|
227
|
+
this.applyAllScopeValues(req, scopeMap, true);
|
|
228
|
+
}
|
|
229
|
+
setDefaultFilters(req, scopeMap) {
|
|
230
|
+
if (!req.filter)
|
|
231
|
+
req.filter = {};
|
|
232
|
+
const referenceFilter = req.filter;
|
|
233
|
+
const requestedScope = this.getRequestedScopeForDefaultFilters(req);
|
|
234
|
+
const levelLimit = this.getScopeLevelLimit(requestedScope, scopeMap);
|
|
235
|
+
for (const [scope, mapping] of scopeMap) {
|
|
236
|
+
if (levelLimit !== undefined && mapping.level !== undefined && mapping.level > levelLimit)
|
|
237
|
+
continue;
|
|
238
|
+
const claimKey = mapping.claimKey ?? "custom:" + scope;
|
|
239
|
+
const claimValue = req.identity?.[claimKey] || req.identity?.attributes?.[claimKey] || req.identity?.sub;
|
|
240
|
+
const eqField = mapping.filterField + ".keyword__eq";
|
|
241
|
+
if (claimValue && this.isUnset(referenceFilter[eqField])) {
|
|
242
|
+
referenceFilter[eqField] = claimValue;
|
|
243
|
+
}
|
|
234
244
|
}
|
|
235
|
-
|
|
245
|
+
delete referenceFilter.scope;
|
|
246
|
+
}
|
|
247
|
+
getRequestedScopeForDefaultFilters(req) {
|
|
248
|
+
const scopeRaw = req.filter?.scope || req.queryStringParameters?.scope || req.customQueryParameters?.scope;
|
|
249
|
+
if (typeof scopeRaw !== "string")
|
|
250
|
+
return undefined;
|
|
251
|
+
const normalized = scopeRaw.trim().toLowerCase();
|
|
252
|
+
return normalized.length ? normalized : undefined;
|
|
253
|
+
}
|
|
254
|
+
getScopeLevelLimit(requestedScope, scopeMap) {
|
|
255
|
+
if (!requestedScope)
|
|
256
|
+
return undefined; // no scope => include all levels
|
|
257
|
+
for (const [scopeName, mapping] of scopeMap) {
|
|
258
|
+
if (scopeName.toLowerCase() === requestedScope) {
|
|
259
|
+
return mapping.level; // level1 => only level1, level2 => level1+2, level3 => all
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return undefined;
|
|
263
|
+
}
|
|
264
|
+
applyAllScopeValues(req, scopeMap, defaultsOnly = false) {
|
|
265
|
+
const referenceBody = req.body;
|
|
236
266
|
for (const [scope, mapping] of scopeMap) {
|
|
237
267
|
const claimKey = mapping.claimKey ?? "custom:" + scope;
|
|
238
268
|
const claimValue = req.identity?.[claimKey] || req.identity?.attributes?.[claimKey] || req.identity?.sub;
|
|
239
|
-
if (claimValue) {
|
|
240
|
-
|
|
269
|
+
if (claimValue && (!defaultsOnly || this.isUnset(referenceBody[mapping.filterField]))) {
|
|
270
|
+
referenceBody[mapping.filterField] = claimValue;
|
|
241
271
|
}
|
|
242
272
|
}
|
|
243
|
-
|
|
244
|
-
|
|
273
|
+
}
|
|
274
|
+
isUnset(value) {
|
|
275
|
+
return value === undefined || value === null || value === "";
|
|
245
276
|
}
|
|
246
277
|
clearScopeFilters(req, scopeMap) {
|
|
247
278
|
for (const [, entry] of scopeMap) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller-role.js","sourceRoot":"","sources":["../../src/controller/controller-role.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AACxB,4CAAyC;AAIzC,sEAAkE;AAClE,iDAAoG;AACpG,8DAA4E;AAC5E,sDAAuD;AAEvD,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E,MAAM,YAAY,GAAG,OAAC,CAAC,MAAM,CAAC;IAC5B,GAAG,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC3B,IAAI,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC5B,KAAK,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC7B,GAAG,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC3B,MAAM,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,OAAC,CAAC,MAAM,CAAC;IAChC,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,kBAAkB,CAAC;IAC3C,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,sBAAsB,CAAC;IACnD,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,mBAAmB,CAAC;IAC7C,MAAM,EAAE,YAAY;CACrB,CAAC,CAAC;AAEH,MAAM,mBAAmB,GAAG,OAAC,CAAC,MAAM,CAAC;IACnC,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,QAAQ,EAAE;IACtD,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAC,QAAQ,EAAE;IAC9D,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,QAAQ,EAAE;IACxD,MAAM,EAAE,YAAY,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;AAEvD,MAAM,QAAQ,GAAG,OAAC,CAAC,MAAM,CAAC;IACxB,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,wBAAwB,CAAC;IACvD,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,uBAAuB,CAAC;IACrD,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,OAAC,CAAC,MAAM,CAAC;IAC5B,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,wBAAwB,CAAC;IACvD,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,sBAAsB,CAAC;IACnD,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,uBAAuB,CAAC;CACtD,CAAC,CAAC;AAQH;;;;;;;GAOG;AACH,MAAa,cAAc;IACN,iBAAiB,CAAoB;IAEvC,SAAS,GAAiC;QACzD,YAAY,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC;QACzF,iBAAiB,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC;QAC9F,eAAe,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC;QAC7E,oBAAoB,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC;KACpG,CAAC;IAEF,YAAY,aAAqB;QAC/B,IAAI,CAAC,iBAAiB,GAAG,IAAI,sCAAiB,CAAC,aAAa,CAAC,CAAC;IAChE,CAAC;IAED,8EAA8E;IAC9E,kBAAkB;IAClB,8EAA8E;IAE9E,KAAK,CAAC,aAAa,CAAC,KAKnB;QACC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,gBAAgB,CACpB,EAAU,EACV,OAA4E;QAE5E,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QAC9B,IAAI,CAAC,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAC9D,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,EAAU;QAC/B,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,EAAU;QAC5B,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,OAAO,IAAI,CAAC,iBAAiB,CAAC,eAAe,EAAE,CAAC;IAClD,CAAC;IAED,8EAA8E;IAC9E,uBAAuB;IACvB,8EAA8E;IAE9E,KAAK,CAAC,OAAO,CAAC,UAAkB,EAAE,SAAiB,EAAE,WAAoB;QACvE,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;QAChE,OAAO,IAAA,qBAAW,EAAC,UAAU,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,UAAkB,EAAE,SAAiB;QACpD,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;QACnD,OAAO,IAAA,qBAAW,EAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,UAAkB,EAAE,QAAgB,EAAE,SAAiB;QACtE,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QACjE,OAAO,IAAA,wBAAc,EAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,UAAkB,EAAE,QAAgB,EAAE,SAAiB;QACxE,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QACjE,OAAO,IAAA,6BAAmB,EAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC9D,CAAC;IAED,8EAA8E;IAC9E,mBAAmB;IACnB,8EAA8E;IAE9E,KAAK,CAAC,aAAa,CAAC,IAAY,EAAE,QAAgB,EAAE,KAAa,EAAE,MAAc;QAC/E,OAAO,IAAI,CAAC,iBAAiB,CAAC,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC7E,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,aAAqB;QAC5C,OAAO,IAAI,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;IAClE,CAAC;IAED,8EAA8E;IAC9E,yDAAyD;IACzD,8EAA8E;IAE9E,KAAK,CAAC,uBAAuB,CAC3B,GAAgB,EAChB,IAAY,EACZ,aAA4B,EAC5B,WAAqB;QAErB,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAE5D,IAAI,GAAG,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;YAC3B,MAAM,cAAc,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,CAAC;YAC7C,MAAM,QAAQ,GAAG,IAAA,6BAAe,EAAC,aAAa,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;YAE/D,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC/D,IAAI,cAAc,KAAK,GAAG,QAAQ,GAAG,MAAM,EAAE,EAAE,CAAC;oBAC9C,OAAO,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC1C,CAAC;YACH,CAAC;YAED,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC;QAED,QAAQ,GAAG,CAAC,OAAO,EAAE,CAAC;YACpB,KAAK,KAAK;gBACR,OAAO,IAAI,CAAC,eAAe,EAAE,CAAC;YAChC,KAAK,OAAO;gBACV,OAAO,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;YACvD,KAAK,QAAQ;gBACX,OAAO,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC7C;gBACE,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,2BAA2B,CAAC,CAAC;QACzF,CAAC;IACH,CAAC;IAED,8EAA8E;IAC9E,kDAAkD;IAClD,8EAA8E;IAE9E,KAAK,CAAC,eAAe,CAAC,GAAgB,EAAE,QAAgB,EAAE,QAAkB,EAAE,WAAsB;QAClG,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QAErC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YAClB,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAAE,mCAAmC,CAAC,CAAC;QACrG,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QAEzC,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,MAAM,KAAK,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;YACtD,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC9C,CAAC;QAED,IAAI,WAAW,EAAE,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC;YAC5D,OAAO;QACT,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;YAC1F,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO;YACT,CAAC;QACH,CAAC;QAED,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC;QACtD,MAAM,IAAI,qBAAS,CACjB,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,kBAAkB,EAAE,EACxC,4BAA4B,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,MAAM,GAAG,CACjE,CAAC;IACJ,CAAC;IAED,oBAAoB,CAAC,aAAuB,EAAE,WAAqB;QACjE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,WAAW,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,0BAA0B,CAAC,CAAC;QAC7F,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,8EAA8E;IAC9E,kBAAkB;IAClB,8EAA8E;IAEtE,OAAO,CAAC,aAAmC,EAAE,WAAqB;QACxE,OAAO,aAAa,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC;IAC9E,CAAC;IAEO,QAAQ,CAAsB,MAAS,EAAE,IAAa;QAC5D,IAAI,CAAC;YACH,OAAO,IAAA,oCAAkB,EAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,eAAe,GAAG,IAAA,8BAAY,EAAC,KAAK,CAAC,CAAC;YAC5C,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,eAAe,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,GAAgB;QACnC,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,EAAE,cAAc,EAAE,YAAY,IAAI,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;QAC/E,OAAO,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,CAAC;IAEO,YAAY,CAAC,GAAgB;QACnC,OAAO,GAAG,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,CAAC;IACpC,CAAC;IAEO,YAAY,CAAC,GAAgB,EAAE,QAAkB;QACvD,MAAM,KAAK,GAAG,GAAG,CAAC,qBAAqB,EAAE,KAAK,IAAI,GAAG,CAAC,qBAAqB,EAAE,KAAK,CAAC;QAEnF,IAAI,CAAC,KAAK;YAAE,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAM,CAAC;QAEjD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvD,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,kBAAkB,KAAK,eAAe,OAAO,EAAE,CAAC,CAAC;QAC3G,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,gBAAgB,CAAC,GAAgB,EAAE,KAAa,EAAE,QAAkB;QAC1E,IAAI,CAAC,GAAG,CAAC,MAAM;YAAE,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;QAEjC,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAEtC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,SAAS,GAAG,KAAK,CAAC;QACvD,MAAM,UAAU,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,QAAQ,CAAC,CAAC;QAEpF,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,qBAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAAE,kBAAkB,QAAQ,gBAAgB,KAAK,GAAG,CAAC,CAAC;QACpH,CAAC;QAED,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,UAAU,CAAC;QAC7C,OAAO,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC;IAC3B,CAAC;IAEO,gBAAgB,CAAC,GAAgB,EAAE,QAAkB;QAC3D,IAAI,CAAC,GAAG,CAAC,IAAI;YAAE,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;QAC7B,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC;QACrC,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAClD,CAAC;IAEO,mBAAmB,CAAC,GAAgB,EAAE,MAAyB,EAAE,QAAkB;QACzF,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxB,IAAI,CAAC,GAAG,CAAC,MAAM;gBAAE,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;YACjC,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACxC,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;QAExD,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,QAAQ,EAAE,CAAC;YACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,SAAS,GAAG,KAAK,CAAC;YACvD,MAAM,UAAU,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC;YACzG,IAAI,UAAU,EAAE,CAAC;gBACf,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,UAAU,CAAC;YACxC,CAAC;QACH,CAAC;QAED,IAAI,MAAM,KAAK,QAAQ;YAAE,OAAO,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC;IACpD,CAAC;IAEO,iBAAiB,CAAC,GAAgB,EAAE,QAAkB;QAC5D,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,QAAQ,EAAE,CAAC;YACjC,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;CACF;AApQD,wCAoQC","sourcesContent":["import { z } from \"zod\";\nimport { ErrorHttp } from \"../exception\";\nimport { Permission } from \"../model/role.model\";\nimport { PermissionMap, ScopeMap } from \"../model/base.model\";\nimport { HttpRequest } from \"../utils/http/http.util\";\nimport { PermissionService } from \"../service/permission.service\";\nimport { createGroup, deleteGroup, addUserToGroup, removeUserFromGroup } from \"../function/cognito\";\nimport { validateWithSchema, formatErrors } from \"../utils/validation.util\";\nimport { trimSpecialChar } from \"../utils/string.util\";\n\n// ---------------------------------------------------------------------------\n// DTO Schemas\n// ---------------------------------------------------------------------------\n\nconst MethodSchema = z.object({\n GET: z.boolean().optional(),\n POST: z.boolean().optional(),\n PATCH: z.boolean().optional(),\n PUT: z.boolean().optional(),\n DELETE: z.boolean().optional(),\n});\n\nconst AddPermissionDto = z.object({\n role: z.string().min(1, \"Role is required\"),\n resource: z.string().min(1, \"Resource is required\"),\n scope: z.string().min(1, \"Scope is required\"),\n method: MethodSchema,\n});\n\nconst UpdatePermissionDto = z.object({\n role: z.string().min(1, \"Role is required\").optional(),\n resource: z.string().min(1, \"Resource is required\").optional(),\n scope: z.string().min(1, \"Scope is required\").optional(),\n method: MethodSchema.optional(),\n});\n\nconst IdParamDto = z.string().min(1, \"Id is required\");\n\nconst GroupDto = z.object({\n userPoolId: z.string().min(1, \"UserPoolId is required\"),\n groupName: z.string().min(1, \"GroupName is required\"),\n description: z.string().optional(),\n});\n\nconst UserGroupDto = z.object({\n userPoolId: z.string().min(1, \"UserPoolId is required\"),\n username: z.string().min(1, \"Username is required\"),\n groupName: z.string().min(1, \"GroupName is required\"),\n});\n\n// ---------------------------------------------------------------------------\n// Route map for permission sub-paths (POST only)\n// ---------------------------------------------------------------------------\n\ntype RouteHandler = (permissionMap: PermissionMap, body: any) => Promise<any>;\n\n/**\n * ControllerRole — centralized Permission CRUD + RBAC access enforcement.\n *\n * All caching and DB orchestration lives in PermissionService.\n *\n * Scope validation, scope filtering, and permission checks are centralized here\n * so that ControllerApi (and any other consumer) delegates without duplicating logic.\n */\nexport class ControllerRole {\n protected readonly permissionService: PermissionService;\n\n private readonly subRoutes: Record<string, RouteHandler> = {\n \"/add-group\": (pm, body) => this.addRole(pm.userPoolId, body.groupName, body.description),\n \"/add-user-group\": (pm, body) => this.assignRole(pm.userPoolId, body.username, body.groupName),\n \"/remove-group\": (pm, body) => this.removeRole(pm.userPoolId, body.groupName),\n \"/remove-user-group\": (pm, body) => this.unassignRole(pm.userPoolId, body.username, body.groupName),\n };\n\n constructor(roleTableName: string) {\n this.permissionService = new PermissionService(roleTableName);\n }\n\n // ---------------------------------------------------------------------------\n // Permission CRUD\n // ---------------------------------------------------------------------------\n\n async addPermission(input: {\n role: string;\n resource: string;\n scope: string;\n method: Permission[\"method\"];\n }): Promise<Permission> {\n this.validate(AddPermissionDto, input);\n return this.permissionService.createPermission(input);\n }\n\n async updatePermission(\n id: string,\n updates: Partial<Pick<Permission, \"role\" | \"resource\" | \"scope\" | \"method\">>,\n ): Promise<Permission> {\n this.validate(IdParamDto, id);\n this.validate(UpdatePermissionDto, updates);\n return this.permissionService.updatePermission(id, updates);\n }\n\n async deletePermission(id: string): Promise<boolean> {\n this.validate(IdParamDto, id);\n return this.permissionService.deletePermission(id);\n }\n\n async getPermission(id: string): Promise<Permission | null> {\n this.validate(IdParamDto, id);\n return this.permissionService.getPermissionById(id);\n }\n\n async listPermissions(): Promise<Permission[]> {\n return this.permissionService.listPermissions();\n }\n\n // ---------------------------------------------------------------------------\n // Role (Cognito group)\n // ---------------------------------------------------------------------------\n\n async addRole(userPoolId: string, groupName: string, description?: string) {\n this.validate(GroupDto, { userPoolId, groupName, description });\n return createGroup(userPoolId, groupName, description);\n }\n\n async removeRole(userPoolId: string, groupName: string) {\n this.validate(GroupDto, { userPoolId, groupName });\n return deleteGroup(userPoolId, groupName);\n }\n\n async assignRole(userPoolId: string, username: string, groupName: string) {\n this.validate(UserGroupDto, { userPoolId, username, groupName });\n return addUserToGroup(userPoolId, username, groupName);\n }\n\n async unassignRole(userPoolId: string, username: string, groupName: string) {\n this.validate(UserGroupDto, { userPoolId, username, groupName });\n return removeUserFromGroup(userPoolId, username, groupName);\n }\n\n // ---------------------------------------------------------------------------\n // Permission check\n // ---------------------------------------------------------------------------\n\n async hasPermission(role: string, resource: string, scope: string, method: string): Promise<boolean> {\n return this.permissionService.hasPermission(role, resource, scope, method);\n }\n\n async getPermissionByKey(permissionKey: string): Promise<Permission | null> {\n return this.permissionService.getPermissionByKey(permissionKey);\n }\n\n // ---------------------------------------------------------------------------\n // Permission request handler (routes from ControllerApi)\n // ---------------------------------------------------------------------------\n\n async handlePermissionRequest(\n req: HttpRequest,\n path: string,\n permissionMap: PermissionMap,\n adminGroups: string[],\n ): Promise<any> {\n this.checkAdminPermission(req.identity.groups, adminGroups);\n\n if (req.methode === \"POST\") {\n const normalizedPath = trimSpecialChar(path);\n const rolePath = trimSpecialChar(permissionMap.rolePath ?? \"\");\n\n for (const [suffix, handler] of Object.entries(this.subRoutes)) {\n if (normalizedPath === `${rolePath}${suffix}`) {\n return handler(permissionMap, req.body);\n }\n }\n\n return this.addPermission(req.body);\n }\n\n switch (req.methode) {\n case \"GET\":\n return this.listPermissions();\n case \"PATCH\":\n return this.updatePermission(req.entityId, req.body);\n case \"DELETE\":\n return this.deletePermission(req.entityId);\n default:\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] unsupported method\");\n }\n }\n\n // ---------------------------------------------------------------------------\n // RBAC access enforcement (used by ControllerApi)\n // ---------------------------------------------------------------------------\n\n async checkRbacAccess(req: HttpRequest, resource: string, scopeMap: ScopeMap, adminGroups?: string[]): Promise<void> {\n const roles = this.extractRoles(req);\n\n if (!roles.length) {\n throw new ErrorHttp({ code: 403, error: \"PermissionDenied\" }, \"Permission denied: Role Not Found\");\n }\n\n const scope = this.resolveScope(req, scopeMap);\n const method = req.methode.toUpperCase();\n\n if (method === \"POST\") {\n this.applyScopeToBody(req, scopeMap);\n } else if (method === \"GET\" && this.isSearchPath(req)) {\n this.applyAllScopeValues(req, \"filter\", scopeMap);\n } else {\n this.applyScopeFilter(req, scope, scopeMap);\n }\n\n if (adminGroups?.length && this.isAdmin(roles, adminGroups)) {\n return;\n }\n\n for (const role of roles) {\n const allowed = await this.permissionService.hasPermission(role, resource, scope, method);\n if (allowed) {\n return;\n }\n }\n\n const key = `${roles.join(\",\")}#${resource}#${scope}`;\n throw new ErrorHttp(\n { code: 403, error: \"PermissionDenied\" },\n `Permission denied: roles=${roles.join(\",\")} \"${key}.${method}\"`,\n );\n }\n\n checkAdminPermission(cognitoGroups: string[], adminGroups: string[]) {\n if (!this.isAdmin(cognitoGroups, adminGroups)) {\n throw new ErrorHttp({ code: 403, error: \"Permission Denied\" }, \"[CORE] Permission Denied\");\n }\n return true;\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private isAdmin(cognitoGroups: string[] | undefined, adminGroups: string[]): boolean {\n return cognitoGroups?.some((group) => adminGroups.includes(group)) ?? false;\n }\n\n private validate<T extends z.ZodType>(schema: T, data: unknown): z.infer<T> {\n try {\n return validateWithSchema(schema, data);\n } catch (error) {\n const formattedErrors = formatErrors(error);\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, formattedErrors);\n }\n }\n\n private isSearchPath(req: HttpRequest): boolean {\n const path = req.event?.requestContext?.resourcePath ?? req.resourcePath ?? \"\";\n return /\\/(search\\/query)(\\/|$)/i.test(path);\n }\n\n private extractRoles(req: HttpRequest): string[] {\n return req.identity?.groups ?? [];\n }\n\n private resolveScope(req: HttpRequest, scopeMap: ScopeMap): string {\n const scope = req.queryStringParameters?.scope || req.customQueryParameters?.scope;\n\n if (!scope) return scopeMap.keys().next().value!;\n\n if (!scopeMap.has(scope)) {\n const allowed = Array.from(scopeMap.keys()).join(\", \");\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, `Invalid scope \"${scope}\". Allowed: ${allowed}`);\n }\n\n return scope;\n }\n\n private applyScopeFilter(req: HttpRequest, scope: string, scopeMap: ScopeMap): void {\n if (!req.filter) req.filter = {};\n\n this.clearScopeFilters(req, scopeMap);\n\n const mapping = scopeMap.get(scope);\n if (!mapping) return;\n\n const claimKey = mapping.claimKey ?? \"custom:\" + scope;\n const claimValue = req.identity?.[claimKey] || req.identity?.attributes?.[claimKey];\n\n if (!claimValue) {\n throw new ErrorHttp({ code: 403, error: \"PermissionDenied\" }, `Missing claim \"${claimKey}\" for scope \"${scope}\"`);\n }\n\n req.filter[mapping.filterField] = claimValue;\n delete req.filter?.scope;\n }\n\n private applyScopeToBody(req: HttpRequest, scopeMap: ScopeMap): void {\n if (!req.body) req.body = {};\n req.body.ownerId = req.identity?.sub;\n this.applyAllScopeValues(req, \"body\", scopeMap);\n }\n\n private applyAllScopeValues(req: HttpRequest, target: \"filter\" | \"body\", scopeMap: ScopeMap): void {\n if (target === \"filter\") {\n if (!req.filter) req.filter = {};\n this.clearScopeFilters(req, scopeMap);\n }\n\n const obj = target === \"filter\" ? req.filter : req.body;\n\n for (const [scope, mapping] of scopeMap) {\n const claimKey = mapping.claimKey ?? \"custom:\" + scope;\n const claimValue = req.identity?.[claimKey] || req.identity?.attributes?.[claimKey] || req.identity?.sub;\n if (claimValue) {\n obj[mapping.filterField] = claimValue;\n }\n }\n\n if (target === \"filter\") delete req.filter?.scope;\n }\n\n private clearScopeFilters(req: HttpRequest, scopeMap: ScopeMap): void {\n for (const [, entry] of scopeMap) {\n delete req.filter[entry.filterField];\n }\n delete req.filter[\"scope\"];\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"controller-role.js","sourceRoot":"","sources":["../../src/controller/controller-role.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\nimport { ErrorHttp } from \"../exception\";\nimport { Permission } from \"../model/role.model\";\nimport { List, PermissionMap, ScopeMap } from \"../model/base.model\";\nimport { HttpRequest } from \"../utils/http/http.util\";\nimport { PermissionService } from \"../service/permission.service\";\nimport { createGroup, deleteGroup, addUserToGroup, removeUserFromGroup } from \"../function/cognito\";\nimport { validateWithSchema, formatErrors } from \"../utils/validation.util\";\nimport { trimSpecialChar } from \"../utils/string.util\";\nimport { Filter } from \"@chinggis/types\";\n\n// ---------------------------------------------------------------------------\n// DTO Schemas\n// ---------------------------------------------------------------------------\n\nconst MethodSchema = z.object({\n GET: z.boolean().optional(),\n POST: z.boolean().optional(),\n PATCH: z.boolean().optional(),\n PUT: z.boolean().optional(),\n DELETE: z.boolean().optional(),\n});\n\nconst AddPermissionDto = z.object({\n role: z.string().min(1, \"Role is required\"),\n resource: z.string().min(1, \"Resource is required\"),\n scope: z.string().min(1, \"Scope is required\"),\n method: MethodSchema,\n});\n\nconst UpdatePermissionDto = z.object({\n role: z.string().min(1, \"Role is required\").optional(),\n resource: z.string().min(1, \"Resource is required\").optional(),\n scope: z.string().min(1, \"Scope is required\").optional(),\n method: MethodSchema.optional(),\n});\n\nconst IdParamDto = z.string().min(1, \"Id is required\");\n\nconst GroupDto = z.object({\n userPoolId: z.string().min(1, \"UserPoolId is required\"),\n groupName: z.string().min(1, \"GroupName is required\"),\n description: z.string().optional(),\n});\n\nconst UserGroupDto = z.object({\n userPoolId: z.string().min(1, \"UserPoolId is required\"),\n username: z.string().min(1, \"Username is required\"),\n groupName: z.string().min(1, \"GroupName is required\"),\n});\n\n// ---------------------------------------------------------------------------\n// Route map for permission sub-paths (POST only)\n// ---------------------------------------------------------------------------\n\ntype RouteHandler = (permissionMap: PermissionMap, body: any) => Promise<any>;\n\n/**\n * ControllerRole — centralized Permission CRUD + RBAC access enforcement.\n *\n * All caching and DB orchestration lives in PermissionService.\n *\n * Scope validation, scope filtering, and permission checks are centralized here\n * so that ControllerApi (and any other consumer) delegates without duplicating logic.\n */\nexport class ControllerRole {\n protected readonly permissionService: PermissionService;\n\n private readonly subRoutes: Record<string, RouteHandler> = {\n \"/add-group\": (pm, body) => this.addRole(pm.userPoolId, body.groupName, body.description),\n \"/add-user-group\": (pm, body) => this.assignRole(pm.userPoolId, body.username, body.groupName),\n \"/remove-group\": (pm, body) => this.removeRole(pm.userPoolId, body.groupName),\n \"/remove-user-group\": (pm, body) => this.unassignRole(pm.userPoolId, body.username, body.groupName),\n };\n\n constructor(roleTableName: string) {\n this.permissionService = new PermissionService(roleTableName);\n }\n\n // ---------------------------------------------------------------------------\n // Permission CRUD\n // ---------------------------------------------------------------------------\n\n async addPermission(input: {\n role: string;\n resource: string;\n scope: string;\n method: Permission[\"method\"];\n }): Promise<Permission> {\n this.validate(AddPermissionDto, input);\n return this.permissionService.createPermission(input);\n }\n\n async updatePermission(\n id: string,\n updates: Partial<Pick<Permission, \"role\" | \"resource\" | \"scope\" | \"method\">>,\n ): Promise<Permission> {\n this.validate(IdParamDto, id);\n this.validate(UpdatePermissionDto, updates);\n return this.permissionService.updatePermission(id, updates);\n }\n\n async deletePermission(id: string): Promise<boolean> {\n this.validate(IdParamDto, id);\n return this.permissionService.deletePermission(id);\n }\n\n async getPermission(id: string): Promise<Permission | null> {\n this.validate(IdParamDto, id);\n return this.permissionService.getPermissionById(id);\n }\n\n async listPermissions(filter?: Filter): Promise<List<Partial<Permission>>> {\n return this.permissionService.listPermissions(filter);\n }\n\n // ---------------------------------------------------------------------------\n // Role (Cognito group)\n // ---------------------------------------------------------------------------\n\n async addRole(userPoolId: string, groupName: string, description?: string) {\n this.validate(GroupDto, { userPoolId, groupName, description });\n return createGroup(userPoolId, groupName, description);\n }\n\n async removeRole(userPoolId: string, groupName: string) {\n this.validate(GroupDto, { userPoolId, groupName });\n return deleteGroup(userPoolId, groupName);\n }\n\n async assignRole(userPoolId: string, username: string, groupName: string) {\n this.validate(UserGroupDto, { userPoolId, username, groupName });\n return addUserToGroup(userPoolId, username, groupName);\n }\n\n async unassignRole(userPoolId: string, username: string, groupName: string) {\n this.validate(UserGroupDto, { userPoolId, username, groupName });\n return removeUserFromGroup(userPoolId, username, groupName);\n }\n\n // ---------------------------------------------------------------------------\n // Permission check\n // ---------------------------------------------------------------------------\n\n async hasPermission(role: string, resource: string, scope: string, method: string): Promise<boolean> {\n return this.permissionService.hasPermission(role, resource, scope, method);\n }\n\n async getPermissionByKey(permissionKey: string): Promise<Permission | null> {\n return this.permissionService.getPermissionByKey(permissionKey);\n }\n\n // ---------------------------------------------------------------------------\n // Permission request handler (routes from ControllerApi)\n // ---------------------------------------------------------------------------\n\n async handlePermissionRequest(\n req: HttpRequest,\n path: string,\n permissionMap: PermissionMap,\n adminGroups: string[],\n ): Promise<any> {\n this.checkAdminPermission(req.identity.groups, adminGroups);\n\n if (req.methode === \"POST\") {\n const normalizedPath = trimSpecialChar(path);\n const rolePath = trimSpecialChar(permissionMap.rolePath ?? \"\");\n\n for (const [suffix, handler] of Object.entries(this.subRoutes)) {\n if (normalizedPath === `${rolePath}${suffix}`) {\n return handler(permissionMap, req.body);\n }\n }\n\n return this.addPermission(req.body);\n }\n\n switch (req.methode) {\n case \"GET\":\n return this.listPermissions(req.filter);\n case \"PATCH\":\n return this.updatePermission(req.entityId, req.body);\n case \"DELETE\":\n return this.deletePermission(req.entityId);\n default:\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"[CORE] unsupported method\");\n }\n }\n\n // ---------------------------------------------------------------------------\n // RBAC access enforcement (used by ControllerApi)\n // ---------------------------------------------------------------------------\n\n private permissionDenied(message: string = \"Permission denied: no role accessible\") {\n throw new ErrorHttp({ code: 403, error: \"PermissionDenied\" }, message);\n }\n\n async checkAccess(req: HttpRequest, resource: string, scopeMap: ScopeMap, adminGroups?: string[]): Promise<boolean> {\n const roles = this.extractRoles(req);\n if (roles?.length) {\n const method = req.methode.toUpperCase();\n const scope = this.getScope(req, scopeMap);\n\n if (method === \"POST\") {\n this.setDefaultIndexFields(req, scopeMap);\n }\n\n if (method === \"GET\" && this.isOpenSearchPath(req)) {\n this.setDefaultFilters(req, scopeMap);\n } else if (method === \"GET\") {\n this.applyScopeFilter(req, scope, scopeMap);\n }\n\n if (adminGroups?.length && this.isAdmin(roles, adminGroups)) return true;\n\n const hasPermission = await this.hasAnyRolePermission(roles, resource, scope, method);\n\n if (hasPermission) return true;\n\n this.permissionDenied(`Permission denied: ${roles.join(\",\")}: \"${resource}#${scope}.${method}\"`);\n }\n\n this.permissionDenied();\n }\n\n checkAdminPermission(cognitoGroups: string[], adminGroups: string[]) {\n if (this.isAdmin(cognitoGroups, adminGroups)) return true;\n this.permissionDenied(\"Permission Denied\");\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private isAdmin(cognitoGroups: string[] | undefined, adminGroups: string[]): boolean {\n return cognitoGroups?.some((group) => adminGroups.includes(group)) ?? false;\n }\n\n private validate<T extends z.ZodType>(schema: T, data: unknown): z.infer<T> {\n try {\n return validateWithSchema(schema, data);\n } catch (error) {\n const formattedErrors = formatErrors(error);\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, formattedErrors);\n }\n }\n\n private isOpenSearchPath(req: HttpRequest): boolean {\n const path = trimSpecialChar(req.event?.requestContext?.resourcePath ?? req.resourcePath ?? \"\");\n return path.endsWith(\"search/query\");\n }\n\n private extractRoles(req: HttpRequest): string[] {\n return req.identity?.groups ?? [];\n }\n\n private getScope(req: HttpRequest, scopeMap: ScopeMap): string {\n return req.queryStringParameters?.scope || req.customQueryParameters?.scope || scopeMap.keys().next().value!;\n }\n\n private async hasAnyRolePermission(\n roles: string[],\n resource: string,\n scope: string,\n method: string,\n ): Promise<boolean> {\n for (const role of roles) {\n const allowed = await this.permissionService.hasPermission(role, resource, scope, method);\n if (allowed) return true;\n }\n return false;\n }\n\n private applyScopeFilter(req: HttpRequest, scope: string, scopeMap: ScopeMap): void {\n if (!req.filter) req.filter = {};\n\n this.clearScopeFilters(req, scopeMap);\n\n const mapping = scopeMap.get(scope);\n if (!mapping) return;\n\n let claimValue = req.identity?.[mapping.claimKey] || req.identity?.attributes?.[mapping.claimKey];\n\n if (!claimValue && req?.filter[mapping.filterField]) {\n claimValue = req.filter[mapping.filterField];\n } else {\n req.filter[mapping.filterField] = claimValue;\n }\n delete req.filter?.scope;\n }\n\n private setDefaultIndexFields(req: HttpRequest, scopeMap: ScopeMap): void {\n if (!req.body) req.body = {};\n if (this.isUnset(req.body.ownerId)) req.body.ownerId = req.identity?.sub;\n this.applyAllScopeValues(req, scopeMap, true);\n }\n\n private setDefaultFilters(req: HttpRequest, scopeMap: ScopeMap): void {\n if (!req.filter) req.filter = {};\n\n const referenceFilter = req.filter;\n const requestedScope = this.getRequestedScopeForDefaultFilters(req);\n const levelLimit = this.getScopeLevelLimit(requestedScope, scopeMap);\n\n for (const [scope, mapping] of scopeMap) {\n if (levelLimit !== undefined && mapping.level !== undefined && mapping.level > levelLimit) continue;\n\n const claimKey = mapping.claimKey ?? \"custom:\" + scope;\n const claimValue = req.identity?.[claimKey] || req.identity?.attributes?.[claimKey] || req.identity?.sub;\n const eqField = mapping.filterField + \".keyword__eq\";\n if (claimValue && this.isUnset(referenceFilter[eqField])) {\n referenceFilter[eqField] = claimValue;\n }\n }\n\n delete referenceFilter.scope;\n }\n\n private getRequestedScopeForDefaultFilters(req: HttpRequest): string | undefined {\n const scopeRaw = req.filter?.scope || req.queryStringParameters?.scope || req.customQueryParameters?.scope;\n if (typeof scopeRaw !== \"string\") return undefined;\n const normalized = scopeRaw.trim().toLowerCase();\n return normalized.length ? normalized : undefined;\n }\n\n private getScopeLevelLimit(requestedScope: string | undefined, scopeMap: ScopeMap): number | undefined {\n if (!requestedScope) return undefined; // no scope => include all levels\n\n for (const [scopeName, mapping] of scopeMap) {\n if (scopeName.toLowerCase() === requestedScope) {\n return mapping.level; // level1 => only level1, level2 => level1+2, level3 => all\n }\n }\n\n return undefined;\n }\n\n private applyAllScopeValues(req: HttpRequest, scopeMap: ScopeMap, defaultsOnly = false): void {\n const referenceBody = req.body;\n\n for (const [scope, mapping] of scopeMap) {\n const claimKey = mapping.claimKey ?? \"custom:\" + scope;\n const claimValue = req.identity?.[claimKey] || req.identity?.attributes?.[claimKey] || req.identity?.sub;\n if (claimValue && (!defaultsOnly || this.isUnset(referenceBody[mapping.filterField]))) {\n referenceBody[mapping.filterField] = claimValue;\n }\n }\n }\n\n private isUnset(value: unknown): boolean {\n return value === undefined || value === null || value === \"\";\n }\n\n private clearScopeFilters(req: HttpRequest, scopeMap: ScopeMap): void {\n for (const [, entry] of scopeMap) {\n delete req.filter[entry.filterField];\n }\n delete req.filter[\"scope\"];\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.model.js","sourceRoot":"","sources":["../../src/model/base.model.ts"],"names":[],"mappings":";;;AAwDA,IAAY,aAGX;AAHD,WAAY,aAAa;IACvB,oCAAmB,CAAA;IACnB,oCAAmB,CAAA;AACrB,CAAC,EAHW,aAAa,6BAAb,aAAa,QAGxB;AAOD,MAAa,QAAS,SAAQ,
|
|
1
|
+
{"version":3,"file":"base.model.js","sourceRoot":"","sources":["../../src/model/base.model.ts"],"names":[],"mappings":";;;AAwDA,IAAY,aAGX;AAHD,WAAY,aAAa;IACvB,oCAAmB,CAAA;IACnB,oCAAmB,CAAA;AACrB,CAAC,EAHW,aAAa,6BAAb,aAAa,QAGxB;AAOD,MAAa,QAAS,SAAQ,GAAuE;CAAG;AAAxG,4BAAwG","sourcesContent":["import { RequestType } from \"./validation.model\";\nimport { Action } from \"./http.model\";\n\nexport interface BaseEntity {\n id?: string;\n createdAt?: string;\n updatedAt?: string;\n\n createdBy?: any;\n updatedBy?: any;\n\n ownerId?: string;\n ownerParentId?: string;\n\n permission?: Map<string, Permission[]>;\n\n history?: ChangeHistory[];\n\n year?: string;\n yearMonth?: string;\n}\n\nexport interface ChangedField {\n fieldName: string;\n oldValue: string;\n newValue: string;\n}\n\nexport interface ChangeHistory {\n action: string;\n user: string;\n date: string;\n changes?: ChangedField[];\n}\n\nexport interface Permission {\n role: RequestType;\n actions: Action[];\n}\n\nexport interface Attachment {\n thumbnail: string;\n original: string;\n}\n\nexport interface List<T> {\n items: Array<T>;\n total?: number;\n lastKey?: string;\n}\n\nexport interface TraceChange {\n fields: string[];\n mode: InclusionMode;\n}\n\nexport enum InclusionMode {\n INCLUDE = \"include\",\n EXCLUDE = \"exclude\",\n}\n\nexport interface RolePermission {\n role: string;\n permissions: string[];\n}\n\nexport class ScopeMap extends Map<string, { filterField: string; level?: number; claimKey?: string }> {}\n\nexport interface PermissionMap {\n scopeMap: ScopeMap;\n roleTable: string;\n userPoolId?: string;\n rolePath?: string;\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Permission } from "../model/role.model";
|
|
2
2
|
import { List } from "../model/base.model";
|
|
3
|
+
import { Filter } from "../model/index.js";
|
|
3
4
|
/**
|
|
4
5
|
* Repository layer for Permission table.
|
|
5
6
|
* Pure DB operations — no caching, no business logic.
|
|
@@ -9,6 +10,7 @@ export declare class PermissionRepo {
|
|
|
9
10
|
constructor(tableName: string);
|
|
10
11
|
findById(id: string): Promise<Permission | null>;
|
|
11
12
|
findByPermissionKey(permissionKey: string): Promise<Permission | null>;
|
|
13
|
+
findByIndex(filter?: Filter): Promise<List<Partial<Permission>>>;
|
|
12
14
|
save(permission: Partial<Permission>): Promise<Permission>;
|
|
13
15
|
update(permission: Partial<Permission>): Promise<Permission>;
|
|
14
16
|
delete(id: string): Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permission.repo.js","sourceRoot":"","sources":["../../src/service/permission.repo.ts"],"names":[],"mappings":";;;AAAA,+DAA8D;AAC9D,4DAAyD;AAEzD,4DAAuD;
|
|
1
|
+
{"version":3,"file":"permission.repo.js","sourceRoot":"","sources":["../../src/service/permission.repo.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseRepoDBImpl } from \"../repositories/base-db.repo\";\nimport { DynamoIndexMap } from \"../model/dynamodb.model\";\nimport { Permission } from \"../model/role.model\";\nimport { generateUUID } from \"../utils/dynamodb.utils\";\nimport { List } from \"../model/base.model\";\nimport { Filter } from \"@chinggis/types\";\n\nfunction createPermissionIndexMap(): DynamoIndexMap {\n const map = new DynamoIndexMap();\n map.partitionKey = \"id\";\n map.set(\"byPermissionKey\", { field: \"permissionKey\", rFields: [\"role\", \"resource\", \"scope\"], fieldSeparator: \"#\" });\n map.mapFields = [\"method\"];\n return map;\n}\n\n/**\n * Repository layer for Permission table.\n * Pure DB operations — no caching, no business logic.\n */\nexport class PermissionRepo {\n private readonly db: BaseRepoDBImpl<Permission>;\n\n constructor(tableName: string) {\n this.db = new BaseRepoDBImpl<Permission>();\n this.db.setTable(tableName);\n this.db.setIndexMap(createPermissionIndexMap());\n }\n\n async findById(id: string): Promise<Permission | null> {\n return this.db.findById(id);\n }\n\n async findByPermissionKey(permissionKey: string): Promise<Permission | null> {\n return this.db.findOne({\n indexName: \"byPermissionKey\",\n indexValue: permissionKey,\n });\n }\n\n async findByIndex(filter?: Filter): Promise<List<Partial<Permission>>> {\n return this.db.find(filter);\n }\n\n async save(permission: Partial<Permission>): Promise<Permission> {\n if (!permission.id) permission.id = generateUUID();\n\n const now = new Date().toISOString();\n if (!permission.createdAt) permission.createdAt = now;\n permission.updatedAt = now;\n\n // Build composite key: role#resource#scope\n if (permission.role && permission.resource && permission.scope) {\n permission.permissionKey = `${permission.role}#${permission.resource}#${permission.scope}`;\n }\n\n return this.db.save(permission);\n }\n\n async update(permission: Partial<Permission>): Promise<Permission> {\n permission.updatedAt = new Date().toISOString();\n\n // Rebuild composite key if components changed\n if (permission.role && permission.resource && permission.scope) {\n permission.permissionKey = `${permission.role}#${permission.resource}#${permission.scope}`;\n }\n\n return this.db.update(permission);\n }\n\n async delete(id: string): Promise<boolean> {\n return this.db.delete(id);\n }\n\n async scan(): Promise<List<Partial<Permission>>> {\n return this.db.scan({});\n }\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Permission } from "../model/role.model";
|
|
2
|
+
import { Filter, List } from "../model/index.js";
|
|
2
3
|
/**
|
|
3
4
|
* PermissionService — cache + orchestration layer for Permission entities.
|
|
4
5
|
*
|
|
@@ -34,6 +35,6 @@ export declare class PermissionService {
|
|
|
34
35
|
}): Promise<Permission>;
|
|
35
36
|
updatePermission(id: string, updates: Partial<Pick<Permission, "role" | "resource" | "scope" | "method">>): Promise<Permission>;
|
|
36
37
|
deletePermission(id: string): Promise<boolean>;
|
|
37
|
-
listPermissions(): Promise<Permission
|
|
38
|
+
listPermissions(filter?: Filter): Promise<List<Partial<Permission>>>;
|
|
38
39
|
clearCache(): void;
|
|
39
40
|
}
|
|
@@ -136,9 +136,8 @@ class PermissionService {
|
|
|
136
136
|
// ---------------------------------------------------------------------------
|
|
137
137
|
// CRUD — list
|
|
138
138
|
// ---------------------------------------------------------------------------
|
|
139
|
-
async listPermissions() {
|
|
140
|
-
|
|
141
|
-
return (result.items ?? []);
|
|
139
|
+
async listPermissions(filter) {
|
|
140
|
+
return this.repo.findByIndex(filter);
|
|
142
141
|
}
|
|
143
142
|
// ---------------------------------------------------------------------------
|
|
144
143
|
// Cache control (for testing)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permission.service.js","sourceRoot":"","sources":["../../src/service/permission.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Permission } from \"../model/role.model\";\nimport { ErrorHttp } from \"../exception\";\nimport { PermissionCache } from \"./permission.cache\";\nimport { PermissionRepo } from \"./permission.repo\";\n\n/**\n * PermissionService — cache + orchestration layer for Permission entities.\n *\n * Design decisions:\n * - Read-through cache via PermissionCache (in-flight dedup, TTL).\n * - Repository handles only DB I/O.\n * - Cache invalidation on every mutation.\n * - ~100 roles total, read-heavy → caching makes sense.\n * - Cache keyed by `perm:{permissionKey}` for deterministic, namespaced lookup.\n */\nexport class PermissionService {\n private readonly repo: PermissionRepo;\n private readonly cache: PermissionCache;\n\n constructor(tableName: string, cacheTtlMs?: number) {\n this.repo = new PermissionRepo(tableName);\n this.cache = new PermissionCache(cacheTtlMs);\n }\n\n // ---------------------------------------------------------------------------\n // Core lookup\n // ---------------------------------------------------------------------------\n\n /** Fetch Permission by composite key (role#resource#scope). Read-through cached. */\n async getPermissionByKey(permissionKey: string): Promise<Permission | null> {\n if (!permissionKey) return null;\n\n return this.cache.getOrFetch(`perm:${permissionKey}`, () => this.repo.findByPermissionKey(permissionKey));\n }\n\n /** Fetch Permission by id. Read-through cached. */\n async getPermissionById(id: string): Promise<Permission | null> {\n if (!id) return null;\n\n return this.cache.getOrFetch(`id:${id}`, () => this.repo.findById(id));\n }\n\n // ---------------------------------------------------------------------------\n // Permission check\n // ---------------------------------------------------------------------------\n\n /**\n * Check if the given role+resource+scope has a specific HTTP method allowed.\n *\n * Builds the permissionKey `role#resource#scope`, fetches the Permission,\n * and checks the method map.\n *\n * @returns `true` if allowed, `false` otherwise.\n */\n async hasPermission(role: string, resource: string, scope: string, method: string): Promise<boolean> {\n if (!role || !resource || !scope || !method) return false;\n\n const permissionKey = `${role}#${resource}#${scope}`;\n const permission = await this.getPermissionByKey(permissionKey);\n if (!permission?.method) return false;\n\n const methodLower = method.toUpperCase() as keyof Permission[\"method\"];\n\n return permission.method[methodLower] === true;\n }\n\n // ---------------------------------------------------------------------------\n // CRUD — create\n // ---------------------------------------------------------------------------\n\n async createPermission(input: {\n role: string;\n resource: string;\n scope: string;\n method: Permission[\"method\"];\n }): Promise<Permission> {\n if (!input.role?.trim()) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Role is required\");\n }\n if (!input.resource?.trim()) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Resource is required\");\n }\n if (!input.scope?.trim()) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Scope is required\");\n }\n\n // Duplicate check\n const permissionKey = `${input.role}#${input.resource}#${input.scope}`;\n const existing = await this.repo.findByPermissionKey(permissionKey);\n if (existing) {\n throw new ErrorHttp({ code: 409, error: \"Conflict\" }, `Permission \"${permissionKey}\" already exists`);\n }\n\n const saved = await this.repo.save({\n role: input.role.trim(),\n resource: input.resource.trim(),\n scope: input.scope.trim(),\n method: input.method ?? {},\n permissionKey,\n });\n\n this.cache.clear();\n return saved;\n }\n\n // ---------------------------------------------------------------------------\n // CRUD — update\n // ---------------------------------------------------------------------------\n\n async updatePermission(\n id: string,\n updates: Partial<Pick<Permission, \"role\" | \"resource\" | \"scope\" | \"method\">>,\n ): Promise<Permission> {\n if (!id) throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Permission id is required\");\n\n const existing = await this.repo.findById(id);\n if (!existing) throw new ErrorHttp({ code: 404, error: \"NotFound\" }, `Permission \"${id}\" not found`);\n\n const data: Partial<Permission> = { id };\n if (updates.role !== undefined) data.role = updates.role.trim();\n if (updates.resource !== undefined) data.resource = updates.resource.trim();\n if (updates.scope !== undefined) data.scope = updates.scope.trim();\n if (updates.method !== undefined) data.method = updates.method;\n\n // Rebuild key if any key component changed\n const role = data.role ?? existing.role;\n const resource = data.resource ?? existing.resource;\n const scope = data.scope ?? existing.scope;\n data.permissionKey = `${role}#${resource}#${scope}`;\n\n // Check for duplicate key if components changed\n if (data.permissionKey !== existing.permissionKey) {\n const conflict = await this.repo.findByPermissionKey(data.permissionKey);\n if (conflict) {\n throw new ErrorHttp({ code: 409, error: \"Conflict\" }, `Permission \"${data.permissionKey}\" already exists`);\n }\n }\n\n const updated = await this.repo.update(data);\n\n this.cache.clear();\n return updated;\n }\n\n // ---------------------------------------------------------------------------\n // CRUD — delete\n // ---------------------------------------------------------------------------\n\n async deletePermission(id: string): Promise<boolean> {\n if (!id) throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Permission id is required\");\n\n const existing = await this.repo.findById(id);\n if (!existing) throw new ErrorHttp({ code: 404, error: \"NotFound\" }, `Permission \"${id}\" not found`);\n\n const result = await this.repo.delete(id);\n\n this.cache.clear();\n return result;\n }\n\n // ---------------------------------------------------------------------------\n // CRUD — list\n // ---------------------------------------------------------------------------\n\n async listPermissions(): Promise<Permission[]> {\n const result = await this.repo.scan();\n return (result.items ?? []) as Permission[];\n }\n\n // ---------------------------------------------------------------------------\n // Cache control (for testing)\n // ---------------------------------------------------------------------------\n\n clearCache(): void {\n this.cache.clear();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"permission.service.js","sourceRoot":"","sources":["../../src/service/permission.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Permission } from \"../model/role.model\";\nimport { ErrorHttp } from \"../exception\";\nimport { PermissionCache } from \"./permission.cache\";\nimport { PermissionRepo } from \"./permission.repo\";\nimport { Filter, List } from \"@chinggis/types\";\n\n/**\n * PermissionService — cache + orchestration layer for Permission entities.\n *\n * Design decisions:\n * - Read-through cache via PermissionCache (in-flight dedup, TTL).\n * - Repository handles only DB I/O.\n * - Cache invalidation on every mutation.\n * - ~100 roles total, read-heavy → caching makes sense.\n * - Cache keyed by `perm:{permissionKey}` for deterministic, namespaced lookup.\n */\nexport class PermissionService {\n private readonly repo: PermissionRepo;\n private readonly cache: PermissionCache;\n\n constructor(tableName: string, cacheTtlMs?: number) {\n this.repo = new PermissionRepo(tableName);\n this.cache = new PermissionCache(cacheTtlMs);\n }\n\n // ---------------------------------------------------------------------------\n // Core lookup\n // ---------------------------------------------------------------------------\n\n /** Fetch Permission by composite key (role#resource#scope). Read-through cached. */\n async getPermissionByKey(permissionKey: string): Promise<Permission | null> {\n if (!permissionKey) return null;\n\n return this.cache.getOrFetch(`perm:${permissionKey}`, () => this.repo.findByPermissionKey(permissionKey));\n }\n\n /** Fetch Permission by id. Read-through cached. */\n async getPermissionById(id: string): Promise<Permission | null> {\n if (!id) return null;\n\n return this.cache.getOrFetch(`id:${id}`, () => this.repo.findById(id));\n }\n\n // ---------------------------------------------------------------------------\n // Permission check\n // ---------------------------------------------------------------------------\n\n /**\n * Check if the given role+resource+scope has a specific HTTP method allowed.\n *\n * Builds the permissionKey `role#resource#scope`, fetches the Permission,\n * and checks the method map.\n *\n * @returns `true` if allowed, `false` otherwise.\n */\n async hasPermission(role: string, resource: string, scope: string, method: string): Promise<boolean> {\n if (!role || !resource || !scope || !method) return false;\n\n const permissionKey = `${role}#${resource}#${scope}`;\n const permission = await this.getPermissionByKey(permissionKey);\n if (!permission?.method) return false;\n\n const methodLower = method.toUpperCase() as keyof Permission[\"method\"];\n\n return permission.method[methodLower] === true;\n }\n\n // ---------------------------------------------------------------------------\n // CRUD — create\n // ---------------------------------------------------------------------------\n\n async createPermission(input: {\n role: string;\n resource: string;\n scope: string;\n method: Permission[\"method\"];\n }): Promise<Permission> {\n if (!input.role?.trim()) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Role is required\");\n }\n if (!input.resource?.trim()) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Resource is required\");\n }\n if (!input.scope?.trim()) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Scope is required\");\n }\n\n // Duplicate check\n const permissionKey = `${input.role}#${input.resource}#${input.scope}`;\n const existing = await this.repo.findByPermissionKey(permissionKey);\n if (existing) {\n throw new ErrorHttp({ code: 409, error: \"Conflict\" }, `Permission \"${permissionKey}\" already exists`);\n }\n\n const saved = await this.repo.save({\n role: input.role.trim(),\n resource: input.resource.trim(),\n scope: input.scope.trim(),\n method: input.method ?? {},\n permissionKey,\n });\n\n this.cache.clear();\n return saved;\n }\n\n // ---------------------------------------------------------------------------\n // CRUD — update\n // ---------------------------------------------------------------------------\n\n async updatePermission(\n id: string,\n updates: Partial<Pick<Permission, \"role\" | \"resource\" | \"scope\" | \"method\">>,\n ): Promise<Permission> {\n if (!id) throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Permission id is required\");\n\n const existing = await this.repo.findById(id);\n if (!existing) throw new ErrorHttp({ code: 404, error: \"NotFound\" }, `Permission \"${id}\" not found`);\n\n const data: Partial<Permission> = { id };\n if (updates.role !== undefined) data.role = updates.role.trim();\n if (updates.resource !== undefined) data.resource = updates.resource.trim();\n if (updates.scope !== undefined) data.scope = updates.scope.trim();\n if (updates.method !== undefined) data.method = updates.method;\n\n // Rebuild key if any key component changed\n const role = data.role ?? existing.role;\n const resource = data.resource ?? existing.resource;\n const scope = data.scope ?? existing.scope;\n data.permissionKey = `${role}#${resource}#${scope}`;\n\n // Check for duplicate key if components changed\n if (data.permissionKey !== existing.permissionKey) {\n const conflict = await this.repo.findByPermissionKey(data.permissionKey);\n if (conflict) {\n throw new ErrorHttp({ code: 409, error: \"Conflict\" }, `Permission \"${data.permissionKey}\" already exists`);\n }\n }\n\n const updated = await this.repo.update(data);\n\n this.cache.clear();\n return updated;\n }\n\n // ---------------------------------------------------------------------------\n // CRUD — delete\n // ---------------------------------------------------------------------------\n\n async deletePermission(id: string): Promise<boolean> {\n if (!id) throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Permission id is required\");\n\n const existing = await this.repo.findById(id);\n if (!existing) throw new ErrorHttp({ code: 404, error: \"NotFound\" }, `Permission \"${id}\" not found`);\n\n const result = await this.repo.delete(id);\n\n this.cache.clear();\n return result;\n }\n\n // ---------------------------------------------------------------------------\n // CRUD — list\n // ---------------------------------------------------------------------------\n\n async listPermissions(filter?: Filter): Promise<List<Partial<Permission>>> {\n return this.repo.findByIndex(filter);\n }\n\n // ---------------------------------------------------------------------------\n // Cache control (for testing)\n // ---------------------------------------------------------------------------\n\n clearCache(): void {\n this.cache.clear();\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
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"]}
|
|
@@ -1 +0,0 @@
|
|
|
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"]}
|
|
@@ -1 +0,0 @@
|
|
|
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"]}
|
|
@@ -1,19 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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"]}
|
/package/dist/_examples/controller/{property/property-crud.d.ts → properties/properties-crud.d.ts}
RENAMED
|
File without changes
|