Refactor API endpoints to use sendEmptySuccessResponse instead of sendEmptyResponse

This commit is contained in:
Simon Larsen
2024-04-28 19:52:57 +01:00
parent 7414c6563d
commit 8377285a27
27 changed files with 251 additions and 81 deletions

View File

@@ -275,7 +275,7 @@ router.post(
logger.error(err);
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
return Response.sendErrorResponse(
@@ -390,7 +390,7 @@ router.post(
logger.error(err);
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
return next(err);
}
@@ -482,7 +482,7 @@ router.post(
logger.error(err);
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
return next(err);
}
@@ -499,7 +499,7 @@ router.post(
try {
CookieUtil.removeAllCookies(req, res);
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
return next(err);
}

View File

@@ -51,7 +51,7 @@ router.post(
CookieUtil.getUserTokenKey(statusPageId)
); // remove the cookie.
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
return next(err);
}
@@ -178,7 +178,7 @@ router.post(
logger.error(err);
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
throw new BadDataException(
@@ -320,7 +320,7 @@ router.post(
logger.error(err);
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
return next(err);
}

View File

@@ -32,7 +32,7 @@ router.post(
customTwilioConfig: body['customTwilioConfig'] as any,
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
);
@@ -137,7 +137,7 @@ router.post('/test', async (req: ExpressRequest, res: ExpressResponse) => {
);
}
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
});
export default router;

View File

@@ -44,7 +44,7 @@ router.post(
(body['userOnCallLogTimelineId'] as ObjectID) || undefined,
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
);

View File

@@ -35,7 +35,7 @@ router.post(
}
);
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
);
@@ -135,7 +135,7 @@ router.post('/test', async (req: ExpressRequest, res: ExpressResponse) => {
);
}
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
});
export default router;

View File

@@ -98,7 +98,7 @@ router.post('/test', async (req: ExpressRequest, res: ExpressResponse) => {
);
}
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
});
export default router;

View File

