webstudio/server/src/core/controllers/http_controller.ts
IDONTSUDO 6840402b1f deleted unnecessary files
added new features
2024-04-09 16:31:25 +03:00

215 lines
7 KiB
TypeScript

import { validationModelMiddleware } from "../middlewares/validation_model";
import { Result } from "../helpers/result";
import { Router, Request, Response } from "express";
import { IRouteModel, Routes } from "../interfaces/router";
import { CoreValidation } from "../validations/core_validation";
export type HttpMethodType = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "PATCH" | "HEAD";
export type ResponseBase = Promise<Result<any, any>>;
export abstract class CallbackStrategyWithEmpty {
abstract call(): ResponseBase;
}
export abstract class CallbackStrategyWithValidationModel<V> {
abstract validationModel: V;
abstract call(model: V): ResponseBase;
}
export abstract class CallbackStrategyWithIdQuery {
abstract idValidationExpression: CoreValidation;
abstract call(id: string): ResponseBase;
}
export abstract class CallBackStrategyWithQueryPage {
abstract validationPageExpression: RegExp | null;
abstract call(page: string): ResponseBase;
}
export abstract class CallbackStrategyWithFileUpload {
abstract checkingFileExpression: RegExp;
abstract idValidationExpression: CoreValidation;
abstract call(file: File, id: string): ResponseBase;
}
interface ISubSetFeatureRouter<T> {
method: HttpMethodType;
subUrl: string;
fn:
| CallbackStrategyWithValidationModel<T>
| CallbackStrategyWithEmpty
| CallbackStrategyWithIdQuery
| CallBackStrategyWithQueryPage
| CallbackStrategyWithFileUpload;
}
abstract class ICoreHttpController {
abstract mainURL: string;
public router = Router();
abstract call(): Routes;
}
export class CoreHttpController<V> implements ICoreHttpController {
mainURL: string;
validationModel: any;
subRoutes: ISubSetFeatureRouter<V>[] = [];
routes = {
POST: null,
GET: null,
DELETE: null,
PUT: null,
};
public router = Router();
constructor(routerModel: IRouteModel) {
this.mainURL = "/" + routerModel.url;
this.validationModel = routerModel.validationModel;
}
async responseHelper(res: Response, fn: ResponseBase) {
(await fn).fold(
(ok) => {
res.json(ok);
return;
},
(err) => {
res.status(400).json({ error: String(err) });
return;
}
);
}
call(): Routes {
if (this.subRoutes.isNotEmpty()) {
this.subRoutes.map((el) => {
this.router[el.method.toLowerCase()](this.mainURL + "/" + el.subUrl, async (req, res) => {
if (el.fn instanceof CallbackStrategyWithValidationModel) {
// TODO(IDONTSUDO):
throw Error("needs to be implimed");
}
if (el.fn instanceof CallbackStrategyWithIdQuery) {
if (req.query.id === undefined) {
res.status(400).json("request query id is null, need query id ?id={id:String}");
return;
}
if (el.fn.idValidationExpression !== undefined) {
if (!el.fn.idValidationExpression.regExp.test(req.query.id)) {
res
.status(400)
.json(
`request query id must fall under the pattern: ${el.fn.idValidationExpression.regExp} message: ${el.fn.idValidationExpression.message} `
);
return;
} else {
await this.responseHelper(res, el.fn.call(req.query.id));
}
} else {
await this.responseHelper(res, el.fn.call(req["files"]["file"]));
}
}
if (el.fn instanceof CallBackStrategyWithQueryPage) {
throw Error("needs to be implimed");
}
if (el.fn instanceof CallbackStrategyWithEmpty) {
await this.responseHelper(res, el.fn.call());
return;
}
if (el.fn instanceof CallbackStrategyWithFileUpload) {
if (req["files"] === undefined) {
res.status(400).json("need files to form-data request");
return;
}
if (req["files"]["file"] === undefined) {
res.status(400).json("need file to form data request");
return;
}
// if (req.query.description === undefined) {
// res
// .status(400)
// .json("request query description is null, need query description &description={description:String}");
// return;
// }
if (req.query.id === undefined) {
res.status(400).json("request query id is null, need query id ?id={id:String}");
return;
}
if (!el.fn.idValidationExpression.regExp.test(req.query.id)) {
res.status(400).json(el.fn.idValidationExpression.message);
return;
}
if (el.fn instanceof CallbackStrategyWithFileUpload) {
if (!el.fn.checkingFileExpression.test(req["files"]["file"]["name"])) {
res.status(400).json("a file with this extension is expected: " + String(el.fn.checkingFileExpression));
return;
}
}
await this.responseHelper(res, el.fn.call(req["files"]["file"], req.query.id));
}
});
});
}
if (this.routes["POST"] != null) {
this.router.post(this.mainURL, validationModelMiddleware(this.validationModel), (req, res) =>
this.requestResponseController<V>(req, res, this.routes["POST"])
);
}
if (this.routes["DELETE"] != null) {
this.router.delete(this.mainURL, (req, res) =>
this.requestResponseController<V>(req, res, this.routes["DELETE"])
);
}
if (this.routes["PUT"] != null) {
this.router.put(this.mainURL, validationModelMiddleware(this.validationModel), (req, res) =>
this.requestResponseController<V>(req, res, this.routes["PUT"])
);
}
if (this.routes["GET"] != null) {
this.router.get(this.mainURL, (req, res) => this.requestResponseController<V>(req, res, this.routes["GET"]));
}
return {
router: this.router,
};
}
public put(usecase: CallbackStrategyWithValidationModel<V>) {
this.routes["PUT"] = usecase;
}
public delete(usecase: CallbackStrategyWithValidationModel<V>) {
this.routes["DELETE"] = usecase;
}
public async requestResponseController<T>(
req: Request,
res: Response,
usecase: CallbackStrategyWithValidationModel<T>
) {
let payload = null;
const useCase = usecase as any;
if (req["model"] != undefined) {
payload = req.body as T;
}
if (req.query.page !== undefined) {
payload = String(req.query.page);
}
if (req.query.id !== undefined) {
payload = String(req.query.id);
}
(await useCase(payload)).fold(
(ok) => {
return res.json(ok);
},
(err) => {
return res.status(400).json({ error: String(err) });
}
);
}
// TODO(IDONTSUDO):need fix to CallbackStrategyWithValidationModel<V>
public post(usecase: any) {
this.routes["POST"] = usecase;
}
public get(usecase: any) {
this.routes["GET"] = usecase;
}
}