Compare commits
60 Commits
3232e5fac1
...
deadline
| Author | SHA1 | Date | |
|---|---|---|---|
|
7fead5486b
|
|||
|
5cc214a29b
|
|||
|
65a6ae2e3c
|
|||
|
83d07a2812
|
|||
|
e8acfd7b30
|
|||
|
438ae4b5d0
|
|||
|
6ccc899320
|
|||
|
5afb6e22bf
|
|||
|
bdba2f6e29
|
|||
|
30c6f2e3f1
|
|||
|
b47ec6c440
|
|||
|
b4f200cb32
|
|||
|
ec53fcb247
|
|||
|
371d960cf3
|
|||
|
3525fb12e6
|
|||
|
82afff9878
|
|||
|
fef2bda082
|
|||
|
f87aecaf75
|
|||
|
170b9a5693
|
|||
|
c9ca39ddfa
|
|||
|
da028ea2c4
|
|||
|
1c643b3625
|
|||
|
33d6793758
|
|||
|
c95ac03680
|
|||
|
03fc5307e6
|
|||
|
b6a2a74ba0
|
|||
|
f310bedeff
|
|||
|
838ea4ad22
|
|||
|
00064fd054
|
|||
|
70a6e5df54
|
|||
|
7f52a9d75e
|
|||
|
62742e6afe
|
|||
|
bdfc598218
|
|||
|
1cbc771251
|
|||
|
8644b5add6
|
|||
|
b66a5aff6d
|
|||
|
3d3da77df0
|
|||
|
abaeafea8a
|
|||
|
cb41c68f77
|
|||
|
e98729c9e5
|
|||
|
cd09a0c61b
|
|||
|
1723a8588a
|
|||
|
3fe6453b0c
|
|||
|
98477c5f27
|
|||
|
3472c59ac2
|
|||
|
3b6726113d
|
|||
|
d78b0aec4c
|
|||
|
ae6b25fbd6
|
|||
|
d7f9cb0b37
|
|||
|
cb1c2ee87c
|
|||
|
23ce32cb6f
|
|||
|
f6d18fc58d
|
|||
|
5163d79056
|
|||
|
ea3b7aa68b
|
|||
|
bc12f94e41
|
|||
|
df28d3aa52
|
|||
|
3d5ea6ac30
|
|||
|
2fb6cd6e83
|
|||
|
34f028ef9f
|
|||
|
0635c512cc
|
@@ -1036,7 +1036,7 @@ brief\\_05|schema||user_brief05||UPDATE|G</Grants>
|
||||
</schema>
|
||||
<schema id="325" parent="1" name="brief_05">
|
||||
<Current>1</Current>
|
||||
<LastIntrospectionLocalTimestamp>2024-04-29.12:54:42</LastIntrospectionLocalTimestamp>
|
||||
<LastIntrospectionLocalTimestamp>2024-05-03.07:39:06</LastIntrospectionLocalTimestamp>
|
||||
<CollationName>latin1_swedish_ci</CollationName>
|
||||
</schema>
|
||||
<user id="326" parent="1" name="user_brief05"/>
|
||||
@@ -1063,7 +1063,7 @@ brief\\_05|schema||user_brief05||UPDATE|G</Grants>
|
||||
<Engine>InnoDB</Engine>
|
||||
<CollationName>latin1_swedish_ci</CollationName>
|
||||
</table>
|
||||
<table id="332" parent="325" name="rent">
|
||||
<table id="332" parent="325" name="rents">
|
||||
<Engine>InnoDB</Engine>
|
||||
<CollationName>latin1_swedish_ci</CollationName>
|
||||
</table>
|
||||
@@ -1270,7 +1270,7 @@ brief\\_05|schema||user_brief05||UPDATE|G</Grants>
|
||||
<Position>7</Position>
|
||||
</column>
|
||||
<column id="376" parent="332" name="id">
|
||||
<DasType>tinyint(1)|0s</DasType>
|
||||
<DasType>varchar(36)|0s</DasType>
|
||||
<NotNull>1</NotNull>
|
||||
<Position>8</Position>
|
||||
</column>
|
||||
|
||||
2
.idea/inspectionProfiles/Project_Default.xml
generated
2
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -3,7 +3,7 @@
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<Languages>
|
||||
<language minSize="114" name="TypeScript" />
|
||||
<language minSize="174" name="TypeScript" />
|
||||
</Languages>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
|
||||
10
db.sql
10
db.sql
@@ -74,13 +74,13 @@ CREATE TABLE `models` (
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `rent`
|
||||
-- Table structure for table `rents`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `rent`;
|
||||
DROP TABLE IF EXISTS `rents`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `rent` (
|
||||
CREATE TABLE `rents` (
|
||||
`vehicle_id` varchar(36) NOT NULL,
|
||||
`user_id` varchar(36) NOT NULL,
|
||||
`active` tinyint(1) NOT NULL,
|
||||
@@ -88,7 +88,7 @@ CREATE TABLE `rent` (
|
||||
`eat` date NOT NULL,
|
||||
`need_survey` tinyint(1) DEFAULT NULL,
|
||||
`km_at_start` int(11) DEFAULT NULL,
|
||||
`id` tinyint(1) NOT NULL,
|
||||
`id` varchar(36) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `rent_vehicles_id_fk` (`vehicle_id`),
|
||||
KEY `rent_users_id_fk` (`user_id`),
|
||||
@@ -152,4 +152,4 @@ CREATE TABLE `vehicles` (
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2024-04-29 14:54:00
|
||||
-- Dump completed on 2024-05-03 14:56:07
|
||||
|
||||
BIN
schema-db.png
BIN
schema-db.png
Binary file not shown.
|
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 198 KiB |
@@ -51,7 +51,13 @@ try {
|
||||
|
||||
try {
|
||||
app.listen(process.env["APP_PORT"]);
|
||||
logger.info("Server is running !");
|
||||
logger.info(
|
||||
`Server is running !\n >> Memory total: ${Math.round(
|
||||
process.memoryUsage().rss / 1_000_000,
|
||||
)} Mio\n >> Memory heap: ${Math.round(
|
||||
process.memoryUsage().heapUsed / 1_000_000,
|
||||
)} Mio\n`,
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error(`Server failed to start: ${error}`);
|
||||
process.exit(1);
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import JwtService from "@services/jwt.service";
|
||||
|
||||
import type { IReqEditUserData } from "@interfaces/IReqEditUserData";
|
||||
import { HttpStatusCode } from "@interfaces/requests/HttpStatusCode";
|
||||
import type { IReqRegister } from "@interfaces/requests/IReqRegister";
|
||||
import UserService from "@services/user.service";
|
||||
import { isDebugMode } from "@utils/debugState";
|
||||
import { isEmail } from "@utils/validators/email";
|
||||
import type { Request, Response } from "express";
|
||||
import { Logger } from "tslog";
|
||||
|
||||
@@ -9,24 +13,19 @@ const logger = new Logger({
|
||||
name: "AuthController",
|
||||
});
|
||||
|
||||
//FIX Better return object interface
|
||||
/**
|
||||
* Registers a user with the given request data.
|
||||
* Registers a user.
|
||||
*
|
||||
* @param {Request} req - The request object containing user data.
|
||||
* @param {Response} res - The response object to send the registration result.
|
||||
* @param {Request} req - The request object.
|
||||
* @param {Response} res - The response object.
|
||||
*
|
||||
* @return {Promise} A promise that resolves to the registration result.
|
||||
* It can have the following properties:
|
||||
* - error: "gdprNotApproved" if GDPR is not approved
|
||||
* - error: "exist" if the user already exists
|
||||
* - Otherwise, the registered user data
|
||||
* @return {Promise} - A promise that resolves with the registration result or rejects with an error.
|
||||
*/
|
||||
async function registerUser(req: Request, res: Response): Promise<unknown> {
|
||||
const body = req.body;
|
||||
async function registerUser(req: Request, res: Response): Promise<Response> {
|
||||
const body: IReqRegister = req.body;
|
||||
if (!body) {
|
||||
logger.warn(`Invalid input data (${req.ip})`);
|
||||
return res.type("application/json").status(400).json({
|
||||
return res.type("application/json").status(HttpStatusCode.BadRequest).json({
|
||||
error: "Invalid input data",
|
||||
});
|
||||
}
|
||||
@@ -35,21 +34,28 @@ async function registerUser(req: Request, res: Response): Promise<unknown> {
|
||||
!body.username ||
|
||||
!body.firstName ||
|
||||
!body.lastName ||
|
||||
!body.displayName
|
||||
!body.email
|
||||
) {
|
||||
logger.warn(`Field(s) missing (${req.ip})`);
|
||||
return res.type("application/json").status(400).json({
|
||||
return res.type("application/json").status(HttpStatusCode.BadRequest).json({
|
||||
error: "Field(s) missing",
|
||||
});
|
||||
}
|
||||
|
||||
if (!isEmail(body.email)) {
|
||||
logger.warn(`Invalid email format (${req.ip})`);
|
||||
return res.type("application/json").status(HttpStatusCode.BadRequest).json({
|
||||
error: "Invalid email format",
|
||||
});
|
||||
}
|
||||
|
||||
let gdpr = false;
|
||||
if (body.gdpr === true) {
|
||||
gdpr = true;
|
||||
}
|
||||
const sanitizeData = {
|
||||
const sanitizeData: IReqRegister = {
|
||||
username: `${body.username}`,
|
||||
displayName: `${body.displayName}`,
|
||||
email: `${body.email.toLowerCase()}`,
|
||||
gdpr: gdpr,
|
||||
password: `${body.password}`,
|
||||
firstName: `${body.firstName}`,
|
||||
@@ -58,24 +64,33 @@ async function registerUser(req: Request, res: Response): Promise<unknown> {
|
||||
|
||||
const RegisterServiceResult = await UserService.register(sanitizeData);
|
||||
|
||||
if (RegisterServiceResult.error === "gdprNotApproved") {
|
||||
if (
|
||||
typeof RegisterServiceResult !== "string" &&
|
||||
RegisterServiceResult.message === "GDPR acceptance is required."
|
||||
) {
|
||||
logger.warn(`GDPR not approved (${req.ip})`);
|
||||
return res.status(400).json({
|
||||
return res.status(HttpStatusCode.BadRequest).json({
|
||||
error: RegisterServiceResult.error,
|
||||
message: "GDPR not accepted.",
|
||||
});
|
||||
}
|
||||
if (RegisterServiceResult.error === "exist") {
|
||||
logger.warn(`The user already exists (${req.ip})`);
|
||||
return res.type("application/json").status(400).json({
|
||||
if (
|
||||
typeof RegisterServiceResult !== "string" &&
|
||||
RegisterServiceResult.error === 5
|
||||
) {
|
||||
logger.warn(`The user already exists (${sanitizeData.email})`);
|
||||
return res.type("application/json").status(HttpStatusCode.Conflict).json({
|
||||
error: RegisterServiceResult.error,
|
||||
message: "The user already exists.",
|
||||
});
|
||||
}
|
||||
|
||||
// SUCCESS
|
||||
logger.info(`User registered successfully (${req.ip})`);
|
||||
return res.type("application/json").status(201).json(RegisterServiceResult);
|
||||
//logger.info(`User registered successfully (${sanitizeData.username})`);
|
||||
return res
|
||||
.type("application/json")
|
||||
.status(HttpStatusCode.Ok)
|
||||
.json({ token: RegisterServiceResult });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,34 +104,39 @@ async function registerUser(req: Request, res: Response): Promise<unknown> {
|
||||
async function loginUser(req: Request, res: Response): Promise<void> {
|
||||
const body = req.body;
|
||||
if (!body) {
|
||||
res.type("application/json").status(400).json({
|
||||
res.type("application/json").status(HttpStatusCode.BadRequest).json({
|
||||
error: "Invalid input data",
|
||||
});
|
||||
}
|
||||
if (!body.password || !body.username) {
|
||||
if (!body.password || !body.email) {
|
||||
logger.warn(`Field(s) missing (${req.ip})`);
|
||||
res.type("application/json").status(400).json({
|
||||
res.type("application/json").status(HttpStatusCode.BadRequest).json({
|
||||
error: "Field(s) missing",
|
||||
});
|
||||
}
|
||||
|
||||
const loginData = {
|
||||
username: `${body.username}`,
|
||||
email: `${body.email}`,
|
||||
password: `${body.password}`,
|
||||
};
|
||||
console.log(body);
|
||||
const LoginServiceResult = await UserService.login(loginData);
|
||||
console.log(LoginServiceResult);
|
||||
|
||||
if (LoginServiceResult.error === "userNotFound") {
|
||||
console.log("POOL");
|
||||
res.type("application/json").status(404).json({
|
||||
if (
|
||||
typeof LoginServiceResult !== "string" &&
|
||||
LoginServiceResult.error === 3
|
||||
) {
|
||||
res.type("application/json").status(HttpStatusCode.NotFound).json({
|
||||
error: LoginServiceResult.error,
|
||||
message: "User not found.",
|
||||
});
|
||||
}
|
||||
if (LoginServiceResult.error === "invalidPassword") {
|
||||
res.type("application/json").status(401).json({
|
||||
if (
|
||||
typeof LoginServiceResult !== "string" &&
|
||||
LoginServiceResult.error === 5
|
||||
) {
|
||||
res.type("application/json").status(HttpStatusCode.NotAcceptable).json({
|
||||
error: LoginServiceResult.error,
|
||||
message: "Invalid password.",
|
||||
});
|
||||
@@ -124,74 +144,97 @@ async function loginUser(req: Request, res: Response): Promise<void> {
|
||||
res.type("application/json").status(200).json(LoginServiceResult);
|
||||
}
|
||||
|
||||
//ToTest
|
||||
async function getAllUsers(req: Request, res: Response) {
|
||||
const authHeader = req.headers.authorization;
|
||||
const bearerToken = authHeader?.split(" ")[1];
|
||||
if (!bearerToken) {
|
||||
logger.warn(`Bearer token not provided (${req.ip})`);
|
||||
return res.type("application/json").status(401).json({
|
||||
error: "Unauthorized",
|
||||
return res.type("application/json").status(HttpStatusCode.Forbidden).json({
|
||||
error: "Invalid token",
|
||||
});
|
||||
}
|
||||
const payload = await JwtService.verify(bearerToken);
|
||||
if (!payload) {
|
||||
if (!payload || !payload.sub) {
|
||||
logger.warn(`Unauthorized access attempt (${req.ip})`);
|
||||
return res.type("application/json").status(401).json({
|
||||
error: "Unauthorized",
|
||||
return res.type("application/json").status(HttpStatusCode.Forbidden).json({
|
||||
error: "Invalid token",
|
||||
});
|
||||
}
|
||||
const sourceUser = await UserService.getFromId(payload.sub);
|
||||
if (!sourceUser) {
|
||||
return res.type("application/json").status(404).json({
|
||||
return res.type("application/json").status(HttpStatusCode.ImATeapot).json({
|
||||
error: "You dont exist anymore",
|
||||
});
|
||||
}
|
||||
if (!sourceUser.is_admin) {
|
||||
return res.type("application/json").status(403).json({
|
||||
if ("id" in sourceUser && !sourceUser.is_admin) {
|
||||
return res.type("application/json").status(HttpStatusCode.Forbidden).json({
|
||||
error: "Unauthorized",
|
||||
});
|
||||
}
|
||||
const AllUserResponse = await UserService.getAll();
|
||||
if (!AllUserResponse.users) {
|
||||
return res.type("application/json").status(500).json({
|
||||
error: "Internal server error",
|
||||
});
|
||||
if (typeof AllUserResponse === "object") {
|
||||
return res
|
||||
.type("application/json")
|
||||
.status(HttpStatusCode.InternalServerError)
|
||||
.json({
|
||||
error: "Internal server error",
|
||||
});
|
||||
}
|
||||
return res.type("application/json").status(200).json(AllUserResponse);
|
||||
return res
|
||||
.type("application/json")
|
||||
.status(HttpStatusCode.Found)
|
||||
.json(AllUserResponse);
|
||||
}
|
||||
|
||||
//ToTest
|
||||
async function getUser(req: Request, res: Response) {
|
||||
const authHeader = req.headers.authorization;
|
||||
const bearerToken = authHeader?.split(" ")[1];
|
||||
if (!bearerToken) {
|
||||
logger.warn(`Bearer token not provided (${req.ip})`);
|
||||
return res.type("application/json").status(401).json({
|
||||
error: "Unauthorized",
|
||||
});
|
||||
return res
|
||||
.type("application/json")
|
||||
.status(HttpStatusCode.Unauthorized)
|
||||
.json({
|
||||
error: "Unauthorized",
|
||||
});
|
||||
}
|
||||
const payload = await JwtService.verify(bearerToken);
|
||||
if (!payload) {
|
||||
if (!payload || !payload.sub) {
|
||||
logger.warn(`Unauthorized access attempt (${req.ip})`);
|
||||
return res.type("application/json").status(401).json({
|
||||
error: "Unauthorized",
|
||||
});
|
||||
return res
|
||||
.type("application/json")
|
||||
.status(HttpStatusCode.Unauthorized)
|
||||
.json({
|
||||
error: "Unauthorized",
|
||||
});
|
||||
}
|
||||
const sourceUser = await UserService.getFromId(payload.sub);
|
||||
if (!sourceUser) {
|
||||
return res.type("application/json").status(404).json({
|
||||
return res.type("application/json").status(HttpStatusCode.ImATeapot).json({
|
||||
error: "You dont exist anymore",
|
||||
});
|
||||
}
|
||||
if (!sourceUser.is_admin) {
|
||||
return res.type("application/json").status(403).json({
|
||||
error: "Unauthorized",
|
||||
});
|
||||
if ("username" in sourceUser && !sourceUser.is_admin) {
|
||||
return res
|
||||
.type("application/json")
|
||||
.status(HttpStatusCode.Unauthorized)
|
||||
.json({
|
||||
error: "Unauthorized",
|
||||
});
|
||||
}
|
||||
const userId = req.params["id"];
|
||||
if (!userId) {
|
||||
logger.warn(`User ID not provided (${req.ip})`);
|
||||
return res.type("application/json").status(HttpStatusCode.BadRequest).json({
|
||||
error: "User ID not provided",
|
||||
});
|
||||
}
|
||||
const dbUser = await UserService.getFromId(userId);
|
||||
if (!dbUser) {
|
||||
logger.warn(`User not found (${req.ip})`);
|
||||
return res.type("application/json").status(404).json({
|
||||
return res.type("application/json").status(HttpStatusCode.NotFound).json({
|
||||
error: "User not found",
|
||||
});
|
||||
}
|
||||
@@ -199,10 +242,11 @@ async function getUser(req: Request, res: Response) {
|
||||
delete dbUser.passwordHash;
|
||||
// @ts-ignore
|
||||
delete dbUser._id;
|
||||
return res.type("application/json").status(200).json(dbUser);
|
||||
return res.type("application/json").status(HttpStatusCode.Found).json(dbUser);
|
||||
}
|
||||
|
||||
//FEAT - Implement re-auth by current password in case of password change
|
||||
//ToTest
|
||||
async function editUser(req: Request, res: Response) {
|
||||
const body: IReqEditUserData | null = req.body;
|
||||
if (!body) {
|
||||
@@ -219,7 +263,7 @@ async function editUser(req: Request, res: Response) {
|
||||
});
|
||||
}
|
||||
const payload = await JwtService.verify(bearerToken);
|
||||
if (!payload) {
|
||||
if (!payload || !payload.sub) {
|
||||
logger.warn(`Unauthorized access attempt (${req.ip})`);
|
||||
return res.type("application/json").status(401).json({
|
||||
error: "Unauthorized",
|
||||
@@ -237,7 +281,10 @@ async function editUser(req: Request, res: Response) {
|
||||
error: "You dont exist anymore",
|
||||
});
|
||||
}
|
||||
if (sourceUser.is_admin || sourceUser.id === payload.sub) {
|
||||
if (
|
||||
("id" in sourceUser && sourceUser.is_admin) ||
|
||||
("id" in sourceUser && sourceUser.id === payload.sub)
|
||||
) {
|
||||
if (sourceUser.is_admin) {
|
||||
logger.info(
|
||||
`EDIT :> Source user is an admin (${sourceUser.firstname} ${sourceUser.lastname})`,
|
||||
@@ -264,13 +311,19 @@ async function editUser(req: Request, res: Response) {
|
||||
`${targetUserId}`,
|
||||
modifiedData,
|
||||
);
|
||||
if (EditUserServiceResult.error === "userNotFound") {
|
||||
if (
|
||||
typeof EditUserServiceResult !== "boolean" &&
|
||||
EditUserServiceResult.error === 3
|
||||
) {
|
||||
logger.warn(`User not found (${req.ip})`);
|
||||
return res.type("application/json").status(404).json({
|
||||
error: "User not found",
|
||||
});
|
||||
}
|
||||
if (EditUserServiceResult.error !== "none") {
|
||||
if (
|
||||
typeof EditUserServiceResult !== "boolean" &&
|
||||
EditUserServiceResult.error
|
||||
) {
|
||||
logger.error(`Error occurred during user edit (${req.ip})`);
|
||||
return res.type("application/json").status(500).json({
|
||||
error: "Internal server error",
|
||||
@@ -285,6 +338,7 @@ async function editUser(req: Request, res: Response) {
|
||||
});
|
||||
}
|
||||
|
||||
//ToTest
|
||||
async function deleteUser(req: Request, res: Response): Promise<Response> {
|
||||
const authHeader = req.headers.authorization;
|
||||
const bearerToken = authHeader?.split(" ")[1];
|
||||
@@ -296,7 +350,7 @@ async function deleteUser(req: Request, res: Response): Promise<Response> {
|
||||
}
|
||||
const payload = await JwtService.verify(bearerToken);
|
||||
|
||||
if (!payload) {
|
||||
if (!payload || !payload.sub) {
|
||||
logger.warn(`Invalid token (${req.ip})`);
|
||||
return res.type("application/json").status(401).json({
|
||||
error: "Invalid token",
|
||||
@@ -310,7 +364,10 @@ async function deleteUser(req: Request, res: Response): Promise<Response> {
|
||||
error: "You dont exist anymore",
|
||||
});
|
||||
}
|
||||
if (sourceUser.is_admin || sourceUser.id === payload.sub) {
|
||||
if (
|
||||
("id" in sourceUser && sourceUser.is_admin) ||
|
||||
("id" in sourceUser && sourceUser.id === payload.sub)
|
||||
) {
|
||||
const deleteUserServiceResult = await UserService.delete(`${targetUserId}`);
|
||||
if (!deleteUserServiceResult) {
|
||||
logger.error(`Error occurred during user delete (${req.ip})`);
|
||||
@@ -328,6 +385,7 @@ async function deleteUser(req: Request, res: Response): Promise<Response> {
|
||||
});
|
||||
}
|
||||
|
||||
//ToTest
|
||||
async function deleteSelf(req: Request, res: Response) {
|
||||
const authHeader = req.headers.authorization;
|
||||
const bearerToken = authHeader?.split(" ")[1];
|
||||
@@ -338,7 +396,7 @@ async function deleteSelf(req: Request, res: Response) {
|
||||
});
|
||||
}
|
||||
const payload = await JwtService.verify(bearerToken);
|
||||
if (!payload) {
|
||||
if (!payload || !payload.sub) {
|
||||
logger.warn(`Unauthorized access attempt (${req.ip})`);
|
||||
return res.type("application/json").status(401).json({
|
||||
error: "Unauthorized",
|
||||
@@ -350,23 +408,27 @@ async function deleteSelf(req: Request, res: Response) {
|
||||
error: "You dont exist anymore",
|
||||
});
|
||||
}
|
||||
if (sourceUser.id !== req.params["id"]) {
|
||||
if ("id" in sourceUser && sourceUser.id !== req.params["id"]) {
|
||||
return res.type("application/json").status(403).json({
|
||||
error: "Unauthorized",
|
||||
});
|
||||
}
|
||||
const deleteResult = await UserService.delete(sourceUser.id);
|
||||
if (!deleteResult) {
|
||||
logger.error(`Failed to delete user (${req.ip})`);
|
||||
return res.type("application/json").status(500).json({
|
||||
error: "Failed to delete user",
|
||||
});
|
||||
if ("id" in sourceUser) {
|
||||
const deleteResult = await UserService.delete(sourceUser.id);
|
||||
|
||||
if (!deleteResult) {
|
||||
logger.error(`Failed to delete user (${req.ip})`);
|
||||
return res.type("application/json").status(500).json({
|
||||
error: "Failed to delete user",
|
||||
});
|
||||
}
|
||||
}
|
||||
return res.type("application/json").status(200).json({
|
||||
message: "User deleted successfully",
|
||||
});
|
||||
}
|
||||
|
||||
//ToTest
|
||||
async function getSelf(req: Request, res: Response) {
|
||||
const authHeader = req.headers.authorization;
|
||||
const bearerToken = authHeader?.split(" ")[1];
|
||||
@@ -376,27 +438,29 @@ async function getSelf(req: Request, res: Response) {
|
||||
});
|
||||
}
|
||||
const payload = await JwtService.verify(bearerToken);
|
||||
if (!payload) {
|
||||
if (!payload || !payload.sub) {
|
||||
logger.warn(`Unauthorized access attempt (${req.ip})`);
|
||||
return res.type("application/json").status(401).json({
|
||||
error: "Unauthorized",
|
||||
});
|
||||
}
|
||||
const dbUser = await UserService.getFromId(payload.sub);
|
||||
if (!dbUser) {
|
||||
return res.type("application/json").status(404).json({
|
||||
error: "User not found",
|
||||
const GetUserResult = await UserService.getFromId(payload.sub);
|
||||
if ("id" in GetUserResult) {
|
||||
return res.type("application/json").status(200).json({
|
||||
id: GetUserResult.id,
|
||||
username: GetUserResult.username,
|
||||
firstName: GetUserResult.firstname,
|
||||
lastName: GetUserResult.lastname,
|
||||
isAdmin: GetUserResult.is_admin,
|
||||
});
|
||||
}
|
||||
return res.type("application/json").status(200).json({
|
||||
id: dbUser.id,
|
||||
username: dbUser.username,
|
||||
firstName: dbUser.firstname,
|
||||
lastName: dbUser.firstname,
|
||||
isAdmin: dbUser.firstname,
|
||||
return res.type("application/json").status(404).json({
|
||||
error: "User not found",
|
||||
});
|
||||
}
|
||||
|
||||
if (isDebugMode()) logger.debug("\nController loaded.");
|
||||
|
||||
const AuthController = {
|
||||
register: registerUser,
|
||||
login: loginUser,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Logger } from "tslog";
|
||||
|
||||
import type IDbBrand from "@interfaces/database/IDbBrand";
|
||||
import BrandService from "@services/brand.service";
|
||||
import { isDebugMode } from "@utils/debugState";
|
||||
//import {body} from "express-validator";
|
||||
|
||||
const logger = new Logger({
|
||||
@@ -171,6 +172,8 @@ async function deleteBrand(req: Request, res: Response): Promise<Response> {
|
||||
|
||||
//TODO get models of the brand
|
||||
|
||||
if (isDebugMode()) logger.debug("\nController loaded.");
|
||||
|
||||
const BrandController = {
|
||||
create: createBrand,
|
||||
update: updateBrand,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type IDbCategory from "@interfaces/database/IDbCategory";
|
||||
import CategoryService from "@services/category.service";
|
||||
import { isDebugMode } from "@utils/debugState";
|
||||
import type { Request, Response } from "express";
|
||||
import { Logger } from "tslog";
|
||||
//import {validationResult} from "express-validator";
|
||||
@@ -177,6 +178,8 @@ async function getBySlugCategory(
|
||||
});
|
||||
}
|
||||
|
||||
if (isDebugMode()) logger.debug("\nController loaded.");
|
||||
|
||||
const CategoryController = {
|
||||
create: createCategory,
|
||||
update: updateCategory,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type IDbModel from "@interfaces/database/IDbModel";
|
||||
import CategoryService from "@services/category.service";
|
||||
import ModelService from "@services/model.service";
|
||||
import { isDebugMode } from "@utils/debugState";
|
||||
import type { Request, Response } from "express";
|
||||
import { Logger } from "tslog";
|
||||
//import {validationResult} from "express-validator";
|
||||
@@ -41,7 +42,7 @@ async function createModel(req: Request, res: Response): Promise<Response> {
|
||||
|
||||
async function updateModel(req: Request, res: Response): Promise<Response> {
|
||||
const body: IDbModel = req.body;
|
||||
const doesExist = await ModelService.getBySlug(`${body.slug_name}`);
|
||||
const doesExist = await ModelService.getBySlug(`${req.params["modelSlug"]}`);
|
||||
if (!doesExist) {
|
||||
logger.error("Model does not exist");
|
||||
return res.status(404).json({
|
||||
@@ -131,6 +132,8 @@ async function deleteModel(req: Request, res: Response): Promise<Response> {
|
||||
|
||||
//TODO get model with vehicle available.
|
||||
|
||||
if (isDebugMode()) logger.debug("\nController loaded.");
|
||||
|
||||
const ModelController = {
|
||||
create: createModel,
|
||||
update: updateModel,
|
||||
|
||||
150
src/controllers/rent.controller.ts
Normal file
150
src/controllers/rent.controller.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import { isDebugMode } from "@utils/debugState";
|
||||
import type { Request, Response } from "express";
|
||||
import { Logger } from "tslog";
|
||||
import RentService from "@services/rent.service";
|
||||
import {HttpStatusCode} from "@interfaces/requests/HttpStatusCode";
|
||||
import type IDbRent from "@interfaces/database/IDbRent";
|
||||
import JwtService from "@services/jwt.service";
|
||||
import UserService from "@services/user.service";
|
||||
|
||||
|
||||
const logger = new Logger({
|
||||
name: "RentController",
|
||||
});
|
||||
|
||||
async function createRent(req: Request, res: Response): Promise<Response> {
|
||||
try {
|
||||
const rentData: IDbRent = req.body;
|
||||
if (!rentData.active || !rentData.need_survey || !rentData.eat || !rentData.iat || !rentData.user_id || !rentData.vehicle_id || !rentData.km_at_start || !rentData.active) {
|
||||
logger.error("Invalid rent data");
|
||||
return res.status(HttpStatusCode.BadRequest).json({
|
||||
error: "Invalid rent data",
|
||||
});
|
||||
}
|
||||
const rent = await RentService.create(rentData);
|
||||
logger.info(`\n\n> Rent created successfully! (ID: ${rentData.vehicle_id})\n`);
|
||||
return res.status(201).json({
|
||||
message: "Rent created successfully",
|
||||
rent,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(`\n\n> Failed to create rent !\n${error}\n`);
|
||||
return res.status(500).json({
|
||||
error: "Failed to create rent",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function updateRent(req: Request, res: Response): Promise<Response> {
|
||||
const body: IDbRent = req.body;
|
||||
if (!body.vehicle_id || !body.user_id || !body.active || !body.need_survey || !body.eat || !body.iat || !body.km_at_start) {
|
||||
logger.error("Invalid rent data");
|
||||
return res.status(HttpStatusCode.BadRequest).json({
|
||||
error: "Invalid rent data",
|
||||
});
|
||||
}
|
||||
const rentId = req.params["rentId"];
|
||||
if (!rentId || rentId.length !== 36) {
|
||||
logger.error("Invalid rent ID");
|
||||
return res.status(HttpStatusCode.BadRequest).json({
|
||||
error: "Invalid rent ID",
|
||||
});
|
||||
}
|
||||
const result = await RentService.update({
|
||||
id: rentId,
|
||||
vehicle_id: ``,
|
||||
user_id: ``,
|
||||
active: !!body.active,
|
||||
need_survey: !!body.need_survey,
|
||||
eat: body.eat,
|
||||
iat: body.iat,
|
||||
km_at_start: body.km_at_start,
|
||||
})
|
||||
if (!result) {
|
||||
logger.error(`Failed to update rent with ID: ${rentId}`);
|
||||
return res.status(HttpStatusCode.InternalServerError).json({
|
||||
error: `Failed to update rent with ID: ${rentId}`,
|
||||
});
|
||||
}
|
||||
logger.info(`Rent with ID: ${rentId} updated successfully`);
|
||||
return res.status(HttpStatusCode.Ok).json({
|
||||
message: `Rent with ID: ${rentId} updated successfully`,
|
||||
});
|
||||
}
|
||||
|
||||
async function getAllAssigned(res: Response): Promise<Response> {
|
||||
const rents = await RentService.getAll();
|
||||
if (rents.length === 0) {
|
||||
return res.status(HttpStatusCode.NotFound).json({
|
||||
error: "No assigned rents found",
|
||||
});
|
||||
}
|
||||
return res.status(HttpStatusCode.Ok).json({
|
||||
iat: Date.now(),
|
||||
rents: rents,
|
||||
total: rents.length
|
||||
});
|
||||
}
|
||||
|
||||
async function getAssignedToUser(req: Request, res: Response): Promise<Response> {
|
||||
const authHeader = req.headers.authorization;
|
||||
const bearerToken = authHeader?.split(" ")[1];
|
||||
if (!bearerToken) {
|
||||
logger.warn(`Bearer token not provided (${req.ip})`);
|
||||
return res
|
||||
.type("application/json")
|
||||
.status(HttpStatusCode.Unauthorized)
|
||||
.json({
|
||||
error: "Unauthorized",
|
||||
});
|
||||
}
|
||||
const payload = await JwtService.verify(bearerToken);
|
||||
if (!payload || !payload.sub) {
|
||||
logger.warn(`Unauthorized access attempt (${req.ip})`);
|
||||
return res
|
||||
.type("application/json")
|
||||
.status(HttpStatusCode.Unauthorized)
|
||||
.json({
|
||||
error: "Unauthorized",
|
||||
});
|
||||
}
|
||||
const sourceUser = await UserService.getFromId(payload.sub);
|
||||
if (!sourceUser) {
|
||||
return res.type("application/json").status(HttpStatusCode.ImATeapot).json({
|
||||
error: "You dont exist anymore",
|
||||
});
|
||||
}
|
||||
const userId: string = payload.sub;
|
||||
if (!userId || userId.length !== 36) {
|
||||
logger.error("Invalid user ID");
|
||||
return res.status(HttpStatusCode.BadRequest).json({
|
||||
error: "Invalid user ID",
|
||||
});
|
||||
}
|
||||
let targetId = userId
|
||||
if ("is_admin" in sourceUser && sourceUser.is_admin) {
|
||||
targetId = req.body.targetId || userId
|
||||
}
|
||||
const rents = await RentService.getUserRent(targetId);
|
||||
if (!rents) {
|
||||
return res.status(HttpStatusCode.NotFound).json({
|
||||
error: "No assigned rents found for the user",
|
||||
});
|
||||
}
|
||||
return res.status(HttpStatusCode.Ok).json({
|
||||
iat: Date.now(),
|
||||
rents: rents,
|
||||
total: rents.length,
|
||||
});
|
||||
}
|
||||
|
||||
if (isDebugMode()) logger.debug("\nController loaded.");
|
||||
|
||||
const RentController = {
|
||||
create: createRent,
|
||||
update: updateRent,
|
||||
getAll: getAllAssigned,
|
||||
getAssignedToUser,
|
||||
};
|
||||
|
||||
export default RentController;
|
||||
174
src/controllers/vehicle.controller.ts
Normal file
174
src/controllers/vehicle.controller.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
import type { IDbVehicle } from "@interfaces/database/IDbVehicle";
|
||||
import VehicleService from "@services/vehicle.service";
|
||||
import { isDebugMode } from "@utils/debugState";
|
||||
import type { Request, Response } from "express";
|
||||
import { Logger } from "tslog";
|
||||
//import {validationResult} from "express-validator";
|
||||
|
||||
const logger = new Logger({
|
||||
name: "VehicleController",
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates a new vehicle in the database.
|
||||
*
|
||||
* @param {Request} req - The request object containing the vehicle details in the body.
|
||||
* @param {Response} res - The response object used to send the result of the operation.
|
||||
* @returns {Promise<Response>} The response with the result of the operation.
|
||||
*/
|
||||
async function createVehicle(req: Request, res: Response): Promise<Response> {
|
||||
const body: IDbVehicle = req.body;
|
||||
const createResult = await VehicleService.create({
|
||||
plate_number: `${body.plate_number}`,
|
||||
model_id: `${body.plate_number}`,
|
||||
odometer: Number.parseInt(`${body.odometer}`),
|
||||
health_state: Number.parseInt(`${body.health_state}`),
|
||||
});
|
||||
if (!createResult) {
|
||||
logger.error("Failed to create vehicle");
|
||||
return res.status(500).json({
|
||||
error: "Failed to create vehicle",
|
||||
});
|
||||
}
|
||||
logger.info(`Vehicle created successfully ! (${body.plate_number})`);
|
||||
return res.status(201).json({
|
||||
message: "Vehicle created successfully",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a vehicle in the database.
|
||||
*
|
||||
* @param {Request} req - The request object containing the vehicle data in the request body and the vehicle ID in the request parameters.
|
||||
* @param {Response} res - The response object used to send the result of the update operation.
|
||||
*
|
||||
* @return {Promise<Response>} A promise that resolves to the response object with a status and a JSON body indicating the result of the update operation.
|
||||
*/
|
||||
async function updateVehicle(req: Request, res: Response): Promise<Response> {
|
||||
const body: IDbVehicle = req.body;
|
||||
const vehicleId = req.params["vehicleId"];
|
||||
if (!vehicleId || vehicleId.length !== 36) {
|
||||
if (isDebugMode()) logger.error("Vehicle ID is missing");
|
||||
return res.status(400).json({
|
||||
error: "Vehicle ID is missing or not valid",
|
||||
});
|
||||
}
|
||||
const updateResult = await VehicleService.update({
|
||||
plate_number: `${body.plate_number}`,
|
||||
model_id: `${body.plate_number}`,
|
||||
odometer: Number.parseInt(`${body.odometer}`),
|
||||
health_state: Number.parseInt(`${body.health_state}`),
|
||||
});
|
||||
if (!updateResult) {
|
||||
logger.error("Failed to update vehicle");
|
||||
return res.status(500).json({
|
||||
error: "Failed to update vehicle",
|
||||
});
|
||||
}
|
||||
logger.info(`Vehicle updated successfully ! (${body.plate_number})`);
|
||||
return res.status(200).json({
|
||||
message: "Vehicle updated successfully",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all vehicles from the vehicle service.
|
||||
*
|
||||
* @param {Response} res - The response object from the client.
|
||||
* @returns {Promise<Response>} A promise that resolves to a response object containing the result of the operation. The result is a JSON object containing all vehicles.
|
||||
*/
|
||||
async function getAllVehicle(res: Response): Promise<Response> {
|
||||
const getAllVehicleResult = await VehicleService.getAll();
|
||||
if (!getAllVehicleResult) {
|
||||
logger.error("Failed to get all vehicles");
|
||||
return res.status(500).json({
|
||||
error: "Failed to get all vehicles",
|
||||
});
|
||||
}
|
||||
return res.status(200).json(getAllVehicleResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the available vehicles from the VehicleService
|
||||
*
|
||||
* @param {Response} res - The Response object to send the result to
|
||||
* @returns {Promise<Response<any, Record<string, any>>>} - A promise that resolves to a Response object containing the available vehicles or an error message
|
||||
*/
|
||||
async function getAvailableVehicle(res: Response): Promise<Response<any, Record<string, any>>> {
|
||||
const getAvailableVehicleResult = await VehicleService.getAvailable();
|
||||
if (!getAvailableVehicleResult) {
|
||||
logger.error("Failed to get available vehicles");
|
||||
return res.status(500).json({
|
||||
error: "Failed to get available vehicles",
|
||||
});
|
||||
}
|
||||
return res.status(200).json(getAvailableVehicleResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a vehicle by its ID.
|
||||
*
|
||||
* @param {Request} req - The request object containing the vehicle ID.
|
||||
* @param {Response} res - The response object used to send the result.
|
||||
*
|
||||
* @return {Promise<Response>} A promise that resolves to the result of the retrieval operation.
|
||||
*/
|
||||
async function getVehicleById(req: Request, res: Response): Promise<Response> {
|
||||
const vehicleId = req.params["vehicleId"];
|
||||
if (!vehicleId || vehicleId.length !== 36) {
|
||||
if (isDebugMode()) logger.error("Vehicle ID is missing or not valid");
|
||||
return res.status(400).json({
|
||||
error: "Vehicle ID is missing or not valid",
|
||||
});
|
||||
}
|
||||
const getVehicleResult = await VehicleService.getById(vehicleId);
|
||||
if (!getVehicleResult) {
|
||||
logger.error(`Failed to get vehicle by ID: ${vehicleId}`);
|
||||
return res.status(500).json({
|
||||
error: `Failed to get vehicle by ID: ${vehicleId}`,
|
||||
});
|
||||
}
|
||||
return res.status(200).json(getVehicleResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a vehicle.
|
||||
*
|
||||
* @param {Object} req - The request object.
|
||||
* @param {Object} res - The response object.
|
||||
*
|
||||
* @return {Promise<Response>} A promise that resolves to the response JSON object.
|
||||
*/
|
||||
async function deleteVehicle(req: Request, res: Response): Promise<Response> {
|
||||
const vehicleId = req.params["vehicleId"];
|
||||
if (!vehicleId || vehicleId.length !== 36) {
|
||||
if (isDebugMode()) logger.error("Vehicle ID is missing or not valid");
|
||||
return res.status(400).json({
|
||||
error: "Vehicle ID is missing or not valid",
|
||||
});
|
||||
}
|
||||
const deleteResult = await VehicleService.delete(vehicleId);
|
||||
if (!deleteResult) {
|
||||
logger.error(`Failed to delete vehicle with ID: ${vehicleId}`);
|
||||
return res.status(500).json({
|
||||
error: `Failed to delete vehicle with ID: ${vehicleId}`,
|
||||
});
|
||||
}
|
||||
logger.info(`Vehicle deleted successfully ! (ID: ${vehicleId})`);
|
||||
return res.status(200).json({
|
||||
message: "Vehicle deleted successfully",
|
||||
});
|
||||
}
|
||||
|
||||
if (isDebugMode()) logger.debug("\nController loaded.");
|
||||
|
||||
const VehicleController = {
|
||||
create: createVehicle,
|
||||
update: updateVehicle,
|
||||
getAll: getAllVehicle,
|
||||
delete: deleteVehicle,
|
||||
getById: getVehicleById,
|
||||
getAvailable: getAvailableVehicle,
|
||||
};
|
||||
|
||||
export default VehicleController;
|
||||
54
src/interfaces/database/IDbFactorize.ts
Normal file
54
src/interfaces/database/IDbFactorize.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Represents the output of the factorization function.
|
||||
*/
|
||||
export interface IDbFactorizeOutput {
|
||||
/**
|
||||
* Description: The variable `_valuesArray` is an array that can contain values of type `string`, `boolean`, `number`, or `Date`.
|
||||
* (The value associated with the keys of `_keysTemplate`)
|
||||
*
|
||||
* @type {Array<string | boolean | number | Date>}
|
||||
*/
|
||||
_valuesArray: Array<string | boolean | number | Date>;
|
||||
/**
|
||||
* Represents the SQL Query template for the keys.
|
||||
* @type {string}
|
||||
*/
|
||||
_keysTemplate: string;
|
||||
|
||||
/**
|
||||
* The list of ? for the "VALUE" section
|
||||
*/
|
||||
_questionMarksFields: string;
|
||||
|
||||
/**
|
||||
* The total number of fields.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
totalFields: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface IDbFactorizeInput represents the input required to factorize a SQL query.
|
||||
*/
|
||||
export interface IDbFactorizeInput {
|
||||
/**
|
||||
* An object containing values that will be in a SQL Query.
|
||||
*
|
||||
* @type {Array<string | boolean | number | Date>}
|
||||
*/
|
||||
values: object;
|
||||
/**
|
||||
* Represents the name of the action that will result of the prepared SQL Query.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
actionName: string;
|
||||
/**
|
||||
* Indicates whether an error should be thrown when encountering an error.
|
||||
* If set to true, an error will be thrown. If set to false or not provided, the error will not be thrown.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
throwOnError?: true;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
export interface IDbRent {
|
||||
id?: string;
|
||||
vehicle_id: string;
|
||||
user_id: string;
|
||||
active: boolean;
|
||||
|
||||
@@ -5,7 +5,7 @@ export interface IDbUser {
|
||||
lastname: string;
|
||||
dob: Date;
|
||||
email: string;
|
||||
is_mail_verified: boolean;
|
||||
is_email_verified: boolean;
|
||||
is_admin: boolean;
|
||||
gdpr: Date;
|
||||
hash: string;
|
||||
|
||||
@@ -4,4 +4,5 @@ export interface IDbVehicle {
|
||||
model_id: string;
|
||||
odometer: number;
|
||||
health_state: number;
|
||||
isAvailable?: boolean;
|
||||
}
|
||||
|
||||
269
src/interfaces/requests/HttpStatusCode.ts
Normal file
269
src/interfaces/requests/HttpStatusCode.ts
Normal file
@@ -0,0 +1,269 @@
|
||||
export enum HttpStatusCode {
|
||||
/**
|
||||
* Status code for a request indicating that the server received the request headers
|
||||
* and the client should proceed to send the request body.
|
||||
* @enum {number}
|
||||
*/
|
||||
Continue = 100,
|
||||
|
||||
/**
|
||||
* Status code for a request indicating that the requester has asked the server to switch protocols.
|
||||
* @enum {number}
|
||||
*/
|
||||
SwitchingProtocols = 101,
|
||||
|
||||
/**
|
||||
* Status code for a request indicating that the server has received and is processing the request,
|
||||
* but no response is available yet.
|
||||
* @enum {number}
|
||||
*/
|
||||
Processing = 102,
|
||||
|
||||
/**
|
||||
* Successful HTTP response
|
||||
* @enum {number}
|
||||
*/
|
||||
Ok = 200,
|
||||
/**
|
||||
* Request has been fulfilled; new resource created as a result.
|
||||
* @enum {number}
|
||||
*/
|
||||
Created = 201,
|
||||
/**
|
||||
* Request accepted, but not yet processed.
|
||||
* @enum {number}
|
||||
*/
|
||||
Accepted = 202,
|
||||
/**
|
||||
* Request successful. Meta-information returned is from original server, not local.
|
||||
* @enum {number}
|
||||
*/
|
||||
NonAuthoritativeInformation = 203,
|
||||
/**
|
||||
* Request processed. No content returned.
|
||||
* @enum {number}
|
||||
*/
|
||||
NoContent = 204,
|
||||
/**
|
||||
* Server specifies part of document should be reset.
|
||||
* @enum {number}
|
||||
*/
|
||||
ResetContent = 205,
|
||||
/**
|
||||
* Partial content returned due to GET.
|
||||
* @enum {number}
|
||||
*/
|
||||
PartialContent = 206,
|
||||
/**
|
||||
* Multiple Resource Meta-Data: Could be used for collection instances.
|
||||
* @enum {number}
|
||||
*/
|
||||
MultiStatus = 207,
|
||||
/**
|
||||
* Status code used to indicate that a certain request has been already reported.
|
||||
* @enum {number}
|
||||
*/
|
||||
AlreadyReported = 208,
|
||||
/**
|
||||
* The server has fulfilled the request for the content, and the content is being conveyed in a manner described by the Content-Encoding, Content-Range, and Content-Type headers.
|
||||
* @enum {number}
|
||||
*/
|
||||
ImUsed = 226,
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
* @description HTTP status code for multiple choices
|
||||
*/
|
||||
MultipleChoices = 300,
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
* @description HTTP status code for moved permanently
|
||||
*/
|
||||
MovedPermanently = 301,
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
* @description HTTP status code for found
|
||||
*/
|
||||
Found = 302,
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
* @description HTTP status code for see other
|
||||
*/
|
||||
SeeOther = 303,
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
* @description HTTP status code for not modified
|
||||
*/
|
||||
NotModified = 304,
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
* @description HTTP status code for use proxy
|
||||
*/
|
||||
UseProxy = 305,
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
* @description HTTP status code for temporary redirect
|
||||
*/
|
||||
TemporaryRedirect = 307,
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
* @description HTTP status code for permanent redirect
|
||||
*/
|
||||
PermanentRedirect = 308,
|
||||
|
||||
/** @description Client error: The server could not understand the request due to invalid syntax. */
|
||||
BadRequest = 400,
|
||||
|
||||
/** @description Client error: The client must authenticate itself to get the requested response. */
|
||||
Unauthorized = 401,
|
||||
|
||||
/** @description Client error: This response code is reserved for future use. */
|
||||
PaymentRequired = 402,
|
||||
|
||||
/** @description Client error: The client does not have access rights to the content; that is, it is unauthorized, so the server is refusing to give the requested resource. */
|
||||
Forbidden = 403,
|
||||
|
||||
/** @description Client error: The server cannot find requested resource. */
|
||||
NotFound = 404,
|
||||
|
||||
/** @description Client error: The request method is not supported by the server and cannot be handled. */
|
||||
MethodNotAllowed = 405,
|
||||
|
||||
/** @description Client error: This response is sent when the web server, after performing server-driven content negotiation, doesn't find any content following the criteria given by the user agent. */
|
||||
NotAcceptable = 406,
|
||||
|
||||
/** @description Client error: This is similar to 401 (Unauthorised), but indicates that the client must authenticate itself to get the requested response. */
|
||||
ProxyAuthenticationRequired = 407,
|
||||
|
||||
/** @description Client error: This response is sent on an idle connection by some servers, even without any previous request by the client. */
|
||||
RequestTimeout = 408,
|
||||
|
||||
/** @description Client error: This response is sent when a request conflicts with the current state of the server. */
|
||||
Conflict = 409,
|
||||
|
||||
/** @description Client error: This response is sent when the requested content has been permanently deleted from server, with no forwarding address. */
|
||||
Gone = 410,
|
||||
|
||||
/** @description Client error: The server refuses to accept the request without a defined Content- Length. */
|
||||
LengthRequired = 411,
|
||||
|
||||
/** @description Client error: The precondition given in the request evaluated to false by the server. */
|
||||
PreconditionFailed = 412,
|
||||
|
||||
/** @description Client error: Request entity is larger than limits defined by server. */
|
||||
PayloadTooLarge = 413,
|
||||
|
||||
/** @description Client error: The URI requested by the client is longer than the server is willing to interpret. */
|
||||
UriTooLong = 414,
|
||||
|
||||
/** @description Client error: The media format of the requested data is not supported by the server, so the server is rejecting the request. */
|
||||
UnsupportedMediaType = 415,
|
||||
|
||||
/** @description Client error: The range specified by the Range header field in the request can't be fulfilled. */
|
||||
RangeNotSatisfiable = 416,
|
||||
|
||||
/** @description Client error: This response code means the expectation indicated by the Expect request header field can't be met by the server. */
|
||||
ExpectationFailed = 417,
|
||||
|
||||
/** @description Client error: The server refuses to brew coffee because it is, permanently, a teapot. */
|
||||
ImATeapot = 418,
|
||||
|
||||
/**
|
||||
* @enum
|
||||
* @name MisdirectedRequest
|
||||
* @description Represents HTTP status code 421: Misdirected Request.
|
||||
* The client should switch to a different protocol such as TLS/1.0.
|
||||
*/
|
||||
MisdirectedRequest = 421,
|
||||
|
||||
/**
|
||||
* @enum
|
||||
* @name UnprocessableEntity
|
||||
* @description Represents HTTP status code 422: Unprocessable Entity.
|
||||
* The request was well-formed but was unable to be followed due to semantic errors.
|
||||
*/
|
||||
UnprocessableEntity = 422,
|
||||
|
||||
/**
|
||||
* @enum
|
||||
* @name Locked
|
||||
* @description Represents HTTP status code 423: Locked.
|
||||
* The resource that is being accessed is locked.
|
||||
*/
|
||||
Locked = 423,
|
||||
|
||||
/**
|
||||
* @enum
|
||||
* @name FailedDependency
|
||||
* @description Represents HTTP status code 424: Failed Dependency.
|
||||
* The request failed because it depended on another request and that request failed.
|
||||
*/
|
||||
FailedDependency = 424,
|
||||
|
||||
/**
|
||||
* @enum
|
||||
* @name TooEarly
|
||||
* @description Represents HTTP status code 425: Too Early.
|
||||
* Indicates that the server is unwilling to risk processing a request that might be replayed.
|
||||
*/
|
||||
TooEarly = 425,
|
||||
|
||||
/**
|
||||
* @enum
|
||||
* @name UpgradeRequired
|
||||
* @description Represents HTTP status code 426: Upgrade Required.
|
||||
* The client should switch to a different protocol.
|
||||
*/
|
||||
UpgradeRequired = 426,
|
||||
|
||||
/**
|
||||
* @enum
|
||||
* @name PreconditionRequired
|
||||
* @description Represents HTTP status code 428: Precondition Required.
|
||||
* The client must first fulfill certain precondition.
|
||||
*/
|
||||
PreconditionRequired = 428,
|
||||
|
||||
/**
|
||||
* @enum
|
||||
* @name TooManyRequests
|
||||
* @description Represents HTTP status code 429: Too Many Requests.
|
||||
* The user has sent too many requests in a certain amount of time.
|
||||
*/
|
||||
TooManyRequests = 429,
|
||||
|
||||
/**
|
||||
* @enum
|
||||
* @name RequestHeaderFieldsTooLarge
|
||||
* @description Represents HTTP status code 431: Request Header Fields Too Large.
|
||||
* The server is unwilling to process the request because its header fields are too large.
|
||||
*/
|
||||
RequestHeaderFieldsTooLarge = 431,
|
||||
|
||||
/**
|
||||
* @enum
|
||||
* @name UnavailableForLegalReasons
|
||||
* @description Represents HTTP status code 451: Unavailable For Legal Reasons.
|
||||
* The server is denying access for legal reasons.
|
||||
*/
|
||||
UnavailableForLegalReasons = 451,
|
||||
|
||||
InternalServerError = 500,
|
||||
NotImplemented = 501,
|
||||
BadGateway = 502,
|
||||
ServiceUnavailable = 503,
|
||||
GatewayTimeout = 504,
|
||||
HttpVersionNotSupported = 505,
|
||||
VariantAlsoNegotiates = 506,
|
||||
InsufficientStorage = 507,
|
||||
LoopDetected = 508,
|
||||
NotExtended = 510,
|
||||
NetworkAuthenticationRequired = 511,
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export interface IReqLogin {
|
||||
username: string;
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ export interface IReqRegister {
|
||||
username: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
dob: Date;
|
||||
/*dob: Date;*/
|
||||
email: string;
|
||||
gdpr?: boolean;
|
||||
password: string;
|
||||
|
||||
8
src/interfaces/services/IUserUpdate.ts
Normal file
8
src/interfaces/services/IUserUpdate.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export interface IUserUpdate {
|
||||
id?: string;
|
||||
username?: string;
|
||||
firstname?: string;
|
||||
lastname?: string;
|
||||
dob?: Date;
|
||||
gdpr?: Date;
|
||||
}
|
||||
@@ -1,27 +1,29 @@
|
||||
import AdminGuard from "@validators/AdminGuard";
|
||||
import UserGuard from "@validators/UserGuard";
|
||||
import express, { type Router } from "express";
|
||||
import VehicleController from "@controllers/vehicle.controller";
|
||||
import RentController from "@controllers/rent.controller";
|
||||
|
||||
const RentRouter: Router = express.Router();
|
||||
|
||||
// Get rent affected to the user
|
||||
RentRouter.route("/affected").get(UserGuard);
|
||||
RentRouter.route("/affected").get(UserGuard, RentController.getAssignedToUser);
|
||||
|
||||
// Get all vehicle in rent (admin only)
|
||||
RentRouter.route("/affected/all").get(AdminGuard);
|
||||
RentRouter.route("/affected/all").get(AdminGuard, RentController.getAll);
|
||||
|
||||
// Add a new vehicle (admin only)
|
||||
RentRouter.route("/veh/new").post(AdminGuard);
|
||||
RentRouter.route("/veh/new").post(AdminGuard, VehicleController.create);
|
||||
|
||||
// Get all vehicles
|
||||
RentRouter.route("/veh/all").get();
|
||||
RentRouter.route("/veh/all").get(VehicleController.getAll);
|
||||
|
||||
// Rent a specific vehicle
|
||||
RentRouter.route("/veh/rent/:vehicleId").post(UserGuard);
|
||||
|
||||
RentRouter.route("/veh/:vehicleId")
|
||||
.get(UserGuard)
|
||||
.patch(AdminGuard)
|
||||
.delete(AdminGuard);
|
||||
.get(UserGuard, VehicleController.getById)
|
||||
.patch(AdminGuard, VehicleController.update)
|
||||
.delete(AdminGuard, VehicleController.delete);
|
||||
|
||||
export default RentRouter;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type IDbBrand from "@interfaces/database/IDbBrand";
|
||||
import MysqlService from "@services/mysql.service";
|
||||
import { isDebugMode } from "@utils/debugState";
|
||||
import { Logger } from "tslog";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
@@ -168,6 +169,8 @@ async function deleteBrand(brandId: string): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isDebugMode()) logger.debug("\nService loaded.");
|
||||
|
||||
const BrandService = {
|
||||
create: createBrand,
|
||||
update: updateBrand,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { IDbCategory } from "@interfaces/database/IDbCategory";
|
||||
import MysqlService from "@services/mysql.service";
|
||||
import { isDebugMode } from "@utils/debugState";
|
||||
import { Logger } from "tslog";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
@@ -127,6 +128,8 @@ async function deleteCategory(id: string): Promise<unknown> {
|
||||
}
|
||||
}
|
||||
|
||||
if (isDebugMode()) logger.debug("\nService loaded.");
|
||||
|
||||
const CategoryService = {
|
||||
create: createCategory,
|
||||
delete: deleteCategory,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { isDebugMode } from "@utils/debugState";
|
||||
import {
|
||||
type JWTHeaderParameters,
|
||||
type JWTPayload,
|
||||
@@ -64,6 +65,8 @@ async function JwtSignService(
|
||||
.sign(new TextEncoder().encode(`${process.env["JWT_SECRET"]}`));
|
||||
}
|
||||
|
||||
if (isDebugMode()) logger.debug("\nService loaded.");
|
||||
|
||||
const JwtService = {
|
||||
verify: JwtVerifyService,
|
||||
sign: JwtSignService,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type IDbModel from "@interfaces/database/IDbModel";
|
||||
import MysqlService from "@services/mysql.service";
|
||||
import { isDebugMode } from "@utils/debugState";
|
||||
import { Logger } from "tslog";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
@@ -79,12 +80,14 @@ async function deleteModel(modelSlug: string): Promise<boolean> {
|
||||
}
|
||||
logger.info(`Deleting model with ID: ${modelSlug}`);
|
||||
const doesExist = await MysqlService.Model.getBySlug(DbHandler, modelSlug);
|
||||
if (!doesExist || !doesExist.id) {
|
||||
if (!doesExist[0]) {
|
||||
logger.warn(`Model with slug ${modelSlug} not found`);
|
||||
return false;
|
||||
}
|
||||
const target = doesExist[0]
|
||||
if (!target.id) return false;
|
||||
try {
|
||||
await MysqlService.Model.delete(DbHandler, doesExist.id);
|
||||
await MysqlService.Model.delete(DbHandler, target.id);
|
||||
logger.info("Deletion Successful !");
|
||||
return true;
|
||||
} catch (error) {
|
||||
@@ -103,11 +106,11 @@ async function getBySlugModel(modelSlug: string): Promise<IDbModel | null> {
|
||||
logger.info(`Fetching model with slug: ${modelSlug}`);
|
||||
try {
|
||||
const model = await MysqlService.Model.getBySlug(DbHandler, modelSlug);
|
||||
if (!model) {
|
||||
if (!model[0]) {
|
||||
logger.warn(`Model with slug ${modelSlug} not found`);
|
||||
return null;
|
||||
}
|
||||
return model;
|
||||
return model[0];
|
||||
} catch (error) {
|
||||
logger.error(`Error fetching model by slug: ${error}`);
|
||||
return null;
|
||||
@@ -135,6 +138,8 @@ async function getAllModels(): Promise<IDbModel[] | null> {
|
||||
}
|
||||
}
|
||||
|
||||
if (isDebugMode()) logger.debug("\nService loaded.");
|
||||
|
||||
/**
|
||||
* ModelService is responsible for managing models.
|
||||
* @namespace
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
182
src/services/rent.service.ts
Normal file
182
src/services/rent.service.ts
Normal file
@@ -0,0 +1,182 @@
|
||||
//import { ErrorType, type ISError } from "@interfaces/services/ISError";
|
||||
import MySqlService from "@services/mysql.service";
|
||||
import { isDebugMode } from "@utils/debugState";
|
||||
import { Logger } from "tslog";
|
||||
import { v4 } from "uuid";
|
||||
import IDbRent from "@interfaces/database/IDbRent";
|
||||
|
||||
const logger = new Logger({
|
||||
name: "RentService",
|
||||
});
|
||||
|
||||
const DbHandler = new MySqlService.Handler("RentService");
|
||||
|
||||
async function createRentService(data: IDbRent): Promise<boolean> {
|
||||
if (isDebugMode()) logger.debug(`\n\n> Creating a new rent...\n`);
|
||||
const wantedVehicleId = data.id;
|
||||
const targetUserId = data.user_id;
|
||||
if (!targetUserId || !wantedVehicleId) {
|
||||
logger.error(`Missing targetUserId or targetVehicleId`);
|
||||
return false;
|
||||
}
|
||||
const userIfExist = await MySqlService.User.getById(DbHandler, targetUserId);
|
||||
if (!userIfExist[0]) {
|
||||
logger.error(`User does not exist`);
|
||||
return false;
|
||||
}
|
||||
const targetUser = userIfExist[0]
|
||||
if (!targetUser.id) return false;
|
||||
const vehicleIfExist = await MySqlService.Vehicle.getById(DbHandler, wantedVehicleId);
|
||||
if (!vehicleIfExist[0] || !vehicleIfExist[0].id) {
|
||||
logger.error(`Vehicle does not exist`);
|
||||
return false;
|
||||
}
|
||||
const vehicleId = vehicleIfExist[0].id
|
||||
if (!vehicleIfExist[0].isAvailable) {
|
||||
logger.error(`Vehicle is not available`);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const result = await MySqlService.Rent.insert(DbHandler, {
|
||||
id: v4(),
|
||||
vehicle_id: vehicleId,
|
||||
user_id: targetUser.id,
|
||||
active: data.active,
|
||||
iat: new Date(Date.parse(`${data.iat}`)),
|
||||
eat: new Date(Date.parse(`${data.eat}`)),
|
||||
need_survey: data.need_survey,
|
||||
km_at_start: Number.parseInt(`${data.km_at_start}`)
|
||||
});
|
||||
if (result.affectedRows !== 0) {
|
||||
logger.info("\n\n> Success !");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
logger.error(`\n\n> Error creating category: \n${error}\n`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function updateRentService(data: IDbRent) {
|
||||
if (isDebugMode()) logger.debug(`\n\n> Updating a rent...\n`);
|
||||
const wantedVehicleId = data.id;
|
||||
const targetUserId = data.user_id;
|
||||
if (!targetUserId || !wantedVehicleId || !data.id) {
|
||||
logger.error(`Missing targetUserId or targetVehicleId`);
|
||||
return false;
|
||||
}
|
||||
const rentIfExist = await MySqlService.Rent.getById(DbHandler, data.id);
|
||||
if (!rentIfExist[0]) {
|
||||
logger.error(`Rent does not exist`);
|
||||
return false;
|
||||
}
|
||||
const rentId = rentIfExist[0].id;
|
||||
if (!rentId) {
|
||||
logger.error(`RentId does not exist`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const userIfExist = await MySqlService.User.getById(DbHandler, targetUserId);
|
||||
if (!userIfExist[0]) {
|
||||
logger.error(`User does not exist`);
|
||||
return false;
|
||||
}
|
||||
const targetUser = userIfExist[0]
|
||||
if (!targetUser.id) return false;
|
||||
const vehicleIfExist = await MySqlService.Vehicle.getById(DbHandler, wantedVehicleId);
|
||||
if (!vehicleIfExist[0] || !vehicleIfExist[0].id) {
|
||||
logger.error(`Vehicle does not exist`);
|
||||
return false;
|
||||
}
|
||||
const vehicleId = vehicleIfExist[0].id
|
||||
try {
|
||||
const result = await MySqlService.Rent.update(DbHandler, {
|
||||
id: rentId,
|
||||
vehicle_id: vehicleId,
|
||||
user_id: targetUser.id,
|
||||
active: data.active,
|
||||
iat: new Date(Date.parse(`${data.iat}`)),
|
||||
eat: new Date(Date.parse(`${data.eat}`)),
|
||||
need_survey: data.need_survey,
|
||||
km_at_start: Number.parseInt(`${data.km_at_start}`)
|
||||
});
|
||||
if (result.affectedRows !== 0) {
|
||||
logger.info("\n\n> Success !");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
logger.error(`\n\n> Error updating category: \n${error}\n`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function getAllAssignedRentService() {
|
||||
const result = await MySqlService.Rent.getAllAssigned(DbHandler);
|
||||
if (result.length > 0) {
|
||||
return result;
|
||||
}
|
||||
logger.warn(`No assigned rents found`);
|
||||
return [];
|
||||
}
|
||||
|
||||
async function getRentByIdService(rentId: string) {
|
||||
if (!rentId || rentId.length !== 36) {
|
||||
logger.warn(`Id missing or not conform`)
|
||||
return false;
|
||||
}
|
||||
const rent = await MySqlService.Rent.getById(DbHandler, rentId);
|
||||
if (rent.length > 0) {
|
||||
return rent[0];
|
||||
}
|
||||
logger.warn(`Rent not found`);
|
||||
return null;
|
||||
}
|
||||
|
||||
async function deleteRentService(rentId: string) {
|
||||
const rentIfExist = await MySqlService.Rent.getById(DbHandler, rentId);
|
||||
if (!rentIfExist[0]) {
|
||||
logger.error(`Rent does not exist`);
|
||||
return false;
|
||||
}
|
||||
const target = rentIfExist[0]
|
||||
if (!target.id) return false;
|
||||
try {
|
||||
const result = await MySqlService.Rent.delete(DbHandler, target.id);
|
||||
if (result.affectedRows !== 0) {
|
||||
logger.info("\n\n> Success !");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
logger.error(`\n\n> Error deleting rent: \n${error}\n`);
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function getUserRentService(userId: string) {
|
||||
if (!userId) {
|
||||
logger.warn(`Missing userId`);
|
||||
return false;
|
||||
}
|
||||
const rents = await MySqlService.Rent.getAssignedToUser(DbHandler, userId);
|
||||
if (rents.length > 0) {
|
||||
return rents;
|
||||
}
|
||||
logger.warn(`No rents found for user`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isDebugMode()) logger.debug("\nService loaded.");
|
||||
|
||||
const VehicleService = {
|
||||
create: createRentService,
|
||||
update: updateRentService,
|
||||
getAll: getAllAssignedRentService,
|
||||
getById: getRentByIdService,
|
||||
delete: deleteRentService,
|
||||
getUserRent: getUserRentService,
|
||||
};
|
||||
|
||||
export default VehicleService;
|
||||
@@ -1,14 +1,14 @@
|
||||
import type {IDbUser} from "@interfaces/database/IDbUser";
|
||||
import type {IReqLogin} from "@interfaces/requests/IReqLogin";
|
||||
import type {IReqRegister} from "@interfaces/requests/IReqRegister";
|
||||
import {ErrorType, type ISError} from "@interfaces/services/ISError";
|
||||
import type { IDbUser } from "@interfaces/database/IDbUser";
|
||||
import type { IReqLogin } from "@interfaces/requests/IReqLogin";
|
||||
import type { IReqRegister } from "@interfaces/requests/IReqRegister";
|
||||
import { ErrorType, type ISError } from "@interfaces/services/ISError";
|
||||
import type { IUserUpdate } from "@interfaces/services/IUserUpdate";
|
||||
import CredentialService from "@services/credential.service";
|
||||
import JwtService from "@services/jwt.service";
|
||||
import MySqlService from "@services/mysql.service";
|
||||
import MysqlService from "@services/mysql.service";
|
||||
import {Logger} from "tslog";
|
||||
import {v4} from "uuid";
|
||||
|
||||
import { isDebugMode } from "@utils/debugState";
|
||||
import { Logger } from "tslog";
|
||||
import { v4 } from "uuid";
|
||||
|
||||
const logger = new Logger({
|
||||
name: "UserService",
|
||||
@@ -28,14 +28,18 @@ const DbHandler = new MySqlService.Handler("UserService");
|
||||
async function getUserByEmail(targetEmail: string): Promise<IDbUser | ISError> {
|
||||
try {
|
||||
const dbUser = await MySqlService.User.getByEmail(DbHandler, targetEmail);
|
||||
if (dbUser === undefined) {
|
||||
logger.info(`User not found (${targetEmail})`);
|
||||
if (dbUser.length === 0) {
|
||||
logger.info(`\n\n> User not found (${targetEmail})\n`);
|
||||
return {
|
||||
error: ErrorType.NotFound,
|
||||
message: "The user was not fund.",
|
||||
};
|
||||
}
|
||||
return dbUser;
|
||||
if (dbUser.length === 1 && dbUser[0]) return dbUser[0];
|
||||
return {
|
||||
error: ErrorType.ServiceError,
|
||||
message: "To many user found, suspicious.",
|
||||
};
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
return {
|
||||
@@ -54,21 +58,26 @@ async function getUserByEmail(targetEmail: string): Promise<IDbUser | ISError> {
|
||||
async function getUserFromIdService(id: string): Promise<IDbUser | ISError> {
|
||||
try {
|
||||
if (!id || id.length !== 36) {
|
||||
logger.info(`Invalid ID (${id})`);
|
||||
logger.info(`\n\n> Invalid ID (${id})\n`);
|
||||
return {
|
||||
error: ErrorType.InvalidData,
|
||||
message: "Invalid ID length.",
|
||||
};
|
||||
}
|
||||
const dbUser = await MySqlService.User.getById(DbHandler, id);
|
||||
if (dbUser === undefined) {
|
||||
if (dbUser.length === 0) {
|
||||
logger.info(`User not found (${id})`);
|
||||
return {
|
||||
error: ErrorType.NotFound,
|
||||
message: "The user was not found.",
|
||||
};
|
||||
}
|
||||
return dbUser;
|
||||
const firstUser = dbUser[0];
|
||||
if (firstUser) return firstUser;
|
||||
return {
|
||||
error: ErrorType.ServiceError,
|
||||
message: "No user found.",
|
||||
};
|
||||
} catch (err) {
|
||||
return {
|
||||
error: ErrorType.DatabaseError,
|
||||
@@ -77,181 +86,237 @@ async function getUserFromIdService(id: string): Promise<IDbUser | ISError> {
|
||||
}
|
||||
}
|
||||
|
||||
async function register(ReqData: IReqRegister): Promise<ISError | string> {
|
||||
if (ReqData.password.length < 6) {
|
||||
/*
|
||||
DbHandler.factorize({
|
||||
values: {
|
||||
id: '011010101',
|
||||
username: 'avnyr',
|
||||
age: 42,
|
||||
is_admin: true
|
||||
},
|
||||
actionName: "Testing"
|
||||
}).then((result)=>{
|
||||
logger.trace(`\n\n> ${result._valuesArray.join(', ')}\n\n> ${result.totalFields}\n\n> ${result._keysTemplate}\n`)
|
||||
})*/
|
||||
|
||||
/**
|
||||
* Registers a new user.
|
||||
*
|
||||
* @param {IReqRegister} inputData - The input data for registration.
|
||||
* @return {Promise<ISError | string>} - A Promise that resolves to either an error or a token.
|
||||
*/
|
||||
async function register(inputData: IReqRegister): Promise<ISError | string> {
|
||||
try {
|
||||
if (inputData.password.length < 6) {
|
||||
return {
|
||||
error: ErrorType.InvalidData,
|
||||
message: "Password must be at least 6 characters long.",
|
||||
};
|
||||
}
|
||||
|
||||
const passwordHash = await CredentialService.hash(`${inputData.password}`);
|
||||
|
||||
// Does the new user has accepted GDPR ?
|
||||
if (inputData.gdpr !== true) {
|
||||
return {
|
||||
error: ErrorType.InvalidData,
|
||||
message: "GDPR acceptance is required.",
|
||||
};
|
||||
}
|
||||
const currentDate = new Date();
|
||||
|
||||
// Check if exist and return
|
||||
const dbUserIfExist: IDbUser | ISError = await getUserByEmail(
|
||||
inputData.email,
|
||||
);
|
||||
if ("username" in dbUserIfExist) {
|
||||
logger.info(
|
||||
`\n\n> User already exist for email "${inputData.email}".\n(${dbUserIfExist.username}::${dbUserIfExist.id})\n`,
|
||||
);
|
||||
return {
|
||||
error: ErrorType.UnAuthorized,
|
||||
message: "User already exists.",
|
||||
};
|
||||
}
|
||||
const currentId = v4();
|
||||
logger.info(`\n\n> Trying to insert a new user... (${currentId})\n`);
|
||||
const NewUser = await MySqlService.User.insert(DbHandler, {
|
||||
id: currentId,
|
||||
email: inputData.email,
|
||||
username: inputData.username,
|
||||
firstname: inputData.firstName,
|
||||
lastname: inputData.lastName,
|
||||
dob: new Date(),
|
||||
hash: passwordHash,
|
||||
gdpr: currentDate,
|
||||
is_admin: false,
|
||||
is_email_verified: false,
|
||||
});
|
||||
if ("error" in NewUser && NewUser.affectedRows === 0) {
|
||||
return {
|
||||
error: ErrorType.DatabaseError,
|
||||
message: "Error when inserting user in database.",
|
||||
};
|
||||
}
|
||||
logger.info(
|
||||
`\n\n> New user created ! (${inputData.username}::${currentId})\n`,
|
||||
);
|
||||
|
||||
// JWT
|
||||
return await JwtService.sign(
|
||||
{
|
||||
sub: currentId,
|
||||
},
|
||||
{
|
||||
alg: "HS512",
|
||||
},
|
||||
"1d",
|
||||
"user",
|
||||
);
|
||||
} catch (err) {
|
||||
logger.error(`\n\n${err}\n`);
|
||||
return {
|
||||
error: ErrorType.InvalidData,
|
||||
message: "Password must be at least 6 characters long.",
|
||||
error: ErrorType.DatabaseError,
|
||||
message: "An unknown error occurred.",
|
||||
};
|
||||
}
|
||||
const passwordHash = await CredentialService.hash(`${ReqData.password}`);
|
||||
|
||||
// Does the new user has accepted GDPR ?
|
||||
if (ReqData.gdpr !== true) {
|
||||
return {
|
||||
error: ErrorType.InvalidData,
|
||||
message: "GDPR acceptance is required.",
|
||||
};
|
||||
}
|
||||
const currentDate = new Date();
|
||||
|
||||
// Check if exist and return
|
||||
const dbUserIfExist: IDbUser | ISError = await getUserByEmail(ReqData.email);
|
||||
if ("error" in dbUserIfExist) {
|
||||
return {
|
||||
error: dbUserIfExist.error,
|
||||
message: dbUserIfExist.message,
|
||||
};
|
||||
}
|
||||
|
||||
const NewUser = await MySqlService.User.insert(DbHandler, {
|
||||
id: v4(),
|
||||
email: ReqData.email,
|
||||
username: ReqData.username,
|
||||
firstname: ReqData.firstName,
|
||||
lastname: ReqData.lastName,
|
||||
dob: ReqData.dob,
|
||||
hash: passwordHash,
|
||||
gdpr: currentDate,
|
||||
is_admin: false,
|
||||
is_mail_verified: false,
|
||||
});
|
||||
if ("error" in NewUser || !NewUser.id) {
|
||||
return {
|
||||
error: ErrorType.DatabaseError,
|
||||
message: 'Error when inserting user in database.'
|
||||
};
|
||||
}
|
||||
|
||||
// JWT
|
||||
const token = await JwtService.sign(
|
||||
{
|
||||
sub: NewUser.id,
|
||||
},
|
||||
{
|
||||
alg: "HS512",
|
||||
},
|
||||
"1d",
|
||||
"user",
|
||||
);
|
||||
return token;
|
||||
}
|
||||
|
||||
async function login(ReqData: IReqLogin) {
|
||||
//const passwordHash = await getHashFromPassword(sanitizedData.password);
|
||||
const dbUser = await MysqlService.User.getByUsername(
|
||||
DbHandler,
|
||||
ReqData.username,
|
||||
);
|
||||
if (!dbUser) {
|
||||
console.log(`LoginService :> User does not exist (${ReqData.username})`);
|
||||
/**
|
||||
* Logs in a user with the provided input data.
|
||||
*
|
||||
* @param inputData - The input data for the login operation.
|
||||
* @property email - The email of the user.
|
||||
* @property password - The password of the user.
|
||||
* @returns A promise that resolves to either an error or a token string.
|
||||
* @throws {ISError} - If an error occurs in the login process.
|
||||
* @throws {string} - If the login was successful, returns a token string.
|
||||
*/
|
||||
async function login(inputData: IReqLogin): Promise<ISError | string> {
|
||||
try {
|
||||
const dbUser = await getUserByEmail(inputData.email);
|
||||
if ("error" in dbUser) {
|
||||
return {
|
||||
error: dbUser.error,
|
||||
message: dbUser.message,
|
||||
};
|
||||
}
|
||||
if (!dbUser?.id) {
|
||||
return {
|
||||
error: ErrorType.NotFound,
|
||||
message: "User not found.",
|
||||
};
|
||||
}
|
||||
const isPasswordValid = await CredentialService.compare(
|
||||
inputData.password,
|
||||
dbUser.hash,
|
||||
);
|
||||
if (!isPasswordValid) {
|
||||
return {
|
||||
error: ErrorType.UnAuthorized,
|
||||
message: "Invalid password.",
|
||||
};
|
||||
}
|
||||
// Generate the JSDoc definition for those html status code
|
||||
const token = await JwtService.sign(
|
||||
{
|
||||
sub: dbUser.id,
|
||||
p: [
|
||||
{
|
||||
isAdmin: dbUser.is_admin,
|
||||
gdpr: dbUser.gdpr,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
alg: "HS512",
|
||||
},
|
||||
"1d",
|
||||
"user",
|
||||
);
|
||||
if (isDebugMode())
|
||||
logger.trace(
|
||||
`\n\n> New token for login of "${dbUser.username}".\n${token}`,
|
||||
);
|
||||
return token;
|
||||
} catch (err) {
|
||||
logger.error(`\n\n${err}\n`);
|
||||
return {
|
||||
error: "userNotFound",
|
||||
error: ErrorType.DatabaseError,
|
||||
message: "An unknown error occurred.",
|
||||
};
|
||||
}
|
||||
if (ReqData.password.length < 6) {
|
||||
console.log("X");
|
||||
console.log(`LoginService :> Invalid password (${ReqData.username})`);
|
||||
return {
|
||||
error: "invalidPassword",
|
||||
};
|
||||
}
|
||||
const isPasswordValid = await CredentialService.compare(
|
||||
ReqData.password,
|
||||
dbUser.hash,
|
||||
);
|
||||
if (!isPasswordValid) {
|
||||
console.log(isPasswordValid);
|
||||
console.log(`LoginService :> Invalid password (${ReqData.username})`);
|
||||
return {
|
||||
error: "invalidPassword",
|
||||
};
|
||||
}
|
||||
// biome-ignore lint/style/useConst: <explanation>
|
||||
let userData = {
|
||||
error: "none",
|
||||
jwt: "",
|
||||
user: {
|
||||
id: dbUser.id,
|
||||
username: dbUser.username,
|
||||
displayName: dbUser.displayName,
|
||||
},
|
||||
};
|
||||
|
||||
userData.jwt = await JwtService.sign(
|
||||
{
|
||||
sub: dbUser.id,
|
||||
},
|
||||
{
|
||||
alg: "HS512",
|
||||
},
|
||||
"7d",
|
||||
"user",
|
||||
);
|
||||
|
||||
console.log("USERDATA :>");
|
||||
console.log(userData);
|
||||
return userData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a user from the database by email.
|
||||
*
|
||||
* @param {string} email - The email associated with the user.
|
||||
* @return {Promise<IDbUser | false>} - A Promise that resolves to the user (if found) or false (if not found).
|
||||
*/
|
||||
async function getByEmailService(email: string): Promise<IDbUser | false> {
|
||||
const dbUser = await MySqlService.User.getByEmail(DbHandler, email);
|
||||
if (dbUser.length === 0) {
|
||||
if (isDebugMode()) logger.trace(`\n\n> User not found in DB (${email})\n`);
|
||||
return false;
|
||||
}
|
||||
if (isDebugMode()) logger.trace(dbUser);
|
||||
if (dbUser.length > 1 && dbUser[0]) return dbUser[0];
|
||||
return false;
|
||||
}
|
||||
|
||||
//TOTest
|
||||
/**
|
||||
* Retrieves all users from the database.
|
||||
*
|
||||
* @async
|
||||
* @function getAllUsersService
|
||||
* @returns {Promise<{iat: number, users: Array<user>, length: number}>} - The response object containing the users array and its length.
|
||||
* @returns {Promise<Array<IDbUser> | ISError>} The list of users, or an error object if an error occurred.
|
||||
*/
|
||||
async function getAllUsersService() {
|
||||
const users = await Db.collection("users").find().toArray();
|
||||
// biome-ignore lint/complexity/noForEach: <explanation>
|
||||
users.forEach((user) => {
|
||||
delete user.passwordHash;
|
||||
delete user._id;
|
||||
delete user.gdpr;
|
||||
});
|
||||
logger.info(`Query ${users.length} user(s)`);
|
||||
return {
|
||||
iat: Date.now(),
|
||||
users: users,
|
||||
length: users.length,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits a user in the database.
|
||||
*
|
||||
* @param {string} targetId - The ID of the user to be edited.
|
||||
* @param {object} sanitizedData - The sanitized data to update the user with.
|
||||
* @returns {object} - An object indicating the result of the operation.
|
||||
* If the user is not found, the error property will be a string "userNotFound".
|
||||
* Otherwise, the error property will be a string "none".
|
||||
*/
|
||||
async function editUserService(targetId, sanitizedData) {
|
||||
if (sanitizedData.password) {
|
||||
const passwordHash = await getHashFromPassword(sanitizedData.password);
|
||||
delete sanitizedData.password;
|
||||
logger.info(`Changing password for user "${targetId}"`);
|
||||
sanitizedData.passwordHash = passwordHash;
|
||||
}
|
||||
const updatedUserResult = await Db.collection("users").updateOne(
|
||||
{
|
||||
id: targetId,
|
||||
},
|
||||
{
|
||||
$set: sanitizedData,
|
||||
},
|
||||
);
|
||||
if (updatedUserResult.modifiedCount === 0) {
|
||||
logger.info(`EDIT :> User not found (${targetId})`);
|
||||
async function getAllUsersService(): Promise<Array<IDbUser> | ISError> {
|
||||
try {
|
||||
const allUsers = await MySqlService.User.getAll(DbHandler);
|
||||
if (allUsers === undefined) {
|
||||
logger.error(`Error retrieving all users.`);
|
||||
return {
|
||||
error: ErrorType.DatabaseError,
|
||||
message: "An unknown error occurred.",
|
||||
};
|
||||
}
|
||||
return allUsers;
|
||||
} catch (err) {
|
||||
logger.error(`\n\n${err}\n`);
|
||||
return {
|
||||
error: "userNotFound",
|
||||
error: ErrorType.DatabaseError,
|
||||
message: "An unknown error occurred.",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(`EDIT :> User updated (${targetId})`);
|
||||
return {
|
||||
error: "none",
|
||||
};
|
||||
async function editUserService(
|
||||
targetId: string,
|
||||
inputData: IUserUpdate,
|
||||
): Promise<ISError | boolean> {
|
||||
if (!targetId || targetId.length !== 36) {
|
||||
logger.info(`\n\n> Invalid ID (${targetId})\n`);
|
||||
return {
|
||||
error: ErrorType.InvalidData,
|
||||
message: "Invalid ID length.",
|
||||
};
|
||||
}
|
||||
const dbUser = await MySqlService.User.getById(DbHandler, targetId);
|
||||
if (!dbUser[0] || !dbUser[0].id) {
|
||||
return {
|
||||
error: ErrorType.NotFound,
|
||||
message: "User not found.",
|
||||
};
|
||||
}
|
||||
const result = await MySqlService.User.update(DbHandler, inputData);
|
||||
if (result.affectedRows === 0) {
|
||||
return {
|
||||
error: ErrorType.DatabaseError,
|
||||
message: "An unknown error occurred.",
|
||||
};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,24 +325,25 @@ async function editUserService(targetId, sanitizedData) {
|
||||
* @param {string} targetId - The ID of the user to be deleted.
|
||||
* @return {Promise<boolean>} - A promise that resolves to true if the user is successfully deleted, or false if an error occurs.
|
||||
*/
|
||||
async function deleteUserService(targetId) {
|
||||
async function deleteUserService(targetId: string): Promise<boolean> {
|
||||
logger.info(`Deleting user ${targetId}`);
|
||||
try {
|
||||
await Db.collection("users").deleteOne({
|
||||
id: targetId,
|
||||
});
|
||||
return true;
|
||||
const DeleteResult = await MySqlService.User.delete(DbHandler, targetId);
|
||||
return DeleteResult.affectedRows !== 0;
|
||||
} catch (e) {
|
||||
logger.warn(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDebugMode()) logger.debug("\nService loaded.");
|
||||
|
||||
const UserService = {
|
||||
register: register,
|
||||
login: login,
|
||||
getAll: getAllUsersService,
|
||||
getFromId: getUserFromIdService,
|
||||
getByEmail: getByEmailService,
|
||||
edit: editUserService,
|
||||
delete: deleteUserService,
|
||||
};
|
||||
|
||||
125
src/services/vehicle.service.ts
Normal file
125
src/services/vehicle.service.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import type { IDbVehicle } from "@interfaces/database/IDbVehicle";
|
||||
//import { ErrorType, type ISError } from "@interfaces/services/ISError";
|
||||
import MySqlService from "@services/mysql.service";
|
||||
import { isDebugMode } from "@utils/debugState";
|
||||
import { Logger } from "tslog";
|
||||
import { v4 } from "uuid";
|
||||
|
||||
const logger = new Logger({
|
||||
name: "VehicleService",
|
||||
});
|
||||
|
||||
const DbHandler = new MySqlService.Handler("VehicleService");
|
||||
|
||||
async function createVehicleService(data: IDbVehicle) {
|
||||
if (isDebugMode()) logger.debug(`\n\n> Creating a new vehicle...\n`);
|
||||
try {
|
||||
const result = await MySqlService.Vehicle.insert(DbHandler, {
|
||||
id: v4(),
|
||||
plate_number: data.plate_number,
|
||||
model_id: data.model_id,
|
||||
odometer: data.odometer | 0,
|
||||
health_state: data.health_state,
|
||||
});
|
||||
if (result.affectedRows !== 0) {
|
||||
logger.info("\n\n> Success !");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
logger.error(`\n\n> Error creating category: \n${error}\n`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function updateVehicleService(data: IDbVehicle) {
|
||||
if (isDebugMode()) logger.debug(`\n\n> Updating vehicle...\n`);
|
||||
try {
|
||||
if (!data.id) {
|
||||
return false;
|
||||
}
|
||||
const result = await MySqlService.Vehicle.update(DbHandler, {
|
||||
id: data.id,
|
||||
plate_number: data.plate_number,
|
||||
model_id: data.model_id,
|
||||
odometer: data.odometer | 0,
|
||||
health_state: data.health_state,
|
||||
});
|
||||
if (result.affectedRows !== 0) {
|
||||
logger.info("\n\n> Success !");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
logger.error(`\n\n> Error updating vehicle: \n${error}\n`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function getAllVehiclesService() {
|
||||
try {
|
||||
const result = await MySqlService.Vehicle.getAll(DbHandler);
|
||||
return {
|
||||
iat: Date.now(),
|
||||
vehicles: result,
|
||||
total: result.length,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error(`\n\n> Error getting vehicles: \n${error}\n`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function getVehicleByIdService(vehicleId: string) {
|
||||
try {
|
||||
const result = await MySqlService.Vehicle.getById(DbHandler, vehicleId);
|
||||
return {
|
||||
iat: Date.now(),
|
||||
vehicle: result,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error(`\n\n> Error getting vehicle by id: \n${error}\n`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function getAvailableVehicleService() {
|
||||
try {
|
||||
const result = await MySqlService.Vehicle.getAvailable(DbHandler);
|
||||
return {
|
||||
iat: Date.now(),
|
||||
vehicles: result,
|
||||
total: result.length,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error(`\n\n> Error getting available vehicles: \n${error}\n`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteVehicleService(vehicleId: string) {
|
||||
try {
|
||||
const result = await MySqlService.Vehicle.delete(DbHandler, vehicleId);
|
||||
if (result.affectedRows !== 0) {
|
||||
logger.info("\n\n> Success !");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
logger.error(`\n\n> Error deleting vehicle: \n${error}\n`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDebugMode()) logger.debug("\nService loaded.");
|
||||
|
||||
const VehicleService = {
|
||||
create: createVehicleService,
|
||||
update: updateVehicleService,
|
||||
getAll: getAllVehiclesService,
|
||||
getById: getVehicleByIdService,
|
||||
delete: deleteVehicleService,
|
||||
getAvailable: getAvailableVehicleService,
|
||||
};
|
||||
|
||||
export default VehicleService;
|
||||
8
src/utils/debugState.ts
Normal file
8
src/utils/debugState.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import process from "node:process";
|
||||
|
||||
export function isDebugMode() {
|
||||
if (process.env["DEBUG"] === "true") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
5
src/utils/validators/email.ts
Normal file
5
src/utils/validators/email.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export function isEmail(email: string) {
|
||||
const re =
|
||||
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
return re.test(String(email).toLowerCase());
|
||||
}
|
||||
@@ -33,7 +33,7 @@ async function AdminGuard(req: Request, res: Response, next: NextFunction) {
|
||||
|
||||
const token = await JwtService.verify(bearerToken);
|
||||
|
||||
if (token) {
|
||||
if (token && token.sub) {
|
||||
// @ts-ignore
|
||||
const isSourceAdmin = await MysqlService.User.getAdminStateForId(
|
||||
DbHandler,
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2017",
|
||||
"module": "es6",
|
||||
"rootDir": "./src",
|
||||
"moduleResolution": "node",
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "ES2021",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"noImplicitAny": true,
|
||||
"strictBindCallApply": true,
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"paths": {
|
||||
"@services/*": [
|
||||
"src/services/*"
|
||||
@@ -26,19 +38,11 @@
|
||||
]
|
||||
},
|
||||
"resolveJsonModule": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"removeComments": false,
|
||||
"noEmitOnError": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictBindCallApply": true,
|
||||
"strictPropertyInitialization": true,
|
||||
"noImplicitThis": true,
|
||||
"useUnknownInCatchVariables": true,
|
||||
@@ -47,12 +51,10 @@
|
||||
"noUnusedParameters": true,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"allowUnusedLabels": true,
|
||||
"allowUnreachableCode": true,
|
||||
"skipLibCheck": true
|
||||
"allowUnreachableCode": true
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user