@@ -342,7 +342,7 @@ export default class BaseAPI<
props: await CommonAPI.getDatabaseCommonInteractionProps(req),
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
public async updateItem(
@@ -370,7 +370,7 @@ export default class BaseAPI<
props: await CommonAPI.getDatabaseCommonInteractionProps(req),
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
public async createItem(

View File

@@ -340,7 +340,7 @@ export default class BaseAnalyticsAPI<
props: await CommonAPI.getDatabaseCommonInteractionProps(req),
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
public async updateItem(
@@ -370,7 +370,7 @@ export default class BaseAnalyticsAPI<
props: await CommonAPI.getDatabaseCommonInteractionProps(req),
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
public async createItem(

View File

@@ -166,7 +166,7 @@ export default class UserAPI extends BaseAPI<
},
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
next(err);
}

View File

@@ -111,7 +111,7 @@ router.post(
return Response.sendErrorResponse(req, res, err as Exception);
}
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
);

View File

@@ -125,7 +125,7 @@ export default class StatusPageAPI extends BaseAPI<
);
}
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
);
@@ -1219,7 +1219,7 @@ export default class StatusPageAPI extends BaseAPI<
) => {
try {
await this.subscribeToStatusPage(req);
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
next(err);
}
@@ -1265,7 +1265,7 @@ export default class StatusPageAPI extends BaseAPI<
try {
await this.subscribeToStatusPage(req);
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
next(err);
}

View File

@@ -0,0 +1,205 @@
import StatusPageDomain from "Model/Models/StatusPageDomain";
import BaseAPI from "./BaseAPI";
import StatusPageDomainService, {
Service as StatusPageDomainServiceType,
} from '../Services/StatusPageDomainService';
import { ExpressRequest, ExpressResponse } from "../Utils/Express";
import BadDataException from "Common/Types/Exception/BadDataException";
import Response from "../Utils/Response";
import ObjectID from "Common/Types/ObjectID";
import UserMiddleware from "../Middleware/UserAuthorization";
import DatabaseCommonInteractionProps from "Common/Types/BaseDatabase/DatabaseCommonInteractionProps";
import CommonAPI from "./CommonAPI";
export default class StatusPageAPI extends BaseAPI<
StatusPageDomain,
StatusPageDomainServiceType
> {
public constructor() {
super(StatusPageDomain, StatusPageDomainService);
// CNAME verification api. THis API will be used from the dashboard to validate the CNAME MANUALLY.
this.router.get(
`${new this.entityType()
.getCrudApiPath()
?.toString()}/verify-cname/:id`,
UserMiddleware.getUserMiddleware,
async (req: ExpressRequest, res: ExpressResponse) => {
const databaseProps: DatabaseCommonInteractionProps =
await CommonAPI.getDatabaseCommonInteractionProps(req);
const id: ObjectID = new ObjectID(req.params['id'] as string);
const domain: StatusPageDomain | null =
await StatusPageDomainService.findOneBy({
query: {
id: id,
},
select: {
_id: true,
fullDomain: true,
cnameVerificationToken: true,
},
props: databaseProps,
});
if (!domain) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('Invalid token.')
);
}
if (!domain.cnameVerificationToken) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('Invalid token.')
);
}
if (!domain.fullDomain) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('Invalid domain.')
);
}
const isValid = await StatusPageDomainService.isCnameValid(domain.fullDomain!, domain.cnameVerificationToken!);
if (isValid) {
// mark as verified.
await StatusPageDomainService.updateOneById({
id: domain.id!,
data: {
isCnameVerified: true,
},
props: {
isRoot: true,
},
});
}
return Response.sendEmptySuccessResponse(req, res);
}
);
// Provision SSL API. THis API will be used from the dashboard to validate the CNAME MANUALLY.
this.router.get(
`${new this.entityType()
.getCrudApiPath()
?.toString()}/provision-ssl/:id`,
UserMiddleware.getUserMiddleware,
async (req: ExpressRequest, res: ExpressResponse) => {
const databaseProps: DatabaseCommonInteractionProps =
await CommonAPI.getDatabaseCommonInteractionProps(req);
const id: ObjectID = new ObjectID(req.params['id'] as string);
const domain: StatusPageDomain | null =
await StatusPageDomainService.findOneBy({
query: {
id: id,
},
select: {
_id: true,
fullDomain: true,
cnameVerificationToken: true,
isCnameVerified: true,
isSslProvisioned: true,
},
props: databaseProps,
});
if (!domain) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('Invalid token.')
);
}
if (!domain.cnameVerificationToken) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('Invalid token.')
);
}
if(!domain.isCnameVerified){
return Response.sendErrorResponse(
req,
res,
new BadDataException('CNAME is not verified. Please verify CNAME first before you provision SSL.')
);
}
if(domain.isSslProvisioned){
return Response.sendErrorResponse(
req,
res,
new BadDataException('SSL is already provisioned.')
);
}
if (!domain.fullDomain) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('Invalid domain.')
);
}
// check cname again, just to be sure.
const isCnameValid = await StatusPageDomainService.isCnameValid(domain.fullDomain!, domain.cnameVerificationToken!);
if(!isCnameValid){
await StatusPageDomainService.updateOneById({
id: domain.id!,
data: {
isCnameVerified: false,
},
props: {
isRoot: true,
},
});
return Response.sendErrorResponse(
req,
res,
new BadDataException('CNAME is not verified. Please verify CNAME first before you provision SSL.')
);
}
if (isCnameValid) {
// mark as verified.
await StatusPageDomainService.updateOneById({
id: domain.id!,
data: {
isCnameVerified: true,
},
props: {
isRoot: true,
},
});
}
return Response.sendEmptySuccessResponse(req, res);
}
);
}
}

View File

@@ -95,7 +95,7 @@ export default class UserCallAPI extends BaseAPI<
},
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
);
@@ -115,7 +115,7 @@ export default class UserCallAPI extends BaseAPI<
await this.service.resendVerificationCode(req.body.itemId);
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
);
}

View File

@@ -94,7 +94,7 @@ export default class UserEmailAPI extends BaseAPI<
},
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
);
@@ -116,7 +116,7 @@ export default class UserEmailAPI extends BaseAPI<
await this.service.resendVerificationCode(req.body.itemId);
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
);
}

View File

@@ -91,7 +91,7 @@ export default class UserSMSAPI extends BaseAPI<UserSMS, UserSMSServiceType> {
},
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
);
@@ -111,7 +111,7 @@ export default class UserSMSAPI extends BaseAPI<UserSMS, UserSMSServiceType> {
await this.service.resendVerificationCode(req.body.itemId);
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
}
);
}

View File

