type: style

scope: services, interfaces

subject: Apply code formatting

- Correct indentation and formatting to match code style standards in multiple 'interfaces' and 'services' files.
- Also ensure lines at the end of the files.

Signed-off-by: Mathis <yidhra@tuta.io>
This commit is contained in:
Mathis H (Avnyr) 2024-04-30 10:55:37 +02:00
parent cda313866f
commit 56bfd8cd0d
Signed by: Mathis
GPG Key ID: DD9E0666A747D126
33 changed files with 1708 additions and 1176 deletions

View File

@ -3,6 +3,15 @@
"organizeImports": { "organizeImports": {
"enabled": true "enabled": true
}, },
"files": {
"include": [
"./src/**/*.ts"
]
},
"vcs": {
"enabled": true,
"clientKind": "git"
},
"linter": { "linter": {
"enabled": true, "enabled": true,
"rules": { "rules": {
@ -17,8 +26,8 @@
} }
}, },
"formatter": { "formatter": {
"indentStyle": "space", "indentStyle": "tab",
"indentWidth": 2, "indentWidth": 2,
"lineWidth": 15 "lineWidth": 64
} }
} }

View File

@ -7,7 +7,8 @@
"author": "Mathis HERRIOT", "author": "Mathis HERRIOT",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"bun:dev": "bun run --watch src/app.ts" "bun:dev": "bun run --watch src/app.ts",
"bun:check": "bunx biome check --skip-errors --apply src"
}, },
"dependencies": { "dependencies": {
"@node-rs/argon2": "^1.8.3", "@node-rs/argon2": "^1.8.3",

View File

@ -1,21 +1,22 @@
import express, { type Express } from 'express'; import * as process from "node:process";
import cors from 'cors';
import compression from 'compression';
import {Logger} from "tslog";
import helmet from "helmet";
import AuthRouter from "@routes/auth/authRouter"; import AuthRouter from "@routes/auth/authRouter";
import CatalogRouter from "@routes/catalog/catalogRouter"; import CatalogRouter from "@routes/catalog/catalogRouter";
import RentRouter from "@routes/rent/rentRouter"; import RentRouter from "@routes/rent/rentRouter";
import * as process from "node:process"; import compression from "compression";
import cors from "cors";
import express, { type Express } from "express";
import helmet from "helmet";
import { Logger } from "tslog";
const logger = new Logger({
const logger = new Logger({ name: "App" }); name: "App",
});
const app: Express = express(); const app: Express = express();
// enable cors // enable cors
app.use(cors()); app.use(cors());
app.options('*', cors()); app.options("*", cors());
// enable xss sanitizer // enable xss sanitizer
app.use( app.use(
@ -23,30 +24,34 @@ app.use(
xXssProtection: true, xXssProtection: true,
}), }),
); );
app.use(helmet.xXssProtection()) app.use(helmet.xXssProtection());
// parse json request body // parse json request body
app.use(express.json()); app.use(express.json());
// parse urlencoded request body // parse urlencoded request body
app.use(express.urlencoded({ extended: true })); app.use(
express.urlencoded({
extended: true,
}),
);
// gzip compression // gzip compression
app.use(compression()) app.use(compression());
try { try {
app.use('/auth', AuthRouter) app.use("/auth", AuthRouter);
app.use('/catalog', CatalogRouter) app.use("/catalog", CatalogRouter);
app.use('/rent', RentRouter) app.use("/rent", RentRouter);
logger.info('Routers loaded !') logger.info("Routers loaded !");
} catch (err) { } catch (err) {
logger.error(err) logger.error(err);
throw null; throw null;
} }
try { try {
app.listen(process.env["APP_PORT"]) app.listen(process.env["APP_PORT"]);
logger.info('Server is running !') logger.info("Server is running !");
} catch (error) { } catch (error) {
logger.error(`Server failed to start: ${error}`); logger.error(`Server failed to start: ${error}`);
process.exit(1); process.exit(1);

View File

@ -1,13 +1,13 @@
import JwtService from "@services/jwt.service"; import JwtService from "@services/jwt.service";
import type { IReqEditUserData } from "@interfaces/IReqEditUserData"; import type { IReqEditUserData } from "@interfaces/IReqEditUserData";
import UserService from "@services/user.service"; import UserService from "@services/user.service";
import type { Request, Response } from "express"; import type { Request, Response } from "express";
import { Logger } from "tslog"; import { Logger } from "tslog";
const logger = new Logger({
const logger = new Logger({ name: "AuthController" }); name: "AuthController",
});
//FIX Better return object interface //FIX Better return object interface
/** /**
@ -22,25 +22,34 @@ const logger = new Logger({ name: "AuthController" });
* - error: "exist" if the user already exists * - error: "exist" if the user already exists
* - Otherwise, the registered user data * - Otherwise, the registered user data
*/ */
async function registerUser(req: Request, res: Response): Promise<unknown> { async function registerUser(
req: Request,
res: Response,
): Promise<unknown> {
const body = req.body; const body = req.body;
if (!body) { if (!body) {
logger.warn(`Invalid input data (${req.ip})`); logger.warn(`Invalid input data (${req.ip})`);
return res return res.type("application/json").status(400).json({
.type('application/json') error: "Invalid input data",
.status(400) });
.json({ error: 'Invalid input data' });
} }
if (!body.password || !body.username || !body.firstName || !body.lastName || !body.displayName) { if (
!body.password ||
!body.username ||
!body.firstName ||
!body.lastName ||
!body.displayName
) {
logger.warn(`Field(s) missing (${req.ip})`); logger.warn(`Field(s) missing (${req.ip})`);
return res return res.type("application/json").status(400).json({
.type('application/json') error: "Field(s) missing",
.status(400) });
.json({ error: 'Field(s) missing' });
} }
let gdpr = false let gdpr = false;
if (body.gdpr === true) {gdpr = true} if (body.gdpr === true) {
gdpr = true;
}
const sanitizeData = { const sanitizeData = {
username: `${body.username}`, username: `${body.username}`,
displayName: `${body.displayName}`, displayName: `${body.displayName}`,
@ -50,32 +59,28 @@ async function registerUser(req: Request, res: Response): Promise<unknown> {
lastName: `${body.lastName}`, lastName: `${body.lastName}`,
}; };
const RegisterServiceResult = await UserService.register(sanitizeData) const RegisterServiceResult =
await UserService.register(sanitizeData);
if (RegisterServiceResult.error === "gdprNotApproved") { if (RegisterServiceResult.error === "gdprNotApproved") {
logger.warn(`GDPR not approved (${req.ip})`); logger.warn(`GDPR not approved (${req.ip})`);
return res return res.status(400).json({
.status(400)
.json({
error: RegisterServiceResult.error, error: RegisterServiceResult.error,
message: "GDPR not accepted." message: "GDPR not accepted.",
}); });
} }
if (RegisterServiceResult.error === "exist") { if (RegisterServiceResult.error === "exist") {
logger.warn(`The user already exists (${req.ip})`); logger.warn(`The user already exists (${req.ip})`);
return res return res.type("application/json").status(400).json({
.type('application/json')
.status(400)
.json({
error: RegisterServiceResult.error, error: RegisterServiceResult.error,
message: "The user already exists." message: "The user already exists.",
}); });
} }
// SUCCESS // SUCCESS
logger.info(`User registered successfully (${req.ip})`); logger.info(`User registered successfully (${req.ip})`);
return res return res
.type('application/json') .type("application/json")
.status(201) .status(201)
.json(RegisterServiceResult); .json(RegisterServiceResult);
} }
@ -88,366 +93,340 @@ async function registerUser(req: Request, res: Response): Promise<unknown> {
* *
* @return {Promise<void>} A promise that resolves when the user is logged in or rejects with an error. * @return {Promise<void>} A promise that resolves when the user is logged in or rejects with an error.
*/ */
async function loginUser(req: Request, res: Response): Promise<void> { async function loginUser(
req: Request,
res: Response,
): Promise<void> {
const body = req.body; const body = req.body;
if (!body) { if (!body) {
res res.type("application/json").status(400).json({
.type('application/json') error: "Invalid input data",
.status(400) });
.json({ error: 'Invalid input data' });
} }
if (!body.password || !body.username) { if (!body.password || !body.username) {
logger.warn(`Field(s) missing (${req.ip})`); logger.warn(`Field(s) missing (${req.ip})`);
res res.type("application/json").status(400).json({
.type('application/json') error: "Field(s) missing",
.status(400) });
.json({ error: 'Field(s) missing' });
} }
const loginData = { const loginData = {
username: `${body.username}`, username: `${body.username}`,
password: `${body.password}` password: `${body.password}`,
}; };
console.log(body) console.log(body);
const LoginServiceResult = await UserService.login(loginData); const LoginServiceResult = await UserService.login(loginData);
console.log(LoginServiceResult) console.log(LoginServiceResult);
if (LoginServiceResult.error === "userNotFound") { if (LoginServiceResult.error === "userNotFound") {
console.log('POOL') console.log("POOL");
res res.type("application/json").status(404).json({
.type('application/json')
.status(404)
.json({
error: LoginServiceResult.error, error: LoginServiceResult.error,
message: "User not found." message: "User not found.",
}); });
} }
if (LoginServiceResult.error === "invalidPassword") { if (LoginServiceResult.error === "invalidPassword") {
res res.type("application/json").status(401).json({
.type('application/json')
.status(401)
.json({
error: LoginServiceResult.error, error: LoginServiceResult.error,
message: "Invalid password." message: "Invalid password.",
}); });
} }
res res
.type('application/json') .type("application/json")
.status(200) .status(200)
.json(LoginServiceResult); .json(LoginServiceResult);
} }
async function getAllUsers(req: Request, res: Response) { async function getAllUsers(req: Request, res: Response) {
const authHeader = req.headers.authorization; const authHeader = req.headers.authorization;
const bearerToken = authHeader?.split(' ')[1]; const bearerToken = authHeader?.split(" ")[1];
if (!bearerToken) { if (!bearerToken) {
logger.warn(`Bearer token not provided (${req.ip})`); logger.warn(`Bearer token not provided (${req.ip})`);
return res return res.type("application/json").status(401).json({
.type('application/json') error: "Unauthorized",
.status(401) });
.json({ error: 'Unauthorized' });
} }
const payload = await JwtService.verify(bearerToken); const payload = await JwtService.verify(bearerToken);
if (!payload) { if (!payload) {
logger.warn(`Unauthorized access attempt (${req.ip})`); logger.warn(`Unauthorized access attempt (${req.ip})`);
return res return res.type("application/json").status(401).json({
.type('application/json') error: "Unauthorized",
.status(401) });
.json({ error: 'Unauthorized' });
} }
const sourceUser = await UserService.getFromId(payload.sub) const sourceUser = await UserService.getFromId(payload.sub);
if (!sourceUser) { if (!sourceUser) {
return res return res.type("application/json").status(404).json({
.type('application/json') error: "You dont exist anymore",
.status(404) });
.json({ error: 'You dont exist anymore' });
} }
if (!sourceUser.is_admin) { if (!sourceUser.is_admin) {
return res return res.type("application/json").status(403).json({
.type('application/json') error: "Unauthorized",
.status(403) });
.json({ error: 'Unauthorized' });
} }
const AllUserResponse = await UserService.getAll() const AllUserResponse = await UserService.getAll();
if (!AllUserResponse.users) { if (!AllUserResponse.users) {
return res return res.type("application/json").status(500).json({
.type('application/json') error: "Internal server error",
.status(500) });
.json({ error: 'Internal server error' });
} }
return res return res
.type('application/json') .type("application/json")
.status(200) .status(200)
.json(AllUserResponse); .json(AllUserResponse);
} }
async function getUser(req: Request, res: Response) { async function getUser(req: Request, res: Response) {
const authHeader = req.headers.authorization; const authHeader = req.headers.authorization;
const bearerToken = authHeader?.split(' ')[1]; const bearerToken = authHeader?.split(" ")[1];
if (!bearerToken) { if (!bearerToken) {
logger.warn(`Bearer token not provided (${req.ip})`); logger.warn(`Bearer token not provided (${req.ip})`);
return res return res.type("application/json").status(401).json({
.type('application/json') error: "Unauthorized",
.status(401) });
.json({ error: 'Unauthorized' });
} }
const payload = await JwtService.verify(bearerToken); const payload = await JwtService.verify(bearerToken);
if (!payload) { if (!payload) {
logger.warn(`Unauthorized access attempt (${req.ip})`); logger.warn(`Unauthorized access attempt (${req.ip})`);
return res return res.type("application/json").status(401).json({
.type('application/json') error: "Unauthorized",
.status(401) });
.json({ error: 'Unauthorized' });
} }
const sourceUser = await UserService.getFromId(payload.sub) const sourceUser = await UserService.getFromId(payload.sub);
if (!sourceUser) { if (!sourceUser) {
return res return res.type("application/json").status(404).json({
.type('application/json') error: "You dont exist anymore",
.status(404) });
.json({ error: 'You dont exist anymore' });
} }
if (!sourceUser.is_admin) { if (!sourceUser.is_admin) {
return res return res.type("application/json").status(403).json({
.type('application/json') error: "Unauthorized",
.status(403) });
.json({ error: 'Unauthorized' });
} }
const userId = req.params["id"]; const userId = req.params["id"];
const dbUser = await UserService.getFromId(userId); const dbUser = await UserService.getFromId(userId);
if (!dbUser) { if (!dbUser) {
logger.warn(`User not found (${req.ip})`); logger.warn(`User not found (${req.ip})`);
return res return res.type("application/json").status(404).json({
.type('application/json') error: "User not found",
.status(404) });
.json({ error: 'User not found' });
} }
// @ts-ignore // @ts-ignore
delete dbUser.passwordHash delete dbUser.passwordHash;
// @ts-ignore // @ts-ignore
delete dbUser._id delete dbUser._id;
return res return res.type("application/json").status(200).json(dbUser);
.type('application/json')
.status(200)
.json(dbUser);
} }
//FEAT - Implement re-auth by current password in case of password change //FEAT - Implement re-auth by current password in case of password change
async function editUser(req: Request, res: Response) { async function editUser(req: Request, res: Response) {
const body: IReqEditUserData | null = req.body; const body: IReqEditUserData | null = req.body;
if (!body) { if (!body) {
return res return res.type("application/json").status(400).json({
.type('application/json') error: "Field(s) missing",
.status(400) });
.json({ error: 'Field(s) missing' });
} }
const authHeader = req.headers.authorization; const authHeader = req.headers.authorization;
const bearerToken = authHeader?.split(' ')[1]; const bearerToken = authHeader?.split(" ")[1];
if (!bearerToken) { if (!bearerToken) {
logger.warn(`Bearer token not provided (${req.ip})`); logger.warn(`Bearer token not provided (${req.ip})`);
return res return res.type("application/json").status(401).json({
.type('application/json') error: "Unauthorized",
.status(401) });
.json({ error: 'Unauthorized' });
} }
const payload = await JwtService.verify(bearerToken); const payload = await JwtService.verify(bearerToken);
if (!payload) { if (!payload) {
logger.warn(`Unauthorized access attempt (${req.ip})`); logger.warn(`Unauthorized access attempt (${req.ip})`);
return res return res.type("application/json").status(401).json({
.type('application/json') error: "Unauthorized",
.status(401) });
.json({ error: 'Unauthorized' });
} }
const sourceUser = await UserService.getFromId(payload.sub) const sourceUser = await UserService.getFromId(payload.sub);
//@ts-ignore //@ts-ignore
const targetUserId = req.params.id || payload.sub const targetUserId = req.params.id || payload.sub;
console.log(targetUserId) console.log(targetUserId);
if (!sourceUser) { if (!sourceUser) {
logger.warn(`Unauthorized access attempt (${req.ip})`); logger.warn(`Unauthorized access attempt (${req.ip})`);
return res return res.type("application/json").status(404).json({
.type('application/json') error: "You dont exist anymore",
.status(404) });
.json({ error: 'You dont exist anymore' });
} }
if (sourceUser.is_admin || sourceUser.id === payload.sub) { if (sourceUser.is_admin || sourceUser.id === payload.sub) {
if (sourceUser.is_admin) { if (sourceUser.is_admin) {
logger.info(`EDIT :> Source user is an admin (${sourceUser.firstname} ${sourceUser.lastname})`) logger.info(
`EDIT :> Source user is an admin (${sourceUser.firstname} ${sourceUser.lastname})`,
);
} else { } else {
logger.info(`EDIT :> Source user modify itself (${sourceUser.firstname} ${sourceUser.lastname})`) logger.info(
`EDIT :> Source user modify itself (${sourceUser.firstname} ${sourceUser.lastname})`,
);
} }
//TODO Interface //TODO Interface
const modifiedData = { const modifiedData = {};
}
//@ts-ignore //@ts-ignore
if (body.firstName) modifiedData.firstName = `${body.firstName}`; if (body.firstName)
modifiedData.firstName = `${body.firstName}`;
//@ts-ignore //@ts-ignore
if (body.lastName) modifiedData.lastName = `${body.lastName}`; if (body.lastName)
modifiedData.lastName = `${body.lastName}`;
//@ts-ignore //@ts-ignore
if (body.displayName) modifiedData.displayName = `${body.displayName}`; if (body.displayName)
modifiedData.displayName = `${body.displayName}`;
//TODO Case handled with hashing by the service. //TODO Case handled with hashing by the service.
//if (body.password) modifiedData.password = `${body.password}`; //if (body.password) modifiedData.password = `${body.password}`;
//Call service //Call service
const EditUserServiceResult = await UserService.edit(`${targetUserId}`, modifiedData); const EditUserServiceResult = await UserService.edit(
if (EditUserServiceResult.error === 'userNotFound') { `${targetUserId}`,
modifiedData,
);
if (EditUserServiceResult.error === "userNotFound") {
logger.warn(`User not found (${req.ip})`); logger.warn(`User not found (${req.ip})`);
return res return res.type("application/json").status(404).json({
.type('application/json') error: "User not found",
.status(404) });
.json({ error: 'User not found' });
} }
if (EditUserServiceResult.error !== 'none') { if (EditUserServiceResult.error !== "none") {
logger.error(`Error occurred during user edit (${req.ip})`); logger.error(
return res `Error occurred during user edit (${req.ip})`,
.type('application/json') );
.status(500) return res.type("application/json").status(500).json({
.json({ error: 'Internal server error' }); error: "Internal server error",
});
} }
return res return res
.type('application/json') .type("application/json")
.status(200) .status(200)
.json(EditUserServiceResult); .json(EditUserServiceResult);
} }
//Not itself or //Not itself or
logger.warn(`Unauthorized access attempt, not self or admin (${req.ip})`); logger.warn(
return res `Unauthorized access attempt, not self or admin (${req.ip})`,
.type('application/json') );
.status(403) return res.type("application/json").status(403).json({
.json({ error: 'Unauthorized' }); error: "Unauthorized",
});
} }
async function deleteUser(req: Request, res: Response): Promise<Response> { async function deleteUser(
req: Request,
res: Response,
): Promise<Response> {
const authHeader = req.headers.authorization; const authHeader = req.headers.authorization;
const bearerToken = authHeader?.split(' ')[1]; const bearerToken = authHeader?.split(" ")[1];
if (!bearerToken) { if (!bearerToken) {
logger.warn(`Bearer token not provided (${req.ip})`); logger.warn(`Bearer token not provided (${req.ip})`);
return res return res.type("application/json").status(401).json({
.type('application/json') error: "Unauthorized",
.status(401) });
.json({ error: 'Unauthorized' });
} }
const payload = await JwtService.verify(bearerToken); const payload = await JwtService.verify(bearerToken);
if (!payload) { if (!payload) {
logger.warn(`Invalid token (${req.ip})`); logger.warn(`Invalid token (${req.ip})`);
return res return res.type("application/json").status(401).json({
.type('application/json') error: "Invalid token",
.status(401) });
.json({ error: 'Invalid token' });
} }
const sourceUser = await UserService.getFromId(payload?.sub) const sourceUser = await UserService.getFromId(payload?.sub);
const targetUserId = req.params["id"] const targetUserId = req.params["id"];
if (!sourceUser) { if (!sourceUser) {
logger.warn(`Unauthorized access attempt (${req.ip})`); logger.warn(`Unauthorized access attempt (${req.ip})`);
return res return res.type("application/json").status(404).json({
.type('application/json') error: "You dont exist anymore",
.status(404) });
.json({ error: 'You dont exist anymore' });
} }
if (sourceUser.is_admin || sourceUser.id === payload.sub) { if (sourceUser.is_admin || sourceUser.id === payload.sub) {
const deleteUserServiceResult = await UserService.delete(`${targetUserId}`); const deleteUserServiceResult = await UserService.delete(
`${targetUserId}`,
);
if (!deleteUserServiceResult) { if (!deleteUserServiceResult) {
logger.error(`Error occurred during user delete (${req.ip})`); logger.error(
return res `Error occurred during user delete (${req.ip})`,
.type('application/json') );
.status(500) return res.type("application/json").status(500).json({
.json({ error: 'Internal server error' }); error: "Internal server error",
});
} }
return res return res.type("application/json").status(200).json({
.type('application/json') message: "User deleted successfully",
.status(200) });
.json({ message: 'User deleted successfully' });
} }
return res return res.type("application/json").status(403).json({
.type('application/json') error: "Unauthorized",
.status(403) });
.json({ error: 'Unauthorized' });
} }
async function deleteSelf(req: Request, res: Response) { async function deleteSelf(req: Request, res: Response) {
const authHeader = req.headers.authorization; const authHeader = req.headers.authorization;
const bearerToken = authHeader?.split(' ')[1]; const bearerToken = authHeader?.split(" ")[1];
if (!bearerToken) { if (!bearerToken) {
logger.warn(`Bearer token not provided (${req.ip})`); logger.warn(`Bearer token not provided (${req.ip})`);
return res return res.type("application/json").status(401).json({
.type('application/json') error: "Unauthorized",
.status(401) });
.json({ error: 'Unauthorized' });
} }
const payload = await JwtService.verify(bearerToken); const payload = await JwtService.verify(bearerToken);
if (!payload) { if (!payload) {
logger.warn(`Unauthorized access attempt (${req.ip})`); logger.warn(`Unauthorized access attempt (${req.ip})`);
return res return res.type("application/json").status(401).json({
.type('application/json') error: "Unauthorized",
.status(401) });
.json({ error: 'Unauthorized' });
} }
const sourceUser = await UserService.getFromId(payload.sub) const sourceUser = await UserService.getFromId(payload.sub);
if (!sourceUser) { if (!sourceUser) {
return res return res.type("application/json").status(404).json({
.type('application/json') error: "You dont exist anymore",
.status(404) });
.json({ error: 'You dont exist anymore' });
} }
if (sourceUser.id !== req.params["id"]) { if (sourceUser.id !== req.params["id"]) {
return res return res.type("application/json").status(403).json({
.type('application/json') error: "Unauthorized",
.status(403) });
.json({ error: 'Unauthorized' });
} }
const deleteResult = await UserService.delete(sourceUser.id); const deleteResult = await UserService.delete(sourceUser.id);
if (!deleteResult) { if (!deleteResult) {
logger.error(`Failed to delete user (${req.ip})`); logger.error(`Failed to delete user (${req.ip})`);
return res return res.type("application/json").status(500).json({
.type('application/json') error: "Failed to delete user",
.status(500) });
.json({ error: 'Failed to delete user' });
} }
return res return res.type("application/json").status(200).json({
.type('application/json') message: "User deleted successfully",
.status(200) });
.json({ message: 'User deleted successfully' });
} }
async function getSelf(req: Request, res: Response) { async function getSelf(req: Request, res: Response) {
const authHeader = req.headers.authorization; const authHeader = req.headers.authorization;
const bearerToken = authHeader?.split(' ')[1]; const bearerToken = authHeader?.split(" ")[1];
if (!bearerToken) { if (!bearerToken) {
return res return res.type("application/json").status(401).json({
.type('application/json') error: "Unauthorized",
.status(401) });
.json({ error: 'Unauthorized' });
} }
const payload = await JwtService.verify(bearerToken); const payload = await JwtService.verify(bearerToken);
if (!payload) { if (!payload) {
logger.warn(`Unauthorized access attempt (${req.ip})`); logger.warn(`Unauthorized access attempt (${req.ip})`);
return res return res.type("application/json").status(401).json({
.type('application/json') error: "Unauthorized",
.status(401) });
.json({ error: 'Unauthorized' });
} }
const dbUser = await UserService.getFromId(payload.sub) const dbUser = await UserService.getFromId(payload.sub);
if (!dbUser) { if (!dbUser) {
return res return res.type("application/json").status(404).json({
.type('application/json') error: "User not found",
.status(404) });
.json({ error: 'User not found' });
} }
return res return res.type("application/json").status(200).json({
.type('application/json')
.status(200)
.json({
id: dbUser.id, id: dbUser.id,
username: dbUser.username, username: dbUser.username,
firstName: dbUser.firstname, firstName: dbUser.firstname,
lastName: dbUser.firstname, lastName: dbUser.firstname,
isAdmin: dbUser.firstname isAdmin: dbUser.firstname,
}); });
} }
@ -459,7 +438,7 @@ const AuthController = {
editUser, editUser,
deleteUser, deleteUser,
deleteSelf, deleteSelf,
getSelf getSelf,
} };
export default AuthController; export default AuthController;

View File

@ -1,13 +1,13 @@
import type { Request, Response } from "express"; import type { Request, Response } from "express";
import { Logger } from "tslog"; import { Logger } from "tslog";
import type IDbBrand from "@interfaces/database/IDbBrand"; import type IDbBrand from "@interfaces/database/IDbBrand";
import BrandService from "@services/brand.service"; import BrandService from "@services/brand.service";
//import {body} from "express-validator"; //import {body} from "express-validator";
const logger = new Logger({
const logger = new Logger({ name: "BrandController" }); name: "BrandController",
});
/** /**
* Creates a new brand. * Creates a new brand.
@ -17,24 +17,37 @@ const logger = new Logger({ name: "BrandController" });
* *
* @returns A Promise that resolves to the response object with a status code and a JSON message indicating the success or failure of brand creation. * @returns A Promise that resolves to the response object with a status code and a JSON message indicating the success or failure of brand creation.
*/ */
async function createBrand(req: Request, res: Response): Promise<Response> { async function createBrand(
const body: IDbBrand = req.body req: Request,
const doesExist = await BrandService.getBySlug(`${body.slug_name}`) res: Response,
): Promise<Response> {
const body: IDbBrand = req.body;
const doesExist = await BrandService.getBySlug(
`${body.slug_name}`,
);
if (doesExist) { if (doesExist) {
logger.error("Brand already exists"); logger.error("Brand already exists");
return res.status(400).json({ error: "Brand already exists" }); return res.status(400).json({
error: "Brand already exists",
});
} }
const createResult = await BrandService.create({ const createResult = await BrandService.create({
slug_name: `${body.slug_name}`, slug_name: `${body.slug_name}`,
display_name: `${body.display_name}`, display_name: `${body.display_name}`,
image_blob: `${body.image_blob}` image_blob: `${body.image_blob}`,
}) });
if (!createResult) { if (!createResult) {
logger.error("Failed to create brand"); logger.error("Failed to create brand");
return res.status(500).json({ error: "Failed to create brand" }); return res.status(500).json({
error: "Failed to create brand",
});
} }
logger.info(`Brand created successfully ! (${body.slug_name})`) logger.info(
return res.status(201).json({ message: "Brand created successfully" }); `Brand created successfully ! (${body.slug_name})`,
);
return res.status(201).json({
message: "Brand created successfully",
});
} }
/** /**
@ -44,29 +57,40 @@ async function createBrand(req: Request, res: Response): Promise<Response> {
* @param {Response} res - The HTTP response object. * @param {Response} res - The HTTP response object.
* @return {Promise<Response>} A promise that resolves with the HTTP response. * @return {Promise<Response>} A promise that resolves with the HTTP response.
*/ */
async function updateBrand(req: Request, res: Response): Promise<Response> { async function updateBrand(
req: Request,
res: Response,
): Promise<Response> {
const body: IDbBrand = req.body; const body: IDbBrand = req.body;
const brandSlug = req.params["brandSlug"]; const brandSlug = req.params["brandSlug"];
if (!brandSlug) { if (!brandSlug) {
logger.error("Brand slug is missing"); logger.error("Brand slug is missing");
return res.status(400).json({ error: "Brand slug is missing" }); return res.status(400).json({
error: "Brand slug is missing",
});
} }
const doesExist = await BrandService.getBySlug(brandSlug); const doesExist = await BrandService.getBySlug(brandSlug);
if (!doesExist) { if (!doesExist) {
logger.error("Brand not found"); logger.error("Brand not found");
return res.status(404).json({ error: "Brand not found" }); return res.status(404).json({
error: "Brand not found",
});
} }
const updateResult = await BrandService.update({ const updateResult = await BrandService.update({
slug_name: `${body.slug_name}`, slug_name: `${body.slug_name}`,
display_name: `${body.display_name}`, display_name: `${body.display_name}`,
image_blob: `${body.image_blob}` image_blob: `${body.image_blob}`,
}); });
if (!updateResult) { if (!updateResult) {
logger.error("Failed to update brand"); logger.error("Failed to update brand");
return res.status(500).json({ error: "Failed to update brand" }); return res.status(500).json({
error: "Failed to update brand",
});
} }
logger.info(`Brand updated successfully ! (${brandSlug})`); logger.info(`Brand updated successfully ! (${brandSlug})`);
return res.status(200).json({ message: "Brand updated successfully" }); return res.status(200).json({
message: "Brand updated successfully",
});
} }
/** /**
@ -76,16 +100,23 @@ async function updateBrand(req: Request, res: Response): Promise<Response> {
* @param {Response} res - The response object to send the result. * @param {Response} res - The response object to send the result.
* @returns {Promise<Response>} - A promise that resolves to the response with the retrieved brand. * @returns {Promise<Response>} - A promise that resolves to the response with the retrieved brand.
*/ */
async function getBySlugBrand(req: Request, res: Response): Promise<Response> { async function getBySlugBrand(
req: Request,
res: Response,
): Promise<Response> {
const brandSlug = req.params["brandSlug"]; const brandSlug = req.params["brandSlug"];
if (!brandSlug) { if (!brandSlug) {
logger.error("Brand slug is missing"); logger.error("Brand slug is missing");
return res.status(400).json({ error: "Brand slug is missing" }); return res.status(400).json({
error: "Brand slug is missing",
});
} }
const brand = await BrandService.getBySlug(brandSlug); const brand = await BrandService.getBySlug(brandSlug);
if (!brand) { if (!brand) {
logger.error("Brand not found"); logger.error("Brand not found");
return res.status(404).json({ error: "Brand not found" }); return res.status(404).json({
error: "Brand not found",
});
} }
logger.info(`Brand retrieved successfully ! (${brandSlug})`); logger.info(`Brand retrieved successfully ! (${brandSlug})`);
return res.status(200).json(brand); return res.status(200).json(brand);
@ -98,17 +129,22 @@ async function getBySlugBrand(req: Request, res: Response): Promise<Response> {
* @param {Response} res - The response object. * @param {Response} res - The response object.
* @returns {Promise<Response>} - A promise with the response object. * @returns {Promise<Response>} - A promise with the response object.
*/ */
async function getAllBrand(_req: Request, res: Response): Promise<Response> { async function getAllBrand(
_req: Request,
res: Response,
): Promise<Response> {
const brands = await BrandService.getAll(); const brands = await BrandService.getAll();
if (!brands) { if (!brands) {
logger.error("Failed to retrieve brands"); logger.error("Failed to retrieve brands");
return res.status(500).json({ error: "Failed to retrieve brands" }); return res.status(500).json({
error: "Failed to retrieve brands",
});
} }
logger.info("Brands retrieved successfully !"); logger.info("Brands retrieved successfully !");
return res.status(200).json({ return res.status(200).json({
uat: Date.now(), uat: Date.now(),
brands: brands, brands: brands,
total: brands.length total: brands.length,
}); });
} }
@ -120,25 +156,36 @@ async function getAllBrand(_req: Request, res: Response): Promise<Response> {
* @param {Response} res - The response object. * @param {Response} res - The response object.
* @returns {Promise<Response>} - The response object indicating the success or failure of the delete operation. * @returns {Promise<Response>} - The response object indicating the success or failure of the delete operation.
*/ */
async function deleteBrand(req: Request, res: Response): Promise<Response> { async function deleteBrand(
req: Request,
res: Response,
): Promise<Response> {
const brandSlug = req.params["brandSlug"]; const brandSlug = req.params["brandSlug"];
if (!brandSlug) { if (!brandSlug) {
logger.error("Brand slug is missing"); logger.error("Brand slug is missing");
return res.status(400).json({ error: "Brand slug is missing" }); return res.status(400).json({
error: "Brand slug is missing",
});
} }
//TODO verify if models linked to brand //TODO verify if models linked to brand
const doesExist = await BrandService.getBySlug(brandSlug); const doesExist = await BrandService.getBySlug(brandSlug);
if (!doesExist) { if (!doesExist) {
logger.error("Brand not found"); logger.error("Brand not found");
return res.status(404).json({ error: "Brand not found" }); return res.status(404).json({
error: "Brand not found",
});
} }
const deleteResult = await BrandService.delete(brandSlug); const deleteResult = await BrandService.delete(brandSlug);
if (!deleteResult) { if (!deleteResult) {
logger.error("Failed to delete brand"); logger.error("Failed to delete brand");
return res.status(500).json({ error: "Failed to delete brand" }); return res.status(500).json({
error: "Failed to delete brand",
});
} }
logger.info(`Brand deleted successfully ! (${brandSlug})`); logger.info(`Brand deleted successfully ! (${brandSlug})`);
return res.status(200).json({ message: "Brand deleted successfully" }); return res.status(200).json({
message: "Brand deleted successfully",
});
} }
//TODO get models of the brand //TODO get models of the brand
@ -149,6 +196,6 @@ const BrandController = {
getBySlug: getBySlugBrand, getBySlug: getBySlugBrand,
getAll: getAllBrand, getAll: getAllBrand,
delete: deleteBrand, delete: deleteBrand,
} };
export default BrandController; export default BrandController;

View File

@ -1,12 +1,12 @@
import type {Request, Response} from "express";
import {Logger} from "tslog";
import type IDbCategory from "@interfaces/database/IDbCategory"; import type IDbCategory from "@interfaces/database/IDbCategory";
import CategoryService from "@services/category.service"; import CategoryService from "@services/category.service";
import type { Request, Response } from "express";
import { Logger } from "tslog";
//import {validationResult} from "express-validator"; //import {validationResult} from "express-validator";
const logger = new Logger({
const logger = new Logger({ name: "CategoryController" }); name: "CategoryController",
});
/** /**
* Creates a new category. * Creates a new category.
@ -15,23 +15,36 @@ const logger = new Logger({ name: "CategoryController" });
* @param {Response} res - The response object to send back to the client. * @param {Response} res - The response object to send back to the client.
* @returns {Promise<Response>} The response object indicating the outcome of the category creation. * @returns {Promise<Response>} The response object indicating the outcome of the category creation.
*/ */
async function createCategory(req: Request, res: Response): Promise<Response> { async function createCategory(
const body: IDbCategory = req.body req: Request,
const doesExist = await CategoryService.getBySlug(`${body.slug_name}`) res: Response,
): Promise<Response> {
const body: IDbCategory = req.body;
const doesExist = await CategoryService.getBySlug(
`${body.slug_name}`,
);
if (doesExist) { if (doesExist) {
logger.error("Category already exists"); logger.error("Category already exists");
return res.status(400).json({ error: "Category already exists" }); return res.status(400).json({
error: "Category already exists",
});
} }
const createResult = await CategoryService.create({ const createResult = await CategoryService.create({
display_name: `${body.display_name}`, display_name: `${body.display_name}`,
slug_name: `${body.slug_name}` slug_name: `${body.slug_name}`,
}) });
if (!createResult) { if (!createResult) {
logger.error("Failed to create category"); logger.error("Failed to create category");
return res.status(500).json({ error: "Failed to create category" }); return res.status(500).json({
error: "Failed to create category",
});
} }
logger.info(`Category created successfully ! (${body.slug_name})`) logger.info(
return res.status(201).json({ message: "Category created successfully" }); `Category created successfully ! (${body.slug_name})`,
);
return res.status(201).json({
message: "Category created successfully",
});
} }
/** /**
@ -42,29 +55,42 @@ async function createCategory(req: Request, res: Response): Promise<Response> {
* *
* @return {Promise<Response>} - A promise that will be resolved with the result of the update operation. * @return {Promise<Response>} - A promise that will be resolved with the result of the update operation.
*/ */
async function updateCategory(req: Request, res:Response): Promise<Response> { async function updateCategory(
req: Request,
res: Response,
): Promise<Response> {
const body: IDbCategory = req.body; const body: IDbCategory = req.body;
const categoryId = req.params["categorySlug"]; const categoryId = req.params["categorySlug"];
if (!categoryId) { if (!categoryId) {
logger.error("Category slug is missing"); logger.error("Category slug is missing");
return res.status(400).json({ error: "Category slug is missing" }); return res.status(400).json({
error: "Category slug is missing",
});
} }
const doesExist = await CategoryService.getById(`${categoryId}`) const doesExist = await CategoryService.getById(
`${categoryId}`,
);
if (!doesExist || !doesExist.id) { if (!doesExist || !doesExist.id) {
logger.error("Category not found"); logger.error("Category not found");
return res.status(404).json({ error: "Category not found" }); return res.status(404).json({
error: "Category not found",
});
} }
const updateResult = await CategoryService.update({ const updateResult = await CategoryService.update({
id: doesExist.id, id: doesExist.id,
slug_name: `${body.slug_name}`, slug_name: `${body.slug_name}`,
display_name: `${body.display_name}` display_name: `${body.display_name}`,
}) });
if (!updateResult) { if (!updateResult) {
logger.error("Failed to update category"); logger.error("Failed to update category");
return res.status(500).json({ error: "Failed to update category" }); return res.status(500).json({
error: "Failed to update category",
});
} }
logger.info(`Category updated successfully! (${categoryId})`); logger.info(`Category updated successfully! (${categoryId})`);
return res.status(200).json({ message: "Category updated successfully" }); return res.status(200).json({
message: "Category updated successfully",
});
} }
/** /**
@ -74,24 +100,41 @@ async function updateCategory(req: Request, res:Response): Promise<Response> {
* @param {Response} res - The response object to send the result. * @param {Response} res - The response object to send the result.
* @returns {Promise<Response>} A Promise that resolves to the response object. * @returns {Promise<Response>} A Promise that resolves to the response object.
*/ */
async function deleteCategory(req: Request, res: Response): Promise<Response> { async function deleteCategory(
req: Request,
res: Response,
): Promise<Response> {
const categorySlug = req.params["categorySlug"]; const categorySlug = req.params["categorySlug"];
if (!categorySlug) { if (!categorySlug) {
logger.error("Category slug is missing"); logger.error("Category slug is missing");
return res.status(400).json({ error: "Category slug is missing" }); return res.status(400).json({
error: "Category slug is missing",
});
} }
const doesExist = await CategoryService.getBySlug(`${categorySlug}`); const doesExist = await CategoryService.getBySlug(
`${categorySlug}`,
);
if (!doesExist || !doesExist.id) { if (!doesExist || !doesExist.id) {
logger.error("Category not found"); logger.error("Category not found");
return res.status(404).json({ error: "Category not found" }); return res.status(404).json({
error: "Category not found",
});
} }
const deleteResult = await CategoryService.delete(`${doesExist.id}`); const deleteResult = await CategoryService.delete(
`${doesExist.id}`,
);
if (!deleteResult) { if (!deleteResult) {
logger.error("Failed to delete category"); logger.error("Failed to delete category");
return res.status(500).json({ error: "Failed to delete category" }); return res.status(500).json({
error: "Failed to delete category",
});
} }
logger.info(`Category deleted successfully! (${categorySlug})`); logger.info(
return res.status(200).json({ message: "Category deleted successfully" }); `Category deleted successfully! (${categorySlug})`,
);
return res.status(200).json({
message: "Category deleted successfully",
});
} }
/** /**
@ -101,23 +144,26 @@ async function deleteCategory(req: Request, res: Response): Promise<Response> {
* @param {Response} res - The response object. * @param {Response} res - The response object.
* @return {Promise<Response>} - A promise that resolves to the response object. * @return {Promise<Response>} - A promise that resolves to the response object.
*/ */
async function getAllCategory(_req: Request, res: Response): Promise<Response> { async function getAllCategory(
_req: Request,
res: Response,
): Promise<Response> {
const categories = await CategoryService.getAll(); const categories = await CategoryService.getAll();
if (!categories) { if (!categories) {
logger.error("Failed to get categories"); logger.error("Failed to get categories");
return res.status(500).json({ error: "Failed to get categories" }); return res.status(500).json({
error: "Failed to get categories",
});
} }
logger.info("Categories retrieved successfully"); logger.info("Categories retrieved successfully");
return res return res.status(200).json({
.status(200)
.json({
iat: Date.now(), iat: Date.now(),
categories: categories.map((category: IDbCategory) => ({ categories: categories.map((category: IDbCategory) => ({
id: category.id, id: category.id,
display_name: category.display_name, display_name: category.display_name,
slug_name: category.slug_name slug_name: category.slug_name,
})), })),
total: categories.length total: categories.length,
}); });
} }
@ -129,22 +175,33 @@ async function getAllCategory(_req: Request, res: Response): Promise<Response> {
* *
* @return {Promise<Response>} - The response with category data or error message * @return {Promise<Response>} - The response with category data or error message
*/ */
async function getBySlugCategory(req: Request, res:Response): Promise<Response> { async function getBySlugCategory(
req: Request,
res: Response,
): Promise<Response> {
const categorySlug = req.params["categorySlug"]; const categorySlug = req.params["categorySlug"];
if (!categorySlug) { if (!categorySlug) {
logger.error("Category slug is missing"); logger.error("Category slug is missing");
return res.status(400).json({ error: "Category slug is missing" }); return res.status(400).json({
error: "Category slug is missing",
});
} }
const category = await CategoryService.getBySlug(`${categorySlug}`); const category = await CategoryService.getBySlug(
`${categorySlug}`,
);
if (!category || !category.id) { if (!category || !category.id) {
logger.error("Category not found"); logger.error("Category not found");
return res.status(404).json({ error: "Category not found" }); return res.status(404).json({
error: "Category not found",
});
} }
logger.info(`Category retrieved successfully! (${categorySlug})`); logger.info(
`Category retrieved successfully! (${categorySlug})`,
);
return res.status(200).json({ return res.status(200).json({
id: category.id, id: category.id,
display_name: category.display_name, display_name: category.display_name,
slug_name: category.slug_name slug_name: category.slug_name,
}); });
} }
@ -153,7 +210,7 @@ const CategoryController = {
update: updateCategory, update: updateCategory,
delete: deleteCategory, delete: deleteCategory,
getAll: getAllCategory, getAll: getAllCategory,
getBySlug: getBySlugCategory getBySlug: getBySlugCategory,
} };
export default CategoryController; export default CategoryController;

View File

@ -1,20 +1,27 @@
import type IDbModel from "@interfaces/database/IDbModel";
import CategoryService from "@services/category.service";
import ModelService from "@services/model.service";
import type { Request, Response } from "express"; import type { Request, Response } from "express";
import { Logger } from "tslog"; import { Logger } from "tslog";
import CategoryService from "@services/category.service";
import type IDbModel from "@interfaces/database/IDbModel";
import ModelService from "@services/model.service";
//import {validationResult} from "express-validator"; //import {validationResult} from "express-validator";
const logger = new Logger({
name: "ModelController",
});
const logger = new Logger({ name: "ModelController" }); async function createModel(
req: Request,
res: Response,
async function createModel(req: Request, res: Response): Promise<Response> { ): Promise<Response> {
const body: IDbModel = req.body const body: IDbModel = req.body;
const doesExist = await CategoryService.getBySlug(`${body.slug_name}`) const doesExist = await CategoryService.getBySlug(
`${body.slug_name}`,
);
if (doesExist) { if (doesExist) {
logger.error("Category already exists"); logger.error("Category already exists");
return res.status(400).json({ error: "Category already exists" }); return res.status(400).json({
error: "Category already exists",
});
} }
const createResult = await ModelService.create({ const createResult = await ModelService.create({
display_name: `${body.display_name}`, display_name: `${body.display_name}`,
@ -23,22 +30,35 @@ async function createModel(req: Request, res: Response): Promise<Response> {
base_price: Number.parseFloat(`${body.base_price}`), base_price: Number.parseFloat(`${body.base_price}`),
brand_id: `${body.brand_id}`, brand_id: `${body.brand_id}`,
image_blob: `${body.image_blob}`, image_blob: `${body.image_blob}`,
is_trending: !!body.is_trending is_trending: !!body.is_trending,
}) });
if (!createResult) { if (!createResult) {
logger.error("Failed to create category"); logger.error("Failed to create category");
return res.status(500).json({ error: "Failed to create category" }); return res.status(500).json({
error: "Failed to create category",
});
} }
logger.info(`Category created successfully ! (${body.slug_name})`) logger.info(
return res.status(201).json({ message: "Category created successfully" }); `Category created successfully ! (${body.slug_name})`,
);
return res.status(201).json({
message: "Category created successfully",
});
} }
async function updateModel(req: Request, res: Response): Promise<Response> { async function updateModel(
req: Request,
res: Response,
): Promise<Response> {
const body: IDbModel = req.body; const body: IDbModel = req.body;
const doesExist = await ModelService.getBySlug(`${body.slug_name}`); const doesExist = await ModelService.getBySlug(
`${body.slug_name}`,
);
if (!doesExist) { if (!doesExist) {
logger.error("Model does not exist"); logger.error("Model does not exist");
return res.status(404).json({ error: "Model does not exist" }); return res.status(404).json({
error: "Model does not exist",
});
} }
const updateResult = await ModelService.update({ const updateResult = await ModelService.update({
id: `${body.id}`, id: `${body.id}`,
@ -48,57 +68,85 @@ async function updateModel(req: Request, res: Response): Promise<Response> {
base_price: Number.parseFloat(`${body.base_price}`), base_price: Number.parseFloat(`${body.base_price}`),
brand_id: `${body.brand_id}`, brand_id: `${body.brand_id}`,
image_blob: `${body.image_blob}`, image_blob: `${body.image_blob}`,
is_trending: !!body.is_trending is_trending: !!body.is_trending,
}); });
if (!updateResult) { if (!updateResult) {
logger.error("Failed to update model"); logger.error("Failed to update model");
return res.status(500).json({ error: "Failed to update model" }); return res.status(500).json({
error: "Failed to update model",
});
} }
logger.info(`Model updated successfully! (${body.slug_name})`); logger.info(
return res.status(200).json({ message: "Model updated successfully" }); `Model updated successfully! (${body.slug_name})`,
);
return res.status(200).json({
message: "Model updated successfully",
});
} }
async function getAllModel(res: Response): Promise<Response> { async function getAllModel(res: Response): Promise<Response> {
const models = await ModelService.getAll(); const models = await ModelService.getAll();
if (!models) { if (!models) {
logger.error("Failed to get all models"); logger.error("Failed to get all models");
return res.status(500).json({ error: "Failed to get all models" }); return res.status(500).json({
error: "Failed to get all models",
});
} }
return res.status(200).json({ return res.status(200).json({
uat: Date.now(), uat: Date.now(),
models: models, models: models,
total: models.length total: models.length,
}); });
} }
async function getModelBySlug(req: Request, res: Response): Promise<Response> { async function getModelBySlug(
req: Request,
res: Response,
): Promise<Response> {
const slug = req.params["modelSlug"]; const slug = req.params["modelSlug"];
if (!slug) { if (!slug) {
logger.error("Invalid slug"); logger.error("Invalid slug");
return res.status(400).json({ error: "Invalid slug" }); return res.status(400).json({
error: "Invalid slug",
});
} }
const model = await ModelService.getBySlug(slug); const model = await ModelService.getBySlug(slug);
if (!model) { if (!model) {
logger.error("Model not found"); logger.error("Model not found");
return res.status(404).json({ error: "Model not found" }); return res.status(404).json({
error: "Model not found",
});
} }
return res.status(200).json({ model }); return res.status(200).json({
model,
});
} }
async function deleteModel(req: Request, res: Response): Promise<Response> { async function deleteModel(
req: Request,
res: Response,
): Promise<Response> {
const modelSlug = req.params["modelSlug"]; const modelSlug = req.params["modelSlug"];
if (!modelSlug) { if (!modelSlug) {
logger.error("Invalid model slug"); logger.error("Invalid model slug");
return res.status(400).json({ error: "Invalid model slug" }); return res.status(400).json({
error: "Invalid model slug",
});
} }
//TODO Check if vehicle related to model //TODO Check if vehicle related to model
const deleteResult = await ModelService.delete(modelSlug); const deleteResult = await ModelService.delete(modelSlug);
if (!deleteResult) { if (!deleteResult) {
logger.error("Failed to delete model"); logger.error("Failed to delete model");
return res.status(500).json({ error: "Failed to delete model" }); return res.status(500).json({
error: "Failed to delete model",
});
} }
logger.info(`Model deleted successfully! (SLUG: ${modelSlug})`); logger.info(
return res.status(200).json({ message: "Model deleted successfully" }); `Model deleted successfully! (SLUG: ${modelSlug})`,
);
return res.status(200).json({
message: "Model deleted successfully",
});
} }
//TODO get all vehicles of an model by slug //TODO get all vehicles of an model by slug
@ -111,6 +159,6 @@ const ModelController = {
getAll: getAllModel, getAll: getAllModel,
getBySlug: getModelBySlug, getBySlug: getModelBySlug,
delete: deleteModel, delete: deleteModel,
} };
export default ModelController; export default ModelController;

View File

@ -20,4 +20,4 @@ interface DbUserData {
uat: Date; uat: Date;
} }
export default DbUserData export default DbUserData;

View File

@ -1,7 +1,7 @@
export interface IDbCategory { export interface IDbCategory {
id?: string; id?: string;
slug_name: string; slug_name: string;
display_name: string display_name: string;
} }
export default IDbCategory; export default IDbCategory;

View File

@ -5,7 +5,7 @@ export interface IDbRent {
iat: Date; iat: Date;
eat: Date; eat: Date;
need_survey: boolean; need_survey: boolean;
km_at_start: number km_at_start: number;
} }
export default IDbRent; export default IDbRent;

View File

@ -8,5 +8,5 @@ export interface IDbUser {
is_mail_verified: boolean; is_mail_verified: boolean;
is_admin: boolean; is_admin: boolean;
gdpr: Date; gdpr: Date;
hash: string hash: string;
} }

View File

@ -1 +1 @@
export * from './UserData' export * from "./UserData";

View File

@ -1,38 +1,39 @@
import express, {type Router} from "express";
import UserGuard from "@validators/UserGuard";
import AdminGuard from "@validators/AdminGuard";
import AuthController from "@controllers/auth.controller"; import AuthController from "@controllers/auth.controller";
import AdminGuard from "@validators/AdminGuard";
import UserGuard from "@validators/UserGuard";
import express, { type Router } from "express";
const AuthRouter: Router = express.Router(); const AuthRouter: Router = express.Router();
AuthRouter.route('/login').post(AuthController.login) AuthRouter.route("/login").post(AuthController.login);
AuthRouter.route('/register').post(AuthController.register) AuthRouter.route("/register").post(AuthController.register);
// PATCH // PATCH
//TODO - To test //TODO - To test
AuthRouter.route('/me') AuthRouter.route("/me").patch(
.patch(UserGuard, AuthController.editUser) UserGuard,
AuthController.editUser,
);
// GET // GET
AuthRouter.route('/me') AuthRouter.route("/me").get(UserGuard, AuthController.getSelf);
.get(UserGuard, AuthController.getSelf)
// DELETE // DELETE
AuthRouter.route('/me') AuthRouter.route("/me").delete(
.delete(UserGuard, AuthController.deleteSelf) UserGuard,
AuthController.deleteSelf,
);
// GET // GET
AuthRouter.route('/all') AuthRouter.route("/all").get(
.get(AdminGuard, AuthController.getAllUsers) AdminGuard,
AuthController.getAllUsers,
);
// GET // GET
AuthRouter.route('/user/:targetId') AuthRouter.route("/user/:targetId")
.get(AdminGuard, AuthController.getUser) .get(AdminGuard, AuthController.getUser)
.patch(AdminGuard, AuthController.editUser) .patch(AdminGuard, AuthController.editUser)
.delete(AdminGuard, AuthController.deleteUser) .delete(AdminGuard, AuthController.deleteUser);
export default AuthRouter;
export default AuthRouter

View File

@ -1,44 +1,52 @@
import express, {type Router} from "express"; import BrandController from "@controllers/brand.controller";
import AdminGuard from "@validators/AdminGuard";
import UserGuard from "@validators/UserGuard";
import CategoryController from "@controllers/category.controller"; import CategoryController from "@controllers/category.controller";
import ModelController from "@controllers/model.controller"; import ModelController from "@controllers/model.controller";
import BrandController from "@controllers/brand.controller"; import AdminGuard from "@validators/AdminGuard";
import UserGuard from "@validators/UserGuard";
import express, { type Router } from "express";
const CatalogRouter: Router = express.Router(); const CatalogRouter: Router = express.Router();
//-- MODELS >> //-- MODELS >>
CatalogRouter.route('/model/new').get(AdminGuard, ModelController.create) CatalogRouter.route("/model/new").get(
AdminGuard,
ModelController.create,
);
CatalogRouter.route('/model/all').get(ModelController.getAll) CatalogRouter.route("/model/all").get(ModelController.getAll);
CatalogRouter.route('/model/:modelSlug') CatalogRouter.route("/model/:modelSlug")
.get(UserGuard, ModelController.getBySlug) .get(UserGuard, ModelController.getBySlug)
.patch(AdminGuard, ModelController.update) .patch(AdminGuard, ModelController.update)
.delete(AdminGuard, ModelController.delete) .delete(AdminGuard, ModelController.delete);
//-- CATEGORY >> //-- CATEGORY >>
CatalogRouter.route('/category/new').get(AdminGuard, CategoryController.create) CatalogRouter.route("/category/new").get(
AdminGuard,
CategoryController.create,
);
CatalogRouter.route('/category/all').get(CategoryController.getAll) CatalogRouter.route("/category/all").get(
CategoryController.getAll,
);
CatalogRouter.route('/category/:categorySlug') CatalogRouter.route("/category/:categorySlug")
.get(UserGuard, CategoryController.getBySlug) .get(UserGuard, CategoryController.getBySlug)
.patch(AdminGuard, CategoryController.update) .patch(AdminGuard, CategoryController.update)
.delete(AdminGuard, CategoryController.delete) .delete(AdminGuard, CategoryController.delete);
//-- BRAND >> //-- BRAND >>
CatalogRouter.route('/brand/new').post(AdminGuard, BrandController.create) CatalogRouter.route("/brand/new").post(
CatalogRouter.route('/brand/all').get(BrandController.getAll) AdminGuard,
CatalogRouter.route('/brand/:brandSlug') BrandController.create,
);
CatalogRouter.route("/brand/all").get(BrandController.getAll);
CatalogRouter.route("/brand/:brandSlug")
.get(UserGuard, BrandController.getBySlug) .get(UserGuard, BrandController.getBySlug)
.patch(AdminGuard, BrandController.update) .patch(AdminGuard, BrandController.update)
.delete(AdminGuard, BrandController.delete) .delete(AdminGuard, BrandController.delete);
export default CatalogRouter; export default CatalogRouter;

View File

@ -1,3 +1,3 @@
export * from 'src/routes/auth/authRouter' export * from "src/routes/auth/authRouter";
export * from 'src/routes/catalog/catalogRouter' export * from "src/routes/catalog/catalogRouter";
export * from 'src/routes/rent/rentRouter' export * from "src/routes/rent/rentRouter";

View File

@ -1,34 +1,27 @@
import express, {type Router} from "express";
import AdminGuard from "@validators/AdminGuard"; import AdminGuard from "@validators/AdminGuard";
import UserGuard from "@validators/UserGuard"; import UserGuard from "@validators/UserGuard";
import express, { type Router } from "express";
const RentRouter: Router = express.Router(); const RentRouter: Router = express.Router();
// Get rent affected to the user // Get rent affected to the user
RentRouter.route('/affected') RentRouter.route("/affected").get(UserGuard);
.get(UserGuard)
// Get all vehicle in rent (admin only) // Get all vehicle in rent (admin only)
RentRouter.route('/affected/all') RentRouter.route("/affected/all").get(AdminGuard);
.get(AdminGuard)
// Add a new vehicle (admin only) // Add a new vehicle (admin only)
RentRouter.route('/veh/new') RentRouter.route("/veh/new").post(AdminGuard);
.post(AdminGuard)
// Get all vehicles // Get all vehicles
RentRouter.route('/veh/all') RentRouter.route("/veh/all").get();
.get()
// Rent a specific vehicle // Rent a specific vehicle
RentRouter.route('/veh/rent/:vehicleId') RentRouter.route("/veh/rent/:vehicleId").post(UserGuard);
.post(UserGuard)
RentRouter.route("/veh/:vehicleId")
RentRouter.route('/veh/:vehicleId')
.get(UserGuard) .get(UserGuard)
.patch(AdminGuard) .patch(AdminGuard)
.delete(AdminGuard) .delete(AdminGuard);
export default RentRouter; export default RentRouter;

View File

@ -1,10 +1,12 @@
import type IDbBrand from "@interfaces/database/IDbBrand"; import type IDbBrand from "@interfaces/database/IDbBrand";
import MysqlService from "@services/mysql.service"; import MysqlService from "@services/mysql.service";
import { Logger } from "tslog"; import { Logger } from "tslog";
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from "uuid";
const DbHandler = new MysqlService.Handler('BrandService') const DbHandler = new MysqlService.Handler("BrandService");
const logger = new Logger({name: 'BrandService'}) const logger = new Logger({
name: "BrandService",
});
//SEC todo Blob validation //SEC todo Blob validation
/** /**
@ -14,24 +16,39 @@ const logger = new Logger({name: 'BrandService'})
* @return {Promise<unknown>} A promise that resolves to the result of the operation. * @return {Promise<unknown>} A promise that resolves to the result of the operation.
*/ */
async function createBrand(data: IDbBrand): Promise<unknown> { async function createBrand(data: IDbBrand): Promise<unknown> {
const doesExist = await MysqlService.Brand.getBySlug(DbHandler, data.slug_name); const doesExist = await MysqlService.Brand.getBySlug(
DbHandler,
data.slug_name,
);
if (doesExist) { if (doesExist) {
logger.error(`Brand already exists (${data.slug_name})`) logger.error(`Brand already exists (${data.slug_name})`);
return {error: 'exist'} return {
error: "exist",
};
} }
const brandId = uuidv4(); const brandId = uuidv4();
const createdBrand = await MysqlService.Brand.insert(DbHandler, { const createdBrand = await MysqlService.Brand.insert(
DbHandler,
{
id: brandId, id: brandId,
slug_name: `${data.slug_name}`, slug_name: `${data.slug_name}`,
display_name: `${data.display_name}`, display_name: `${data.display_name}`,
image_blob: data.image_blob image_blob: data.image_blob,
}); },
);
if (createdBrand) { if (createdBrand) {
logger.info(`Brand created successfully (${data.slug_name})`); logger.info(
return { success: true, brand: createdBrand }; `Brand created successfully (${data.slug_name})`,
);
return {
success: true,
brand: createdBrand,
};
} }
logger.error(`Failed to create brand (${data.slug_name})`); logger.error(`Failed to create brand (${data.slug_name})`);
return { error: 'failed' }; return {
error: "failed",
};
} }
//SEC todo Blob validation //SEC todo Blob validation
@ -46,19 +63,27 @@ async function updateBrand(data: IDbBrand): Promise<boolean> {
logger.error("Brand ID is missing"); logger.error("Brand ID is missing");
return false; return false;
} }
const doesExist = await MysqlService.Brand.getBySlug(DbHandler, data.slug_name); const doesExist = await MysqlService.Brand.getBySlug(
DbHandler,
data.slug_name,
);
if (doesExist && doesExist.id !== data.id) { if (doesExist && doesExist.id !== data.id) {
logger.error(`Brand already exists (${data.slug_name})`); logger.error(`Brand already exists (${data.slug_name})`);
return false; return false;
} }
const updatedBrand = await MysqlService.Brand.update(DbHandler, { const updatedBrand = await MysqlService.Brand.update(
DbHandler,
{
id: data.id, id: data.id,
slug_name: `${data.slug_name}`, slug_name: `${data.slug_name}`,
display_name: `${data.display_name}`, display_name: `${data.display_name}`,
image_blob: data.image_blob image_blob: data.image_blob,
}); },
);
if (updatedBrand) { if (updatedBrand) {
logger.info(`Brand updated successfully (${data.slug_name})`); logger.info(
`Brand updated successfully (${data.slug_name})`,
);
return true; return true;
} }
logger.error(`Failed to update brand (${data.slug_name})`); logger.error(`Failed to update brand (${data.slug_name})`);
@ -75,7 +100,9 @@ async function getAllBrand(): Promise<Array<IDbBrand>| false> {
logger.error("Failed to retrieve brands"); logger.error("Failed to retrieve brands");
return false; return false;
} }
logger.info(`Retrieved all brands successfully (${brands.length})`); logger.info(
`Retrieved all brands successfully (${brands.length})`,
);
return brands; return brands;
} }
@ -85,17 +112,24 @@ async function getAllBrand(): Promise<Array<IDbBrand>| false> {
* @param {string} brandSlug - The slug of the brand. * @param {string} brandSlug - The slug of the brand.
* @returns {Promise<IDbBrand|false>} - A promise that resolves to the retrieved brand object or false if the brand is not found. * @returns {Promise<IDbBrand|false>} - A promise that resolves to the retrieved brand object or false if the brand is not found.
*/ */
async function getBySlugBrand(brandSlug: string): Promise<IDbBrand | false> { async function getBySlugBrand(
brandSlug: string,
): Promise<IDbBrand | false> {
if (!brandSlug) { if (!brandSlug) {
logger.error("Brand slug is missing"); logger.error("Brand slug is missing");
return false; return false;
} }
const brand = await MysqlService.Brand.getBySlug(DbHandler, brandSlug); const brand = await MysqlService.Brand.getBySlug(
DbHandler,
brandSlug,
);
if (!brand) { if (!brand) {
logger.error(`Brand not found (${brandSlug})`); logger.error(`Brand not found (${brandSlug})`);
return false; return false;
} }
logger.info(`Retrieved brand by slug successfully (${brandSlug})`); logger.info(
`Retrieved brand by slug successfully (${brandSlug})`,
);
return brand; return brand;
} }
@ -106,7 +140,9 @@ async function getBySlugBrand(brandSlug: string): Promise<IDbBrand | false> {
* *
* @returns {Promise<IDbBrand | false>} A promise that resolves to the retrieved brand object, or false if the brand is not found or the ID is invalid. * @returns {Promise<IDbBrand | false>} A promise that resolves to the retrieved brand object, or false if the brand is not found or the ID is invalid.
*/ */
async function getByIdBrand(brandId: string): Promise<IDbBrand | false> { async function getByIdBrand(
brandId: string,
): Promise<IDbBrand | false> {
if (!brandId) { if (!brandId) {
logger.error("Brand ID is missing"); logger.error("Brand ID is missing");
return false; return false;
@ -115,12 +151,17 @@ async function getByIdBrand(brandId: string): Promise<IDbBrand | false> {
logger.error("Invalid brand ID"); logger.error("Invalid brand ID");
return false; return false;
} }
const brand = await MysqlService.Brand.getById(DbHandler, brandId); const brand = await MysqlService.Brand.getById(
DbHandler,
brandId,
);
if (!brand) { if (!brand) {
logger.error(`Brand not found (${brandId})`); logger.error(`Brand not found (${brandId})`);
return false; return false;
} }
logger.info(`Retrieved brand by ID successfully (${brandId})`); logger.info(
`Retrieved brand by ID successfully (${brandId})`,
);
return brand; return brand;
} }
@ -144,7 +185,10 @@ async function deleteBrand(brandId: string): Promise<boolean> {
return false; return false;
} }
//TODO verify if as models linked //TODO verify if as models linked
const deletedBrand = await MysqlService.Brand.delete(DbHandler, brandId); const deletedBrand = await MysqlService.Brand.delete(
DbHandler,
brandId,
);
if (!deletedBrand) { if (!deletedBrand) {
logger.error(`Failed to delete brand (${brandId})`); logger.error(`Failed to delete brand (${brandId})`);
return false; return false;
@ -160,6 +204,6 @@ const BrandService = {
getBySlug: getBySlugBrand, getBySlug: getBySlugBrand,
getById: getByIdBrand, getById: getByIdBrand,
delete: deleteBrand, delete: deleteBrand,
} };
export default BrandService; export default BrandService;

View File

@ -1,12 +1,12 @@
import type { IDbCategory } from "@interfaces/database/IDbCategory"; import type { IDbCategory } from "@interfaces/database/IDbCategory";
import MysqlService from "@services/mysql.service"; import MysqlService from "@services/mysql.service";
import { Logger } from "tslog"; import { Logger } from "tslog";
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from "uuid";
const DbHandler = new MysqlService.Handler('CategoryService')
const logger = new Logger({name: 'CategoryService'})
const DbHandler = new MysqlService.Handler("CategoryService");
const logger = new Logger({
name: "CategoryService",
});
/** /**
* Creates a new category with the given data. * Creates a new category with the given data.
@ -15,14 +15,18 @@ const logger = new Logger({name: 'CategoryService'})
* @returns {Promise<boolean>} A promise that resolves with the created category. * @returns {Promise<boolean>} A promise that resolves with the created category.
* If an error occurs, the promise will reject with the error. * If an error occurs, the promise will reject with the error.
*/ */
async function createCategory(data: IDbCategory): Promise<boolean> { async function createCategory(
logger.info(`Creating a new category... (${data.display_name})`) data: IDbCategory,
): Promise<boolean> {
logger.info(
`Creating a new category... (${data.display_name})`,
);
try { try {
await MysqlService.Category.insert(DbHandler, { await MysqlService.Category.insert(DbHandler, {
id: uuidv4(), id: uuidv4(),
display_name: data.display_name, display_name: data.display_name,
slug_name: data.slug_name slug_name: data.slug_name,
}) });
//TODO Return the new id //TODO Return the new id
return true; return true;
} catch (error) { } catch (error) {
@ -43,19 +47,19 @@ async function createCategory(data: IDbCategory): Promise<boolean> {
*/ */
async function updateCategory(data: IDbCategory) { async function updateCategory(data: IDbCategory) {
if (!data.id) { if (!data.id) {
logger.error("Category id is missing.") logger.error("Category id is missing.");
return false return false;
} }
try { try {
await MysqlService.Category.update(DbHandler, { await MysqlService.Category.update(DbHandler, {
id: data.id, id: data.id,
slug_name: data.slug_name, slug_name: data.slug_name,
display_name: data.display_name display_name: data.display_name,
}); });
//TODO Return id //TODO Return id
return true; return true;
} catch (err) { } catch (err) {
logger.error(err) logger.error(err);
return false; return false;
} }
} }
@ -65,7 +69,9 @@ async function updateCategory(data: IDbCategory) {
* *
* @returns {Promise<Array<IDbCategory>> | null} Promise that resolves to an array of IDbCategory objects or null if an error occurred. * @returns {Promise<Array<IDbCategory>> | null} Promise that resolves to an array of IDbCategory objects or null if an error occurred.
*/ */
async function getAll(): Promise<Promise<Array<IDbCategory>> | null> { async function getAll(): Promise<Promise<
Array<IDbCategory>
> | null> {
try { try {
logger.info("Getting all categories..."); logger.info("Getting all categories...");
return await MysqlService.Category.getAll(DbHandler); return await MysqlService.Category.getAll(DbHandler);
@ -75,17 +81,21 @@ async function getAll(): Promise<Promise<Array<IDbCategory>> | null> {
} }
} }
/** /**
* Gets a category by its slug * Gets a category by its slug
* *
* @param {string} slug - The slug of the category * @param {string} slug - The slug of the category
* @return {Promise<IDbCategory|null>} - A promise that resolves to the category object or null if not found * @return {Promise<IDbCategory|null>} - A promise that resolves to the category object or null if not found
*/ */
async function getBySlug(slug: string): Promise<IDbCategory | null> { async function getBySlug(
slug: string,
): Promise<IDbCategory | null> {
try { try {
logger.info(`Getting category by slug... (${slug})`); logger.info(`Getting category by slug... (${slug})`);
return await MysqlService.Category.getBySlug(DbHandler, slug); return await MysqlService.Category.getBySlug(
DbHandler,
slug,
);
} catch (error) { } catch (error) {
logger.error(`Error getting category by slug: ${error}`); logger.error(`Error getting category by slug: ${error}`);
return null; return null;
@ -98,7 +108,9 @@ async function getBySlug(slug: string): Promise<IDbCategory | null> {
* @param {string} id - The id of the category to retrieve. * @param {string} id - The id of the category to retrieve.
* @returns {Promise<IDbCategory | null>} - A Promise that resolves with the retrieved category object or null if not found. * @returns {Promise<IDbCategory | null>} - A Promise that resolves with the retrieved category object or null if not found.
*/ */
async function getById(id: string):Promise<IDbCategory | null> { async function getById(
id: string,
): Promise<IDbCategory | null> {
try { try {
logger.info(`Getting category by id... (${id})`); logger.info(`Getting category by id... (${id})`);
return await MysqlService.Category.getById(DbHandler, id); return await MysqlService.Category.getById(DbHandler, id);
@ -110,7 +122,6 @@ async function getById(id: string):Promise<IDbCategory | null> {
//FEAT Get all models in category (slug) //FEAT Get all models in category (slug)
/** /**
* Deletes a category with the given ID from the database. * Deletes a category with the given ID from the database.
* *
@ -135,7 +146,7 @@ const CategoryService = {
update: updateCategory, update: updateCategory,
getAll, getAll,
getBySlug, getBySlug,
getById getById,
} };
export default CategoryService; export default CategoryService;

View File

@ -4,21 +4,24 @@ import Argon2id from "@node-rs/argon2";
export async function getHashFromPassword(password: string) { export async function getHashFromPassword(password: string) {
return await Argon2id.hash(password, { return await Argon2id.hash(password, {
secret: Buffer.from(`${process.env["HASH_SECRET"]}`), secret: Buffer.from(`${process.env["HASH_SECRET"]}`),
algorithm: 2 algorithm: 2,
}) });
} }
//ToTest //ToTest
export async function comparePassword(password: string, hash: string) { export async function comparePassword(
password: string,
hash: string,
) {
return await Argon2id.verify(hash, password, { return await Argon2id.verify(hash, password, {
secret: Buffer.from(`${process.env["HASH_SECRET"]}`), secret: Buffer.from(`${process.env["HASH_SECRET"]}`),
algorithm: 2 algorithm: 2,
}); });
} }
const CredentialService = { const CredentialService = {
compare: comparePassword, compare: comparePassword,
hash: getHashFromPassword, hash: getHashFromPassword,
} };
export default CredentialService; export default CredentialService;

View File

@ -1,2 +1,2 @@
export * from './jwt.service'; export * from "./jwt.service";
export * as MySqlService from './mysql.service' export * as MySqlService from "./mysql.service";

View File

@ -1,7 +1,14 @@
import {type JWTHeaderParameters, type JWTPayload, jwtVerify, SignJWT} from "jose"; import {
type JWTHeaderParameters,
type JWTPayload,
SignJWT,
jwtVerify,
} from "jose";
import { Logger } from "tslog"; import { Logger } from "tslog";
const logger = new Logger({ name: "JwtService" }); const logger = new Logger({
name: "JwtService",
});
/** /**
* Verify a JWT token. * Verify a JWT token.
@ -11,22 +18,22 @@ const logger = new Logger({ name: "JwtService" });
* @returns {Promise<null | JWTPayload>} * @returns {Promise<null | JWTPayload>}
* - The payload of the verified JWT token or null if verification fails. * - The payload of the verified JWT token or null if verification fails.
*/ */
async function JwtVerifyService(jwt: string | Uint8Array): Promise<null | JWTPayload> { async function JwtVerifyService(
jwt: string | Uint8Array,
): Promise<null | JWTPayload> {
try { try {
const result = await jwtVerify( const result = await jwtVerify(
jwt, jwt,
new TextEncoder() new TextEncoder().encode(`${process.env["JWT_SECRET"]}`),
.encode(`${process.env["JWT_SECRET"]}`), {},
{ );
})
return result.payload; return result.payload;
} catch (error) { } catch (error) {
logger.error(error) logger.error(error);
return null return null;
} }
} }
/** /**
* Asynchronously signs a JWT token using the provided payload, header, expiration time, and audience. * Asynchronously signs a JWT token using the provided payload, header, expiration time, and audience.
* *
@ -42,19 +49,26 @@ async function JwtVerifyService(jwt: string | Uint8Array): Promise<null | JWTPay
* @returns {Promise<string>} * @returns {Promise<string>}
* - A promise that resolves with the signed JWT token. * - A promise that resolves with the signed JWT token.
*/ */
async function JwtSignService(payload: JWTPayload, pHeader: JWTHeaderParameters, expTime: string | number | Date, audience: string | string[]): Promise<string> { async function JwtSignService(
payload: JWTPayload,
pHeader: JWTHeaderParameters,
expTime: string | number | Date,
audience: string | string[],
): Promise<string> {
return await new SignJWT(payload) return await new SignJWT(payload)
.setProtectedHeader(pHeader) .setProtectedHeader(pHeader)
.setIssuedAt(new Date()) .setIssuedAt(new Date())
.setIssuer(`${process.env["JWT_SECRET"]} - Mathis HERRIOT`) .setIssuer(`${process.env["JWT_SECRET"]} - Mathis HERRIOT`)
.setAudience(audience) .setAudience(audience)
.setExpirationTime(expTime) .setExpirationTime(expTime)
.sign(new TextEncoder().encode(`${process.env["JWT_SECRET"]}`)) .sign(
new TextEncoder().encode(`${process.env["JWT_SECRET"]}`),
);
} }
const JwtService = { const JwtService = {
verify: JwtVerifyService, verify: JwtVerifyService,
sign: JwtSignService sign: JwtSignService,
} };
export default JwtService export default JwtService;

View File

@ -1,10 +1,12 @@
import type IDbModel from "@interfaces/database/IDbModel"; import type IDbModel from "@interfaces/database/IDbModel";
import MysqlService from "@services/mysql.service"; import MysqlService from "@services/mysql.service";
import { Logger } from "tslog"; import { Logger } from "tslog";
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from "uuid";
const DbHandler = new MysqlService.Handler('ModelService') const DbHandler = new MysqlService.Handler("ModelService");
const logger = new Logger({name: 'ModelService'}) const logger = new Logger({
name: "ModelService",
});
//SEC TODO validate blob //SEC TODO validate blob
/** /**
@ -15,7 +17,7 @@ const logger = new Logger({name: 'ModelService'})
* @return {Promise<boolean>} - Indicates whether the model was created successfully. * @return {Promise<boolean>} - Indicates whether the model was created successfully.
*/ */
async function createModel(data: IDbModel): Promise<boolean> { async function createModel(data: IDbModel): Promise<boolean> {
logger.info(`Creating a new model... (${data.display_name})`) logger.info(`Creating a new model... (${data.display_name})`);
//TODO Validate IDbModel data //TODO Validate IDbModel data
try { try {
await MysqlService.Model.insert(DbHandler, { await MysqlService.Model.insert(DbHandler, {
@ -26,10 +28,10 @@ async function createModel(data: IDbModel): Promise<boolean> {
brand_id: data.brand_id, brand_id: data.brand_id,
category_id: data.category_id, category_id: data.category_id,
base_price: data.base_price, base_price: data.base_price,
is_trending: data.is_trending is_trending: data.is_trending,
}) });
//TODO Return the new id //TODO Return the new id
logger.info('Success !') logger.info("Success !");
return true; return true;
} catch (error) { } catch (error) {
logger.error(`Error creating category: ${error}`); logger.error(`Error creating category: ${error}`);
@ -70,13 +72,18 @@ async function updateModel(data: IDbModel): Promise<boolean> {
* @param {string} modelSlug - The slug of the model to be deleted. * @param {string} modelSlug - The slug of the model to be deleted.
* @return {Promise<boolean>} - A promise that resolves to true if the deletion is successful, else false. * @return {Promise<boolean>} - A promise that resolves to true if the deletion is successful, else false.
*/ */
async function deleteModel(modelSlug: string): Promise<boolean> { async function deleteModel(
modelSlug: string,
): Promise<boolean> {
if (!modelSlug) { if (!modelSlug) {
logger.error("Model slug is missing"); logger.error("Model slug is missing");
return false return false;
} }
logger.info(`Deleting model with ID: ${modelSlug}`); logger.info(`Deleting model with ID: ${modelSlug}`);
const doesExist = await MysqlService.Model.getBySlug(DbHandler, modelSlug); const doesExist = await MysqlService.Model.getBySlug(
DbHandler,
modelSlug,
);
if (!doesExist || !doesExist.id) { if (!doesExist || !doesExist.id) {
logger.warn(`Model with slug ${modelSlug} not found`); logger.warn(`Model with slug ${modelSlug} not found`);
return false; return false;
@ -91,17 +98,21 @@ async function deleteModel(modelSlug: string): Promise<boolean> {
} }
} }
/** /**
* Fetches a model by slug from the database. * Fetches a model by slug from the database.
* *
* @param {string} modelSlug - The slug of the model to be fetched. * @param {string} modelSlug - The slug of the model to be fetched.
* @return {Promise<IDbModel | null>} - A promise that resolves to the model if found, else null. * @return {Promise<IDbModel | null>} - A promise that resolves to the model if found, else null.
*/ */
async function getBySlugModel(modelSlug: string): Promise<IDbModel | null> { async function getBySlugModel(
modelSlug: string,
): Promise<IDbModel | null> {
logger.info(`Fetching model with slug: ${modelSlug}`); logger.info(`Fetching model with slug: ${modelSlug}`);
try { try {
const model = await MysqlService.Model.getBySlug(DbHandler, modelSlug); const model = await MysqlService.Model.getBySlug(
DbHandler,
modelSlug,
);
if (!model) { if (!model) {
logger.warn(`Model with slug ${modelSlug} not found`); logger.warn(`Model with slug ${modelSlug} not found`);
return null; return null;
@ -113,7 +124,6 @@ async function getBySlugModel(modelSlug: string): Promise<IDbModel | null> {
} }
} }
/** /**
* Fetches all models from the database. * Fetches all models from the database.
* *
@ -127,7 +137,7 @@ async function getAllModels(): Promise<IDbModel[] | null> {
logger.warn("No models found on the database"); logger.warn("No models found on the database");
return null; return null;
} }
logger.info(`Found ${models.length} model(s)`) logger.info(`Found ${models.length} model(s)`);
return models; return models;
} catch (error) { } catch (error) {
logger.error(`Error fetching all models: ${error}`); logger.error(`Error fetching all models: ${error}`);
@ -135,8 +145,6 @@ async function getAllModels(): Promise<IDbModel[] | null> {
} }
} }
/** /**
* ModelService is responsible for managing models. * ModelService is responsible for managing models.
* @namespace * @namespace
@ -149,6 +157,6 @@ const ModelService = {
getAll: getAllModels, getAll: getAllModels,
//getByCategory: getByCategoryModel, //getByCategory: getByCategoryModel,
//getByBrand: getModelsByBrand, //getByBrand: getModelsByBrand,
} };
export default ModelService; export default ModelService;

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,16 @@
import {Logger} from "tslog"; import type { IReqLogin } from "@interfaces/requests/IReqLogin";
import MySqlService from "@services/mysql.service"; import type { IReqRegister } from "@interfaces/requests/IReqRegister";
import CredentialService from "@services/credential.service"; import CredentialService from "@services/credential.service";
import JwtService from "@services/jwt.service"; import JwtService from "@services/jwt.service";
import MySqlService from "@services/mysql.service";
import MysqlService from "@services/mysql.service"; import MysqlService from "@services/mysql.service";
import type {IReqRegister} from "@interfaces/requests/IReqRegister"; import { Logger } from "tslog";
import {IReqLogin} from "@interfaces/requests/IReqLogin";
const logger = new Logger({
name: "UserService",
});
const logger = new Logger({ name: "UserService" }); const DbHandler = new MySqlService.Handler("UserService");
const DbHandler = new MySqlService.Handler('UserService')
/** /**
* Retrieves a user object from the database based on the given username. * Retrieves a user object from the database based on the given username.
@ -17,8 +18,13 @@ const DbHandler = new MySqlService.Handler('UserService')
* @param {string} username - The username of the user to retrieve. * @param {string} username - The username of the user to retrieve.
* @returns {Promise<Object | null>} - The user object if found, or null if not found. * @returns {Promise<Object | null>} - The user object if found, or null if not found.
*/ */
async function getUserFromUsername(username: string): Promise<object | null> { async function getUserFromUsername(
const dbUser = await MySqlService.User.getByUsername(DbHandler, username) username: string,
): Promise<object | null> {
const dbUser = await MySqlService.User.getByUsername(
DbHandler,
username,
);
if (dbUser === undefined) return null; if (dbUser === undefined) return null;
return dbUser; return dbUser;
} }
@ -31,41 +37,65 @@ async function getUserFromIdService(id: string | undefined) {
async function register(ReqData: IReqRegister) { async function register(ReqData: IReqRegister) {
if (ReqData.password.length < 6) { if (ReqData.password.length < 6) {
logger.info(`REGISTER :> Invalid password (${ReqData.username})`) logger.info(
return { error: "invalidPassword" }; `REGISTER :> Invalid password (${ReqData.username})`,
);
return {
error: "invalidPassword",
};
} }
const passwordHash = await CredentialService.hash(ReqData.password) const passwordHash = await CredentialService.hash(
ReqData.password,
);
// Does the new user has accepted GDPR ? // Does the new user has accepted GDPR ?
if (ReqData.gdpr !== true) { if (ReqData.gdpr !== true) {
logger.info(`REGISTER :> GDPR not validated (${ReqData.username})`) logger.info(
return { error: "gdprNotApproved" } `REGISTER :> GDPR not validated (${ReqData.username})`,
);
return {
error: "gdprNotApproved",
};
} }
// Check if exist and return // Check if exist and return
const dbUserIfExist = await getUserFromUsername(ReqData.username) const dbUserIfExist = await getUserFromUsername(
ReqData.username,
);
if (dbUserIfExist) { if (dbUserIfExist) {
logger.info(`REGISTER :> User exist (${dbUserIfExist.username})\n ID:${dbUserIfExist.id}`) logger.info(
return { error: "exist" } `REGISTER :> User exist (${dbUserIfExist.username})\n ID:${dbUserIfExist.id}`,
);
return {
error: "exist",
};
} }
const currentDate = new Date(); const currentDate = new Date();
// New UserService (class) // New UserService (class)
const NewUser = new User(ReqData.username, ReqData.displayName, passwordHash, currentDate); const NewUser = new User(
ReqData.username,
ReqData.displayName,
passwordHash,
currentDate,
);
NewUser.setFirstName(ReqData.firstName); NewUser.setFirstName(ReqData.firstName);
NewUser.setLastName(ReqData.lastName); NewUser.setLastName(ReqData.lastName);
// JWT // JWT
const alg = 'HS512' const alg = "HS512";
const token = await JwtService.sign({ const token = await JwtService.sign(
sub: NewUser.id {
}, alg, sub: NewUser.id,
'1d', },
'user') alg,
"1d",
"user",
);
const userData = { const userData = {
error: "none", error: "none",
@ -75,45 +105,74 @@ async function register(ReqData: IReqRegister) {
username: NewUser.username, username: NewUser.username,
displayName: NewUser.displayName, displayName: NewUser.displayName,
firstName: NewUser.firstName, firstName: NewUser.firstName,
lastName: NewUser.lastName lastName: NewUser.lastName,
}}; },
logger.info(userData) };
logger.info(userData);
await Db.collection("users").insertOne(NewUser); await Db.collection("users").insertOne(NewUser);
logger.info(`REGISTER :> Inserted new user (${NewUser.username})`) logger.info(
return userData `REGISTER :> Inserted new user (${NewUser.username})`,
);
return userData;
} }
async function login(ReqData: IReqLogin) { async function login(ReqData: IReqLogin) {
//const passwordHash = await getHashFromPassword(sanitizedData.password); //const passwordHash = await getHashFromPassword(sanitizedData.password);
const dbUser = await MysqlService.User.getByUsername(DbHandler, ReqData.username); const dbUser = await MysqlService.User.getByUsername(
DbHandler,
ReqData.username,
);
if (!dbUser) { if (!dbUser) {
console.log(`LoginService :> User does not exist (${ReqData.username})`); console.log(
return { error: "userNotFound" }; `LoginService :> User does not exist (${ReqData.username})`,
);
return {
error: "userNotFound",
};
} }
if (ReqData.password.length < 6) { if (ReqData.password.length < 6) {
console.log('X') console.log("X");
console.log(`LoginService :> Invalid password (${ReqData.username})`); console.log(
return { error: "invalidPassword" }; `LoginService :> Invalid password (${ReqData.username})`,
);
return {
error: "invalidPassword",
};
} }
const isPasswordValid = await CredentialService.compare(ReqData.password, dbUser.hash) const isPasswordValid = await CredentialService.compare(
ReqData.password,
dbUser.hash,
);
if (!isPasswordValid) { if (!isPasswordValid) {
console.log(isPasswordValid) console.log(isPasswordValid);
console.log(`LoginService :> Invalid password (${ReqData.username})`); console.log(
return { error: "invalidPassword" }; `LoginService :> Invalid password (${ReqData.username})`,
);
return {
error: "invalidPassword",
};
} }
// biome-ignore lint/style/useConst: <explanation> // biome-ignore lint/style/useConst: <explanation>
let userData = { let userData = {
error: "none", error: "none",
jwt: '', jwt: "",
user: { user: {
id: dbUser.id, id: dbUser.id,
username: dbUser.username, username: dbUser.username,
displayName: dbUser.displayName, displayName: dbUser.displayName,
} },
}; };
userData.jwt = await JwtService.sign({sub: dbUser.id}, {alg: 'HS512'}, '7d', 'user') userData.jwt = await JwtService.sign(
{
sub: dbUser.id,
},
{
alg: "HS512",
},
"7d",
"user",
);
console.log("USERDATA :>"); console.log("USERDATA :>");
console.log(userData); console.log(userData);
@ -130,17 +189,17 @@ async function login(ReqData: IReqLogin) {
async function getAllUsersService() { async function getAllUsersService() {
const users = await Db.collection("users").find().toArray(); const users = await Db.collection("users").find().toArray();
// biome-ignore lint/complexity/noForEach: <explanation> // biome-ignore lint/complexity/noForEach: <explanation>
users.forEach(user => { users.forEach((user) => {
delete user.passwordHash delete user.passwordHash;
delete user._id delete user._id;
delete user.gdpr delete user.gdpr;
}); });
logger.info(`Query ${users.length} user(s)`) logger.info(`Query ${users.length} user(s)`);
return { return {
iat: Date.now(), iat: Date.now(),
users: users, users: users,
length: users.length length: users.length,
} };
} }
/** /**
@ -154,19 +213,34 @@ async function getAllUsersService() {
*/ */
async function editUserService(targetId, sanitizedData) { async function editUserService(targetId, sanitizedData) {
if (sanitizedData.password) { if (sanitizedData.password) {
const passwordHash = await getHashFromPassword(sanitizedData.password) const passwordHash = await getHashFromPassword(
delete sanitizedData.password sanitizedData.password,
logger.info(`Changing password for user "${targetId}"`) );
sanitizedData.passwordHash = passwordHash delete sanitizedData.password;
logger.info(`Changing password for user "${targetId}"`);
sanitizedData.passwordHash = passwordHash;
} }
const updatedUserResult = await Db.collection("users").updateOne({id: targetId}, {$set: sanitizedData}); const updatedUserResult = await Db.collection(
"users",
).updateOne(
{
id: targetId,
},
{
$set: sanitizedData,
},
);
if (updatedUserResult.modifiedCount === 0) { if (updatedUserResult.modifiedCount === 0) {
logger.info(`EDIT :> User not found (${targetId})`); logger.info(`EDIT :> User not found (${targetId})`);
return { error: "userNotFound" }; return {
error: "userNotFound",
};
} }
logger.info(`EDIT :> User updated (${targetId})`); logger.info(`EDIT :> User updated (${targetId})`);
return { error: "none" }; return {
error: "none",
};
} }
/** /**
@ -176,13 +250,15 @@ async function editUserService(targetId, sanitizedData) {
* @return {Promise<boolean>} - A promise that resolves to true if the user is successfully deleted, or false if an error occurs. * @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) {
logger.info(`Deleting user ${targetId}`) logger.info(`Deleting user ${targetId}`);
try { try {
await Db.collection("users").deleteOne({id: targetId}); await Db.collection("users").deleteOne({
return true id: targetId,
});
return true;
} catch (e) { } catch (e) {
logger.warn(e) logger.warn(e);
return false return false;
} }
} }
@ -192,7 +268,7 @@ const UserService = {
getAll: getAllUsersService, getAll: getAllUsersService,
getFromId: getUserFromIdService, getFromId: getUserFromIdService,
edit: editUserService, edit: editUserService,
delete: deleteUserService delete: deleteUserService,
} };
export default UserService; export default UserService;

View File

@ -1,39 +1,58 @@
import JwtService from "@services/jwt.service"; import JwtService from "@services/jwt.service";
import type {NextFunction, Request, Response} from "express";
import MySqlService from "@services/mysql.service"; import MySqlService from "@services/mysql.service";
import MysqlService from "@services/mysql.service"; import MysqlService from "@services/mysql.service";
import type { NextFunction, Request, Response } from "express";
import { Logger } from "tslog"; import { Logger } from "tslog";
const DbHandler = new MySqlService.Handler('AdminGuard') const DbHandler = new MySqlService.Handler("AdminGuard");
const logger = new Logger({name: 'AdminGuard'}) const logger = new Logger({
name: "AdminGuard",
});
const UNAUTHORIZED = 401; const UNAUTHORIZED = 401;
const FORBIDDEN = 403; const FORBIDDEN = 403;
const UNAUTH_MESSAGE = 'Missing Authorization Header'; const UNAUTH_MESSAGE = "Missing Authorization Header";
const INVALID_TOKEN_MESSAGE = 'Invalid or expired token.'; const INVALID_TOKEN_MESSAGE = "Invalid or expired token.";
const PERMISSON_NOT_VALID = 'You are missing the required permission.' const PERMISSON_NOT_VALID =
"You are missing the required permission.";
async function AdminGuard(req: Request, res: Response, next: NextFunction) { async function AdminGuard(
req: Request,
res: Response,
next: NextFunction,
) {
const authHeader = req.headers.authorization; const authHeader = req.headers.authorization;
if (!authHeader) { if (!authHeader) {
logger.warn(`Invalid header (${req.ip})`) logger.warn(`Invalid header (${req.ip})`);
return res.status(UNAUTHORIZED).json({message: UNAUTH_MESSAGE}); return res.status(UNAUTHORIZED).json({
message: UNAUTH_MESSAGE,
});
} }
const bearerToken = authHeader.split(' ')[1]; const bearerToken = authHeader.split(" ")[1];
if (!bearerToken) return res.status(FORBIDDEN).json({message: INVALID_TOKEN_MESSAGE}); if (!bearerToken)
return res.status(FORBIDDEN).json({
message: INVALID_TOKEN_MESSAGE,
});
const token = await JwtService.verify(bearerToken); const token = await JwtService.verify(bearerToken);
if (token) { if (token) {
// @ts-ignore // @ts-ignore
const isSourceAdmin = await MysqlService.User.getAdminStateForId(DbHandler, token.sub) const isSourceAdmin =
await MysqlService.User.getAdminStateForId(
DbHandler,
token.sub,
);
if (isSourceAdmin === true) next(); if (isSourceAdmin === true) next();
return res.status(FORBIDDEN).json({message: PERMISSON_NOT_VALID}); return res.status(FORBIDDEN).json({
message: PERMISSON_NOT_VALID,
});
} }
return res.status(FORBIDDEN).json({message: INVALID_TOKEN_MESSAGE}); return res.status(FORBIDDEN).json({
message: INVALID_TOKEN_MESSAGE,
});
} }
export default AdminGuard export default AdminGuard;

View File

@ -1,26 +1,37 @@
import JwtService from "@services/jwt.service"; import JwtService from "@services/jwt.service";
import type {NextFunction, Request, Response} from "express";
import MySqlService from "@services/mysql.service"; import MySqlService from "@services/mysql.service";
import type { NextFunction, Request, Response } from "express";
import { Logger } from "tslog"; import { Logger } from "tslog";
const DbHandler = new MySqlService.Handler('UserGuard') const DbHandler = new MySqlService.Handler("UserGuard");
const logger = new Logger({name: 'UserGuard'}) const logger = new Logger({
name: "UserGuard",
});
const UNAUTHORIZED = 401; const UNAUTHORIZED = 401;
const FORBIDDEN = 403; const FORBIDDEN = 403;
const UNAUTH_MESSAGE = 'Missing Authorization Header'; const UNAUTH_MESSAGE = "Missing Authorization Header";
const INVALID_TOKEN_MESSAGE = 'Invalid or expired token.'; const INVALID_TOKEN_MESSAGE = "Invalid or expired token.";
const USER_NOT_EXIST = 'You dont exist anymore' const USER_NOT_EXIST = "You dont exist anymore";
async function UserGuard(req: Request, res: Response, next: NextFunction) { async function UserGuard(
req: Request,
res: Response,
next: NextFunction,
) {
const authHeader = req.headers.authorization; const authHeader = req.headers.authorization;
if (!authHeader) { if (!authHeader) {
return res.status(UNAUTHORIZED).json({message: UNAUTH_MESSAGE}); return res.status(UNAUTHORIZED).json({
message: UNAUTH_MESSAGE,
});
} }
const bearerToken = authHeader.split(' ')[1]; const bearerToken = authHeader.split(" ")[1];
if (!bearerToken) return res.status(FORBIDDEN).json({message: INVALID_TOKEN_MESSAGE}); if (!bearerToken)
return res.status(FORBIDDEN).json({
message: INVALID_TOKEN_MESSAGE,
});
const token = await JwtService.verify(bearerToken); const token = await JwtService.verify(bearerToken);
@ -29,16 +40,25 @@ async function UserGuard(req: Request, res: Response, next: NextFunction) {
const userId = token.sub; const userId = token.sub;
if (!userId) { if (!userId) {
logger.error(USER_NOT_EXIST); logger.error(USER_NOT_EXIST);
return res.status(UNAUTHORIZED).json({message: USER_NOT_EXIST}); return res.status(UNAUTHORIZED).json({
message: USER_NOT_EXIST,
});
} }
const user= await MySqlService.User.getById(DbHandler, userId); const user = await MySqlService.User.getById(
DbHandler,
userId,
);
if (user) { if (user) {
logger.info(`An user do a request. (${user?.username})`) logger.info(`An user do a request. (${user?.username})`);
next() next();
} }
return res.status(UNAUTHORIZED).json({message: USER_NOT_EXIST}); return res.status(UNAUTHORIZED).json({
message: USER_NOT_EXIST,
});
} }
return res.status(FORBIDDEN).json({message: INVALID_TOKEN_MESSAGE}); return res.status(FORBIDDEN).json({
message: INVALID_TOKEN_MESSAGE,
});
} }
export default UserGuard export default UserGuard;