mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
refactor base api
This commit is contained in:
@@ -8,14 +8,17 @@ import { TableAccessControl } from '../Types/BaseDatabase/AccessControl';
|
||||
import EnableWorkflowOn from '../Types/BaseDatabase/EnableWorkflowOn';
|
||||
import ObjectID from '../Types/ObjectID';
|
||||
import CommonModel from './CommonModel';
|
||||
import Route from '../Types/API/Route';
|
||||
|
||||
export default class AnalyticsDataModel extends CommonModel {
|
||||
|
||||
public constructor(data: {
|
||||
tableName: string;
|
||||
singularName: string;
|
||||
pluralName: string;
|
||||
tableEngine?: AnalyticsTableEngine | undefined;
|
||||
tableColumns: Array<AnalyticsTableColumn>;
|
||||
crudApiPath?: Route;
|
||||
allowAccessIfSubscriptionIsUnpaid?: boolean | undefined;
|
||||
tableBillingAccessControl?: TableBillingAccessControl | undefined;
|
||||
accessControl?: TableAccessControl | undefined;
|
||||
@@ -100,6 +103,7 @@ export default class AnalyticsDataModel extends CommonModel {
|
||||
data.allowAccessIfSubscriptionIsUnpaid || false;
|
||||
this.accessControl = data.accessControl;
|
||||
this.enableWorkflowOn = data.enableWorkflowOn;
|
||||
this.crudApiPath = data.crudApiPath;
|
||||
|
||||
// initialize Arrays.
|
||||
for (const column of this.tableColumns) {
|
||||
@@ -185,6 +189,17 @@ export default class AnalyticsDataModel extends CommonModel {
|
||||
this._allowAccessIfSubscriptionIsUnpaid = v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private _crudApiPath! : Route;
|
||||
public get crudApiPath() : Route {
|
||||
return this._crudApiPath;
|
||||
}
|
||||
public set crudApiPath(v : Route) {
|
||||
this._crudApiPath = v;
|
||||
}
|
||||
|
||||
|
||||
public getTenantColumn(): AnalyticsTableColumn | null {
|
||||
const column: AnalyticsTableColumn | undefined = this.tableColumns.find(
|
||||
(column: AnalyticsTableColumn) => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import TableColumnType from './Database/TableColumnType';
|
||||
import SerializableObject from './SerializableObject';
|
||||
import SerializableObjectDictionary from './SerializableObjectDictionary';
|
||||
import JSON5 from 'json5';
|
||||
import AnalyticsDataModel from '../AnalyticsModels/BaseModel';
|
||||
|
||||
export default class JSONFunctions {
|
||||
public static isEmptyObject(
|
||||
@@ -21,20 +22,20 @@ export default class JSONFunctions {
|
||||
}
|
||||
|
||||
public static toJSON(
|
||||
model: BaseModel,
|
||||
modelType: { new (): BaseModel }
|
||||
model: BaseModel | AnalyticsDataModel,
|
||||
modelType: { new (): BaseModel | AnalyticsDataModel }
|
||||
): JSONObject {
|
||||
const json: JSONObject = this.toJSONObject(model, modelType);
|
||||
return JSONFunctions.serialize(json);
|
||||
}
|
||||
|
||||
public static toJSONObject(
|
||||
model: BaseModel,
|
||||
modelType: { new (): BaseModel }
|
||||
model: BaseModel | AnalyticsDataModel,
|
||||
modelType: { new (): BaseModel | AnalyticsDataModel }
|
||||
): JSONObject {
|
||||
const json: JSONObject = {};
|
||||
|
||||
const vanillaModel: BaseModel = new modelType();
|
||||
const vanillaModel: BaseModel | AnalyticsDataModel = new modelType();
|
||||
|
||||
for (const key of vanillaModel.getTableColumns().columns) {
|
||||
if ((model as any)[key] === undefined) {
|
||||
@@ -89,8 +90,8 @@ export default class JSONFunctions {
|
||||
}
|
||||
|
||||
public static toJSONArray(
|
||||
list: Array<BaseModel>,
|
||||
modelType: { new (): BaseModel }
|
||||
list: Array<BaseModel | AnalyticsDataModel>,
|
||||
modelType: { new (): BaseModel | AnalyticsDataModel }
|
||||
): JSONArray {
|
||||
const array: JSONArray = [];
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import { IsBillingEnabled } from '../EnvironmentConfig';
|
||||
import ProjectService from '../Services/ProjectService';
|
||||
import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
|
||||
import UserType from 'Common/Types/UserType';
|
||||
import CommonAPI from './CommonAPI';
|
||||
|
||||
export default class BaseAPI<
|
||||
TBaseModel extends BaseModel,
|
||||
@@ -192,7 +193,7 @@ export default class BaseAPI<
|
||||
const permissions: Array<UserPermission> = [];
|
||||
|
||||
const props: DatabaseCommonInteractionProps =
|
||||
await this.getDatabaseCommonInteractionProps(req);
|
||||
await CommonAPI.getDatabaseCommonInteractionProps(req);
|
||||
|
||||
if (
|
||||
props &&
|
||||
@@ -217,63 +218,6 @@ export default class BaseAPI<
|
||||
return null;
|
||||
}
|
||||
|
||||
public async getDatabaseCommonInteractionProps(
|
||||
req: ExpressRequest
|
||||
): Promise<DatabaseCommonInteractionProps> {
|
||||
const props: DatabaseCommonInteractionProps = {
|
||||
tenantId: undefined,
|
||||
userGlobalAccessPermission: undefined,
|
||||
userTenantAccessPermission: undefined,
|
||||
userId: undefined,
|
||||
userType: (req as OneUptimeRequest).userType,
|
||||
isMultiTenantRequest: undefined,
|
||||
};
|
||||
|
||||
if (
|
||||
(req as OneUptimeRequest).userAuthorization &&
|
||||
(req as OneUptimeRequest).userAuthorization?.userId
|
||||
) {
|
||||
props.userId = (req as OneUptimeRequest).userAuthorization!.userId;
|
||||
}
|
||||
|
||||
if ((req as OneUptimeRequest).userGlobalAccessPermission) {
|
||||
props.userGlobalAccessPermission = (
|
||||
req as OneUptimeRequest
|
||||
).userGlobalAccessPermission;
|
||||
}
|
||||
|
||||
if ((req as OneUptimeRequest).userTenantAccessPermission) {
|
||||
props.userTenantAccessPermission = (
|
||||
req as OneUptimeRequest
|
||||
).userTenantAccessPermission;
|
||||
}
|
||||
|
||||
if ((req as OneUptimeRequest).tenantId) {
|
||||
props.tenantId = (req as OneUptimeRequest).tenantId || undefined;
|
||||
}
|
||||
|
||||
if (req.headers['is-multi-tenant-query']) {
|
||||
props.isMultiTenantRequest = true;
|
||||
}
|
||||
|
||||
if (IsBillingEnabled && props.tenantId) {
|
||||
const plan: {
|
||||
plan: PlanSelect | null;
|
||||
isSubscriptionUnpaid: boolean;
|
||||
} = await ProjectService.getCurrentPlan(props.tenantId!);
|
||||
props.currentPlan = plan.plan || undefined;
|
||||
props.isSubscriptionUnpaid = plan.isSubscriptionUnpaid;
|
||||
}
|
||||
|
||||
// check for root permissions.
|
||||
|
||||
if (props.userType === UserType.MasterAdmin) {
|
||||
props.isMasterAdmin = true;
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
public async getList(
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse
|
||||
@@ -313,7 +257,7 @@ export default class BaseAPI<
|
||||
}
|
||||
|
||||
const databaseProps: DatabaseCommonInteractionProps =
|
||||
await this.getDatabaseCommonInteractionProps(req);
|
||||
await CommonAPI.getDatabaseCommonInteractionProps(req);
|
||||
|
||||
const list: Array<BaseModel> = await this.service.findBy({
|
||||
query,
|
||||
@@ -353,7 +297,7 @@ export default class BaseAPI<
|
||||
}
|
||||
|
||||
const databaseProps: DatabaseCommonInteractionProps =
|
||||
await this.getDatabaseCommonInteractionProps(req);
|
||||
await CommonAPI.getDatabaseCommonInteractionProps(req);
|
||||
|
||||
const count: PositiveNumber = await this.service.countBy({
|
||||
query,
|
||||
@@ -382,7 +326,7 @@ export default class BaseAPI<
|
||||
const item: BaseModel | null = await this.service.findOneById({
|
||||
id: objectId,
|
||||
select,
|
||||
props: await this.getDatabaseCommonInteractionProps(req),
|
||||
props: await CommonAPI.getDatabaseCommonInteractionProps(req),
|
||||
});
|
||||
|
||||
return Response.sendEntityResponse(req, res, item, this.entityType);
|
||||
@@ -399,7 +343,7 @@ export default class BaseAPI<
|
||||
query: {
|
||||
_id: objectId.toString(),
|
||||
},
|
||||
props: await this.getDatabaseCommonInteractionProps(req),
|
||||
props: await CommonAPI.getDatabaseCommonInteractionProps(req),
|
||||
});
|
||||
|
||||
return Response.sendEmptyResponse(req, res);
|
||||
@@ -427,7 +371,7 @@ export default class BaseAPI<
|
||||
_id: objectIdString,
|
||||
},
|
||||
data: item,
|
||||
props: await this.getDatabaseCommonInteractionProps(req),
|
||||
props: await CommonAPI.getDatabaseCommonInteractionProps(req),
|
||||
});
|
||||
|
||||
return Response.sendEmptyResponse(req, res);
|
||||
@@ -452,7 +396,7 @@ export default class BaseAPI<
|
||||
const createBy: CreateBy<TBaseModel> = {
|
||||
data: item,
|
||||
miscDataProps: miscDataProps,
|
||||
props: await this.getDatabaseCommonInteractionProps(req),
|
||||
props: await CommonAPI.getDatabaseCommonInteractionProps(req),
|
||||
};
|
||||
|
||||
const savedItem: BaseModel = await this.service.create(createBy);
|
||||
|
||||
457
CommonServer/API/BaseAnalyticsAPI.ts
Normal file
457
CommonServer/API/BaseAnalyticsAPI.ts
Normal file
@@ -0,0 +1,457 @@
|
||||
import Express, {
|
||||
ExpressRequest,
|
||||
ExpressResponse,
|
||||
ExpressRouter,
|
||||
NextFunction,
|
||||
OneUptimeRequest,
|
||||
} from '../Utils/Express';
|
||||
import UserMiddleware from '../Middleware/UserAuthorization';
|
||||
import PositiveNumber from 'Common/Types/PositiveNumber';
|
||||
import BadRequestException from 'Common/Types/Exception/BadRequestException';
|
||||
import Response from '../Utils/Response';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import JSONFunctions from 'Common/Types/JSONFunctions';
|
||||
import CreateBy from '../Types/AnalyticsDatabase/CreateBy';
|
||||
import DatabaseCommonInteractionProps from 'Common/Types/BaseDatabase/DatabaseCommonInteractionProps';
|
||||
import Query from '../Types/AnalyticsDatabase/Query';
|
||||
import Select from '../Types/AnalyticsDatabase/Select';
|
||||
import Sort from '../Types/AnalyticsDatabase/Sort';
|
||||
import {
|
||||
DEFAULT_LIMIT,
|
||||
LIMIT_PER_PROJECT,
|
||||
} from 'Common/Types/Database/LimitMax';
|
||||
import { UserPermission } from 'Common/Types/Permission';
|
||||
import AnalyticsDataModel from 'Common/AnalyticsModels/BaseModel';
|
||||
import AnalyticsDatabaseService from '../Services/AnalyticsDatabaseService';
|
||||
import CommonAPI from './CommonAPI';
|
||||
|
||||
export default class BaseAnalyticsAPI<
|
||||
TAnalyticsDataModel extends AnalyticsDataModel,
|
||||
TBaseService extends AnalyticsDatabaseService<AnalyticsDataModel>
|
||||
> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
public async getPermissionsForTenant(
|
||||
req: ExpressRequest
|
||||
): Promise<Array<UserPermission>> {
|
||||
const permissions: Array<UserPermission> = [];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
public async getList(
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse
|
||||
): Promise<void> {
|
||||
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<AnalyticsDataModel> = {};
|
||||
let select: Select<AnalyticsDataModel> = {};
|
||||
let sort: Sort<AnalyticsDataModel> = {};
|
||||
|
||||
if (req.body) {
|
||||
query = JSONFunctions.deserialize(
|
||||
req.body['query']
|
||||
) as Query<AnalyticsDataModel>;
|
||||
|
||||
select = JSONFunctions.deserialize(
|
||||
req.body['select']
|
||||
) as Select<AnalyticsDataModel>;
|
||||
|
||||
sort = JSONFunctions.deserialize(
|
||||
req.body['sort']
|
||||
) as Sort<AnalyticsDataModel>;
|
||||
}
|
||||
|
||||
const databaseProps: DatabaseCommonInteractionProps =
|
||||
await CommonAPI.getDatabaseCommonInteractionProps(req);
|
||||
|
||||
const list: Array<AnalyticsDataModel> = await this.service.findBy({
|
||||
query,
|
||||
select,
|
||||
skip: skip,
|
||||
limit: limit,
|
||||
sort: sort,
|
||||
props: databaseProps,
|
||||
});
|
||||
|
||||
const count: PositiveNumber = await this.service.countBy({
|
||||
query,
|
||||
props: databaseProps,
|
||||
});
|
||||
|
||||
return Response.sendEntityArrayResponse(
|
||||
req,
|
||||
res,
|
||||
list,
|
||||
count,
|
||||
this.entityType
|
||||
);
|
||||
}
|
||||
|
||||
public async count(
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse
|
||||
): Promise<void> {
|
||||
let query: Query<AnalyticsDataModel> = {};
|
||||
|
||||
await this.onBeforeCount(req, res);
|
||||
|
||||
if (req.body) {
|
||||
query = JSONFunctions.deserialize(
|
||||
req.body['query']
|
||||
) as Query<AnalyticsDataModel>;
|
||||
}
|
||||
|
||||
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(),
|
||||
});
|
||||
}
|
||||
|
||||
public async getItem(
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse
|
||||
): Promise<void> {
|
||||
const objectId: ObjectID = new ObjectID(req.params['id'] as string);
|
||||
await this.onBeforeGet(req, res);
|
||||
let select: Select<AnalyticsDataModel> = {};
|
||||
|
||||
if (req.body) {
|
||||
select = JSONFunctions.deserialize(
|
||||
req.body['select']
|
||||
) as Select<AnalyticsDataModel>;
|
||||
}
|
||||
|
||||
const item: AnalyticsDataModel | null = await this.service.findOneById({
|
||||
id: objectId,
|
||||
select,
|
||||
props: await CommonAPI.getDatabaseCommonInteractionProps(req),
|
||||
});
|
||||
|
||||
return Response.sendEntityResponse(req, res, item, this.entityType);
|
||||
}
|
||||
|
||||
public async deleteItem(
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse
|
||||
): Promise<void> {
|
||||
await this.onBeforeDelete(req, res);
|
||||
const objectId: ObjectID = new ObjectID(req.params['id'] as string);
|
||||
|
||||
await this.service.deleteOneBy({
|
||||
query: {
|
||||
_id: objectId.toString(),
|
||||
},
|
||||
props: await CommonAPI.getDatabaseCommonInteractionProps(req),
|
||||
});
|
||||
|
||||
return Response.sendEmptyResponse(req, res);
|
||||
}
|
||||
|
||||
public async updateItem(
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse
|
||||
): Promise<void> {
|
||||
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: PartialEntity<TAnalyticsDataModel> = JSONFunctions.deserialize(
|
||||
body['data'] as JSONObject
|
||||
) as PartialEntity<TAnalyticsDataModel>;
|
||||
|
||||
delete (item as any)['_id'];
|
||||
delete (item as any)['createdAt'];
|
||||
delete (item as any)['updatedAt'];
|
||||
|
||||
await this.service.updateOneBy({
|
||||
query: {
|
||||
_id: objectIdString,
|
||||
},
|
||||
data: item,
|
||||
props: await CommonAPI.getDatabaseCommonInteractionProps(req),
|
||||
});
|
||||
|
||||
return Response.sendEmptyResponse(req, res);
|
||||
}
|
||||
|
||||
public async createItem(
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse
|
||||
): Promise<void> {
|
||||
await this.onBeforeCreate(req, res);
|
||||
const body: JSONObject = req.body;
|
||||
|
||||
const item: TAnalyticsDataModel = JSONFunctions.fromJSON<TAnalyticsDataModel>(
|
||||
body['data'] as JSONObject,
|
||||
this.entityType
|
||||
) as TAnalyticsDataModel;
|
||||
|
||||
const miscDataProps: JSONObject = JSONFunctions.deserialize(
|
||||
body['miscDataProps'] as JSONObject
|
||||
);
|
||||
|
||||
const createBy: CreateBy<TAnalyticsDataModel> = {
|
||||
data: item,
|
||||
miscDataProps: miscDataProps,
|
||||
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<any> {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
protected async onBeforeCreate(
|
||||
_req: ExpressRequest,
|
||||
_res: ExpressResponse
|
||||
): Promise<any> {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
protected async onBeforeGet(
|
||||
_req: ExpressRequest,
|
||||
_res: ExpressResponse
|
||||
): Promise<any> {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
protected async onBeforeUpdate(
|
||||
_req: ExpressRequest,
|
||||
_res: ExpressResponse
|
||||
): Promise<any> {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
protected async onBeforeDelete(
|
||||
_req: ExpressRequest,
|
||||
_res: ExpressResponse
|
||||
): Promise<any> {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
protected async onBeforeCount(
|
||||
_req: ExpressRequest,
|
||||
_res: ExpressResponse
|
||||
): Promise<any> {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
65
CommonServer/API/CommonAPI.ts
Normal file
65
CommonServer/API/CommonAPI.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { IsBillingEnabled } from '../EnvironmentConfig';
|
||||
import ProjectService from '../Services/ProjectService';
|
||||
import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
|
||||
import UserType from 'Common/Types/UserType';
|
||||
import { ExpressRequest, OneUptimeRequest } from '../Utils/Express';
|
||||
import DatabaseCommonInteractionProps from 'Common/Types/BaseDatabase/DatabaseCommonInteractionProps';
|
||||
|
||||
export default class CommonAPI {
|
||||
public static async getDatabaseCommonInteractionProps(
|
||||
req: ExpressRequest
|
||||
): Promise<DatabaseCommonInteractionProps> {
|
||||
const props: DatabaseCommonInteractionProps = {
|
||||
tenantId: undefined,
|
||||
userGlobalAccessPermission: undefined,
|
||||
userTenantAccessPermission: undefined,
|
||||
userId: undefined,
|
||||
userType: (req as OneUptimeRequest).userType,
|
||||
isMultiTenantRequest: undefined,
|
||||
};
|
||||
|
||||
if (
|
||||
(req as OneUptimeRequest).userAuthorization &&
|
||||
(req as OneUptimeRequest).userAuthorization?.userId
|
||||
) {
|
||||
props.userId = (req as OneUptimeRequest).userAuthorization!.userId;
|
||||
}
|
||||
|
||||
if ((req as OneUptimeRequest).userGlobalAccessPermission) {
|
||||
props.userGlobalAccessPermission = (
|
||||
req as OneUptimeRequest
|
||||
).userGlobalAccessPermission;
|
||||
}
|
||||
|
||||
if ((req as OneUptimeRequest).userTenantAccessPermission) {
|
||||
props.userTenantAccessPermission = (
|
||||
req as OneUptimeRequest
|
||||
).userTenantAccessPermission;
|
||||
}
|
||||
|
||||
if ((req as OneUptimeRequest).tenantId) {
|
||||
props.tenantId = (req as OneUptimeRequest).tenantId || undefined;
|
||||
}
|
||||
|
||||
if (req.headers['is-multi-tenant-query']) {
|
||||
props.isMultiTenantRequest = true;
|
||||
}
|
||||
|
||||
if (IsBillingEnabled && props.tenantId) {
|
||||
const plan: {
|
||||
plan: PlanSelect | null;
|
||||
isSubscriptionUnpaid: boolean;
|
||||
} = await ProjectService.getCurrentPlan(props.tenantId!);
|
||||
props.currentPlan = plan.plan || undefined;
|
||||
props.isSubscriptionUnpaid = plan.isSubscriptionUnpaid;
|
||||
}
|
||||
|
||||
// check for root permissions.
|
||||
|
||||
if (props.userType === UserType.MasterAdmin) {
|
||||
props.isMasterAdmin = true;
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import FileModel from 'Common/Models/FileModel';
|
||||
import Dictionary from 'Common/Types/Dictionary';
|
||||
import StatusCode from 'Common/Types/API/StatusCode';
|
||||
import { DEFAULT_LIMIT } from 'Common/Types/Database/LimitMax';
|
||||
import AnalyticsDataModel from 'Common/AnalyticsModels/BaseModel';
|
||||
|
||||
export default class Response {
|
||||
private static logResponse(
|
||||
@@ -174,7 +175,7 @@ export default class Response {
|
||||
public static sendEntityArrayResponse(
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
list: Array<BaseModel>,
|
||||
list: Array<BaseModel | AnalyticsDataModel>,
|
||||
count: PositiveNumber | number,
|
||||
modelType: { new (): BaseModel }
|
||||
): void {
|
||||
@@ -186,7 +187,7 @@ export default class Response {
|
||||
req,
|
||||
res,
|
||||
JSONFunctions.serializeArray(
|
||||
JSONFunctions.toJSONArray(list as Array<BaseModel>, modelType)
|
||||
JSONFunctions.toJSONArray(list as Array<BaseModel | AnalyticsDataModel>, modelType)
|
||||
),
|
||||
count
|
||||
);
|
||||
|
||||
31
CommonUI/src/Components/LogsViewer/LogItem.tsx
Normal file
31
CommonUI/src/Components/LogsViewer/LogItem.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import React, { FunctionComponent, ReactElement, useEffect } from 'react';
|
||||
import Log from 'Model/AnalyticsModels/Log';
|
||||
|
||||
export interface ComponentProps {
|
||||
log: Log
|
||||
}
|
||||
|
||||
const LogItem: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps
|
||||
): ReactElement => {
|
||||
|
||||
const [isCollapsed, setIsCollapsed] = React.useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
setIsCollapsed(true);
|
||||
}, [])
|
||||
|
||||
if(isCollapsed){
|
||||
return (<div className='color-gray-100 flex'>
|
||||
{/* Collapsable icon when clicked should expand */}
|
||||
</div>)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='color-gray-100'>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LogItem;
|
||||
17
CommonUI/src/Components/LogsViewer/LogsFilters.tsx
Normal file
17
CommonUI/src/Components/LogsViewer/LogsFilters.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import React, { FunctionComponent, ReactElement } from 'react';
|
||||
|
||||
export interface ComponentProps {
|
||||
|
||||
}
|
||||
|
||||
const LogsFilter: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps
|
||||
): ReactElement => {
|
||||
return (
|
||||
<div>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LogsFilter;
|
||||
21
CommonUI/src/Components/LogsViewer/LogsViewer.tsx
Normal file
21
CommonUI/src/Components/LogsViewer/LogsViewer.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import Log from 'Model/AnalyticsModels/Log';
|
||||
import React, { FunctionComponent, ReactElement } from 'react';
|
||||
import LogItem from './LogItem';
|
||||
|
||||
export interface ComponentProps {
|
||||
logs: Array<Log>
|
||||
}
|
||||
|
||||
const LogsViewer: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps
|
||||
): ReactElement => {
|
||||
return (
|
||||
<div className='shadow rounded bg-slate-600 p-2'>
|
||||
{props.logs.map((log: Log) => {
|
||||
return <LogItem log={log} />;
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LogsViewer;
|
||||
24
Dashboard/src/Components/LogsViewer/LogsViewer.tsx
Normal file
24
Dashboard/src/Components/LogsViewer/LogsViewer.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import React, { FunctionComponent, ReactElement } from 'react';
|
||||
|
||||
export interface ComponentProps {
|
||||
telemetryServiceIds: Array<ObjectID>;
|
||||
}
|
||||
|
||||
const LabelsElement: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps
|
||||
): ReactElement => {
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
{props.labels.map((label: Label, i: number) => {
|
||||
return <LabelElement label={label} key={i} />;
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LabelsElement;
|
||||
@@ -14,6 +14,7 @@ const ServiceDelete: FunctionComponent<PageComponentProps> = (
|
||||
): ReactElement => {
|
||||
const modelId: ObjectID = Navigation.getLastParamAsObjectID(1);
|
||||
|
||||
|
||||
return (
|
||||
<ModelPage
|
||||
title="Service"
|
||||
|
||||
@@ -4,6 +4,7 @@ import TableColumnType from 'Common/Types/AnalyticsDatabase/TableColumnType';
|
||||
import AnalyticsTableEngine from 'Common/Types/AnalyticsDatabase/AnalyticsTableEngine';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import KeyValueNestedModel from './NestedModels/KeyValueNestedModel';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
|
||||
export default class Log extends AnalyticsBaseModel {
|
||||
public constructor() {
|
||||
@@ -12,6 +13,7 @@ export default class Log extends AnalyticsBaseModel {
|
||||
tableEngine: AnalyticsTableEngine.MergeTree,
|
||||
singularName: 'Log',
|
||||
pluralName: 'Logs',
|
||||
crudApiPath: new Route('/logs'),
|
||||
tableColumns: [
|
||||
new AnalyticsTableColumn({
|
||||
key: 'projectId',
|
||||
|
||||
@@ -4,6 +4,7 @@ import TableColumnType from 'Common/Types/AnalyticsDatabase/TableColumnType';
|
||||
import AnalyticsTableEngine from 'Common/Types/AnalyticsDatabase/AnalyticsTableEngine';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import KeyValueNestedModel from './NestedModels/KeyValueNestedModel';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
|
||||
export default class Metric extends AnalyticsBaseModel {
|
||||
public constructor() {
|
||||
@@ -11,6 +12,7 @@ export default class Metric extends AnalyticsBaseModel {
|
||||
tableName: 'MetricGauge',
|
||||
tableEngine: AnalyticsTableEngine.MergeTree,
|
||||
singularName: 'Metric Gauge',
|
||||
crudApiPath: new Route('/metrics/gauge'),
|
||||
pluralName: 'Metrics Gauge',
|
||||
tableColumns: [
|
||||
new AnalyticsTableColumn({
|
||||
|
||||
@@ -4,6 +4,7 @@ import TableColumnType from 'Common/Types/AnalyticsDatabase/TableColumnType';
|
||||
import AnalyticsTableEngine from 'Common/Types/AnalyticsDatabase/AnalyticsTableEngine';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import KeyValueNestedModel from './NestedModels/KeyValueNestedModel';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
|
||||
export default class Metric extends AnalyticsBaseModel {
|
||||
public constructor() {
|
||||
@@ -12,6 +13,7 @@ export default class Metric extends AnalyticsBaseModel {
|
||||
tableEngine: AnalyticsTableEngine.MergeTree,
|
||||
singularName: 'Metric Histogram',
|
||||
pluralName: 'Metrics Histogram',
|
||||
crudApiPath: new Route('/metrics/histogram'),
|
||||
tableColumns: [
|
||||
new AnalyticsTableColumn({
|
||||
key: 'projectId',
|
||||
|
||||
@@ -4,6 +4,7 @@ import TableColumnType from 'Common/Types/AnalyticsDatabase/TableColumnType';
|
||||
import AnalyticsTableEngine from 'Common/Types/AnalyticsDatabase/AnalyticsTableEngine';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import KeyValueNestedModel from './NestedModels/KeyValueNestedModel';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
|
||||
export default class Metric extends AnalyticsBaseModel {
|
||||
public constructor() {
|
||||
@@ -11,6 +12,7 @@ export default class Metric extends AnalyticsBaseModel {
|
||||
tableName: 'MetricSum',
|
||||
tableEngine: AnalyticsTableEngine.MergeTree,
|
||||
singularName: 'Metric Sum',
|
||||
crudApiPath: new Route('/metrics/sum'),
|
||||
pluralName: 'Metrics Sum',
|
||||
tableColumns: [
|
||||
new AnalyticsTableColumn({
|
||||
|
||||
@@ -5,6 +5,7 @@ import AnalyticsTableEngine from 'Common/Types/AnalyticsDatabase/AnalyticsTableE
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import KeyValueNestedModel from './NestedModels/KeyValueNestedModel';
|
||||
import NestedModel from 'Common/AnalyticsModels/NestedModel';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
|
||||
export class SpanEvent extends NestedModel {
|
||||
public constructor() {
|
||||
@@ -113,6 +114,7 @@ export default class Span extends AnalyticsBaseModel {
|
||||
tableEngine: AnalyticsTableEngine.MergeTree,
|
||||
singularName: 'Span',
|
||||
pluralName: 'Spans',
|
||||
crudApiPath: new Route('/span'),
|
||||
tableColumns: [
|
||||
new AnalyticsTableColumn({
|
||||
key: 'projectId',
|
||||
|
||||
@@ -479,6 +479,21 @@ server {
|
||||
client_max_body_size 50M;
|
||||
}
|
||||
|
||||
location /analytics-api {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# enable WebSockets (for ws://sockjs not connected error in the accounts source: https://stackoverflow.com/questions/41381444/websocket-connection-failed-error-during-websocket-handshake-unexpected-respon)
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_pass http://dashboard-api;
|
||||
|
||||
client_max_body_size 50M;
|
||||
}
|
||||
|
||||
|
||||
location /heartbeat {
|
||||
proxy_set_header Host $host;
|
||||
|
||||
Reference in New Issue
Block a user