import AggregateBy from "../../Types/BaseDatabase/AggregateBy"; import UserMiddleware from "../Middleware/UserAuthorization"; import AnalyticsDatabaseService from "../Services/AnalyticsDatabaseService"; import CreateBy from "../Types/AnalyticsDatabase/CreateBy"; import GroupBy from "../Types/AnalyticsDatabase/GroupBy"; import Query from "../Types/AnalyticsDatabase/Query"; import Select from "../Types/AnalyticsDatabase/Select"; import Sort from "../Types/AnalyticsDatabase/Sort"; import Express, { ExpressRequest, ExpressResponse, ExpressRouter, NextFunction, OneUptimeRequest, } from "../Utils/Express"; import Response from "../Utils/Response"; import CommonAPI from "./CommonAPI"; import AnalyticsDataModel from "../../Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel"; import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps"; import { DEFAULT_LIMIT, LIMIT_PER_PROJECT, } from "../../Types/Database/LimitMax"; import BadRequestException from "../../Types/Exception/BadRequestException"; import { JSONObject } from "../../Types/JSON"; import JSONFunctions from "../../Types/JSONFunctions"; import ObjectID from "../../Types/ObjectID"; import { UserPermission } from "../../Types/Permission"; import PositiveNumber from "../../Types/PositiveNumber"; import AggregatedResult from "../../Types/BaseDatabase/AggregatedResult"; import CaptureSpan from "../Utils/Telemetry/CaptureSpan"; export default class BaseAnalyticsAPI< TAnalyticsDataModel extends AnalyticsDataModel, TBaseService extends AnalyticsDatabaseService, > { public entityType: { new (): TAnalyticsDataModel }; public router: ExpressRouter; public service: TBaseService; public constructor( type: { new (): TAnalyticsDataModel }, service: TBaseService, ) { this.entityType = type; const router: ExpressRouter = Express.getRouter(); // Create router.post( `${new this.entityType().crudApiPath.toString()}`, UserMiddleware.getUserMiddleware, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => { try { await this.createItem(req, res); } catch (err) { next(err); } }, ); // List router.post( `${new this.entityType().crudApiPath?.toString()}/get-list`, UserMiddleware.getUserMiddleware, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => { try { await this.getList(req, res); } catch (err) { next(err); } }, ); // List router.get( `${new this.entityType().crudApiPath?.toString()}/get-list`, UserMiddleware.getUserMiddleware, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => { try { await this.getList(req, res); } catch (err) { next(err); } }, ); // Aggregate router.post( `${new this.entityType().crudApiPath?.toString()}/aggregate`, UserMiddleware.getUserMiddleware, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => { try { await this.getAggregate(req, res); } catch (err) { next(err); } }, ); // Aggregate router.get( `${new this.entityType().crudApiPath?.toString()}/aggregate`, UserMiddleware.getUserMiddleware, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => { try { await this.getAggregate(req, res); } catch (err) { next(err); } }, ); // count router.post( `${new this.entityType().crudApiPath?.toString()}/count`, UserMiddleware.getUserMiddleware, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => { try { await this.count(req, res); } catch (err) { next(err); } }, ); // Get Item router.post( `${new this.entityType().crudApiPath?.toString()}/:id/get-item`, UserMiddleware.getUserMiddleware, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => { try { await this.getItem(req, res); } catch (err) { next(err); } }, ); // Get Item router.get( `${new this.entityType().crudApiPath?.toString()}/:id/get-item`, UserMiddleware.getUserMiddleware, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => { try { await this.getItem(req, res); } catch (err) { next(err); } }, ); // Update router.put( `${new this.entityType().crudApiPath?.toString()}/:id`, UserMiddleware.getUserMiddleware, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => { try { await this.updateItem(req, res); } catch (err) { next(err); } }, ); // Delete router.delete( `${new this.entityType().crudApiPath?.toString()}/:id`, UserMiddleware.getUserMiddleware, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => { try { await this.deleteItem(req, res); } catch (err) { next(err); } }, ); this.router = router; this.service = service; } @CaptureSpan() public async getPermissionsForTenant( req: ExpressRequest, ): Promise> { const permissions: Array = []; const props: DatabaseCommonInteractionProps = await CommonAPI.getDatabaseCommonInteractionProps(req); if ( props && props.userTenantAccessPermission && props.userTenantAccessPermission[props.tenantId?.toString() || ""] ) { return ( props.userTenantAccessPermission[props.tenantId?.toString() || ""] ?.permissions || [] ); } return permissions; } public getTenantId(req: ExpressRequest): ObjectID | null { if ((req as OneUptimeRequest).tenantId) { return (req as OneUptimeRequest).tenantId as ObjectID; } return null; } @CaptureSpan() public async getList( req: ExpressRequest, res: ExpressResponse, ): Promise { await this.onBeforeList(req, res); const skip: PositiveNumber = req.query["skip"] ? new PositiveNumber(req.query["skip"] as string) : new PositiveNumber(0); const limit: PositiveNumber = req.query["limit"] ? new PositiveNumber(req.query["limit"] as string) : new PositiveNumber(DEFAULT_LIMIT); if (limit.toNumber() > LIMIT_PER_PROJECT) { throw new BadRequestException( "Limit should be less than " + LIMIT_PER_PROJECT, ); } let query: Query = {}; let select: Select = {}; let sort: Sort = {}; let groupBy: GroupBy = {}; if (req.body) { query = JSONFunctions.deserialize(req.body["query"]) as Query; select = JSONFunctions.deserialize( req.body["select"], ) as Select; sort = JSONFunctions.deserialize( req.body["sort"], ) as Sort; groupBy = JSONFunctions.deserialize( req.body["groupBy"], ) as GroupBy; } const databaseProps: DatabaseCommonInteractionProps = await CommonAPI.getDatabaseCommonInteractionProps(req); const list: Array = await this.service.findBy({ query, select, skip: skip, limit: limit, sort: sort, groupBy: groupBy, props: databaseProps, }); const count: PositiveNumber = await this.service.countBy({ query, groupBy: groupBy, props: databaseProps, }); return Response.sendEntityArrayResponse( req, res, list, count, this.entityType, ); } @CaptureSpan() public async getAggregate( req: ExpressRequest, res: ExpressResponse, ): Promise { await this.onBeforeList(req, res); let aggregateBy: AggregateBy | null = null; if (req.body && req.body["aggregateBy"]) { aggregateBy = JSONFunctions.deserialize( req.body["aggregateBy"] as JSONObject, ) as any; } let groupBy: GroupBy | null = req.body["groupBy"] || null; if (groupBy && Object.keys(groupBy).length > 0) { groupBy = JSONFunctions.deserialize(groupBy as JSONObject) as any; } if (groupBy && Object.keys(groupBy).length === 0) { groupBy = null; } if (!aggregateBy) { throw new BadRequestException("AggregateBy is required"); } const databaseProps: DatabaseCommonInteractionProps = await CommonAPI.getDatabaseCommonInteractionProps(req); const aggregateResult: AggregatedResult = await this.service.aggregateBy({ ...aggregateBy, props: databaseProps, }); return Response.sendJsonObjectResponse(req, res, { ...(aggregateResult as any), }); } @CaptureSpan() public async count(req: ExpressRequest, res: ExpressResponse): Promise { let query: Query = {}; await this.onBeforeCount(req, res); if (req.body) { query = JSONFunctions.deserialize(req.body["query"]) as Query; } const databaseProps: DatabaseCommonInteractionProps = await CommonAPI.getDatabaseCommonInteractionProps(req); const count: PositiveNumber = await this.service.countBy({ query, props: databaseProps, }); return Response.sendJsonObjectResponse(req, res, { count: count.toNumber(), }); } @CaptureSpan() public async getItem( req: ExpressRequest, res: ExpressResponse, ): Promise { const objectId: ObjectID = new ObjectID(req.params["id"] as string); await this.onBeforeGet(req, res); let select: Select = {}; if (req.body) { select = JSONFunctions.deserialize( req.body["select"], ) as Select; } const item: AnalyticsDataModel | null = await this.service.findOneById({ id: objectId, select, props: await CommonAPI.getDatabaseCommonInteractionProps(req), }); return Response.sendEntityResponse(req, res, item, this.entityType); } @CaptureSpan() public async deleteItem( req: ExpressRequest, res: ExpressResponse, ): Promise { await this.onBeforeDelete(req, res); const objectId: ObjectID = new ObjectID(req.params["id"] as string); await this.service.deleteBy({ query: { _id: objectId.toString(), }, props: await CommonAPI.getDatabaseCommonInteractionProps(req), }); return Response.sendEmptySuccessResponse(req, res); } @CaptureSpan() public async updateItem( req: ExpressRequest, res: ExpressResponse, ): Promise { await this.onBeforeUpdate(req, res); const objectId: ObjectID = new ObjectID(req.params["id"] as string); const objectIdString: string = objectId.toString(); const body: JSONObject = req.body; const item: TAnalyticsDataModel = AnalyticsDataModel.fromJSON( body["data"] as JSONObject, this.entityType, ) as TAnalyticsDataModel; delete (item as any)["_id"]; delete (item as any)["createdAt"]; delete (item as any)["updatedAt"]; await this.service.updateBy({ query: { _id: objectIdString, }, data: item, props: await CommonAPI.getDatabaseCommonInteractionProps(req), }); return Response.sendEmptySuccessResponse(req, res); } @CaptureSpan() public async createItem( req: ExpressRequest, res: ExpressResponse, ): Promise { await this.onBeforeCreate(req, res); const body: JSONObject = req.body; const item: TAnalyticsDataModel = AnalyticsDataModel.fromJSON( body["data"] as JSONObject, this.entityType, ) as TAnalyticsDataModel; const createBy: CreateBy = { data: item, props: await CommonAPI.getDatabaseCommonInteractionProps(req), }; const savedItem: AnalyticsDataModel = await this.service.create(createBy); return Response.sendEntityResponse(req, res, savedItem, this.entityType); } public getRouter(): ExpressRouter { return this.router; } public getEntityName(): string { return this.entityType.name; } protected async onBeforeList( _req: ExpressRequest, _res: ExpressResponse, ): Promise { return Promise.resolve(true); } protected async onBeforeCreate( _req: ExpressRequest, _res: ExpressResponse, ): Promise { return Promise.resolve(true); } protected async onBeforeGet( _req: ExpressRequest, _res: ExpressResponse, ): Promise { return Promise.resolve(true); } protected async onBeforeUpdate( _req: ExpressRequest, _res: ExpressResponse, ): Promise { return Promise.resolve(true); } protected async onBeforeDelete( _req: ExpressRequest, _res: ExpressResponse, ): Promise { return Promise.resolve(true); } protected async onBeforeCount( _req: ExpressRequest, _res: ExpressResponse, ): Promise { return Promise.resolve(true); } }