@@ -55,41 +55,6 @@ export class Service extends DatabaseService<StatusPageDomain> {
return { createBy, carryForward: null };
}
protected override async onBeforeUpdate(
updateBy: UpdateBy<StatusPageDomain>
): Promise<OnUpdate<StatusPageDomain>> {
if (updateBy.props.isRoot) {
return { updateBy, carryForward: null };
}
if (updateBy.data.isCnameVerified) {
// check if cname is valid.
const domain: Array<StatusPageDomain> = await this.findBy({
query: updateBy.query,
select: { fullDomain: true, cnameVerificationToken: true },
props: updateBy.props,
skip: 0,
limit: LIMIT_MAX,
});
for (const d of domain) {
const isValid: boolean = await this.isCnameValid(
d.fullDomain!,
d.cnameVerificationToken!
);
if (!isValid) {
throw new BadDataException(
`CNAME for this domain is not valid. Please add a CNAME record to ${d.fullDomain!}`
);
}
}
}
return { updateBy, carryForward: null };
}
protected override async onBeforeDelete(
deleteBy: DeleteBy<StatusPageDomain>
): Promise<OnDelete<StatusPageDomain>> {
@@ -365,7 +330,7 @@ export class Service extends DatabaseService<StatusPageDomain> {
}
}
private async isCnameValid(
public async isCnameValid(
fullDomain: string,
token: string
): Promise<boolean> {

View File

@@ -39,7 +39,7 @@ jest.mock('../../Utils/Response', () => {
sendJsonObjectResponse: jest.fn().mockImplementation((...args: []) => {
return args;
}),
sendEmptyResponse: jest.fn(),
sendEmptySuccessResponse: jest.fn(),
sendEntityResponse: jest.fn().mockImplementation((...args: []) => {
return args;
}),
@@ -642,7 +642,7 @@ describe('BaseAPI', () => {
await baseApiInstance.deleteItem(deleteRequest, res);
const sendEmptyResponseSpy: jest.SpyInstance = jest.spyOn(
Response as any,
'sendEmptyResponse'
'sendEmptySuccessResponse'
);
expect(sendEmptyResponseSpy).toHaveBeenCalledWith(
deleteRequest,
@@ -737,7 +737,7 @@ describe('BaseAPI', () => {
await baseApiInstance.updateItem(updateRequest, updateResponse);
const sendEmptyResponseSpy: jest.SpyInstance = jest.spyOn(
Response as any,
'sendEmptyResponse'
'sendEmptySuccessResponse'
);
expect(sendEmptyResponseSpy).toHaveBeenCalledWith(
updateRequest,

View File

@@ -27,7 +27,7 @@ jest.mock('../../Utils/Response', () => {
sendJsonObjectResponse: jest.fn().mockImplementation((...args: []) => {
return args;
}),
sendEmptyResponse: jest.fn(),
sendEmptySuccessResponse: jest.fn(),
sendEntityResponse: jest.fn().mockImplementation((...args: []) => {
return args;
}),

View File

@@ -31,7 +31,7 @@ jest.mock('../../Utils/Response', () => {
sendJsonObjectResponse: jest.fn().mockImplementation((...args: []) => {
return args;
}),
sendEmptyResponse: jest.fn(),
sendEmptySuccessResponse: jest.fn(),
sendEntityResponse: jest.fn().mockImplementation((...args: []) => {
return args;
}),

View File

@@ -28,7 +28,7 @@ jest.mock('../../Utils/Response', () => {
sendJsonObjectResponse: jest.fn().mockImplementation((...args: []) => {
return args;
}),
sendEmptyResponse: jest.fn(),
sendEmptySuccessResponse: jest.fn(),
sendEntityResponse: jest.fn().mockImplementation((...args: []) => {
return args;
}),
@@ -220,7 +220,7 @@ describe('UserSmsAPI', () => {
const response: jest.SpyInstance = jest.spyOn(
Response,
'sendEmptyResponse'
'sendEmptySuccessResponse'
);
expect(response).toHaveBeenCalledWith(mockRequest, mockResponse);
});
@@ -269,7 +269,7 @@ describe('UserSmsAPI', () => {
const response: jest.SpyInstance = jest.spyOn(
Response,
'sendEmptyResponse'
'sendEmptySuccessResponse'
);
expect(response).toHaveBeenCalledWith(mockRequest, mockResponse);
});

View File

@@ -22,7 +22,7 @@ import AnalyticsDataModel, {
} from 'Common/AnalyticsModels/BaseModel';
export default class Response {
public static sendEmptyResponse(
public static sendEmptySuccessResponse(
_req: ExpressRequest,
res: ExpressResponse
): void {

View File

@@ -20,7 +20,7 @@ router.post(
try {
// middleware marks the probe as alive.
// so we don't need to do anything here.
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
return next(err);
}

View File

@@ -79,7 +79,7 @@ router.post(
},
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
return next(err);
}

View File

@@ -68,7 +68,7 @@ const processIncomingRequest: RequestHandler = async (
// process probe response here.
await ProbeMonitorResponseService.processProbeResponse(incomingRequest);
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
return next(err);
}

View File

@@ -271,7 +271,7 @@ router.post(
},
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
return next(err);
}
@@ -523,7 +523,7 @@ router.post(
},
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
return next(err);
}
@@ -695,7 +695,7 @@ router.post(
},
});
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
return next(err);
}

View File

@@ -53,7 +53,7 @@ router.get(
throw new BadDataException('Monitor not found');
}
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
return next(err);
}

View File

@@ -65,7 +65,7 @@ router.post(
// middleware marks the probe as alive.
// so we don't need to do anything here.
return Response.sendEmptyResponse(req, res);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
return next(err);
}