aws-service-stack 0.18.381 → 0.18.382
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/properties/property.config.js +2 -1
- package/dist/_examples/controller/properties/property.config.js.map +1 -1
- package/dist/controller/controller-api.js +1 -1
- package/dist/controller/controller-api.js.map +1 -1
- package/dist/controller/controller-role.d.ts +10 -14
- package/dist/controller/controller-role.js +104 -77
- package/dist/controller/controller-role.js.map +1 -1
- package/dist/service/crud.service.d.ts +1 -0
- package/dist/service/crud.service.interface.d.ts +1 -0
- package/dist/service/crud.service.interface.js.map +1 -1
- package/dist/service/crud.service.js +3 -0
- package/dist/service/crud.service.js.map +1 -1
- package/package.json +1 -1
|
@@ -19,7 +19,8 @@ class PropertyConfig extends base_config_1.EntityConfigImpl {
|
|
|
19
19
|
.setFields("id")
|
|
20
20
|
.set("byAgent", { field: "agentId", rFields: ["agentId"] })
|
|
21
21
|
.set("byBranch", { field: "branchId", rFields: ["branchId"] })
|
|
22
|
-
.set("byOrg", { field: "organizationId", rFields: ["organizationId"] })
|
|
22
|
+
.set("byOrg", { field: "organizationId", rFields: ["organizationId"] })
|
|
23
|
+
.set("byRole", { field: "role", rFields: ["role"] });
|
|
23
24
|
// PERMISSIONS
|
|
24
25
|
const adminGroupNames = ["admin"];
|
|
25
26
|
const policyList = [
|
|
@@ -1 +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;
|
|
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;aACtE,GAAG,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAEvD,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;AAtCD,wCAsCC;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 .set(\"byRole\", { field: \"role\", rFields: [\"role\"] });\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"]}
|
|
@@ -36,7 +36,7 @@ class ControllerApi {
|
|
|
36
36
|
}
|
|
37
37
|
else if (this.config.PERMISSION_MAP && this.roleController) {
|
|
38
38
|
const resource = this.getResource();
|
|
39
|
-
await this.roleController.checkAccess(req, resource, this.config.PERMISSION_MAP.scopeMap, this.adminGroupNames);
|
|
39
|
+
await this.roleController.checkAccess(req, resource, this.config.PERMISSION_MAP.scopeMap, this.adminGroupNames, (id) => this.service.findById(id));
|
|
40
40
|
}
|
|
41
41
|
else {
|
|
42
42
|
throw new exception_1.ErrorHttp({ code: 403, error: "PermissionDenied" }, "Access denied");
|
|
@@ -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.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
|
+
{"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,CACnC,GAAG,EACH,QAAQ,EACR,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,EACnC,IAAI,CAAC,eAAe,EACpB,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAC1C,CAAC;YACJ,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;AA1XD,sCA0XC","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(\n req,\n resource,\n this.config.PERMISSION_MAP.scopeMap,\n this.adminGroupNames,\n (id: string) => this.service.findById(id),\n );\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"]}
|
|
@@ -3,14 +3,6 @@ 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
5
|
import { Filter } from "../model/index.js";
|
|
6
|
-
/**
|
|
7
|
-
* ControllerRole — centralized Permission CRUD + RBAC access enforcement.
|
|
8
|
-
*
|
|
9
|
-
* All caching and DB orchestration lives in PermissionService.
|
|
10
|
-
*
|
|
11
|
-
* Scope validation, scope filtering, and permission checks are centralized here
|
|
12
|
-
* so that ControllerApi (and any other consumer) delegates without duplicating logic.
|
|
13
|
-
*/
|
|
14
6
|
export declare class ControllerRole {
|
|
15
7
|
protected readonly permissionService: PermissionService;
|
|
16
8
|
private readonly subRoutes;
|
|
@@ -43,21 +35,25 @@ export declare class ControllerRole {
|
|
|
43
35
|
hasPermission(role: string, resource: string, scope: string, method: string): Promise<boolean>;
|
|
44
36
|
getPermissionByKey(permissionKey: string): Promise<Permission | null>;
|
|
45
37
|
handlePermissionRequest(req: HttpRequest, path: string, permissionMap: PermissionMap, adminGroups: string[]): Promise<any>;
|
|
46
|
-
|
|
47
|
-
checkAccess(req: HttpRequest, resource: string, scopeMap: ScopeMap, adminGroups?: string[]): Promise<boolean>;
|
|
38
|
+
checkAccess(req: HttpRequest, resource: string, scopeMap: ScopeMap, adminGroups?: string[], findById?: (id: string) => Promise<any>): Promise<boolean>;
|
|
48
39
|
checkAdminPermission(cognitoGroups: string[], adminGroups: string[]): boolean;
|
|
40
|
+
private deny;
|
|
49
41
|
private isAdmin;
|
|
50
|
-
private validate;
|
|
51
|
-
private isOpenSearchPath;
|
|
52
42
|
private extractRoles;
|
|
53
43
|
private getScope;
|
|
54
44
|
private hasAnyRolePermission;
|
|
45
|
+
private validate;
|
|
46
|
+
private verifyScopeOwnership;
|
|
47
|
+
private resolveClaim;
|
|
48
|
+
private resolveClaimWithFallback;
|
|
49
|
+
private applyMethodFilters;
|
|
55
50
|
private applyScopeFilter;
|
|
56
51
|
private setDefaultIndexFields;
|
|
57
52
|
private setDefaultFilters;
|
|
58
|
-
private getRequestedScopeForDefaultFilters;
|
|
59
|
-
private getScopeLevelLimit;
|
|
60
53
|
private applyAllScopeValues;
|
|
54
|
+
private isOpenSearchPath;
|
|
55
|
+
private resolveRequestedScope;
|
|
56
|
+
private getScopeLevelLimit;
|
|
61
57
|
private isUnset;
|
|
62
58
|
private clearScopeFilters;
|
|
63
59
|
}
|
|
@@ -40,14 +40,8 @@ const UserGroupDto = zod_1.z.object({
|
|
|
40
40
|
username: zod_1.z.string().min(1, "Username is required"),
|
|
41
41
|
groupName: zod_1.z.string().min(1, "GroupName is required"),
|
|
42
42
|
});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
*
|
|
46
|
-
* All caching and DB orchestration lives in PermissionService.
|
|
47
|
-
*
|
|
48
|
-
* Scope validation, scope filtering, and permission checks are centralized here
|
|
49
|
-
* so that ControllerApi (and any other consumer) delegates without duplicating logic.
|
|
50
|
-
*/
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
const MUTATING_METHODS = new Set(["PATCH", "PUT", "DELETE"]);
|
|
51
45
|
class ControllerRole {
|
|
52
46
|
permissionService;
|
|
53
47
|
subRoutes = {
|
|
@@ -102,7 +96,7 @@ class ControllerRole {
|
|
|
102
96
|
return (0, cognito_1.removeUserFromGroup)(userPoolId, username, groupName);
|
|
103
97
|
}
|
|
104
98
|
// ---------------------------------------------------------------------------
|
|
105
|
-
// Permission
|
|
99
|
+
// Permission queries
|
|
106
100
|
// ---------------------------------------------------------------------------
|
|
107
101
|
async hasPermission(role, resource, scope, method) {
|
|
108
102
|
return this.permissionService.hasPermission(role, resource, scope, method);
|
|
@@ -137,45 +131,53 @@ class ControllerRole {
|
|
|
137
131
|
}
|
|
138
132
|
}
|
|
139
133
|
// ---------------------------------------------------------------------------
|
|
140
|
-
// RBAC access enforcement
|
|
134
|
+
// RBAC access enforcement
|
|
141
135
|
// ---------------------------------------------------------------------------
|
|
142
|
-
|
|
143
|
-
throw new exception_1.ErrorHttp({ code: 403, error: "PermissionDenied" }, message);
|
|
144
|
-
}
|
|
145
|
-
async checkAccess(req, resource, scopeMap, adminGroups) {
|
|
136
|
+
async checkAccess(req, resource, scopeMap, adminGroups, findById) {
|
|
146
137
|
const roles = this.extractRoles(req);
|
|
147
|
-
if (roles
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
this.applyScopeFilter(req, scope, scopeMap);
|
|
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}"`);
|
|
138
|
+
if (!roles.length)
|
|
139
|
+
this.deny();
|
|
140
|
+
const method = req.methode.toUpperCase();
|
|
141
|
+
const scope = this.getScope(req, scopeMap);
|
|
142
|
+
this.applyMethodFilters(req, method, scope, scopeMap);
|
|
143
|
+
if (adminGroups?.length && this.isAdmin(roles, adminGroups))
|
|
144
|
+
return true;
|
|
145
|
+
const permitted = await this.hasAnyRolePermission(roles, resource, scope, method);
|
|
146
|
+
if (!permitted) {
|
|
147
|
+
this.deny(`Permission denied: ${roles.join(",")}: "${resource}#${scope}.${method}"`);
|
|
165
148
|
}
|
|
166
|
-
|
|
149
|
+
if (MUTATING_METHODS.has(method)) {
|
|
150
|
+
await this.verifyScopeOwnership(req, scope, scopeMap, findById);
|
|
151
|
+
}
|
|
152
|
+
return true;
|
|
167
153
|
}
|
|
168
154
|
checkAdminPermission(cognitoGroups, adminGroups) {
|
|
169
155
|
if (this.isAdmin(cognitoGroups, adminGroups))
|
|
170
156
|
return true;
|
|
171
|
-
this.
|
|
157
|
+
this.deny("Permission Denied");
|
|
172
158
|
}
|
|
173
159
|
// ---------------------------------------------------------------------------
|
|
174
|
-
// Private helpers
|
|
160
|
+
// Private — error + auth helpers
|
|
175
161
|
// ---------------------------------------------------------------------------
|
|
162
|
+
deny(message = "Permission denied: no role accessible") {
|
|
163
|
+
throw new exception_1.ErrorHttp({ code: 403, error: "PermissionDenied" }, message);
|
|
164
|
+
}
|
|
176
165
|
isAdmin(cognitoGroups, adminGroups) {
|
|
177
166
|
return cognitoGroups?.some((group) => adminGroups.includes(group)) ?? false;
|
|
178
167
|
}
|
|
168
|
+
extractRoles(req) {
|
|
169
|
+
return req.identity?.groups ?? [];
|
|
170
|
+
}
|
|
171
|
+
getScope(req, scopeMap) {
|
|
172
|
+
return req.queryStringParameters?.scope || req.customQueryParameters?.scope || scopeMap.keys().next().value;
|
|
173
|
+
}
|
|
174
|
+
async hasAnyRolePermission(roles, resource, scope, method) {
|
|
175
|
+
for (const role of roles) {
|
|
176
|
+
if (await this.permissionService.hasPermission(role, resource, scope, method))
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
179
181
|
validate(schema, data) {
|
|
180
182
|
try {
|
|
181
183
|
return (0, validation_util_1.validateWithSchema)(schema, data);
|
|
@@ -185,23 +187,52 @@ class ControllerRole {
|
|
|
185
187
|
throw new exception_1.ErrorHttp({ code: 400, error: "BadRequest" }, formattedErrors);
|
|
186
188
|
}
|
|
187
189
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
// Private — scope ownership verification
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
async verifyScopeOwnership(req, scope, scopeMap, findById) {
|
|
194
|
+
const mapping = scopeMap.get(scope);
|
|
195
|
+
if (!mapping)
|
|
196
|
+
return;
|
|
197
|
+
const claimValue = this.resolveClaim(req, mapping);
|
|
198
|
+
if (!claimValue)
|
|
199
|
+
this.deny(`Missing claim for scope "${scope}"`);
|
|
200
|
+
if (!findById)
|
|
201
|
+
return;
|
|
202
|
+
if (!req.entityId) {
|
|
203
|
+
throw new exception_1.ErrorHttp({ code: 400, error: "BadRequest" }, "Missing resource id");
|
|
204
|
+
}
|
|
205
|
+
const entity = await findById(req.entityId);
|
|
206
|
+
if (!entity) {
|
|
207
|
+
throw new exception_1.ErrorHttp({ code: 404, error: "NotFound" }, `Resource with id "${req.entityId}" not found`);
|
|
208
|
+
}
|
|
209
|
+
if (entity[mapping.filterField] !== claimValue) {
|
|
210
|
+
this.deny(`Scope mismatch: no access to resource "${req.entityId}"`);
|
|
211
|
+
}
|
|
191
212
|
}
|
|
192
|
-
|
|
193
|
-
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
// Private — claim resolution
|
|
215
|
+
// ---------------------------------------------------------------------------
|
|
216
|
+
resolveClaim(req, mapping) {
|
|
217
|
+
return req.identity?.[mapping.claimKey] || req.identity?.attributes?.[mapping.claimKey];
|
|
194
218
|
}
|
|
195
|
-
|
|
196
|
-
|
|
219
|
+
resolveClaimWithFallback(req, mapping, scopeName) {
|
|
220
|
+
const claimKey = mapping.claimKey ?? "custom:" + scopeName;
|
|
221
|
+
return req.identity?.[claimKey] || req.identity?.attributes?.[claimKey] || req.identity?.sub;
|
|
197
222
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
// Private — filter application
|
|
225
|
+
// ---------------------------------------------------------------------------
|
|
226
|
+
applyMethodFilters(req, method, scope, scopeMap) {
|
|
227
|
+
if (method === "POST") {
|
|
228
|
+
this.setDefaultIndexFields(req, scopeMap);
|
|
229
|
+
}
|
|
230
|
+
else if (method === "GET" && this.isOpenSearchPath(req)) {
|
|
231
|
+
this.setDefaultFilters(req, scopeMap);
|
|
232
|
+
}
|
|
233
|
+
else if (method === "GET") {
|
|
234
|
+
this.applyScopeFilter(req, scope, scopeMap);
|
|
203
235
|
}
|
|
204
|
-
return false;
|
|
205
236
|
}
|
|
206
237
|
applyScopeFilter(req, scope, scopeMap) {
|
|
207
238
|
if (!req.filter)
|
|
@@ -210,14 +241,11 @@ class ControllerRole {
|
|
|
210
241
|
const mapping = scopeMap.get(scope);
|
|
211
242
|
if (!mapping)
|
|
212
243
|
return;
|
|
213
|
-
|
|
214
|
-
if (
|
|
215
|
-
claimValue = req.filter[mapping.filterField];
|
|
216
|
-
}
|
|
217
|
-
else {
|
|
244
|
+
const claimValue = this.resolveClaim(req, mapping);
|
|
245
|
+
if (claimValue || !req.filter[mapping.filterField]) {
|
|
218
246
|
req.filter[mapping.filterField] = claimValue;
|
|
219
247
|
}
|
|
220
|
-
delete req.filter
|
|
248
|
+
delete req.filter.scope;
|
|
221
249
|
}
|
|
222
250
|
setDefaultIndexFields(req, scopeMap) {
|
|
223
251
|
if (!req.body)
|
|
@@ -229,22 +257,32 @@ class ControllerRole {
|
|
|
229
257
|
setDefaultFilters(req, scopeMap) {
|
|
230
258
|
if (!req.filter)
|
|
231
259
|
req.filter = {};
|
|
232
|
-
const
|
|
233
|
-
const requestedScope = this.getRequestedScopeForDefaultFilters(req);
|
|
260
|
+
const requestedScope = this.resolveRequestedScope(req);
|
|
234
261
|
const levelLimit = this.getScopeLevelLimit(requestedScope, scopeMap);
|
|
235
|
-
for (const [
|
|
262
|
+
for (const [scopeName, mapping] of scopeMap) {
|
|
236
263
|
if (levelLimit !== undefined && mapping.level !== undefined && mapping.level > levelLimit)
|
|
237
264
|
continue;
|
|
238
|
-
const
|
|
239
|
-
const claimValue = req.identity?.[claimKey] || req.identity?.attributes?.[claimKey] || req.identity?.sub;
|
|
265
|
+
const claimValue = this.resolveClaimWithFallback(req, mapping, scopeName);
|
|
240
266
|
const eqField = mapping.filterField + ".keyword__eq";
|
|
241
|
-
if (claimValue && this.isUnset(
|
|
242
|
-
|
|
267
|
+
if (claimValue && this.isUnset(req.filter[eqField])) {
|
|
268
|
+
req.filter[eqField] = claimValue;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
delete req.filter.scope;
|
|
272
|
+
}
|
|
273
|
+
applyAllScopeValues(req, scopeMap, defaultsOnly = false) {
|
|
274
|
+
for (const [scopeName, mapping] of scopeMap) {
|
|
275
|
+
const claimValue = this.resolveClaimWithFallback(req, mapping, scopeName);
|
|
276
|
+
if (claimValue && (!defaultsOnly || this.isUnset(req.body[mapping.filterField]))) {
|
|
277
|
+
req.body[mapping.filterField] = claimValue;
|
|
243
278
|
}
|
|
244
279
|
}
|
|
245
|
-
delete referenceFilter.scope;
|
|
246
280
|
}
|
|
247
|
-
|
|
281
|
+
isOpenSearchPath(req) {
|
|
282
|
+
const path = (0, string_util_1.trimSpecialChar)(req.event?.requestContext?.resourcePath ?? req.resourcePath ?? "");
|
|
283
|
+
return path.endsWith("search/query");
|
|
284
|
+
}
|
|
285
|
+
resolveRequestedScope(req) {
|
|
248
286
|
const scopeRaw = req.filter?.scope || req.queryStringParameters?.scope || req.customQueryParameters?.scope;
|
|
249
287
|
if (typeof scopeRaw !== "string")
|
|
250
288
|
return undefined;
|
|
@@ -253,24 +291,13 @@ class ControllerRole {
|
|
|
253
291
|
}
|
|
254
292
|
getScopeLevelLimit(requestedScope, scopeMap) {
|
|
255
293
|
if (!requestedScope)
|
|
256
|
-
return undefined;
|
|
294
|
+
return undefined;
|
|
257
295
|
for (const [scopeName, mapping] of scopeMap) {
|
|
258
|
-
if (scopeName.toLowerCase() === requestedScope)
|
|
259
|
-
return mapping.level;
|
|
260
|
-
}
|
|
296
|
+
if (scopeName.toLowerCase() === requestedScope)
|
|
297
|
+
return mapping.level;
|
|
261
298
|
}
|
|
262
299
|
return undefined;
|
|
263
300
|
}
|
|
264
|
-
applyAllScopeValues(req, scopeMap, defaultsOnly = false) {
|
|
265
|
-
const referenceBody = req.body;
|
|
266
|
-
for (const [scope, mapping] of scopeMap) {
|
|
267
|
-
const claimKey = mapping.claimKey ?? "custom:" + scope;
|
|
268
|
-
const claimValue = req.identity?.[claimKey] || req.identity?.attributes?.[claimKey] || req.identity?.sub;
|
|
269
|
-
if (claimValue && (!defaultsOnly || this.isUnset(referenceBody[mapping.filterField]))) {
|
|
270
|
-
referenceBody[mapping.filterField] = claimValue;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
301
|
isUnset(value) {
|
|
275
302
|
return value === undefined || value === null || value === "";
|
|
276
303
|
}
|
|
@@ -1 +1 @@
|
|
|
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
|
+
{"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\nconst MUTATING_METHODS = new Set([\"PATCH\", \"PUT\", \"DELETE\"]);\n\ntype RouteHandler = (permissionMap: PermissionMap, body: any) => Promise<any>;\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 queries\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\n // ---------------------------------------------------------------------------\n\n async checkAccess(\n req: HttpRequest,\n resource: string,\n scopeMap: ScopeMap,\n adminGroups?: string[],\n findById?: (id: string) => Promise<any>,\n ): Promise<boolean> {\n const roles = this.extractRoles(req);\n if (!roles.length) this.deny();\n\n const method = req.methode.toUpperCase();\n const scope = this.getScope(req, scopeMap);\n\n this.applyMethodFilters(req, method, scope, scopeMap);\n\n if (adminGroups?.length && this.isAdmin(roles, adminGroups)) return true;\n\n const permitted = await this.hasAnyRolePermission(roles, resource, scope, method);\n if (!permitted) {\n this.deny(`Permission denied: ${roles.join(\",\")}: \"${resource}#${scope}.${method}\"`);\n }\n\n if (MUTATING_METHODS.has(method)) {\n await this.verifyScopeOwnership(req, scope, scopeMap, findById);\n }\n\n return true;\n }\n\n checkAdminPermission(cognitoGroups: string[], adminGroups: string[]) {\n if (this.isAdmin(cognitoGroups, adminGroups)) return true;\n this.deny(\"Permission Denied\");\n }\n\n // ---------------------------------------------------------------------------\n // Private — error + auth helpers\n // ---------------------------------------------------------------------------\n\n private deny(message = \"Permission denied: no role accessible\"): never {\n throw new ErrorHttp({ code: 403, error: \"PermissionDenied\" }, message);\n }\n\n private isAdmin(cognitoGroups: string[] | undefined, adminGroups: string[]): boolean {\n return cognitoGroups?.some((group) => adminGroups.includes(group)) ?? false;\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 if (await this.permissionService.hasPermission(role, resource, scope, method)) return true;\n }\n return 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 // ---------------------------------------------------------------------------\n // Private — scope ownership verification\n // ---------------------------------------------------------------------------\n\n private async verifyScopeOwnership(\n req: HttpRequest,\n scope: string,\n scopeMap: ScopeMap,\n findById?: (id: string) => Promise<any>,\n ): Promise<void> {\n const mapping = scopeMap.get(scope);\n if (!mapping) return;\n\n const claimValue = this.resolveClaim(req, mapping);\n if (!claimValue) this.deny(`Missing claim for scope \"${scope}\"`);\n\n if (!findById) return;\n\n if (!req.entityId) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Missing resource id\");\n }\n\n const entity = await findById(req.entityId);\n if (!entity) {\n throw new ErrorHttp({ code: 404, error: \"NotFound\" }, `Resource with id \"${req.entityId}\" not found`);\n }\n\n if (entity[mapping.filterField] !== claimValue) {\n this.deny(`Scope mismatch: no access to resource \"${req.entityId}\"`);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — claim resolution\n // ---------------------------------------------------------------------------\n\n private resolveClaim(req: HttpRequest, mapping: { claimKey?: string }): string | undefined {\n return req.identity?.[mapping.claimKey] || req.identity?.attributes?.[mapping.claimKey];\n }\n\n private resolveClaimWithFallback(req: HttpRequest, mapping: { claimKey?: string }, scopeName: string): string | undefined {\n const claimKey = mapping.claimKey ?? \"custom:\" + scopeName;\n return req.identity?.[claimKey] || req.identity?.attributes?.[claimKey] || req.identity?.sub;\n }\n\n // ---------------------------------------------------------------------------\n // Private — filter application\n // ---------------------------------------------------------------------------\n\n private applyMethodFilters(req: HttpRequest, method: string, scope: string, scopeMap: ScopeMap): void {\n if (method === \"POST\") {\n this.setDefaultIndexFields(req, scopeMap);\n } else 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\n private applyScopeFilter(req: HttpRequest, scope: string, scopeMap: ScopeMap): void {\n if (!req.filter) req.filter = {};\n this.clearScopeFilters(req, scopeMap);\n\n const mapping = scopeMap.get(scope);\n if (!mapping) return;\n\n const claimValue = this.resolveClaim(req, mapping);\n if (claimValue || !req.filter[mapping.filterField]) {\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 requestedScope = this.resolveRequestedScope(req);\n const levelLimit = this.getScopeLevelLimit(requestedScope, scopeMap);\n\n for (const [scopeName, mapping] of scopeMap) {\n if (levelLimit !== undefined && mapping.level !== undefined && mapping.level > levelLimit) continue;\n\n const claimValue = this.resolveClaimWithFallback(req, mapping, scopeName);\n const eqField = mapping.filterField + \".keyword__eq\";\n if (claimValue && this.isUnset(req.filter[eqField])) {\n req.filter[eqField] = claimValue;\n }\n }\n\n delete req.filter.scope;\n }\n\n private applyAllScopeValues(req: HttpRequest, scopeMap: ScopeMap, defaultsOnly = false): void {\n for (const [scopeName, mapping] of scopeMap) {\n const claimValue = this.resolveClaimWithFallback(req, mapping, scopeName);\n if (claimValue && (!defaultsOnly || this.isUnset(req.body[mapping.filterField]))) {\n req.body[mapping.filterField] = claimValue;\n }\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 resolveRequestedScope(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;\n for (const [scopeName, mapping] of scopeMap) {\n if (scopeName.toLowerCase() === requestedScope) return mapping.level;\n }\n return undefined;\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"]}
|
|
@@ -8,6 +8,7 @@ export declare abstract class CrudServiceImpl<T extends BaseEntity, D extends Ba
|
|
|
8
8
|
protected constructor(repoDB: D, repoES: S);
|
|
9
9
|
getTableName(): string;
|
|
10
10
|
findQuery(queryParams: string): Promise<List<Partial<T>>>;
|
|
11
|
+
deleteFields(entityId: string, fields: string[]): Promise<Partial<T>>;
|
|
11
12
|
searchQuery(queryParams: any, debug?: boolean): Promise<{
|
|
12
13
|
items: Partial<T>[];
|
|
13
14
|
total: number;
|
|
@@ -51,6 +51,7 @@ export interface CrudService<T extends BaseEntity> {
|
|
|
51
51
|
* @returns True if the entity was successfully deleted.
|
|
52
52
|
*/
|
|
53
53
|
remove(entityId: string, requestUser?: CognitoUser): Promise<boolean>;
|
|
54
|
+
deleteFields(entityId: string, fields: string[]): Promise<Partial<T>>;
|
|
54
55
|
/**
|
|
55
56
|
* Deletes multiple entities by their IDs for the given user.
|
|
56
57
|
* @param requestUser - Cognito user, system if not exist
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crud.service.interface.js","sourceRoot":"","sources":["../../src/service/crud.service.interface.ts"],"names":[],"mappings":"","sourcesContent":["import { BaseEntity, CognitoUser, DynamoIndexMap, Filter, List } from \"../index\";\nimport { EntityConfig } from \"@chinggis/types\";\n\n/**\n * Defines a generic base service interface for working with entities in both\n * DynamoDB and OpenSearch.\n */\nexport interface CrudService<T extends BaseEntity> {\n setConfig(config: EntityConfig): void;\n\n getTableName(): string;\n /**\n * Creates a new entity for the given user.\n * @param ownerId - The ID of the user who owns the entity.\n * @param entity - The entity to be created.\n * @param parentId\n * @param createdByUser - The created user.\n * @returns The created entity.\n */\n save(entity: Partial<T>, ownerId: string, parentId?: string, createdByUser?: CognitoUser): Promise<T>;\n\n /**\n * Creates multiple new entities for the given user.\n * @param ownerId - The ID of the user who owns the entities.\n * @param entity - An array of entities to be created.\n * @param parentId\n * @param createdByUser - The created user.\n * @param isTransactional - Whether to perform the operation in a transaction.\n * @returns An array of created entities.\n */\n saveAll(\n entity: Partial<T>[],\n ownerId: string,\n parentId?: string,\n createdByUser?: CognitoUser,\n isTransactional?: boolean,\n ): Promise<Partial<T>[]>;\n\n /**\n * Applies partial updates to an entity for the given user.\n * Only the specified fields will be updated.\n * @param requestUser - Cognito user, system if not exist\n * @param entity - The entity with updated fields.\n * @returns The updated entity.\n */\n update(entity: Partial<T>, requestUser?: CognitoUser, fields?: string[]): Promise<T>;\n\n /**\n * Applies partial updates to multiple entities for the given user.\n * Only the specified fields will be updated for each entity.\n * @param requestUser - Cognito user, system if not exist\n * @param entity - An array of entities with updated fields.\n * @param fields - The list of field names to update in each entity.\n * @param isTransactional - Whether to perform the operation in a transaction.\n * @returns True if all entities were successfully updated.\n */\n updateAll(entity: T[], fields: string[], requestUser?: CognitoUser, isTransactional?: boolean): Promise<boolean>;\n\n /**\n * Deletes an entity by ID for the given user.\n * @param requestUser - Cognito user, system if not exist\n * @param entityId - The ID of the entity to delete.\n * @returns True if the entity was successfully deleted.\n */\n remove(entityId: string, requestUser?: CognitoUser): Promise<boolean>;\n\n /**\n * Deletes multiple entities by their IDs for the given user.\n * @param requestUser - Cognito user, system if not exist\n * @param entityIds - An array of entity IDs to delete.\n * @returns True if all entities were successfully deleted.\n */\n removeAll(entityIds: string[], requestUser?: CognitoUser): Promise<boolean>;\n\n removeMatch(filter: Filter | string, requestUser?: CognitoUser): Promise<boolean>;\n\n /**\n * Retrieves an entity by its ID for the given user.\n * @param requestUser - Cognito user, system if not exist\n * @param entityId - The ID of the entity to retrieve.\n * @returns The requested entity.\n */\n findById(entityId: string, requestUser?: CognitoUser): Promise<T>;\n\n /**\n * Retrieves multiple entities by their IDs for the given user.\n * @param requestUser - Cognito user, system if not exist\n * @param entityIds - An array of entity IDs to retrieve.\n * @returns An array of found entities.\n */\n findByIds(entityIds: string[], requestUser?: CognitoUser): Promise<T[]>;\n\n /**\n * Retrieves a paginated and filtered list of entities from DynamoDB.\n *\n * @param filter - Filtering and sorting options.\n * @returns A promise resolving to a paginated list of entities.\n */\n find(filter: Filter | string): Promise<List<Partial<T>>>;\n\n /**\n * Scans the table with non-index filters. Expensive; avoid it for hot paths.\n */\n scan(filter: Filter): Promise<List<Partial<T>>>;\n\n findQuery(queryParams: string): Promise<List<Partial<T>>>;\n\n searchQuery(\n queryParams: any,\n debug?: boolean,\n ): Promise<{ items: Partial<T>[]; total: number; aggs?: Record<string, any> }>;\n\n searchQueryTotalCount(queryParams: any): Promise<number>;\n\n findAll(): Promise<T[]>;\n\n findAllMatch(filter: Filter | string): Promise<T[]>;\n\n findAllByIndex(indexName: string, indexValue: any): Promise<T[]>;\n\n findByField(fieldName: string, fieldValue: any): Promise<List<T>>;\n\n findFirst(fieldName: string, fieldValue: string | boolean | number | Date): Promise<T>;\n\n throwError(code: number, message: string, errorContent?: any): void;\n\n throwErrorHttp(error: { message: string; code: number }, message: string, errorContent?: any): void;\n\n throwErrorsHttp(code: number, message: string, errorContent?: any): void;\n\n throwErrorDatabase(tableName: string, command: any, errorContent?: any): void;\n\n throwErrorValidation(entityName: string, validation: Map<string, any>, errorContent?: any): void;\n\n // throwError(httpStatus: number, message: string): void;\n /**\n * Retrieves a filtered and sorted list of entities from OpenSearch.\n *\n * @param filter - Filtering and sorting options.\n * @returns A promise resolving to the list of matching entities.\n */\n search(filter: Filter | string): Promise<List<Partial<T>>>;\n\n searchFieldNotExist(fieldName: string, from: number, size: number): Promise<Partial<T>[]>;\n\n /**\n * Changes the owner of an entity.\n * @param ownerId - The new owner's ID.\n * @param entityId - The ID of the entity to transfer.\n * @returns The updated entity with the new owner.\n */\n changeOwner(entityId: string, ownerId: string): Promise<T>;\n\n setTable(tableName: string, dynamoIndexMap: DynamoIndexMap): boolean;\n\n setOpensearch(indexName: string, opensearchEndpoint: string): boolean;\n\n getIndexES(): string;\n\n getIndexMapDB(): DynamoIndexMap;\n\n setIndexMapDB(indexMap: DynamoIndexMap): boolean;\n\n incrementValueByField(entityId: string, fieldName: string, value?: number): Promise<T>;\n\n decrementValueByField(entityId: string, fieldName: string, value?: number): Promise<T>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"crud.service.interface.js","sourceRoot":"","sources":["../../src/service/crud.service.interface.ts"],"names":[],"mappings":"","sourcesContent":["import { BaseEntity, CognitoUser, DynamoIndexMap, Filter, List } from \"../index\";\nimport { EntityConfig } from \"@chinggis/types\";\n\n/**\n * Defines a generic base service interface for working with entities in both\n * DynamoDB and OpenSearch.\n */\nexport interface CrudService<T extends BaseEntity> {\n setConfig(config: EntityConfig): void;\n\n getTableName(): string;\n /**\n * Creates a new entity for the given user.\n * @param ownerId - The ID of the user who owns the entity.\n * @param entity - The entity to be created.\n * @param parentId\n * @param createdByUser - The created user.\n * @returns The created entity.\n */\n save(entity: Partial<T>, ownerId: string, parentId?: string, createdByUser?: CognitoUser): Promise<T>;\n\n /**\n * Creates multiple new entities for the given user.\n * @param ownerId - The ID of the user who owns the entities.\n * @param entity - An array of entities to be created.\n * @param parentId\n * @param createdByUser - The created user.\n * @param isTransactional - Whether to perform the operation in a transaction.\n * @returns An array of created entities.\n */\n saveAll(\n entity: Partial<T>[],\n ownerId: string,\n parentId?: string,\n createdByUser?: CognitoUser,\n isTransactional?: boolean,\n ): Promise<Partial<T>[]>;\n\n /**\n * Applies partial updates to an entity for the given user.\n * Only the specified fields will be updated.\n * @param requestUser - Cognito user, system if not exist\n * @param entity - The entity with updated fields.\n * @returns The updated entity.\n */\n update(entity: Partial<T>, requestUser?: CognitoUser, fields?: string[]): Promise<T>;\n\n /**\n * Applies partial updates to multiple entities for the given user.\n * Only the specified fields will be updated for each entity.\n * @param requestUser - Cognito user, system if not exist\n * @param entity - An array of entities with updated fields.\n * @param fields - The list of field names to update in each entity.\n * @param isTransactional - Whether to perform the operation in a transaction.\n * @returns True if all entities were successfully updated.\n */\n updateAll(entity: T[], fields: string[], requestUser?: CognitoUser, isTransactional?: boolean): Promise<boolean>;\n\n /**\n * Deletes an entity by ID for the given user.\n * @param requestUser - Cognito user, system if not exist\n * @param entityId - The ID of the entity to delete.\n * @returns True if the entity was successfully deleted.\n */\n remove(entityId: string, requestUser?: CognitoUser): Promise<boolean>;\n\n deleteFields(entityId: string, fields: string[]): Promise<Partial<T>>;\n\n /**\n * Deletes multiple entities by their IDs for the given user.\n * @param requestUser - Cognito user, system if not exist\n * @param entityIds - An array of entity IDs to delete.\n * @returns True if all entities were successfully deleted.\n */\n removeAll(entityIds: string[], requestUser?: CognitoUser): Promise<boolean>;\n\n removeMatch(filter: Filter | string, requestUser?: CognitoUser): Promise<boolean>;\n\n /**\n * Retrieves an entity by its ID for the given user.\n * @param requestUser - Cognito user, system if not exist\n * @param entityId - The ID of the entity to retrieve.\n * @returns The requested entity.\n */\n findById(entityId: string, requestUser?: CognitoUser): Promise<T>;\n\n /**\n * Retrieves multiple entities by their IDs for the given user.\n * @param requestUser - Cognito user, system if not exist\n * @param entityIds - An array of entity IDs to retrieve.\n * @returns An array of found entities.\n */\n findByIds(entityIds: string[], requestUser?: CognitoUser): Promise<T[]>;\n\n /**\n * Retrieves a paginated and filtered list of entities from DynamoDB.\n *\n * @param filter - Filtering and sorting options.\n * @returns A promise resolving to a paginated list of entities.\n */\n find(filter: Filter | string): Promise<List<Partial<T>>>;\n\n /**\n * Scans the table with non-index filters. Expensive; avoid it for hot paths.\n */\n scan(filter: Filter): Promise<List<Partial<T>>>;\n\n findQuery(queryParams: string): Promise<List<Partial<T>>>;\n\n searchQuery(\n queryParams: any,\n debug?: boolean,\n ): Promise<{ items: Partial<T>[]; total: number; aggs?: Record<string, any> }>;\n\n searchQueryTotalCount(queryParams: any): Promise<number>;\n\n findAll(): Promise<T[]>;\n\n findAllMatch(filter: Filter | string): Promise<T[]>;\n\n findAllByIndex(indexName: string, indexValue: any): Promise<T[]>;\n\n findByField(fieldName: string, fieldValue: any): Promise<List<T>>;\n\n findFirst(fieldName: string, fieldValue: string | boolean | number | Date): Promise<T>;\n\n throwError(code: number, message: string, errorContent?: any): void;\n\n throwErrorHttp(error: { message: string; code: number }, message: string, errorContent?: any): void;\n\n throwErrorsHttp(code: number, message: string, errorContent?: any): void;\n\n throwErrorDatabase(tableName: string, command: any, errorContent?: any): void;\n\n throwErrorValidation(entityName: string, validation: Map<string, any>, errorContent?: any): void;\n\n // throwError(httpStatus: number, message: string): void;\n /**\n * Retrieves a filtered and sorted list of entities from OpenSearch.\n *\n * @param filter - Filtering and sorting options.\n * @returns A promise resolving to the list of matching entities.\n */\n search(filter: Filter | string): Promise<List<Partial<T>>>;\n\n searchFieldNotExist(fieldName: string, from: number, size: number): Promise<Partial<T>[]>;\n\n /**\n * Changes the owner of an entity.\n * @param ownerId - The new owner's ID.\n * @param entityId - The ID of the entity to transfer.\n * @returns The updated entity with the new owner.\n */\n changeOwner(entityId: string, ownerId: string): Promise<T>;\n\n setTable(tableName: string, dynamoIndexMap: DynamoIndexMap): boolean;\n\n setOpensearch(indexName: string, opensearchEndpoint: string): boolean;\n\n getIndexES(): string;\n\n getIndexMapDB(): DynamoIndexMap;\n\n setIndexMapDB(indexMap: DynamoIndexMap): boolean;\n\n incrementValueByField(entityId: string, fieldName: string, value?: number): Promise<T>;\n\n decrementValueByField(entityId: string, fieldName: string, value?: number): Promise<T>;\n}\n"]}
|
|
@@ -30,6 +30,9 @@ class CrudServiceImpl {
|
|
|
30
30
|
this.checkIsIndexedField(filter);
|
|
31
31
|
return await this.find(filter);
|
|
32
32
|
}
|
|
33
|
+
async deleteFields(entityId, fields) {
|
|
34
|
+
return this.repoDB.deleteFields(entityId, fields);
|
|
35
|
+
}
|
|
33
36
|
async searchQuery(queryParams, debug) {
|
|
34
37
|
const query = (0, opensearch_parser_1.buildSearchQueryOS)(queryParams, this.config);
|
|
35
38
|
return await this.repoES.search(query, debug);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crud.service.js","sourceRoot":"","sources":["../../src/service/crud.service.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Action,\n BaseEntity,\n BaseRepoDB,\n BaseRepoDBImpl,\n BaseRepoES,\n BaseRepoESImpl,\n ChangeHistory,\n CognitoUser,\n computeChangedFields,\n DynamoIndexMap,\n Filter,\n List,\n parseFilter,\n parseIndexFilter,\n removeFields,\n} from \"../index\";\nimport { ErrorBase, ErrorDynamoDB, ErrorHttp, ErrorValidation } from \"../exception\";\n\nimport { EntityConfig } from \"@chinggis/types\";\nimport { CrudService } from \"./crud.service.interface\";\nimport dayjs from \"dayjs\";\nimport { buildSearchQueryOS } from \"../utils/opensearch/opensearch.parser\";\n\nexport abstract class CrudServiceImpl<T extends BaseEntity, D extends BaseRepoDB<T>, S extends BaseRepoES<T>>\n implements CrudService<T>\n{\n protected repoDB: D;\n protected repoES: S;\n protected config: EntityConfig;\n\n protected constructor(repoDB: D, repoES: S) {\n if (repoDB != null && !(repoDB instanceof BaseRepoDBImpl))\n console.error(\"repoDB is not an instance of BaseRepoDBImpl\");\n\n if (repoES != null && !(repoES instanceof BaseRepoESImpl))\n console.error(\"repoES is not an instance of BaseRepoESImpl\");\n\n if (repoDB == null && repoES == null) console.error(\"repo initialization is required\");\n\n this.repoDB = repoDB;\n this.repoES = repoES;\n }\n\n getTableName(): string {\n return this.repoDB.getTableName();\n }\n\n async findQuery(queryParams: string): Promise<List<Partial<T>>> {\n const filter = parseIndexFilter(queryParams, this.getIndexMapDB());\n this.checkIsIndexedField(filter);\n return await this.find(filter);\n }\n\n async searchQuery(\n queryParams: any,\n debug?: boolean,\n ): Promise<{ items: Partial<T>[]; total: number; aggs?: Record<string, any> }> {\n const query = buildSearchQueryOS(queryParams, this.config);\n\n return await this.repoES.search(query, debug);\n }\n\n async searchQueryTotalCount(queryParams: any): Promise<number> {\n const query = buildSearchQueryOS(queryParams, this.config);\n\n return this.repoES.count(query);\n }\n\n async incrementValueByField(entityId: string, fieldName: string, value?: number): Promise<T> {\n return await this.repoDB.incrementValueByField(entityId, fieldName, value);\n }\n\n async decrementValueByField(entityId: string, fieldName: string, value?: number): Promise<T> {\n return await this.repoDB.decrementValueByField(entityId, fieldName, value);\n }\n\n async search(filter: Filter | string): Promise<List<Partial<T>>> {\n if (typeof filter === \"string\") filter = parseIndexFilter(filter, this.getIndexMapDB());\n\n let parsedFilter = this.parseOwnerFields(filter, this.config);\n parsedFilter = this.setIndexField(parsedFilter, this.config);\n\n return this.repoES.find(parsedFilter);\n }\n\n async searchFieldNotExist(fieldName: string, from: number, size: number): Promise<Partial<T>[]> {\n return await this.repoES.fieldNotExists(fieldName, from, size);\n }\n\n async save(entity: Partial<T>, ownerId: string, parentId?: string, createdByUser?: string | CognitoUser): Promise<T> {\n entity = this.setSystemData(entity, Action.CREATE, createdByUser);\n\n if (ownerId) {\n entity[this.config.OWNER_ID_FIELD_NAME] = ownerId;\n // if (!entity.createdBy) entity.createdBy = createdByUser || ownerId;\n }\n if (parentId) entity[this.config.OWNER_PARENT_ID_FIELD_NAME] = parentId;\n\n return await this.repoDB.save(entity);\n }\n\n async saveAll(\n entities: Partial<T>[],\n ownerId: string,\n parentId?: string,\n createdByUser?: string | CognitoUser,\n isTransactional?: boolean,\n ): Promise<Partial<T>[]> {\n const entitiesUpdated = [];\n\n for (const item of entities) {\n // const entity = addDatesAndId(item);\n const entity = this.setSystemData(item, Action.CREATE, createdByUser || ownerId);\n\n if (parentId) entity[this.config.OWNER_PARENT_ID_FIELD_NAME] = parentId;\n\n entity[this.config.OWNER_ID_FIELD_NAME] = ownerId;\n\n entitiesUpdated.push(entity);\n }\n\n return await this.repoDB.saveMany(entitiesUpdated, isTransactional);\n }\n\n async update(entity: Partial<T>, requestUser?: CognitoUser, fields?: string[]): Promise<T> {\n const fieldName = this.config.DYNAMO_DB?.MAP?.partitionKey ?? \"id\";\n if (fields && fields.length > 0) fields.push(fieldName);\n if (fields && fields.length > 0) entity = removeFields([entity], fields)[0];\n\n if (!entity || !entity[fieldName]) throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, `id required`);\n\n const item = await this.repoDB.findById(entity[fieldName]);\n\n if (!entity || !item) throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, `id not found`);\n\n if (\n requestUser &&\n !requestUser.isAdmin &&\n (item[this.config.OWNER_ID_FIELD_NAME] !== requestUser.profile ||\n item[this.config.OWNER_PARENT_ID_FIELD_NAME] !== requestUser.parentId)\n )\n throw new ErrorHttp({ code: 403, error: \"PermissionDenied\" }, `No permission to resource: ${entity.id}`);\n\n entity = this.setSystemData(entity, Action.UPDATE, requestUser, item);\n\n // if (!hasPermission(entity, userId, Permission.UPDATE)) throw new Error(\"Unauthorized access\");\n return await this.repoDB.update(entity);\n }\n\n async updateAll(\n entities: Partial<T>[],\n fields: string[],\n requestUser?: CognitoUser,\n isTransactional?: boolean,\n ): Promise<boolean> {\n if (requestUser) log.warn(\"this methode is under development, cannot check ownership by updateAll\");\n\n return await this.repoDB.updateMany(entities, fields, isTransactional);\n }\n\n async remove(entityId: string, requestUser?: CognitoUser): Promise<boolean> {\n if (!entityId) throw new Error(\"Entity id required\");\n\n if (requestUser.isAdmin) return await this.repoDB.delete(entityId);\n\n const entity = await this.repoDB.findById(entityId);\n if (!entity) throw new Error(\"Entity not found\");\n\n if (\n entity[this.config.OWNER_ID_FIELD_NAME] !== requestUser.profile ||\n entity[this.config.OWNER_PARENT_ID_FIELD_NAME] !== requestUser.parentId\n )\n throw new ErrorHttp({ code: 403, error: \"PermissionDenied\" }, `No permission to resource: ${entity.id}`);\n\n return await this.repoDB.delete(entityId);\n }\n\n async removeAll(entityIds: string[], requestUser?: CognitoUser): Promise<boolean> {\n if (requestUser) log.warn(\"this methode is under development, cannot check ownership by removeAll\");\n return await this.repoDB.deleteMany(entityIds);\n }\n\n async removeMatch(filter: Filter | string, requestUser?: CognitoUser): Promise<boolean> {\n const { items } = await this.find(filter);\n if (items.length === 0) return true;\n\n return this.removeAll(\n items.map((item) => item.id),\n requestUser,\n );\n }\n\n async changeOwner(entityId: string, ownerId: string): Promise<T> {\n const entity = await this.repoDB.findById(entityId);\n entity[this.config.OWNER_ID_FIELD_NAME] = ownerId;\n return this.repoDB.update(entity);\n }\n\n setTable(tableName: string, dynamoIndexMap: DynamoIndexMap): boolean {\n this.repoDB.setTable(tableName);\n this.repoDB.setIndexMap(dynamoIndexMap);\n return true;\n }\n\n setOpensearch(indexName: string, opensearchEndpoint: string): boolean {\n this.repoES.setIndexName(indexName);\n this.repoES.setEndpoint(opensearchEndpoint);\n return true;\n }\n\n getIndexES(): string {\n return this.repoES.getIndexName();\n }\n\n getIndexMapDB(): DynamoIndexMap {\n return this.repoDB.getIndexMap();\n }\n\n setIndexMapDB(indexMap: DynamoIndexMap): boolean {\n this.repoDB.setIndexMap(indexMap);\n return true;\n }\n\n async findAll(): Promise<T[]> {\n const result: T[] = [];\n\n const filter = parseIndexFilter(\"size=250\");\n\n do {\n const response = await this.repoDB.find(filter);\n result.push(...(response.items as T[]));\n filter.lastKey = response.lastKey;\n } while (filter.lastKey);\n\n return result;\n }\n\n async findAllMatch(filter: Filter | string): Promise<T[]> {\n if (typeof filter === \"string\") filter = parseIndexFilter(filter, this.getIndexMapDB());\n this.checkIsIndexedField(filter);\n return await this.fetchAll(filter);\n }\n\n async findAllByIndex(indexName: string, indexValue: any): Promise<T[]> {\n // Create a filter object for validation\n const filter = { indexName: indexName, indexValue: indexValue };\n this.checkIsIndexedField(filter);\n\n const parsedFilter = parseIndexFilter(filter, this.getIndexMapDB());\n return this.fetchAll(parsedFilter);\n }\n\n async findByField(fieldName: string, fieldValue: any): Promise<List<T>> {\n // Create a filter object for validation\n const filter = { [fieldName]: fieldValue, size: 100 };\n this.checkIsIndexedField(filter);\n const parsedFilter = parseIndexFilter(fieldName + \"=\" + fieldValue + \"&size=100\", this.getIndexMapDB());\n return (await this.find(parsedFilter)) as List<T>;\n }\n\n async findFirst(fieldName: string, fieldValue: string | boolean | number | Date): Promise<T> {\n // Validate that the field name exists in the index map\n const filter = { [fieldName]: fieldValue };\n this.checkIsIndexedField(filter);\n\n const result = await this.findByField(fieldName, fieldValue);\n return result.items.length > 0 ? result.items[0] : null;\n }\n\n async find(filter: Filter | string): Promise<List<Partial<T>>> {\n if (typeof filter === \"string\") filter = parseIndexFilter(filter, this.getIndexMapDB());\n // Validate that all field names in the filter exist in the index map\n let parsedFilter = this.parseOwnerFields(filter, this.config);\n\n this.checkIsIndexedField(parsedFilter);\n\n parsedFilter = parseIndexFilter(filter, this.getIndexMapDB());\n return await this.repoDB.find(parsedFilter);\n }\n\n async findById(entityId: string, requestUser?: CognitoUser): Promise<T> {\n const entity = await this.repoDB.findById(entityId);\n\n if (!entity) return null;\n\n if (!requestUser || requestUser.isAdmin) return entity;\n\n const isOwnerParent = entity[this.config.OWNER_PARENT_ID_FIELD_NAME] == requestUser.profile;\n const isParent = entity[this.config.OWNER_ID_FIELD_NAME] == requestUser.profile;\n\n if (!requestUser.profile || isOwnerParent || isParent) {\n return entity;\n }\n\n return null;\n }\n\n async findByIds(entityIds: string[], requestUser?: CognitoUser): Promise<T[]> {\n if (entityIds.length > 25) throw new ErrorDynamoDB(this.getTableName(), \"findByIds\", \"Too many entities\");\n\n const entities = await this.repoDB.findByIds(entityIds);\n\n if (!requestUser || requestUser.isAdmin) return entities;\n\n const ownEntities = [];\n for (const entity of entities) {\n if (\n entity[this.config.OWNER_PARENT_ID_FIELD_NAME] == requestUser.profile ||\n entity[this.config.OWNER_ID_FIELD_NAME] == requestUser.profile\n ) {\n ownEntities.push(entity);\n }\n }\n return ownEntities;\n }\n\n async scan(filter: Filter): Promise<List<Partial<T>>> {\n this.checkIsIndexedField(filter);\n const parsedFilter = parseIndexFilter(filter, this.getIndexMapDB());\n return await this.repoDB.scan(parsedFilter);\n }\n\n throwErrorHttp(error: { message: string; code: number }, message?: string, errorContent?: any): void {\n throw new ErrorHttp({ code: error.code, error: error.message }, message, errorContent);\n }\n\n throwErrorsHttp(code: number, message: string, errorContent?: any): void {\n throw new ErrorHttp({ code, error: message }, message, errorContent);\n }\n\n throwErrorDatabase(tableName: string, command: any, errorContent?: any): void {\n throw new ErrorDynamoDB(tableName, command, errorContent);\n }\n\n throwErrorValidation(entityName: string, validation: Map<string, any>, errorContent?: any): void {\n throw new ErrorValidation(entityName, validation, errorContent);\n }\n\n throwError(code: number, message: string, errorContent?: any): void {\n throw new ErrorBase(code, message, errorContent);\n }\n\n setConfig(config: EntityConfig) {\n this.config = config;\n\n if (this.repoDB) {\n this.repoDB.setIndexMap(config.DYNAMO_DB?.MAP);\n this.repoDB.setTable(config.DYNAMO_DB?.NAME);\n }\n\n if (this.repoES) {\n this.repoES.setEndpoint(config.OPEN_SEARCH.DOMAIN);\n this.repoES.setIndexName(config.OPEN_SEARCH.INDEX);\n }\n }\n\n /**\n * Validates that all field names in the filter exist in the index map.\n * Throws a Bad Request error if any field is not found in the available indexes.\n *\n * @param filter - The filter object containing field names to validate\n * @throws ErrorHttp with status 400 if validation fails\n */\n private checkIsIndexedField(filter: Filter): void {\n if (!filter || typeof filter !== \"object\") {\n return; // Skip validation for invalid filters\n }\n\n const indexMap = this.getIndexMapDB();\n if (!indexMap || indexMap.size === 0) {\n throw new ErrorHttp({ code: 400, error: \"Bad Request\" }, \"No indexes configured for this table\");\n }\n\n // Get all valid field names from all indexes\n const validFields = new Set<string>();\n\n // Add a partition key\n if (indexMap.partitionKey) {\n validFields.add(indexMap.partitionKey);\n }\n\n // Add fields from all indexes\n for (const [indexName, indexConfig] of indexMap.entries()) {\n if (indexConfig.field) {\n validFields.add(indexConfig.field);\n }\n if (indexConfig.rFields) {\n indexConfig.rFields.forEach((field) => validFields.add(field));\n }\n if (indexConfig.sortKeyField) {\n validFields.add(indexConfig.sortKeyField);\n }\n }\n\n // Check each field in the filter\n const invalidFields: string[] = [];\n for (const fieldName of Object.keys(filter)) {\n // Skip special filter properties that are not field names\n if (\n [\"indexName\", \"indexValue\", \"size\", \"lastKey\", \"fieldsInclude\", \"fieldsExclude\", \"rangeFilters\"].includes(\n fieldName,\n )\n ) {\n continue;\n }\n\n // Skip range filter fields (ageMin, ageMax, etc.)\n const rangeSuffixes = [\"Min\", \"Max\", \"From\", \"To\", \"Start\", \"End\"];\n const isRangeField = rangeSuffixes.some((suffix) => fieldName.endsWith(suffix));\n if (isRangeField) {\n continue;\n }\n\n if (!validFields.has(fieldName)) {\n invalidFields.push(fieldName);\n }\n }\n\n if (invalidFields.length > 0) {\n const availableFields = Array.from(validFields).sort();\n throw new ErrorHttp(\n { code: 400, error: \"Bad Request\" },\n `Invalid field names in filter: ${invalidFields.join(\", \")}. Available fields: ${availableFields.join(\", \")}`,\n );\n }\n }\n\n private async fetchAll(filter: Filter | string): Promise<T[]> {\n if (typeof filter === \"string\") filter = parseFilter(filter);\n\n const result: Partial<T>[] = [];\n do {\n const response = await this.repoDB.find(filter);\n result.push(...response.items);\n filter.lastKey = response.lastKey;\n } while (filter.lastKey);\n\n return result as T[];\n }\n\n private parseOwnerFields(filter: Filter, entityConfig: EntityConfig) {\n const parsedFilter = filter;\n\n log.debug(\"input filter\", parsedFilter);\n\n if (parsedFilter.ownerParentId && !entityConfig.OWNER_PARENT_ID_FIELD_NAME) {\n parsedFilter.profileId = parsedFilter.ownerParentId;\n delete parsedFilter.ownerParentId;\n }\n if (!parsedFilter.profileId) delete parsedFilter.profileId;\n\n if (parsedFilter.ownerParentId && entityConfig.OWNER_PARENT_ID_FIELD_NAME) {\n parsedFilter[entityConfig.OWNER_PARENT_ID_FIELD_NAME] = parsedFilter.ownerParentId;\n if (entityConfig.OWNER_PARENT_ID_FIELD_NAME !== \"ownerParentId\") delete parsedFilter.ownerParentId;\n }\n\n if (parsedFilter.profileId && entityConfig.OWNER_ID_FIELD_NAME) {\n parsedFilter[entityConfig.OWNER_ID_FIELD_NAME] = parsedFilter.profileId;\n if (entityConfig.OWNER_ID_FIELD_NAME !== \"profileId\") delete parsedFilter.profileId;\n }\n\n if (parsedFilter.ownerId && entityConfig.OWNER_ID_FIELD_NAME) {\n parsedFilter[entityConfig.OWNER_ID_FIELD_NAME] = parsedFilter.ownerId;\n if (entityConfig.OWNER_ID_FIELD_NAME !== \"ownerId\") delete parsedFilter.ownerId;\n }\n log.debug(\"parsedFilter\", parsedFilter);\n\n return parsedFilter;\n }\n private setSystemData(itemNew: Partial<T>, action: Action, requestUser?: string | CognitoUser, itemOld?: T): T {\n if (!action || action === Action.DELETE || action === Action.READ) return itemNew as T;\n\n const date = dayjs().toISOString();\n const user = this.extractUser(requestUser);\n\n switch (action) {\n case Action.CREATE:\n return this.handleCreate(itemNew, user, date);\n case Action.UPDATE:\n return this.handleUpdate(itemNew, itemOld, user, date);\n default:\n return itemNew as T;\n }\n }\n\n private extractUser(requestUser: string | CognitoUser): string {\n if (!requestUser) return undefined;\n\n if (typeof requestUser === \"string\") return requestUser;\n\n return requestUser.username;\n }\n\n private handleCreate(entity: Partial<T>, user: string, date: string): T {\n const dayjsData = dayjs(new Date(date));\n\n const noIdExist = entity[this.config.DYNAMO_DB.MAP.partitionKey ?? \"id\"] === undefined;\n if (noIdExist) entity[this.config.DYNAMO_DB.MAP.partitionKey ?? \"id\"] = crypto.randomUUID();\n\n entity.createdAt = date;\n if (user) entity.createdBy = user;\n entity.year = dayjsData.year().toString();\n entity.yearMonth = dayjsData.format(\"YYYY-MM\");\n\n if (!entity.updatedAt) {\n entity.updatedAt = entity.createdAt;\n }\n\n if (!this.config.TRACE_CHANGE?.fields) return entity as T;\n\n entity.history = this.addHistory(entity.history, { action: Action.CREATE, user, date });\n return entity as T;\n }\n\n private handleUpdate(entity: Partial<T>, itemOld: T | undefined, user: string, date: string): T {\n if (user) entity.updatedBy = user;\n entity.history = entity.history || itemOld?.history;\n\n entity.updatedAt = date;\n\n if (!this.config.TRACE_CHANGE?.fields || !itemOld) {\n return entity as T;\n }\n\n const changes = computeChangedFields(itemOld, entity, this.config.TRACE_CHANGE);\n if (changes.length > 0) {\n entity.history = this.addHistory(entity.history, {\n action: Action.UPDATE,\n user,\n date,\n changes,\n });\n }\n\n return entity as T;\n }\n\n private addHistory(history: ChangeHistory[] | undefined, entry: ChangeHistory): ChangeHistory[] {\n // skip empty or invalid history entries\n if (!entry.changes || entry.changes.length === 0) {\n return history || [];\n }\n\n // clone to avoid accidental mutation\n const newHistory = [...(history || [])];\n\n // optional: limit max history size (e.g., last 100 changes)\n const MAX_HISTORY_ENTRIES = 100;\n if (newHistory.length >= MAX_HISTORY_ENTRIES) {\n newHistory.shift(); // remove oldest\n }\n\n newHistory.push(entry);\n return newHistory;\n }\n\n private setIndexField(filter: Filter, config: EntityConfig) {\n if (!filter.indexName || !filter.indexValue) return filter;\n\n const indexMap = config.DYNAMO_DB.MAP;\n if (!indexMap || indexMap.size === 0) return filter;\n\n const indexConfig = indexMap.get(filter.indexName);\n if (!indexConfig) return filter;\n\n filter.indexName = indexConfig.field;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"crud.service.js","sourceRoot":"","sources":["../../src/service/crud.service.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Action,\n BaseEntity,\n BaseRepoDB,\n BaseRepoDBImpl,\n BaseRepoES,\n BaseRepoESImpl,\n ChangeHistory,\n CognitoUser,\n computeChangedFields,\n DynamoIndexMap,\n Filter,\n List,\n parseFilter,\n parseIndexFilter,\n removeFields,\n} from \"../index\";\nimport { ErrorBase, ErrorDynamoDB, ErrorHttp, ErrorValidation } from \"../exception\";\n\nimport { EntityConfig } from \"@chinggis/types\";\nimport { CrudService } from \"./crud.service.interface\";\nimport dayjs from \"dayjs\";\nimport { buildSearchQueryOS } from \"../utils/opensearch/opensearch.parser\";\n\nexport abstract class CrudServiceImpl<\n T extends BaseEntity,\n D extends BaseRepoDB<T>,\n S extends BaseRepoES<T>,\n> implements CrudService<T> {\n protected repoDB: D;\n protected repoES: S;\n protected config: EntityConfig;\n\n protected constructor(repoDB: D, repoES: S) {\n if (repoDB != null && !(repoDB instanceof BaseRepoDBImpl))\n console.error(\"repoDB is not an instance of BaseRepoDBImpl\");\n\n if (repoES != null && !(repoES instanceof BaseRepoESImpl))\n console.error(\"repoES is not an instance of BaseRepoESImpl\");\n\n if (repoDB == null && repoES == null) console.error(\"repo initialization is required\");\n\n this.repoDB = repoDB;\n this.repoES = repoES;\n }\n\n getTableName(): string {\n return this.repoDB.getTableName();\n }\n\n async findQuery(queryParams: string): Promise<List<Partial<T>>> {\n const filter = parseIndexFilter(queryParams, this.getIndexMapDB());\n this.checkIsIndexedField(filter);\n return await this.find(filter);\n }\n\n async deleteFields(entityId: string, fields: string[]): Promise<Partial<T>> {\n return this.repoDB.deleteFields(entityId, fields);\n }\n\n async searchQuery(\n queryParams: any,\n debug?: boolean,\n ): Promise<{ items: Partial<T>[]; total: number; aggs?: Record<string, any> }> {\n const query = buildSearchQueryOS(queryParams, this.config);\n\n return await this.repoES.search(query, debug);\n }\n\n async searchQueryTotalCount(queryParams: any): Promise<number> {\n const query = buildSearchQueryOS(queryParams, this.config);\n\n return this.repoES.count(query);\n }\n\n async incrementValueByField(entityId: string, fieldName: string, value?: number): Promise<T> {\n return await this.repoDB.incrementValueByField(entityId, fieldName, value);\n }\n\n async decrementValueByField(entityId: string, fieldName: string, value?: number): Promise<T> {\n return await this.repoDB.decrementValueByField(entityId, fieldName, value);\n }\n\n async search(filter: Filter | string): Promise<List<Partial<T>>> {\n if (typeof filter === \"string\") filter = parseIndexFilter(filter, this.getIndexMapDB());\n\n let parsedFilter = this.parseOwnerFields(filter, this.config);\n parsedFilter = this.setIndexField(parsedFilter, this.config);\n\n return this.repoES.find(parsedFilter);\n }\n\n async searchFieldNotExist(fieldName: string, from: number, size: number): Promise<Partial<T>[]> {\n return await this.repoES.fieldNotExists(fieldName, from, size);\n }\n\n async save(entity: Partial<T>, ownerId: string, parentId?: string, createdByUser?: string | CognitoUser): Promise<T> {\n entity = this.setSystemData(entity, Action.CREATE, createdByUser);\n\n if (ownerId) {\n entity[this.config.OWNER_ID_FIELD_NAME] = ownerId;\n // if (!entity.createdBy) entity.createdBy = createdByUser || ownerId;\n }\n if (parentId) entity[this.config.OWNER_PARENT_ID_FIELD_NAME] = parentId;\n\n return await this.repoDB.save(entity);\n }\n\n async saveAll(\n entities: Partial<T>[],\n ownerId: string,\n parentId?: string,\n createdByUser?: string | CognitoUser,\n isTransactional?: boolean,\n ): Promise<Partial<T>[]> {\n const entitiesUpdated = [];\n\n for (const item of entities) {\n // const entity = addDatesAndId(item);\n const entity = this.setSystemData(item, Action.CREATE, createdByUser || ownerId);\n\n if (parentId) entity[this.config.OWNER_PARENT_ID_FIELD_NAME] = parentId;\n\n entity[this.config.OWNER_ID_FIELD_NAME] = ownerId;\n\n entitiesUpdated.push(entity);\n }\n\n return await this.repoDB.saveMany(entitiesUpdated, isTransactional);\n }\n\n async update(entity: Partial<T>, requestUser?: CognitoUser, fields?: string[]): Promise<T> {\n const fieldName = this.config.DYNAMO_DB?.MAP?.partitionKey ?? \"id\";\n if (fields && fields.length > 0) fields.push(fieldName);\n if (fields && fields.length > 0) entity = removeFields([entity], fields)[0];\n\n if (!entity || !entity[fieldName]) throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, `id required`);\n\n const item = await this.repoDB.findById(entity[fieldName]);\n\n if (!entity || !item) throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, `id not found`);\n\n if (\n requestUser &&\n !requestUser.isAdmin &&\n (item[this.config.OWNER_ID_FIELD_NAME] !== requestUser.profile ||\n item[this.config.OWNER_PARENT_ID_FIELD_NAME] !== requestUser.parentId)\n )\n throw new ErrorHttp({ code: 403, error: \"PermissionDenied\" }, `No permission to resource: ${entity.id}`);\n\n entity = this.setSystemData(entity, Action.UPDATE, requestUser, item);\n\n // if (!hasPermission(entity, userId, Permission.UPDATE)) throw new Error(\"Unauthorized access\");\n return await this.repoDB.update(entity);\n }\n\n async updateAll(\n entities: Partial<T>[],\n fields: string[],\n requestUser?: CognitoUser,\n isTransactional?: boolean,\n ): Promise<boolean> {\n if (requestUser) log.warn(\"this methode is under development, cannot check ownership by updateAll\");\n\n return await this.repoDB.updateMany(entities, fields, isTransactional);\n }\n\n async remove(entityId: string, requestUser?: CognitoUser): Promise<boolean> {\n if (!entityId) throw new Error(\"Entity id required\");\n\n if (requestUser.isAdmin) return await this.repoDB.delete(entityId);\n\n const entity = await this.repoDB.findById(entityId);\n if (!entity) throw new Error(\"Entity not found\");\n\n if (\n entity[this.config.OWNER_ID_FIELD_NAME] !== requestUser.profile ||\n entity[this.config.OWNER_PARENT_ID_FIELD_NAME] !== requestUser.parentId\n )\n throw new ErrorHttp({ code: 403, error: \"PermissionDenied\" }, `No permission to resource: ${entity.id}`);\n\n return await this.repoDB.delete(entityId);\n }\n\n async removeAll(entityIds: string[], requestUser?: CognitoUser): Promise<boolean> {\n if (requestUser) log.warn(\"this methode is under development, cannot check ownership by removeAll\");\n return await this.repoDB.deleteMany(entityIds);\n }\n\n async removeMatch(filter: Filter | string, requestUser?: CognitoUser): Promise<boolean> {\n const { items } = await this.find(filter);\n if (items.length === 0) return true;\n\n return this.removeAll(\n items.map((item) => item.id),\n requestUser,\n );\n }\n\n async changeOwner(entityId: string, ownerId: string): Promise<T> {\n const entity = await this.repoDB.findById(entityId);\n entity[this.config.OWNER_ID_FIELD_NAME] = ownerId;\n return this.repoDB.update(entity);\n }\n\n setTable(tableName: string, dynamoIndexMap: DynamoIndexMap): boolean {\n this.repoDB.setTable(tableName);\n this.repoDB.setIndexMap(dynamoIndexMap);\n return true;\n }\n\n setOpensearch(indexName: string, opensearchEndpoint: string): boolean {\n this.repoES.setIndexName(indexName);\n this.repoES.setEndpoint(opensearchEndpoint);\n return true;\n }\n\n getIndexES(): string {\n return this.repoES.getIndexName();\n }\n\n getIndexMapDB(): DynamoIndexMap {\n return this.repoDB.getIndexMap();\n }\n\n setIndexMapDB(indexMap: DynamoIndexMap): boolean {\n this.repoDB.setIndexMap(indexMap);\n return true;\n }\n\n async findAll(): Promise<T[]> {\n const result: T[] = [];\n\n const filter = parseIndexFilter(\"size=250\");\n\n do {\n const response = await this.repoDB.find(filter);\n result.push(...(response.items as T[]));\n filter.lastKey = response.lastKey;\n } while (filter.lastKey);\n\n return result;\n }\n\n async findAllMatch(filter: Filter | string): Promise<T[]> {\n if (typeof filter === \"string\") filter = parseIndexFilter(filter, this.getIndexMapDB());\n this.checkIsIndexedField(filter);\n return await this.fetchAll(filter);\n }\n\n async findAllByIndex(indexName: string, indexValue: any): Promise<T[]> {\n // Create a filter object for validation\n const filter = { indexName: indexName, indexValue: indexValue };\n this.checkIsIndexedField(filter);\n\n const parsedFilter = parseIndexFilter(filter, this.getIndexMapDB());\n return this.fetchAll(parsedFilter);\n }\n\n async findByField(fieldName: string, fieldValue: any): Promise<List<T>> {\n // Create a filter object for validation\n const filter = { [fieldName]: fieldValue, size: 100 };\n this.checkIsIndexedField(filter);\n const parsedFilter = parseIndexFilter(fieldName + \"=\" + fieldValue + \"&size=100\", this.getIndexMapDB());\n return (await this.find(parsedFilter)) as List<T>;\n }\n\n async findFirst(fieldName: string, fieldValue: string | boolean | number | Date): Promise<T> {\n // Validate that the field name exists in the index map\n const filter = { [fieldName]: fieldValue };\n this.checkIsIndexedField(filter);\n\n const result = await this.findByField(fieldName, fieldValue);\n return result.items.length > 0 ? result.items[0] : null;\n }\n\n async find(filter: Filter | string): Promise<List<Partial<T>>> {\n if (typeof filter === \"string\") filter = parseIndexFilter(filter, this.getIndexMapDB());\n // Validate that all field names in the filter exist in the index map\n let parsedFilter = this.parseOwnerFields(filter, this.config);\n\n this.checkIsIndexedField(parsedFilter);\n\n parsedFilter = parseIndexFilter(filter, this.getIndexMapDB());\n return await this.repoDB.find(parsedFilter);\n }\n\n async findById(entityId: string, requestUser?: CognitoUser): Promise<T> {\n const entity = await this.repoDB.findById(entityId);\n\n if (!entity) return null;\n\n if (!requestUser || requestUser.isAdmin) return entity;\n\n const isOwnerParent = entity[this.config.OWNER_PARENT_ID_FIELD_NAME] == requestUser.profile;\n const isParent = entity[this.config.OWNER_ID_FIELD_NAME] == requestUser.profile;\n\n if (!requestUser.profile || isOwnerParent || isParent) {\n return entity;\n }\n\n return null;\n }\n\n async findByIds(entityIds: string[], requestUser?: CognitoUser): Promise<T[]> {\n if (entityIds.length > 25) throw new ErrorDynamoDB(this.getTableName(), \"findByIds\", \"Too many entities\");\n\n const entities = await this.repoDB.findByIds(entityIds);\n\n if (!requestUser || requestUser.isAdmin) return entities;\n\n const ownEntities = [];\n for (const entity of entities) {\n if (\n entity[this.config.OWNER_PARENT_ID_FIELD_NAME] == requestUser.profile ||\n entity[this.config.OWNER_ID_FIELD_NAME] == requestUser.profile\n ) {\n ownEntities.push(entity);\n }\n }\n return ownEntities;\n }\n\n async scan(filter: Filter): Promise<List<Partial<T>>> {\n this.checkIsIndexedField(filter);\n const parsedFilter = parseIndexFilter(filter, this.getIndexMapDB());\n return await this.repoDB.scan(parsedFilter);\n }\n\n throwErrorHttp(error: { message: string; code: number }, message?: string, errorContent?: any): void {\n throw new ErrorHttp({ code: error.code, error: error.message }, message, errorContent);\n }\n\n throwErrorsHttp(code: number, message: string, errorContent?: any): void {\n throw new ErrorHttp({ code, error: message }, message, errorContent);\n }\n\n throwErrorDatabase(tableName: string, command: any, errorContent?: any): void {\n throw new ErrorDynamoDB(tableName, command, errorContent);\n }\n\n throwErrorValidation(entityName: string, validation: Map<string, any>, errorContent?: any): void {\n throw new ErrorValidation(entityName, validation, errorContent);\n }\n\n throwError(code: number, message: string, errorContent?: any): void {\n throw new ErrorBase(code, message, errorContent);\n }\n\n setConfig(config: EntityConfig) {\n this.config = config;\n\n if (this.repoDB) {\n this.repoDB.setIndexMap(config.DYNAMO_DB?.MAP);\n this.repoDB.setTable(config.DYNAMO_DB?.NAME);\n }\n\n if (this.repoES) {\n this.repoES.setEndpoint(config.OPEN_SEARCH.DOMAIN);\n this.repoES.setIndexName(config.OPEN_SEARCH.INDEX);\n }\n }\n\n /**\n * Validates that all field names in the filter exist in the index map.\n * Throws a Bad Request error if any field is not found in the available indexes.\n *\n * @param filter - The filter object containing field names to validate\n * @throws ErrorHttp with status 400 if validation fails\n */\n private checkIsIndexedField(filter: Filter): void {\n if (!filter || typeof filter !== \"object\") {\n return; // Skip validation for invalid filters\n }\n\n const indexMap = this.getIndexMapDB();\n if (!indexMap || indexMap.size === 0) {\n throw new ErrorHttp({ code: 400, error: \"Bad Request\" }, \"No indexes configured for this table\");\n }\n\n // Get all valid field names from all indexes\n const validFields = new Set<string>();\n\n // Add a partition key\n if (indexMap.partitionKey) {\n validFields.add(indexMap.partitionKey);\n }\n\n // Add fields from all indexes\n for (const [indexName, indexConfig] of indexMap.entries()) {\n if (indexConfig.field) {\n validFields.add(indexConfig.field);\n }\n if (indexConfig.rFields) {\n indexConfig.rFields.forEach((field) => validFields.add(field));\n }\n if (indexConfig.sortKeyField) {\n validFields.add(indexConfig.sortKeyField);\n }\n }\n\n // Check each field in the filter\n const invalidFields: string[] = [];\n for (const fieldName of Object.keys(filter)) {\n // Skip special filter properties that are not field names\n if (\n [\"indexName\", \"indexValue\", \"size\", \"lastKey\", \"fieldsInclude\", \"fieldsExclude\", \"rangeFilters\"].includes(\n fieldName,\n )\n ) {\n continue;\n }\n\n // Skip range filter fields (ageMin, ageMax, etc.)\n const rangeSuffixes = [\"Min\", \"Max\", \"From\", \"To\", \"Start\", \"End\"];\n const isRangeField = rangeSuffixes.some((suffix) => fieldName.endsWith(suffix));\n if (isRangeField) {\n continue;\n }\n\n if (!validFields.has(fieldName)) {\n invalidFields.push(fieldName);\n }\n }\n\n if (invalidFields.length > 0) {\n const availableFields = Array.from(validFields).sort();\n throw new ErrorHttp(\n { code: 400, error: \"Bad Request\" },\n `Invalid field names in filter: ${invalidFields.join(\", \")}. Available fields: ${availableFields.join(\", \")}`,\n );\n }\n }\n\n private async fetchAll(filter: Filter | string): Promise<T[]> {\n if (typeof filter === \"string\") filter = parseFilter(filter);\n\n const result: Partial<T>[] = [];\n do {\n const response = await this.repoDB.find(filter);\n result.push(...response.items);\n filter.lastKey = response.lastKey;\n } while (filter.lastKey);\n\n return result as T[];\n }\n\n private parseOwnerFields(filter: Filter, entityConfig: EntityConfig) {\n const parsedFilter = filter;\n\n log.debug(\"input filter\", parsedFilter);\n\n if (parsedFilter.ownerParentId && !entityConfig.OWNER_PARENT_ID_FIELD_NAME) {\n parsedFilter.profileId = parsedFilter.ownerParentId;\n delete parsedFilter.ownerParentId;\n }\n if (!parsedFilter.profileId) delete parsedFilter.profileId;\n\n if (parsedFilter.ownerParentId && entityConfig.OWNER_PARENT_ID_FIELD_NAME) {\n parsedFilter[entityConfig.OWNER_PARENT_ID_FIELD_NAME] = parsedFilter.ownerParentId;\n if (entityConfig.OWNER_PARENT_ID_FIELD_NAME !== \"ownerParentId\") delete parsedFilter.ownerParentId;\n }\n\n if (parsedFilter.profileId && entityConfig.OWNER_ID_FIELD_NAME) {\n parsedFilter[entityConfig.OWNER_ID_FIELD_NAME] = parsedFilter.profileId;\n if (entityConfig.OWNER_ID_FIELD_NAME !== \"profileId\") delete parsedFilter.profileId;\n }\n\n if (parsedFilter.ownerId && entityConfig.OWNER_ID_FIELD_NAME) {\n parsedFilter[entityConfig.OWNER_ID_FIELD_NAME] = parsedFilter.ownerId;\n if (entityConfig.OWNER_ID_FIELD_NAME !== \"ownerId\") delete parsedFilter.ownerId;\n }\n log.debug(\"parsedFilter\", parsedFilter);\n\n return parsedFilter;\n }\n private setSystemData(itemNew: Partial<T>, action: Action, requestUser?: string | CognitoUser, itemOld?: T): T {\n if (!action || action === Action.DELETE || action === Action.READ) return itemNew as T;\n\n const date = dayjs().toISOString();\n const user = this.extractUser(requestUser);\n\n switch (action) {\n case Action.CREATE:\n return this.handleCreate(itemNew, user, date);\n case Action.UPDATE:\n return this.handleUpdate(itemNew, itemOld, user, date);\n default:\n return itemNew as T;\n }\n }\n\n private extractUser(requestUser: string | CognitoUser): string {\n if (!requestUser) return undefined;\n\n if (typeof requestUser === \"string\") return requestUser;\n\n return requestUser.username;\n }\n\n private handleCreate(entity: Partial<T>, user: string, date: string): T {\n const dayjsData = dayjs(new Date(date));\n\n const noIdExist = entity[this.config.DYNAMO_DB.MAP.partitionKey ?? \"id\"] === undefined;\n if (noIdExist) entity[this.config.DYNAMO_DB.MAP.partitionKey ?? \"id\"] = crypto.randomUUID();\n\n entity.createdAt = date;\n if (user) entity.createdBy = user;\n entity.year = dayjsData.year().toString();\n entity.yearMonth = dayjsData.format(\"YYYY-MM\");\n\n if (!entity.updatedAt) {\n entity.updatedAt = entity.createdAt;\n }\n\n if (!this.config.TRACE_CHANGE?.fields) return entity as T;\n\n entity.history = this.addHistory(entity.history, { action: Action.CREATE, user, date });\n return entity as T;\n }\n\n private handleUpdate(entity: Partial<T>, itemOld: T | undefined, user: string, date: string): T {\n if (user) entity.updatedBy = user;\n entity.history = entity.history || itemOld?.history;\n\n entity.updatedAt = date;\n\n if (!this.config.TRACE_CHANGE?.fields || !itemOld) {\n return entity as T;\n }\n\n const changes = computeChangedFields(itemOld, entity, this.config.TRACE_CHANGE);\n if (changes.length > 0) {\n entity.history = this.addHistory(entity.history, {\n action: Action.UPDATE,\n user,\n date,\n changes,\n });\n }\n\n return entity as T;\n }\n\n private addHistory(history: ChangeHistory[] | undefined, entry: ChangeHistory): ChangeHistory[] {\n // skip empty or invalid history entries\n if (!entry.changes || entry.changes.length === 0) {\n return history || [];\n }\n\n // clone to avoid accidental mutation\n const newHistory = [...(history || [])];\n\n // optional: limit max history size (e.g., last 100 changes)\n const MAX_HISTORY_ENTRIES = 100;\n if (newHistory.length >= MAX_HISTORY_ENTRIES) {\n newHistory.shift(); // remove oldest\n }\n\n newHistory.push(entry);\n return newHistory;\n }\n\n private setIndexField(filter: Filter, config: EntityConfig) {\n if (!filter.indexName || !filter.indexValue) return filter;\n\n const indexMap = config.DYNAMO_DB.MAP;\n if (!indexMap || indexMap.size === 0) return filter;\n\n const indexConfig = indexMap.get(filter.indexName);\n if (!indexConfig) return filter;\n\n filter.indexName = indexConfig.field;\n }\n}\n"]}
|