docta-package 1.0.2 → 1.2.0
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/README.md +1 -0
- package/build/config.d.ts +14 -0
- package/build/config.js +15 -0
- package/build/dto/input/doctor.d.ts +28 -0
- package/build/dto/input/doctor.js +131 -0
- package/build/dto/input/education.d.ts +4 -0
- package/build/dto/input/education.js +26 -0
- package/build/dto/input/faq.d.ts +4 -0
- package/build/dto/input/faq.js +26 -0
- package/build/dto/input/index.js +25 -0
- package/build/dto/input/language.d.ts +5 -0
- package/build/dto/input/language.js +28 -0
- package/build/dto/input/location.d.ts +9 -0
- package/build/dto/input/location.js +51 -0
- package/build/dto/input/patient.d.ts +6 -0
- package/build/dto/input/patient.js +33 -0
- package/build/dto/input/position.d.ts +6 -0
- package/build/dto/input/position.js +37 -0
- package/build/dto/input/specialty.d.ts +12 -0
- package/build/dto/input/specialty.js +56 -0
- package/build/dto/input/user.d.ts +29 -0
- package/build/dto/input/user.js +112 -0
- package/build/dto/output/doctor.d.ts +38 -0
- package/build/dto/output/doctor.js +61 -0
- package/build/dto/output/education.d.ts +6 -0
- package/build/dto/output/education.js +10 -0
- package/build/dto/output/faq.d.ts +6 -0
- package/build/dto/output/faq.js +10 -0
- package/build/dto/output/index.js +25 -0
- package/build/dto/output/language.d.ts +6 -0
- package/build/dto/output/language.js +10 -0
- package/build/dto/output/location.d.ts +11 -0
- package/build/dto/output/location.js +16 -0
- package/build/dto/output/patient.d.ts +20 -0
- package/build/dto/output/patient.js +34 -0
- package/build/dto/output/position.d.ts +8 -0
- package/build/dto/output/position.js +13 -0
- package/build/dto/output/specialty.d.ts +23 -0
- package/build/dto/output/specialty.js +40 -0
- package/build/dto/output/user.d.ts +24 -0
- package/build/dto/output/user.js +36 -0
- package/build/enums/gender.d.ts +4 -0
- package/build/enums/gender.js +8 -0
- package/build/enums/index.js +20 -0
- package/build/enums/language-levels.d.ts +8 -0
- package/build/enums/language-levels.js +12 -0
- package/build/enums/status-codes.d.ts +24 -0
- package/build/enums/status-codes.js +28 -0
- package/build/enums/user-role.d.ts +5 -0
- package/build/enums/user-role.js +9 -0
- package/build/errors/BadRequestError.d.ts +8 -0
- package/build/errors/BadRequestError.js +15 -0
- package/build/errors/CustomError.d.ts +8 -0
- package/build/errors/CustomError.js +13 -0
- package/build/errors/NotFoundError.d.ts +8 -0
- package/build/errors/NotFoundError.js +15 -0
- package/build/errors/UnAuthorizedError.d.ts +8 -0
- package/build/errors/UnAuthorizedError.js +15 -0
- package/build/errors/index.js +20 -0
- package/{src/index.ts → build/index.d.ts} +4 -6
- package/build/index.js +25 -0
- package/build/interfaces/LoggedInUserToken.d.ts +6 -0
- package/build/interfaces/LoggedInUserToken.js +2 -0
- package/build/interfaces/index.js +17 -0
- package/build/middleware/errorHandler.d.ts +2 -0
- package/build/middleware/errorHandler.js +26 -0
- package/build/middleware/index.js +21 -0
- package/build/middleware/multer.d.ts +6 -0
- package/build/middleware/multer.js +58 -0
- package/build/middleware/require-auth.d.ts +2 -0
- package/build/middleware/require-auth.js +39 -0
- package/build/middleware/validate-request.d.ts +2 -0
- package/build/middleware/validate-request.js +41 -0
- package/build/middleware/verify-roles.d.ts +3 -0
- package/build/middleware/verify-roles.js +17 -0
- package/build/models/base.d.ts +13 -0
- package/build/models/base.js +41 -0
- package/build/models/doctor.d.ts +33 -0
- package/build/models/doctor.js +55 -0
- package/build/models/education.d.ts +14 -0
- package/build/models/education.js +8 -0
- package/build/models/faq.d.ts +14 -0
- package/build/models/faq.js +8 -0
- package/build/models/index.js +26 -0
- package/build/models/language.d.ts +15 -0
- package/build/models/language.js +14 -0
- package/build/models/location.d.ts +19 -0
- package/{src/models/location.ts → build/models/location.js} +6 -17
- package/build/models/patient.d.ts +15 -0
- package/build/models/patient.js +15 -0
- package/build/models/position.d.ts +16 -0
- package/build/models/position.js +10 -0
- package/build/models/specialty.d.ts +15 -0
- package/build/models/specialty.js +12 -0
- package/build/models/user.d.ts +19 -0
- package/build/models/user.js +47 -0
- package/build/utils/index.js +21 -0
- package/build/utils/orchestration-result.d.ts +38 -0
- package/build/utils/orchestration-result.js +26 -0
- package/build/utils/s3-helper.d.ts +13 -0
- package/build/utils/s3-helper.js +67 -0
- package/build/utils/token-utils.d.ts +11 -0
- package/build/utils/token-utils.js +77 -0
- package/build/utils/validate-info.d.ts +4 -0
- package/build/utils/validate-info.js +20 -0
- package/build/utils/winston.d.ts +3 -0
- package/build/utils/winston.js +32 -0
- package/package.json +9 -2
- package/src/config.ts +0 -25
- package/src/dto/input/doctor.ts +0 -120
- package/src/dto/input/education.ts +0 -11
- package/src/dto/input/faq.ts +0 -11
- package/src/dto/input/language.ts +0 -13
- package/src/dto/input/location.ts +0 -31
- package/src/dto/input/patient.ts +0 -17
- package/src/dto/input/position.ts +0 -21
- package/src/dto/input/specialty.ts +0 -40
- package/src/dto/input/user.ts +0 -87
- package/src/dto/output/doctor.ts +0 -90
- package/src/dto/output/education.ts +0 -11
- package/src/dto/output/faq.ts +0 -11
- package/src/dto/output/language.ts +0 -11
- package/src/dto/output/location.ts +0 -21
- package/src/dto/output/patient.ts +0 -49
- package/src/dto/output/position.ts +0 -15
- package/src/dto/output/specialty.ts +0 -53
- package/src/dto/output/user.ts +0 -57
- package/src/enums/gender.ts +0 -4
- package/src/enums/language-levels.ts +0 -9
- package/src/enums/status-codes.ts +0 -28
- package/src/enums/user-role.ts +0 -5
- package/src/errors/BadRequestError.ts +0 -18
- package/src/errors/CustomError.ts +0 -18
- package/src/errors/NotFoundError.ts +0 -18
- package/src/errors/UnAuthorizedError.ts +0 -18
- package/src/interfaces/LoggedInUserToken.ts +0 -9
- package/src/middleware/errorHandler.ts +0 -31
- package/src/middleware/multer.ts +0 -74
- package/src/middleware/require-auth.ts +0 -46
- package/src/middleware/validate-request.ts +0 -40
- package/src/middleware/verify-roles.ts +0 -17
- package/src/models/base.ts +0 -52
- package/src/models/doctor.ts +0 -96
- package/src/models/education.ts +0 -14
- package/src/models/faq.ts +0 -14
- package/src/models/language.ts +0 -20
- package/src/models/patient.ts +0 -35
- package/src/models/position.ts +0 -19
- package/src/models/specialty.ts +0 -37
- package/src/models/user.ts +0 -67
- package/src/utils/orchestration-result.ts +0 -74
- package/src/utils/s3-helper.ts +0 -72
- package/src/utils/token-utils.ts +0 -86
- package/src/utils/validate-info.ts +0 -26
- package/src/utils/winston.ts +0 -33
- package/tsconfig.json +0 -120
- /package/{src/dto/input/index.ts → build/dto/input/index.d.ts} +0 -0
- /package/{src/dto/output/index.ts → build/dto/output/index.d.ts} +0 -0
- /package/{src/enums/index.ts → build/enums/index.d.ts} +0 -0
- /package/{src/errors/index.ts → build/errors/index.d.ts} +0 -0
- /package/{src/interfaces/index.ts → build/interfaces/index.d.ts} +0 -0
- /package/{src/middleware/index.ts → build/middleware/index.d.ts} +0 -0
- /package/{src/models/index.ts → build/models/index.d.ts} +0 -0
- /package/{src/utils/index.ts → build/utils/index.d.ts} +0 -0
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
export enum EnumStatusCode {
|
|
2
|
-
BAD_REQUEST = "BAD_REQUEST",
|
|
3
|
-
SOMETHING_WENT_WRONG = "SOMETHING_WENT_WRONG",
|
|
4
|
-
UNAUTHORIZED = "UNAUTHORIZED",
|
|
5
|
-
VALIDATION_ERROR = "VALIDATION_ERROR",
|
|
6
|
-
EXISTS_ALREADY = "EXISTS_ALREADY",
|
|
7
|
-
CREATED_SUCCESSFULLY = "CREATED_SUCCESSFULLY",
|
|
8
|
-
UPDATED_SUCCESSFULLY = "UPDATED_SUCCESSFULLY",
|
|
9
|
-
NOT_FOUND = "NOT_FOUND",
|
|
10
|
-
SPECIALTY_NOT_FOUND = "SPECIALTY_NOT_FOUND",
|
|
11
|
-
NOT_ALLOWED = "NOT_ALLOWED",
|
|
12
|
-
DOCTOR_NOT_FOUND = "DOCTOR_NOT_FOUND",
|
|
13
|
-
ACCOUNT_DELETED = "ACCOUNT_DELETED",
|
|
14
|
-
ACCOUNT_DEACTIVATED = "ACCOUNT_DEACTIVATED",
|
|
15
|
-
TOKEN_REFRESHED = "TOKEN_REFRESHED",
|
|
16
|
-
|
|
17
|
-
NO_ACCESS_TOKEN = "NO_ACCESS_TOKEN",
|
|
18
|
-
ACCESS_TOKEN_EXPIRED = "ACCESS_TOKEN_EXPIRED",
|
|
19
|
-
CANNOT_DECODE_ACCESS_TOKEN = "CANNOT_DECODE_ACCESS_TOKEN",
|
|
20
|
-
|
|
21
|
-
RECOVERED_SUCCESSFULLY = "RECOVERED_SUCCESSFULLY",
|
|
22
|
-
|
|
23
|
-
FILE_TYPE_MISMATCH = "FILE_TYPE_MISMATCH",
|
|
24
|
-
FILE_TOO_LARGE = "FILE_TOO_LARGE",
|
|
25
|
-
NO_FILE_UPLOADED = "NO_FILE_UPLOADED",
|
|
26
|
-
|
|
27
|
-
DELETED_SUCCESSFULLY = "DELETED_SUCCESSFULLY",
|
|
28
|
-
}
|
package/src/enums/user-role.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { CustomError } from ".";
|
|
2
|
-
import { EnumStatusCode } from "../enums";
|
|
3
|
-
import { ErrorResult } from "../utils";
|
|
4
|
-
|
|
5
|
-
export class BadRequestError extends CustomError {
|
|
6
|
-
statusCode = 400;
|
|
7
|
-
|
|
8
|
-
constructor(
|
|
9
|
-
code: EnumStatusCode = EnumStatusCode.BAD_REQUEST,
|
|
10
|
-
message: string = "Bad Request"
|
|
11
|
-
) {
|
|
12
|
-
super(message, code, 400);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
serializeErrors(): ErrorResult {
|
|
16
|
-
return { code: this.code, message: this.message };
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { EnumStatusCode } from "../enums";
|
|
2
|
-
import { ErrorResult } from "../utils";
|
|
3
|
-
|
|
4
|
-
export abstract class CustomError extends Error {
|
|
5
|
-
public readonly code: EnumStatusCode;
|
|
6
|
-
public readonly statusCode: number;
|
|
7
|
-
|
|
8
|
-
constructor(message: string, code: EnumStatusCode, statusCode: number) {
|
|
9
|
-
super(message);
|
|
10
|
-
this.code = code;
|
|
11
|
-
this.statusCode = statusCode;
|
|
12
|
-
|
|
13
|
-
// Maintains proper prototype chain for built-in Error
|
|
14
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
abstract serializeErrors(): ErrorResult;
|
|
18
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { CustomError } from ".";
|
|
2
|
-
import { EnumStatusCode } from "../enums";
|
|
3
|
-
import { ErrorResult } from "../utils";
|
|
4
|
-
|
|
5
|
-
export class NotFoundError extends CustomError {
|
|
6
|
-
statusCode = 404;
|
|
7
|
-
|
|
8
|
-
constructor(
|
|
9
|
-
code: EnumStatusCode = EnumStatusCode.NOT_FOUND,
|
|
10
|
-
message: string = "Not Found"
|
|
11
|
-
) {
|
|
12
|
-
super(message, code, 404);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
serializeErrors(): ErrorResult {
|
|
16
|
-
return { code: this.code, message: this.message };
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { CustomError } from ".";
|
|
2
|
-
import { EnumStatusCode } from "../enums";
|
|
3
|
-
import { ErrorResult } from "../utils";
|
|
4
|
-
|
|
5
|
-
export class UnAuthorizedError extends CustomError {
|
|
6
|
-
statusCode = 401;
|
|
7
|
-
|
|
8
|
-
constructor(
|
|
9
|
-
code: EnumStatusCode = EnumStatusCode.UNAUTHORIZED,
|
|
10
|
-
message: string = "Unauthorized"
|
|
11
|
-
) {
|
|
12
|
-
super(message, code, 401);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
serializeErrors(): ErrorResult {
|
|
16
|
-
return { code: this.code, message: this.message };
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { NextFunction, Request, Response } from "express";
|
|
2
|
-
import { CustomError } from "../errors";
|
|
3
|
-
import { EnumStatusCode } from "../enums";
|
|
4
|
-
import { logger } from "../utils";
|
|
5
|
-
|
|
6
|
-
export const errorHandler = (
|
|
7
|
-
err: Error,
|
|
8
|
-
req: Request,
|
|
9
|
-
res: Response,
|
|
10
|
-
next: NextFunction
|
|
11
|
-
): void => {
|
|
12
|
-
if (err instanceof CustomError) {
|
|
13
|
-
res.status(err.statusCode).json(err.serializeErrors());
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Log the error with stack trace and request info
|
|
18
|
-
logger.error("Unhandled error", {
|
|
19
|
-
message: err.message,
|
|
20
|
-
stack: err.stack,
|
|
21
|
-
path: req.originalUrl,
|
|
22
|
-
method: req.method,
|
|
23
|
-
body: req.body,
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
console.error(err);
|
|
27
|
-
res.status(500).json({
|
|
28
|
-
code: EnumStatusCode.SOMETHING_WENT_WRONG,
|
|
29
|
-
message: "Internal Server Error",
|
|
30
|
-
});
|
|
31
|
-
};
|
package/src/middleware/multer.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import multer from "multer";
|
|
2
|
-
import { ErrorRequestHandler } from "express";
|
|
3
|
-
import { BadRequestError } from "../errors";
|
|
4
|
-
import { EnumStatusCode } from "../enums";
|
|
5
|
-
|
|
6
|
-
// 5 MB file size limit
|
|
7
|
-
const fileSize = 5 * 1024 * 1024;
|
|
8
|
-
|
|
9
|
-
// Use memory storage since files are likely forwarded to S3
|
|
10
|
-
const storage = multer.memoryStorage();
|
|
11
|
-
|
|
12
|
-
const allowedTypes = [
|
|
13
|
-
"image/jpeg",
|
|
14
|
-
"image/png",
|
|
15
|
-
"image/gif",
|
|
16
|
-
"image/bmp",
|
|
17
|
-
"image/webp",
|
|
18
|
-
"image/tiff",
|
|
19
|
-
"image/svg+xml",
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
// Base multer instance configured for images
|
|
23
|
-
export const imageUpload = multer({
|
|
24
|
-
storage,
|
|
25
|
-
limits: { fileSize },
|
|
26
|
-
fileFilter(req, file, cb) {
|
|
27
|
-
if (!allowedTypes.includes(file.mimetype)) {
|
|
28
|
-
return cb(
|
|
29
|
-
new BadRequestError(
|
|
30
|
-
EnumStatusCode.FILE_TYPE_MISMATCH,
|
|
31
|
-
"Only image files are allowed!"
|
|
32
|
-
)
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
cb(null, true);
|
|
36
|
-
},
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
// Error transformer to convert Multer errors into our CustomError format
|
|
40
|
-
export const transformMulterError: ErrorRequestHandler = (
|
|
41
|
-
err,
|
|
42
|
-
_req,
|
|
43
|
-
_res,
|
|
44
|
-
next
|
|
45
|
-
) => {
|
|
46
|
-
// Multer throws MulterError for limits and other internal validations
|
|
47
|
-
if (err && (err as any).name === "MulterError") {
|
|
48
|
-
const multerErr = err as multer.MulterError;
|
|
49
|
-
if (multerErr.code === "LIMIT_FILE_SIZE") {
|
|
50
|
-
return next(
|
|
51
|
-
new BadRequestError(
|
|
52
|
-
EnumStatusCode.FILE_TOO_LARGE,
|
|
53
|
-
`File too large. Max ${Math.floor(fileSize / (1024 * 1024))}MB`
|
|
54
|
-
)
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
return next(
|
|
58
|
-
new BadRequestError(EnumStatusCode.BAD_REQUEST, multerErr.message)
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
// If it's already a CustomError or another error, pass it along
|
|
62
|
-
return next(err);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
// Convenience helpers to use directly in routers
|
|
66
|
-
export const uploadSingleImage = (fieldName: string) => [
|
|
67
|
-
imageUpload.single(fieldName),
|
|
68
|
-
transformMulterError,
|
|
69
|
-
];
|
|
70
|
-
|
|
71
|
-
export const uploadArrayImages = (fieldName: string, maxCount: number) => [
|
|
72
|
-
imageUpload.array(fieldName, maxCount),
|
|
73
|
-
transformMulterError,
|
|
74
|
-
];
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from "express";
|
|
2
|
-
import { EnumStatusCode } from "../enums";
|
|
3
|
-
import { UnAuthorizedError } from "../errors";
|
|
4
|
-
import { TokenUtils } from "../utils";
|
|
5
|
-
|
|
6
|
-
export const requireAuth = async (
|
|
7
|
-
req: Request,
|
|
8
|
-
res: Response,
|
|
9
|
-
next: NextFunction
|
|
10
|
-
) => {
|
|
11
|
-
const accessToken = req.header("Authorization")?.replace("Bearer ", "");
|
|
12
|
-
|
|
13
|
-
if (!accessToken) {
|
|
14
|
-
throw new UnAuthorizedError(
|
|
15
|
-
EnumStatusCode.NO_ACCESS_TOKEN,
|
|
16
|
-
"No access token"
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
const decoded = TokenUtils.verifyAccessToken(accessToken);
|
|
22
|
-
|
|
23
|
-
if (!decoded) {
|
|
24
|
-
throw new UnAuthorizedError(
|
|
25
|
-
EnumStatusCode.CANNOT_DECODE_ACCESS_TOKEN,
|
|
26
|
-
"Cannot decode access token"
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
req.currentUser = decoded;
|
|
31
|
-
|
|
32
|
-
next();
|
|
33
|
-
} catch (error: any) {
|
|
34
|
-
if (error.name === "TokenExpiredError") {
|
|
35
|
-
throw new UnAuthorizedError(
|
|
36
|
-
EnumStatusCode.ACCESS_TOKEN_EXPIRED,
|
|
37
|
-
"Access token has expired."
|
|
38
|
-
);
|
|
39
|
-
} else {
|
|
40
|
-
throw new UnAuthorizedError(
|
|
41
|
-
EnumStatusCode.CANNOT_DECODE_ACCESS_TOKEN,
|
|
42
|
-
"Cannot decode access token"
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
};
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { plainToInstance } from "class-transformer";
|
|
2
|
-
import { validate, ValidationError } from "class-validator";
|
|
3
|
-
import { Request, Response, NextFunction, RequestHandler } from "express";
|
|
4
|
-
import { BadRequestError } from "../errors";
|
|
5
|
-
import { EnumStatusCode } from "../enums";
|
|
6
|
-
|
|
7
|
-
export const validationMiddleware = (
|
|
8
|
-
type: any,
|
|
9
|
-
skipMissingProperties = false,
|
|
10
|
-
whitelist = true,
|
|
11
|
-
forbidNonWhitelisted = true
|
|
12
|
-
): RequestHandler => {
|
|
13
|
-
return async (req: Request, res: Response, next: NextFunction) => {
|
|
14
|
-
try {
|
|
15
|
-
const object = plainToInstance(type, req.body);
|
|
16
|
-
const errors = await validate(object, {
|
|
17
|
-
skipMissingProperties,
|
|
18
|
-
whitelist,
|
|
19
|
-
forbidNonWhitelisted,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
if (errors.length > 0) {
|
|
23
|
-
const message = errors
|
|
24
|
-
.map((error: ValidationError) =>
|
|
25
|
-
Object.values(error.constraints ?? {})
|
|
26
|
-
)
|
|
27
|
-
.flat()
|
|
28
|
-
.join(", ");
|
|
29
|
-
return next(
|
|
30
|
-
new BadRequestError(EnumStatusCode.VALIDATION_ERROR, message)
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
req.body = object;
|
|
35
|
-
next();
|
|
36
|
-
} catch (err) {
|
|
37
|
-
next(err);
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from "express";
|
|
2
|
-
import { EnumUserRole } from "../enums/user-role";
|
|
3
|
-
import { UnAuthorizedError } from "../errors";
|
|
4
|
-
import { EnumStatusCode } from "../enums";
|
|
5
|
-
|
|
6
|
-
export const verifyRoles = (roles: EnumUserRole[]) => {
|
|
7
|
-
return (req: Request, res: Response, next: NextFunction) => {
|
|
8
|
-
if (roles.includes(req.currentUser?.role as EnumUserRole)) {
|
|
9
|
-
next();
|
|
10
|
-
} else {
|
|
11
|
-
throw new UnAuthorizedError(
|
|
12
|
-
EnumStatusCode.NOT_ALLOWED,
|
|
13
|
-
"You are not allowed to perform this action."
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
};
|
package/src/models/base.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { Schema, SchemaDefinition } from "mongoose";
|
|
2
|
-
import { IUserDocument } from ".";
|
|
3
|
-
|
|
4
|
-
export interface IBaseModel {
|
|
5
|
-
isDeleted: boolean;
|
|
6
|
-
createdAt: number;
|
|
7
|
-
updatedAt: number;
|
|
8
|
-
deletedAt?: number;
|
|
9
|
-
createdBy?: IUserDocument;
|
|
10
|
-
updatedBy?: IUserDocument;
|
|
11
|
-
deletedBy?: IUserDocument;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// Base Schema
|
|
15
|
-
export const BaseSchemaFields: SchemaDefinition = {
|
|
16
|
-
isDeleted: { type: Boolean, default: false },
|
|
17
|
-
createdAt: { type: Number, required: true, default: Date.now() },
|
|
18
|
-
updatedAt: { type: Number, required: true },
|
|
19
|
-
deletedAt: { type: Number, required: false },
|
|
20
|
-
createdBy: {
|
|
21
|
-
type: Schema.Types.ObjectId,
|
|
22
|
-
ref: "User",
|
|
23
|
-
required: false,
|
|
24
|
-
},
|
|
25
|
-
updatedBy: {
|
|
26
|
-
type: Schema.Types.ObjectId,
|
|
27
|
-
ref: "User",
|
|
28
|
-
required: false,
|
|
29
|
-
},
|
|
30
|
-
deletedBy: {
|
|
31
|
-
type: Schema.Types.ObjectId,
|
|
32
|
-
ref: "User",
|
|
33
|
-
required: false,
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export function BaseSchemaPlugin(schema: Schema) {
|
|
38
|
-
schema.add({
|
|
39
|
-
isDeleted: { type: Boolean, default: false },
|
|
40
|
-
createdAt: { type: Number, default: () => Date.now() },
|
|
41
|
-
updatedAt: { type: Number, default: () => Date.now() },
|
|
42
|
-
deletedAt: { type: Number },
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
schema.pre("save", function () {
|
|
46
|
-
this.updatedAt = Date.now();
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
schema.pre("findOneAndUpdate", function () {
|
|
50
|
-
this.set({ updatedAt: Date.now() });
|
|
51
|
-
});
|
|
52
|
-
}
|
package/src/models/doctor.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { Schema, model, Document, Model } from "mongoose";
|
|
2
|
-
import { ISpecialtyDocument, SpecialtyModel } from ".";
|
|
3
|
-
import { IUserDocument, UserModel } from ".";
|
|
4
|
-
import { BaseSchemaFields, BaseSchemaPlugin, IBaseModel } from ".";
|
|
5
|
-
import { EducationSchema, IEducation } from ".";
|
|
6
|
-
import { PositionSchema, IPosition } from ".";
|
|
7
|
-
import { LanguageSchema, ILanguage } from ".";
|
|
8
|
-
import { FaqSchema, IFaq } from ".";
|
|
9
|
-
import { LocationSchema, ILocation } from ".";
|
|
10
|
-
|
|
11
|
-
export interface IDoctor extends IBaseModel {
|
|
12
|
-
name: string;
|
|
13
|
-
slug: string;
|
|
14
|
-
isActive: boolean;
|
|
15
|
-
user: IUserDocument;
|
|
16
|
-
specialty: ISpecialtyDocument;
|
|
17
|
-
biography: string;
|
|
18
|
-
consultationFee: number;
|
|
19
|
-
isVerified: boolean;
|
|
20
|
-
isVisible: boolean;
|
|
21
|
-
isDeactivatedByAdmin: boolean;
|
|
22
|
-
photo?: string;
|
|
23
|
-
educations: IEducation[];
|
|
24
|
-
positions: IPosition[];
|
|
25
|
-
languages: ILanguage[];
|
|
26
|
-
faqs: IFaq[];
|
|
27
|
-
expertises: string[];
|
|
28
|
-
location?: ILocation;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface IDoctorDocument extends IDoctor, Document {}
|
|
32
|
-
|
|
33
|
-
export interface IDoctorModel extends Model<IDoctorDocument> {}
|
|
34
|
-
|
|
35
|
-
const DoctorSchema = new Schema<IDoctorDocument>({
|
|
36
|
-
...BaseSchemaFields,
|
|
37
|
-
user: {
|
|
38
|
-
type: Schema.Types.ObjectId,
|
|
39
|
-
ref: UserModel,
|
|
40
|
-
required: true,
|
|
41
|
-
onDelete: "cascade",
|
|
42
|
-
},
|
|
43
|
-
specialty: {
|
|
44
|
-
type: Schema.Types.ObjectId,
|
|
45
|
-
ref: SpecialtyModel,
|
|
46
|
-
required: true,
|
|
47
|
-
},
|
|
48
|
-
name: { type: String, required: true, trim: true },
|
|
49
|
-
biography: { type: String, required: false },
|
|
50
|
-
slug: { type: String, required: true, unique: true, trim: true },
|
|
51
|
-
isActive: { type: Boolean, default: false },
|
|
52
|
-
consultationFee: { type: Number, required: false },
|
|
53
|
-
isVerified: { type: Boolean, default: false },
|
|
54
|
-
isVisible: { type: Boolean, default: true },
|
|
55
|
-
isDeactivatedByAdmin: { type: Boolean, default: false },
|
|
56
|
-
photo: { type: String, required: false },
|
|
57
|
-
educations: { type: [EducationSchema], required: true, default: [] },
|
|
58
|
-
positions: { type: [PositionSchema], required: true, default: [] },
|
|
59
|
-
languages: { type: [LanguageSchema], required: true, default: [] },
|
|
60
|
-
faqs: { type: [FaqSchema], required: true, default: [] },
|
|
61
|
-
expertises: { type: [String], required: true, default: [] },
|
|
62
|
-
location: { type: LocationSchema, required: false },
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const createSlug = (text: string): string =>
|
|
66
|
-
text
|
|
67
|
-
.toLowerCase()
|
|
68
|
-
.trim()
|
|
69
|
-
.replace(/[\s\W-]+/g, "-")
|
|
70
|
-
.replace(/^-+|-+$/g, "");
|
|
71
|
-
|
|
72
|
-
DoctorSchema.pre<IDoctorDocument>("validate", async function (next) {
|
|
73
|
-
// Only set slug if it hasn't been set before
|
|
74
|
-
if (this.slug) return next();
|
|
75
|
-
|
|
76
|
-
const baseSlug = createSlug(this.name);
|
|
77
|
-
let slug = baseSlug;
|
|
78
|
-
let counter = 0;
|
|
79
|
-
|
|
80
|
-
const Doctor = this.constructor as IDoctorModel;
|
|
81
|
-
|
|
82
|
-
while (await Doctor.exists({ slug })) {
|
|
83
|
-
counter += 1;
|
|
84
|
-
slug = `${baseSlug}-${counter}`;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
this.slug = slug;
|
|
88
|
-
next();
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
DoctorSchema.plugin(BaseSchemaPlugin);
|
|
92
|
-
|
|
93
|
-
export const DoctorModel = model<IDoctorDocument, IDoctorModel>(
|
|
94
|
-
"Doctor",
|
|
95
|
-
DoctorSchema
|
|
96
|
-
);
|
package/src/models/education.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Schema } from "mongoose";
|
|
2
|
-
|
|
3
|
-
export interface IEducation {
|
|
4
|
-
year: number;
|
|
5
|
-
title: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export const EducationSchema = new Schema<IEducation>(
|
|
9
|
-
{
|
|
10
|
-
year: { type: Number, required: true },
|
|
11
|
-
title: { type: String, required: true, trim: true },
|
|
12
|
-
},
|
|
13
|
-
{ _id: false }
|
|
14
|
-
);
|
package/src/models/faq.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Schema } from "mongoose";
|
|
2
|
-
|
|
3
|
-
export interface IFaq {
|
|
4
|
-
title: string;
|
|
5
|
-
description: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export const FaqSchema = new Schema<IFaq>(
|
|
9
|
-
{
|
|
10
|
-
title: { type: String, required: true, trim: true },
|
|
11
|
-
description: { type: String, required: true, trim: true },
|
|
12
|
-
},
|
|
13
|
-
{ _id: false }
|
|
14
|
-
);
|
package/src/models/language.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Schema } from "mongoose";
|
|
2
|
-
import { EnumLanguageLevel } from "../enums";
|
|
3
|
-
|
|
4
|
-
export interface ILanguage {
|
|
5
|
-
title: string;
|
|
6
|
-
level: EnumLanguageLevel;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const LanguageSchema = new Schema<ILanguage>(
|
|
10
|
-
{
|
|
11
|
-
title: { type: String, required: true, trim: true },
|
|
12
|
-
level: {
|
|
13
|
-
type: String,
|
|
14
|
-
enum: Object.values(EnumLanguageLevel),
|
|
15
|
-
required: true,
|
|
16
|
-
trim: true,
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
{ _id: false }
|
|
20
|
-
);
|
package/src/models/patient.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { Schema, model, Document, Model } from "mongoose";
|
|
2
|
-
import { IUserDocument, UserModel } from ".";
|
|
3
|
-
import { BaseSchemaFields, BaseSchemaPlugin, IBaseModel } from ".";
|
|
4
|
-
import { Gender } from "../enums";
|
|
5
|
-
|
|
6
|
-
export interface IPatient extends IBaseModel {
|
|
7
|
-
user: IUserDocument;
|
|
8
|
-
dob?: number;
|
|
9
|
-
gender?: Gender;
|
|
10
|
-
phoneNumber?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface IPatientDocument extends IPatient, Document {}
|
|
14
|
-
|
|
15
|
-
export interface IPatientModel extends Model<IPatientDocument> {}
|
|
16
|
-
|
|
17
|
-
const PatientSchema = new Schema<IPatientDocument>({
|
|
18
|
-
...BaseSchemaFields,
|
|
19
|
-
user: {
|
|
20
|
-
type: Schema.Types.ObjectId,
|
|
21
|
-
ref: UserModel.modelName,
|
|
22
|
-
required: true,
|
|
23
|
-
onDelete: "cascade",
|
|
24
|
-
},
|
|
25
|
-
dob: { type: Number, required: false },
|
|
26
|
-
phoneNumber: { type: String, required: false },
|
|
27
|
-
gender: { type: String, enum: Object.values(Gender), required: false },
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
PatientSchema.plugin(BaseSchemaPlugin);
|
|
31
|
-
|
|
32
|
-
export const PatientModel = model<IPatientDocument, IPatientModel>(
|
|
33
|
-
"Patient",
|
|
34
|
-
PatientSchema
|
|
35
|
-
);
|
package/src/models/position.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Schema } from "mongoose";
|
|
2
|
-
|
|
3
|
-
export interface IPosition {
|
|
4
|
-
startDate: number; // timestamp (ms)
|
|
5
|
-
endDate?: number; // timestamp (ms), optional
|
|
6
|
-
title: string;
|
|
7
|
-
company: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const PositionSchema = new Schema<IPosition>(
|
|
11
|
-
{
|
|
12
|
-
startDate: { type: Number, required: true },
|
|
13
|
-
endDate: { type: Number, required: false },
|
|
14
|
-
title: { type: String, required: true, trim: true },
|
|
15
|
-
company: { type: String, required: true, trim: true },
|
|
16
|
-
},
|
|
17
|
-
{ _id: false }
|
|
18
|
-
);
|
|
19
|
-
|
package/src/models/specialty.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { Schema, model, Document, Model } from "mongoose";
|
|
2
|
-
import { BaseSchemaFields, BaseSchemaPlugin, IBaseModel } from ".";
|
|
3
|
-
|
|
4
|
-
export interface ILocalizedSpecialtyFields {
|
|
5
|
-
name: string;
|
|
6
|
-
description?: string | null;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface ISpecialty extends IBaseModel {
|
|
10
|
-
en: ILocalizedSpecialtyFields;
|
|
11
|
-
fr?: ILocalizedSpecialtyFields;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface ISpecialtyDocument extends ISpecialty, Document {}
|
|
15
|
-
|
|
16
|
-
export interface ISpecialtyModel extends Model<ISpecialtyDocument> {}
|
|
17
|
-
|
|
18
|
-
const LocalizedFieldsSchema = new Schema<ILocalizedSpecialtyFields>(
|
|
19
|
-
{
|
|
20
|
-
name: { type: String, required: true },
|
|
21
|
-
description: { type: String, default: null },
|
|
22
|
-
},
|
|
23
|
-
{ _id: false }
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
const SpecialtySchema = new Schema<ISpecialtyDocument>({
|
|
27
|
-
...BaseSchemaFields,
|
|
28
|
-
en: { type: LocalizedFieldsSchema, required: true },
|
|
29
|
-
fr: { type: LocalizedFieldsSchema, required: false, default: null },
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
SpecialtySchema.plugin(BaseSchemaPlugin);
|
|
33
|
-
|
|
34
|
-
export const SpecialtyModel = model<ISpecialtyDocument, ISpecialtyModel>(
|
|
35
|
-
"Specialty",
|
|
36
|
-
SpecialtySchema
|
|
37
|
-
);
|