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": {
"enabled": true
},
"files": {
"include": [
"./src/**/*.ts"
]
},
"vcs": {
"enabled": true,
"clientKind": "git"
},
"linter": {
"enabled": true,
"rules": {
@ -17,8 +26,8 @@
}
},
"formatter": {
"indentStyle": "space",
"indentStyle": "tab",
"indentWidth": 2,
"lineWidth": 15
"lineWidth": 64
}
}

View File

@ -7,7 +7,8 @@
"author": "Mathis HERRIOT",
"license": "MIT",
"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": {
"@node-rs/argon2": "^1.8.3",

View File

@ -1,21 +1,22 @@
import express, { type Express } from 'express';
import cors from 'cors';
import compression from 'compression';
import {Logger} from "tslog";
import helmet from "helmet";
import * as process from "node:process";
import AuthRouter from "@routes/auth/authRouter";
import CatalogRouter from "@routes/catalog/catalogRouter";
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({ name: "App" });
const logger = new Logger({
name: "App",
});
const app: Express = express();
// enable cors
app.use(cors());
app.options('*', cors());
app.options("*", cors());
// enable xss sanitizer
app.use(
@ -23,31 +24,35 @@ app.use(
xXssProtection: true,
}),
);
app.use(helmet.xXssProtection())
app.use(helmet.xXssProtection());
// parse json request body
app.use(express.json());
// parse urlencoded request body
app.use(express.urlencoded({ extended: true }));
app.use(
express.urlencoded({
extended: true,
}),
);
// gzip compression
app.use(compression())
app.use(compression());
try {
app.use('/auth', AuthRouter)
app.use('/catalog', CatalogRouter)
app.use('/rent', RentRouter)
logger.info('Routers loaded !')
app.use("/auth", AuthRouter);
app.use("/catalog", CatalogRouter);
app.use("/rent", RentRouter);
logger.info("Routers loaded !");
} catch (err) {
logger.error(err)
logger.error(err);
throw null;
}
try {
app.listen(process.env["APP_PORT"])
logger.info('Server is running !')
app.listen(process.env["APP_PORT"]);
logger.info("Server is running !");
} catch (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 type {IReqEditUserData} from "@interfaces/IReqEditUserData";
import type { IReqEditUserData } from "@interfaces/IReqEditUserData";
import UserService from "@services/user.service";
import type {Request, Response} from "express";
import {Logger} from "tslog";
import type { Request, Response } from "express";
import { Logger } from "tslog";
const logger = new Logger({ name: "AuthController" });
const logger = new Logger({
name: "AuthController",
});
//FIX Better return object interface
/**
@ -22,60 +22,65 @@ const logger = new Logger({ name: "AuthController" });
* - error: "exist" if the user already exists
* - 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;
if (!body) {
logger.warn(`Invalid input data (${req.ip})`);
return res
.type('application/json')
.status(400)
.json({ error: 'Invalid input data' });
return res.type("application/json").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})`);
return res
.type('application/json')
.status(400)
.json({ error: 'Field(s) missing' });
return res.type("application/json").status(400).json({
error: "Field(s) missing",
});
}
let gdpr = false
if (body.gdpr === true) {gdpr = true}
const sanitizeData= {
username: `${body.username}`,
displayName: `${body.displayName}`,
gdpr: gdpr,
password: `${body.password}`,
firstName: `${body.firstName}`,
lastName: `${body.lastName}`,
let gdpr = false;
if (body.gdpr === true) {
gdpr = true;
}
const sanitizeData = {
username: `${body.username}`,
displayName: `${body.displayName}`,
gdpr: gdpr,
password: `${body.password}`,
firstName: `${body.firstName}`,
lastName: `${body.lastName}`,
};
const RegisterServiceResult = await UserService.register(sanitizeData)
const RegisterServiceResult =
await UserService.register(sanitizeData);
if (RegisterServiceResult.error === "gdprNotApproved") {
logger.warn(`GDPR not approved (${req.ip})`);
return res
.status(400)
.json({
error: RegisterServiceResult.error,
message: "GDPR not accepted."
});
return res.status(400).json({
error: RegisterServiceResult.error,
message: "GDPR not accepted.",
});
}
if (RegisterServiceResult.error === "exist") {
logger.warn(`The user already exists (${req.ip})`);
return res
.type('application/json')
.status(400)
.json({
error: RegisterServiceResult.error,
message: "The user already exists."
});
return res.type("application/json").status(400).json({
error: RegisterServiceResult.error,
message: "The user already exists.",
});
}
// SUCCESS
logger.info(`User registered successfully (${req.ip})`);
return res
.type('application/json')
.type("application/json")
.status(201)
.json(RegisterServiceResult);
}
@ -88,378 +93,352 @@ 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.
*/
async function loginUser(req: Request, res: Response): Promise<void> {
async function loginUser(
req: Request,
res: Response,
): Promise<void> {
const body = req.body;
if (!body) {
res
.type('application/json')
.status(400)
.json({ error: 'Invalid input data' });
res.type("application/json").status(400).json({
error: "Invalid input data",
});
}
if (!body.password || !body.username) {
logger.warn(`Field(s) missing (${req.ip})`);
res
.type('application/json')
.status(400)
.json({ error: 'Field(s) missing' });
res.type("application/json").status(400).json({
error: "Field(s) missing",
});
}
const loginData = {
username: `${body.username}`,
password: `${body.password}`
password: `${body.password}`,
};
console.log(body)
console.log(body);
const LoginServiceResult = await UserService.login(loginData);
console.log(LoginServiceResult)
console.log(LoginServiceResult);
if (LoginServiceResult.error === "userNotFound") {
console.log('POOL')
res
.type('application/json')
.status(404)
.json({
error: LoginServiceResult.error,
message: "User not found."
});
console.log("POOL");
res.type("application/json").status(404).json({
error: LoginServiceResult.error,
message: "User not found.",
});
}
if (LoginServiceResult.error === "invalidPassword") {
res
.type('application/json')
.status(401)
.json({
error: LoginServiceResult.error,
message: "Invalid password."
});
res.type("application/json").status(401).json({
error: LoginServiceResult.error,
message: "Invalid password.",
});
}
res
.type('application/json')
.type("application/json")
.status(200)
.json(LoginServiceResult);
}
async function getAllUsers(req: Request, res: Response) {
const authHeader = req.headers.authorization;
const bearerToken = authHeader?.split(' ')[1];
const bearerToken = authHeader?.split(" ")[1];
if (!bearerToken) {
logger.warn(`Bearer token not provided (${req.ip})`);
return res
.type('application/json')
.status(401)
.json({ error: 'Unauthorized' });
return res.type("application/json").status(401).json({
error: "Unauthorized",
});
}
const payload = await JwtService.verify(bearerToken);
if (!payload) {
logger.warn(`Unauthorized access attempt (${req.ip})`);
return res
.type('application/json')
.status(401)
.json({ error: 'Unauthorized' });
return res.type("application/json").status(401).json({
error: "Unauthorized",
});
}
const sourceUser = await UserService.getFromId(payload.sub)
const sourceUser = await UserService.getFromId(payload.sub);
if (!sourceUser) {
return res
.type('application/json')
.status(404)
.json({ error: 'You dont exist anymore' });
return res.type("application/json").status(404).json({
error: "You dont exist anymore",
});
}
if (!sourceUser.is_admin) {
return res
.type('application/json')
.status(403)
.json({ error: 'Unauthorized' });
return res.type("application/json").status(403).json({
error: "Unauthorized",
});
}
const AllUserResponse = await UserService.getAll()
const AllUserResponse = await UserService.getAll();
if (!AllUserResponse.users) {
return res
.type('application/json')
.status(500)
.json({ error: 'Internal server error' });
return res.type("application/json").status(500).json({
error: "Internal server error",
});
}
return res
.type('application/json')
.type("application/json")
.status(200)
.json(AllUserResponse);
}
async function getUser(req: Request, res: Response) {
const authHeader = req.headers.authorization;
const bearerToken = authHeader?.split(' ')[1];
const bearerToken = authHeader?.split(" ")[1];
if (!bearerToken) {
logger.warn(`Bearer token not provided (${req.ip})`);
return res
.type('application/json')
.status(401)
.json({ error: 'Unauthorized' });
return res.type("application/json").status(401).json({
error: "Unauthorized",
});
}
const payload = await JwtService.verify(bearerToken);
if (!payload) {
logger.warn(`Unauthorized access attempt (${req.ip})`);
return res
.type('application/json')
.status(401)
.json({ error: 'Unauthorized' });
return res.type("application/json").status(401).json({
error: "Unauthorized",
});
}
const sourceUser = await UserService.getFromId(payload.sub)
const sourceUser = await UserService.getFromId(payload.sub);
if (!sourceUser) {
return res
.type('application/json')
.status(404)
.json({ error: 'You dont exist anymore' });
return res.type("application/json").status(404).json({
error: "You dont exist anymore",
});
}
if (!sourceUser.is_admin) {
return res
.type('application/json')
.status(403)
.json({ error: 'Unauthorized' });
return res.type("application/json").status(403).json({
error: "Unauthorized",
});
}
const userId = req.params["id"];
const dbUser = await UserService.getFromId(userId);
if (!dbUser) {
logger.warn(`User not found (${req.ip})`);
return res
.type('application/json')
.status(404)
.json({ error: 'User not found' });
return res.type("application/json").status(404).json({
error: "User not found",
});
}
// @ts-ignore
delete dbUser.passwordHash
delete dbUser.passwordHash;
// @ts-ignore
delete dbUser._id
return res
.type('application/json')
.status(200)
.json(dbUser);
delete dbUser._id;
return res.type("application/json").status(200).json(dbUser);
}
//FEAT - Implement re-auth by current password in case of password change
async function editUser(req: Request, res: Response) {
const body: IReqEditUserData | null = req.body;
if (!body) {
return res
.type('application/json')
.status(400)
.json({ error: 'Field(s) missing' });
return res.type("application/json").status(400).json({
error: "Field(s) missing",
});
}
const authHeader = req.headers.authorization;
const bearerToken = authHeader?.split(' ')[1];
const bearerToken = authHeader?.split(" ")[1];
if (!bearerToken) {
logger.warn(`Bearer token not provided (${req.ip})`);
return res
.type('application/json')
.status(401)
.json({ error: 'Unauthorized' });
return res.type("application/json").status(401).json({
error: "Unauthorized",
});
}
const payload = await JwtService.verify(bearerToken);
if (!payload) {
logger.warn(`Unauthorized access attempt (${req.ip})`);
return res
.type('application/json')
.status(401)
.json({ error: 'Unauthorized' });
return res.type("application/json").status(401).json({
error: "Unauthorized",
});
}
const sourceUser = await UserService.getFromId(payload.sub)
const sourceUser = await UserService.getFromId(payload.sub);
//@ts-ignore
const targetUserId = req.params.id || payload.sub
console.log(targetUserId)
const targetUserId = req.params.id || payload.sub;
console.log(targetUserId);
if (!sourceUser) {
logger.warn(`Unauthorized access attempt (${req.ip})`);
return res
.type('application/json')
.status(404)
.json({ error: 'You dont exist anymore' });
return res.type("application/json").status(404).json({
error: "You dont exist anymore",
});
}
if (sourceUser.is_admin || sourceUser.id === payload.sub) {
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 {
logger.info(`EDIT :> Source user modify itself (${sourceUser.firstname} ${sourceUser.lastname})`)
logger.info(
`EDIT :> Source user modify itself (${sourceUser.firstname} ${sourceUser.lastname})`,
);
}
//TODO Interface
const modifiedData = {
}
const modifiedData = {};
//@ts-ignore
if (body.firstName) modifiedData.firstName = `${body.firstName}`;
if (body.firstName)
modifiedData.firstName = `${body.firstName}`;
//@ts-ignore
if (body.lastName) modifiedData.lastName = `${body.lastName}`;
if (body.lastName)
modifiedData.lastName = `${body.lastName}`;
//@ts-ignore
if (body.displayName) modifiedData.displayName = `${body.displayName}`;
if (body.displayName)
modifiedData.displayName = `${body.displayName}`;
//TODO Case handled with hashing by the service.
//if (body.password) modifiedData.password = `${body.password}`;
//Call service
const EditUserServiceResult = await UserService.edit(`${targetUserId}`, modifiedData);
if (EditUserServiceResult.error === 'userNotFound') {
const EditUserServiceResult = await UserService.edit(
`${targetUserId}`,
modifiedData,
);
if (EditUserServiceResult.error === "userNotFound") {
logger.warn(`User not found (${req.ip})`);
return res
.type('application/json')
.status(404)
.json({ error: 'User not found' });
return res.type("application/json").status(404).json({
error: "User not found",
});
}
if (EditUserServiceResult.error !== 'none') {
logger.error(`Error occurred during user edit (${req.ip})`);
return res
.type('application/json')
.status(500)
.json({ error: 'Internal server error' });
if (EditUserServiceResult.error !== "none") {
logger.error(
`Error occurred during user edit (${req.ip})`,
);
return res.type("application/json").status(500).json({
error: "Internal server error",
});
}
return res
.type('application/json')
.type("application/json")
.status(200)
.json(EditUserServiceResult);
}
//Not itself or
logger.warn(`Unauthorized access attempt, not self or admin (${req.ip})`);
return res
.type('application/json')
.status(403)
.json({ error: 'Unauthorized' });
logger.warn(
`Unauthorized access attempt, not self or admin (${req.ip})`,
);
return res.type("application/json").status(403).json({
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 bearerToken = authHeader?.split(' ')[1];
const bearerToken = authHeader?.split(" ")[1];
if (!bearerToken) {
logger.warn(`Bearer token not provided (${req.ip})`);
return res
.type('application/json')
.status(401)
.json({ error: 'Unauthorized' });
return res.type("application/json").status(401).json({
error: "Unauthorized",
});
}
const payload = await JwtService.verify(bearerToken);
if (!payload) {
logger.warn(`Invalid token (${req.ip})`);
return res
.type('application/json')
.status(401)
.json({ error: 'Invalid token' });
return res.type("application/json").status(401).json({
error: "Invalid token",
});
}
const sourceUser = await UserService.getFromId(payload?.sub)
const targetUserId = req.params["id"]
const sourceUser = await UserService.getFromId(payload?.sub);
const targetUserId = req.params["id"];
if (!sourceUser) {
logger.warn(`Unauthorized access attempt (${req.ip})`);
return res
.type('application/json')
.status(404)
.json({ error: 'You dont exist anymore' });
return res.type("application/json").status(404).json({
error: "You dont exist anymore",
});
}
if (sourceUser.is_admin || sourceUser.id === payload.sub) {
const deleteUserServiceResult = await UserService.delete(`${targetUserId}`);
const deleteUserServiceResult = await UserService.delete(
`${targetUserId}`,
);
if (!deleteUserServiceResult) {
logger.error(`Error occurred during user delete (${req.ip})`);
return res
.type('application/json')
.status(500)
.json({ error: 'Internal server error' });
logger.error(
`Error occurred during user delete (${req.ip})`,
);
return res.type("application/json").status(500).json({
error: "Internal server error",
});
}
return res
.type('application/json')
.status(200)
.json({ message: 'User deleted successfully' });
return res.type("application/json").status(200).json({
message: "User deleted successfully",
});
}
return res
.type('application/json')
.status(403)
.json({ error: 'Unauthorized' });
return res.type("application/json").status(403).json({
error: "Unauthorized",
});
}
async function deleteSelf(req: Request, res: Response) {
const authHeader = req.headers.authorization;
const bearerToken = authHeader?.split(' ')[1];
if (!bearerToken) {
logger.warn(`Bearer token not provided (${req.ip})`);
return res
.type('application/json')
.status(401)
.json({ error: 'Unauthorized' });
}
const payload = await JwtService.verify(bearerToken);
if (!payload) {
logger.warn(`Unauthorized access attempt (${req.ip})`);
return res
.type('application/json')
.status(401)
.json({ error: 'Unauthorized' });
}
const sourceUser = await UserService.getFromId(payload.sub)
if (!sourceUser) {
return res
.type('application/json')
.status(404)
.json({ error: 'You dont exist anymore' });
}
if (sourceUser.id !== req.params["id"]) {
return res
.type('application/json')
.status(403)
.json({ error: 'Unauthorized' });
}
const deleteResult = await UserService.delete(sourceUser.id);
const bearerToken = authHeader?.split(" ")[1];
if (!bearerToken) {
logger.warn(`Bearer token not provided (${req.ip})`);
return res.type("application/json").status(401).json({
error: "Unauthorized",
});
}
const payload = await JwtService.verify(bearerToken);
if (!payload) {
logger.warn(`Unauthorized access attempt (${req.ip})`);
return res.type("application/json").status(401).json({
error: "Unauthorized",
});
}
const sourceUser = await UserService.getFromId(payload.sub);
if (!sourceUser) {
return res.type("application/json").status(404).json({
error: "You dont exist anymore",
});
}
if (sourceUser.id !== req.params["id"]) {
return res.type("application/json").status(403).json({
error: "Unauthorized",
});
}
const deleteResult = await UserService.delete(sourceUser.id);
if (!deleteResult) {
logger.error(`Failed to delete user (${req.ip})`);
return res
.type('application/json')
.status(500)
.json({ error: 'Failed to delete user' });
return res.type("application/json").status(500).json({
error: "Failed to delete user",
});
}
return res
.type('application/json')
.status(200)
.json({ message: 'User deleted successfully' });
return res.type("application/json").status(200).json({
message: "User deleted successfully",
});
}
async function getSelf(req: Request, res: Response) {
const authHeader = req.headers.authorization;
const bearerToken = authHeader?.split(' ')[1];
const bearerToken = authHeader?.split(" ")[1];
if (!bearerToken) {
return res
.type('application/json')
.status(401)
.json({ error: 'Unauthorized' });
return res.type("application/json").status(401).json({
error: "Unauthorized",
});
}
const payload = await JwtService.verify(bearerToken);
if (!payload) {
logger.warn(`Unauthorized access attempt (${req.ip})`);
return res
.type('application/json')
.status(401)
.json({ error: 'Unauthorized' });
}
const dbUser = await UserService.getFromId(payload.sub)
if (!dbUser) {
return res
.type('application/json')
.status(404)
.json({ error: 'User not found' });
}
return res
.type('application/json')
.status(200)
.json({
id: dbUser.id,
username: dbUser.username,
firstName: dbUser.firstname,
lastName: dbUser.firstname,
isAdmin: dbUser.firstname
logger.warn(`Unauthorized access attempt (${req.ip})`);
return res.type("application/json").status(401).json({
error: "Unauthorized",
});
}
const dbUser = await UserService.getFromId(payload.sub);
if (!dbUser) {
return res.type("application/json").status(404).json({
error: "User not found",
});
}
return res.type("application/json").status(200).json({
id: dbUser.id,
username: dbUser.username,
firstName: dbUser.firstname,
lastName: dbUser.firstname,
isAdmin: dbUser.firstname,
});
}
const AuthController = {
register: registerUser,
login: loginUser,
getAllUsers,
getUser,
editUser,
deleteUser,
login: loginUser,
getAllUsers,
getUser,
editUser,
deleteUser,
deleteSelf,
getSelf
}
getSelf,
};
export default AuthController;
export default AuthController;

View File

@ -1,13 +1,13 @@
import type {Request, Response} from "express";
import {Logger} from "tslog";
import type { Request, Response } from "express";
import { Logger } from "tslog";
import type IDbBrand from "@interfaces/database/IDbBrand";
import BrandService from "@services/brand.service";
//import {body} from "express-validator";
const logger = new Logger({ name: "BrandController" });
const logger = new Logger({
name: "BrandController",
});
/**
* 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.
*/
async function createBrand(req: Request, res: Response): Promise<Response> {
const body: IDbBrand = req.body
const doesExist = await BrandService.getBySlug(`${body.slug_name}`)
async function createBrand(
req: Request,
res: Response,
): Promise<Response> {
const body: IDbBrand = req.body;
const doesExist = await BrandService.getBySlug(
`${body.slug_name}`,
);
if (doesExist) {
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({
slug_name: `${body.slug_name}`,
display_name: `${body.display_name}`,
image_blob: `${body.image_blob}`
})
image_blob: `${body.image_blob}`,
});
if (!createResult) {
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})`)
return res.status(201).json({ message: "Brand created successfully" });
logger.info(
`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.
* @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 brandSlug = req.params["brandSlug"];
const brandSlug = req.params["brandSlug"];
if (!brandSlug) {
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);
if (!doesExist) {
logger.error("Brand not found");
return res.status(404).json({ error: "Brand not found" });
}
const updateResult = await BrandService.update({
slug_name: `${body.slug_name}`,
display_name: `${body.display_name}`,
image_blob: `${body.image_blob}`
});
if (!updateResult) {
logger.error("Failed to update brand");
return res.status(500).json({ error: "Failed to update brand" });
}
logger.info(`Brand updated successfully ! (${brandSlug})`);
return res.status(200).json({ message: "Brand updated successfully" });
const doesExist = await BrandService.getBySlug(brandSlug);
if (!doesExist) {
logger.error("Brand not found");
return res.status(404).json({
error: "Brand not found",
});
}
const updateResult = await BrandService.update({
slug_name: `${body.slug_name}`,
display_name: `${body.display_name}`,
image_blob: `${body.image_blob}`,
});
if (!updateResult) {
logger.error("Failed to update brand");
return res.status(500).json({
error: "Failed to update brand",
});
}
logger.info(`Brand updated successfully ! (${brandSlug})`);
return res.status(200).json({
message: "Brand updated successfully",
});
}
/**
@ -76,19 +100,26 @@ async function updateBrand(req: Request, res: Response): Promise<Response> {
* @param {Response} res - The response object to send the result.
* @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"];
if (!brandSlug) {
logger.error("Brand slug is missing");
return res.status(400).json({ error: "Brand slug is missing" });
}
const brand = await BrandService.getBySlug(brandSlug);
if (!brand) {
logger.error("Brand not found");
return res.status(404).json({ error: "Brand not found" });
}
logger.info(`Brand retrieved successfully ! (${brandSlug})`);
return res.status(200).json(brand);
if (!brandSlug) {
logger.error("Brand slug is missing");
return res.status(400).json({
error: "Brand slug is missing",
});
}
const brand = await BrandService.getBySlug(brandSlug);
if (!brand) {
logger.error("Brand not found");
return res.status(404).json({
error: "Brand not found",
});
}
logger.info(`Brand retrieved successfully ! (${brandSlug})`);
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.
* @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();
if (!brands) {
logger.error("Failed to retrieve brands");
return res.status(500).json({ error: "Failed to retrieve brands" });
}
logger.info("Brands retrieved successfully !");
return res.status(200).json({
if (!brands) {
logger.error("Failed to retrieve brands");
return res.status(500).json({
error: "Failed to retrieve brands",
});
}
logger.info("Brands retrieved successfully !");
return res.status(200).json({
uat: Date.now(),
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.
* @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"];
if (!brandSlug) {
logger.error("Brand slug is missing");
return res.status(400).json({ error: "Brand slug is missing" });
}
if (!brandSlug) {
logger.error("Brand slug is missing");
return res.status(400).json({
error: "Brand slug is missing",
});
}
//TODO verify if models linked to brand
const doesExist = await BrandService.getBySlug(brandSlug);
if (!doesExist) {
logger.error("Brand not found");
return res.status(404).json({ error: "Brand not found" });
}
const deleteResult = await BrandService.delete(brandSlug);
if (!deleteResult) {
logger.error("Failed to delete brand");
return res.status(500).json({ error: "Failed to delete brand" });
}
logger.info(`Brand deleted successfully ! (${brandSlug})`);
return res.status(200).json({ message: "Brand deleted successfully" });
const doesExist = await BrandService.getBySlug(brandSlug);
if (!doesExist) {
logger.error("Brand not found");
return res.status(404).json({
error: "Brand not found",
});
}
const deleteResult = await BrandService.delete(brandSlug);
if (!deleteResult) {
logger.error("Failed to delete brand");
return res.status(500).json({
error: "Failed to delete brand",
});
}
logger.info(`Brand deleted successfully ! (${brandSlug})`);
return res.status(200).json({
message: "Brand deleted successfully",
});
}
//TODO get models of the brand
@ -149,6 +196,6 @@ const BrandController = {
getBySlug: getBySlugBrand,
getAll: getAllBrand,
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 CategoryService from "@services/category.service";
import type { Request, Response } from "express";
import { Logger } from "tslog";
//import {validationResult} from "express-validator";
const logger = new Logger({ name: "CategoryController" });
const logger = new Logger({
name: "CategoryController",
});
/**
* 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.
* @returns {Promise<Response>} The response object indicating the outcome of the category creation.
*/
async function createCategory(req: Request, res: Response): Promise<Response> {
const body: IDbCategory = req.body
const doesExist = await CategoryService.getBySlug(`${body.slug_name}`)
async function createCategory(
req: Request,
res: Response,
): Promise<Response> {
const body: IDbCategory = req.body;
const doesExist = await CategoryService.getBySlug(
`${body.slug_name}`,
);
if (doesExist) {
logger.error("Category already exists");
return res.status(400).json({ error: "Category already exists" });
}
logger.error("Category already exists");
return res.status(400).json({
error: "Category already exists",
});
}
const createResult = await CategoryService.create({
display_name: `${body.display_name}`,
slug_name: `${body.slug_name}`
})
slug_name: `${body.slug_name}`,
});
if (!createResult) {
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})`)
return res.status(201).json({ message: "Category created successfully" });
logger.info(
`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.
*/
async function updateCategory(req: Request, res:Response): Promise<Response> {
async function updateCategory(
req: Request,
res: Response,
): Promise<Response> {
const body: IDbCategory = req.body;
const categoryId = req.params["categorySlug"];
const categoryId = req.params["categorySlug"];
if (!categoryId) {
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}`)
if (!doesExist || !doesExist.id) {
logger.error("Category not found");
return res.status(404).json({ error: "Category not found" });
}
const updateResult = await CategoryService.update({
const doesExist = await CategoryService.getById(
`${categoryId}`,
);
if (!doesExist || !doesExist.id) {
logger.error("Category not found");
return res.status(404).json({
error: "Category not found",
});
}
const updateResult = await CategoryService.update({
id: doesExist.id,
slug_name: `${body.slug_name}`,
display_name: `${body.display_name}`
})
if (!updateResult) {
logger.error("Failed to update category");
return res.status(500).json({ error: "Failed to update category" });
}
logger.info(`Category updated successfully! (${categoryId})`);
return res.status(200).json({ message: "Category updated successfully" });
display_name: `${body.display_name}`,
});
if (!updateResult) {
logger.error("Failed to update category");
return res.status(500).json({
error: "Failed to update category",
});
}
logger.info(`Category updated successfully! (${categoryId})`);
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.
* @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"];
if (!categorySlug) {
logger.error("Category slug is missing");
return res.status(400).json({ error: "Category slug is missing" });
}
const doesExist = await CategoryService.getBySlug(`${categorySlug}`);
if (!doesExist || !doesExist.id) {
logger.error("Category not found");
return res.status(404).json({ error: "Category not found" });
}
const deleteResult = await CategoryService.delete(`${doesExist.id}`);
if (!deleteResult) {
logger.error("Failed to delete category");
return res.status(500).json({ error: "Failed to delete category" });
}
logger.info(`Category deleted successfully! (${categorySlug})`);
return res.status(200).json({ message: "Category deleted successfully" });
if (!categorySlug) {
logger.error("Category slug is missing");
return res.status(400).json({
error: "Category slug is missing",
});
}
const doesExist = await CategoryService.getBySlug(
`${categorySlug}`,
);
if (!doesExist || !doesExist.id) {
logger.error("Category not found");
return res.status(404).json({
error: "Category not found",
});
}
const deleteResult = await CategoryService.delete(
`${doesExist.id}`,
);
if (!deleteResult) {
logger.error("Failed to delete category");
return res.status(500).json({
error: "Failed to delete category",
});
}
logger.info(
`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.
* @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();
if (!categories) {
logger.error("Failed to get categories");
return res.status(500).json({ error: "Failed to get categories" });
}
logger.info("Categories retrieved successfully");
return res
.status(200)
.json({
if (!categories) {
logger.error("Failed to get categories");
return res.status(500).json({
error: "Failed to get categories",
});
}
logger.info("Categories retrieved successfully");
return res.status(200).json({
iat: Date.now(),
categories: categories.map((category: IDbCategory) => ({
id: category.id,
display_name: category.display_name,
slug_name: category.slug_name
})),
total: categories.length
id: category.id,
display_name: category.display_name,
slug_name: category.slug_name,
})),
total: categories.length,
});
}
@ -129,23 +175,34 @@ async function getAllCategory(_req: Request, res: Response): Promise<Response> {
*
* @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"];
if (!categorySlug) {
logger.error("Category slug is missing");
return res.status(400).json({ error: "Category slug is missing" });
}
const category = await CategoryService.getBySlug(`${categorySlug}`);
if (!category || !category.id) {
logger.error("Category not found");
return res.status(404).json({ error: "Category not found" });
}
logger.info(`Category retrieved successfully! (${categorySlug})`);
return res.status(200).json({
id: category.id,
display_name: category.display_name,
slug_name: category.slug_name
});
if (!categorySlug) {
logger.error("Category slug is missing");
return res.status(400).json({
error: "Category slug is missing",
});
}
const category = await CategoryService.getBySlug(
`${categorySlug}`,
);
if (!category || !category.id) {
logger.error("Category not found");
return res.status(404).json({
error: "Category not found",
});
}
logger.info(
`Category retrieved successfully! (${categorySlug})`,
);
return res.status(200).json({
id: category.id,
display_name: category.display_name,
slug_name: category.slug_name,
});
}
const CategoryController = {
@ -153,7 +210,7 @@ const CategoryController = {
update: updateCategory,
delete: deleteCategory,
getAll: getAllCategory,
getBySlug: getBySlugCategory
}
getBySlug: getBySlugCategory,
};
export default CategoryController;
export default CategoryController;

View File

@ -1,20 +1,27 @@
import type {Request, Response} from "express";
import {Logger} from "tslog";
import CategoryService from "@services/category.service";
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 { Logger } from "tslog";
//import {validationResult} from "express-validator";
const logger = new Logger({
name: "ModelController",
});
const logger = new Logger({ name: "ModelController" });
async function createModel(req: Request, res: Response): Promise<Response> {
const body: IDbModel = req.body
const doesExist = await CategoryService.getBySlug(`${body.slug_name}`)
async function createModel(
req: Request,
res: Response,
): Promise<Response> {
const body: IDbModel = req.body;
const doesExist = await CategoryService.getBySlug(
`${body.slug_name}`,
);
if (doesExist) {
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({
display_name: `${body.display_name}`,
@ -23,82 +30,123 @@ async function createModel(req: Request, res: Response): Promise<Response> {
base_price: Number.parseFloat(`${body.base_price}`),
brand_id: `${body.brand_id}`,
image_blob: `${body.image_blob}`,
is_trending: !!body.is_trending
})
is_trending: !!body.is_trending,
});
if (!createResult) {
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})`)
return res.status(201).json({ message: "Category created successfully" });
logger.info(
`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 doesExist = await ModelService.getBySlug(`${body.slug_name}`);
if (!doesExist) {
const doesExist = await ModelService.getBySlug(
`${body.slug_name}`,
);
if (!doesExist) {
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({
id: `${body.id}`,
display_name: `${body.display_name}`,
slug_name: `${body.slug_name}`,
category_id: `${body.category_id}`,
base_price: Number.parseFloat(`${body.base_price}`),
brand_id: `${body.brand_id}`,
image_blob: `${body.image_blob}`,
is_trending: !!body.is_trending
});
if (!updateResult) {
logger.error("Failed to update model");
return res.status(500).json({ error: "Failed to update model" });
}
logger.info(`Model updated successfully! (${body.slug_name})`);
return res.status(200).json({ message: "Model updated successfully" });
const updateResult = await ModelService.update({
id: `${body.id}`,
display_name: `${body.display_name}`,
slug_name: `${body.slug_name}`,
category_id: `${body.category_id}`,
base_price: Number.parseFloat(`${body.base_price}`),
brand_id: `${body.brand_id}`,
image_blob: `${body.image_blob}`,
is_trending: !!body.is_trending,
});
if (!updateResult) {
logger.error("Failed to update model");
return res.status(500).json({
error: "Failed to update model",
});
}
logger.info(
`Model updated successfully! (${body.slug_name})`,
);
return res.status(200).json({
message: "Model updated successfully",
});
}
async function getAllModel(res: Response): Promise<Response> {
const models = await ModelService.getAll();
if (!models) {
logger.error("Failed to get all models");
return res.status(500).json({ error: "Failed to get all models" });
}
return res.status(200).json({
if (!models) {
logger.error("Failed to get all models");
return res.status(500).json({
error: "Failed to get all models",
});
}
return res.status(200).json({
uat: Date.now(),
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"];
if (!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);
if (!model) {
logger.error("Model not found");
return res.status(404).json({ error: "Model not found" });
}
return res.status(200).json({ model });
const model = await ModelService.getBySlug(slug);
if (!model) {
logger.error("Model not found");
return res.status(404).json({
error: "Model not found",
});
}
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"];
if (!modelSlug) {
logger.error("Invalid model slug");
return res.status(400).json({ error: "Invalid model slug" });
}
if (!modelSlug) {
logger.error("Invalid model slug");
return res.status(400).json({
error: "Invalid model slug",
});
}
//TODO Check if vehicle related to model
const deleteResult = await ModelService.delete(modelSlug);
if (!deleteResult) {
logger.error("Failed to delete model");
return res.status(500).json({ error: "Failed to delete model" });
}
logger.info(`Model deleted successfully! (SLUG: ${modelSlug})`);
return res.status(200).json({ message: "Model deleted successfully" });
const deleteResult = await ModelService.delete(modelSlug);
if (!deleteResult) {
logger.error("Failed to delete model");
return res.status(500).json({
error: "Failed to delete model",
});
}
logger.info(
`Model deleted successfully! (SLUG: ${modelSlug})`,
);
return res.status(200).json({
message: "Model deleted successfully",
});
}
//TODO get all vehicles of an model by slug
@ -108,9 +156,9 @@ async function deleteModel(req: Request, res: Response): Promise<Response> {
const ModelController = {
create: createModel,
update: updateModel,
getAll: getAllModel,
getBySlug: getModelBySlug,
delete: deleteModel,
}
getAll: getAllModel,
getBySlug: getModelBySlug,
delete: deleteModel,
};
export default ModelController;
export default ModelController;

View File

@ -3,4 +3,4 @@ export interface IReqEditUserData {
lastName?: string;
displayName?: string;
password?: string;
}
}

View File

@ -12,7 +12,7 @@ interface DbUserData {
isDisabled: boolean;
resetPasswordToken?: string;
resetPasswordExpires?: Date;
resetPasswordExpires?: Date;
dob: Date;
gdpr: Date;
@ -20,4 +20,4 @@ interface DbUserData {
uat: Date;
}
export default DbUserData
export default DbUserData;

View File

@ -1,8 +1,8 @@
export interface IDbBrand {
id?: string;
slug_name: string;
display_name: string;
image_blob: BinaryType;
id?: string;
slug_name: string;
display_name: string;
image_blob: BinaryType;
}
export default IDbBrand;
export default IDbBrand;

View File

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

View File

@ -1,12 +1,12 @@
export interface IDbModel {
id?: string;
slug_name: string;
display_name: string;
brand_id: string;
category_id: string;
image_blob: BinaryType;
is_trending: boolean;
base_price: number;
id?: string;
slug_name: string;
display_name: string;
brand_id: string;
category_id: string;
image_blob: BinaryType;
is_trending: boolean;
base_price: number;
}
export default IDbModel;
export default IDbModel;

View File

@ -1,11 +1,11 @@
export interface IDbRent {
vehicle_id: string;
user_id: string;
active: boolean;
iat: Date;
eat: Date;
need_survey: boolean;
km_at_start: number
vehicle_id: string;
user_id: string;
active: boolean;
iat: Date;
eat: Date;
need_survey: boolean;
km_at_start: number;
}
export default IDbRent;
export default IDbRent;

View File

@ -6,4 +6,4 @@ export interface IDbStatusResult {
serverStatus: number;
warningStatus: number;
changedRows: number;
}
}

View File

@ -1,12 +1,12 @@
export interface IDbUser {
id?: string;
username: string;
firstname: string;
lastname: string;
dob: Date;
email: string;
is_mail_verified: boolean;
is_admin: boolean;
gdpr: Date;
hash: string
}
id?: string;
username: string;
firstname: string;
lastname: string;
dob: Date;
email: string;
is_mail_verified: boolean;
is_admin: boolean;
gdpr: Date;
hash: string;
}

View File

@ -4,4 +4,4 @@ export interface IDbVehicle {
model_id: string;
odometer: number;
health_state: number;
}
}

View File

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

View File

@ -1,4 +1,4 @@
export interface IReqLogin {
username: string;
password: string;
}
}

View File

@ -5,4 +5,4 @@ export interface IReqRegister {
lastName: string;
password: string;
gdpr?: boolean;
}
}

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 AdminGuard from "@validators/AdminGuard";
import UserGuard from "@validators/UserGuard";
import express, { type Router } from "express";
const AuthRouter: Router = express.Router();
AuthRouter.route('/login').post(AuthController.login)
AuthRouter.route('/register').post(AuthController.register)
AuthRouter.route("/login").post(AuthController.login);
AuthRouter.route("/register").post(AuthController.register);
// PATCH
//TODO - To test
AuthRouter.route('/me')
.patch(UserGuard, AuthController.editUser)
AuthRouter.route("/me").patch(
UserGuard,
AuthController.editUser,
);
// GET
AuthRouter.route('/me')
.get(UserGuard, AuthController.getSelf)
AuthRouter.route("/me").get(UserGuard, AuthController.getSelf);
// DELETE
AuthRouter.route('/me')
.delete(UserGuard, AuthController.deleteSelf)
AuthRouter.route("/me").delete(
UserGuard,
AuthController.deleteSelf,
);
// GET
AuthRouter.route('/all')
.get(AdminGuard, AuthController.getAllUsers)
AuthRouter.route("/all").get(
AdminGuard,
AuthController.getAllUsers,
);
// GET
AuthRouter.route('/user/:targetId')
AuthRouter.route("/user/:targetId")
.get(AdminGuard, AuthController.getUser)
.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 AdminGuard from "@validators/AdminGuard";
import UserGuard from "@validators/UserGuard";
import BrandController from "@controllers/brand.controller";
import CategoryController from "@controllers/category.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();
//-- 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)
.patch(AdminGuard, ModelController.update)
.delete(AdminGuard, ModelController.delete)
.delete(AdminGuard, ModelController.delete);
//-- 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)
.patch(AdminGuard, CategoryController.update)
.delete(AdminGuard, CategoryController.delete)
.delete(AdminGuard, CategoryController.delete);
//-- BRAND >>
CatalogRouter.route('/brand/new').post(AdminGuard, BrandController.create)
CatalogRouter.route('/brand/all').get(BrandController.getAll)
CatalogRouter.route('/brand/:brandSlug')
CatalogRouter.route("/brand/new").post(
AdminGuard,
BrandController.create,
);
CatalogRouter.route("/brand/all").get(BrandController.getAll);
CatalogRouter.route("/brand/:brandSlug")
.get(UserGuard, BrandController.getBySlug)
.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/catalog/catalogRouter'
export * from 'src/routes/rent/rentRouter'
export * from "src/routes/auth/authRouter";
export * from "src/routes/catalog/catalogRouter";
export * from "src/routes/rent/rentRouter";

View File

@ -1,34 +1,27 @@
import express, {type Router} from "express";
import AdminGuard from "@validators/AdminGuard";
import UserGuard from "@validators/UserGuard";
import express, { type Router } from "express";
const RentRouter: Router = express.Router();
// Get rent affected to the user
RentRouter.route('/affected')
.get(UserGuard)
RentRouter.route("/affected").get(UserGuard);
// Get all vehicle in rent (admin only)
RentRouter.route('/affected/all')
.get(AdminGuard)
RentRouter.route("/affected/all").get(AdminGuard);
// Add a new vehicle (admin only)
RentRouter.route('/veh/new')
.post(AdminGuard)
RentRouter.route("/veh/new").post(AdminGuard);
// Get all vehicles
RentRouter.route('/veh/all')
.get()
RentRouter.route("/veh/all").get();
// Rent a specific vehicle
RentRouter.route('/veh/rent/:vehicleId')
.post(UserGuard)
RentRouter.route("/veh/rent/:vehicleId").post(UserGuard);
RentRouter.route('/veh/:vehicleId')
RentRouter.route("/veh/:vehicleId")
.get(UserGuard)
.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 MysqlService from "@services/mysql.service";
import {Logger} from "tslog";
import { v4 as uuidv4 } from 'uuid';
import { Logger } from "tslog";
import { v4 as uuidv4 } from "uuid";
const DbHandler = new MysqlService.Handler('BrandService')
const logger = new Logger({name: 'BrandService'})
const DbHandler = new MysqlService.Handler("BrandService");
const logger = new Logger({
name: "BrandService",
});
//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.
*/
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) {
logger.error(`Brand already exists (${data.slug_name})`)
return {error: 'exist'}
logger.error(`Brand already exists (${data.slug_name})`);
return {
error: "exist",
};
}
const brandId = uuidv4();
const createdBrand = await MysqlService.Brand.insert(DbHandler, {
id: brandId,
slug_name: `${data.slug_name}`,
display_name: `${data.display_name}`,
image_blob: data.image_blob
});
if (createdBrand) {
logger.info(`Brand created successfully (${data.slug_name})`);
return { success: true, brand: createdBrand };
}
logger.error(`Failed to create brand (${data.slug_name})`);
return { error: 'failed' };
const createdBrand = await MysqlService.Brand.insert(
DbHandler,
{
id: brandId,
slug_name: `${data.slug_name}`,
display_name: `${data.display_name}`,
image_blob: data.image_blob,
},
);
if (createdBrand) {
logger.info(
`Brand created successfully (${data.slug_name})`,
);
return {
success: true,
brand: createdBrand,
};
}
logger.error(`Failed to create brand (${data.slug_name})`);
return {
error: "failed",
};
}
//SEC todo Blob validation
@ -44,38 +61,48 @@ async function createBrand(data: IDbBrand): Promise<unknown> {
async function updateBrand(data: IDbBrand): Promise<boolean> {
if (!data.id) {
logger.error("Brand ID is missing");
return false;
return false;
}
const doesExist = await MysqlService.Brand.getBySlug(DbHandler, data.slug_name);
if (doesExist && doesExist.id !== data.id) {
logger.error(`Brand already exists (${data.slug_name})`);
return false;
}
const updatedBrand = await MysqlService.Brand.update(DbHandler, {
id: data.id,
slug_name: `${data.slug_name}`,
display_name: `${data.display_name}`,
image_blob: data.image_blob
});
if (updatedBrand) {
logger.info(`Brand updated successfully (${data.slug_name})`);
return true;
}
logger.error(`Failed to update brand (${data.slug_name})`);
return false;
const doesExist = await MysqlService.Brand.getBySlug(
DbHandler,
data.slug_name,
);
if (doesExist && doesExist.id !== data.id) {
logger.error(`Brand already exists (${data.slug_name})`);
return false;
}
const updatedBrand = await MysqlService.Brand.update(
DbHandler,
{
id: data.id,
slug_name: `${data.slug_name}`,
display_name: `${data.display_name}`,
image_blob: data.image_blob,
},
);
if (updatedBrand) {
logger.info(
`Brand updated successfully (${data.slug_name})`,
);
return true;
}
logger.error(`Failed to update brand (${data.slug_name})`);
return false;
}
/**
* Retrieves all brands from the database.
* @returns {Promise<Array<IDbBrand>|false>} - An array of IDbBrand objects if successful, false otherwise.
*/
async function getAllBrand(): Promise<Array<IDbBrand>| false> {
async function getAllBrand(): Promise<Array<IDbBrand> | false> {
const brands = await MysqlService.Brand.getAll(DbHandler);
if (!brands) {
logger.error("Failed to retrieve brands");
return false;
}
logger.info(`Retrieved all brands successfully (${brands.length})`);
}
logger.info(
`Retrieved all brands successfully (${brands.length})`,
);
return brands;
}
@ -85,18 +112,25 @@ async function getAllBrand(): Promise<Array<IDbBrand>| false> {
* @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.
*/
async function getBySlugBrand(brandSlug: string): Promise<IDbBrand | false> {
async function getBySlugBrand(
brandSlug: string,
): Promise<IDbBrand | false> {
if (!brandSlug) {
logger.error("Brand slug is missing");
return false;
}
const brand = await MysqlService.Brand.getBySlug(DbHandler, brandSlug);
if (!brand) {
logger.error(`Brand not found (${brandSlug})`);
return false;
}
logger.info(`Retrieved brand by slug successfully (${brandSlug})`);
return brand;
logger.error("Brand slug is missing");
return false;
}
const brand = await MysqlService.Brand.getBySlug(
DbHandler,
brandSlug,
);
if (!brand) {
logger.error(`Brand not found (${brandSlug})`);
return false;
}
logger.info(
`Retrieved brand by slug successfully (${brandSlug})`,
);
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.
*/
async function getByIdBrand(brandId: string): Promise<IDbBrand | false> {
async function getByIdBrand(
brandId: string,
): Promise<IDbBrand | false> {
if (!brandId) {
logger.error("Brand ID is missing");
return false;
@ -115,12 +151,17 @@ async function getByIdBrand(brandId: string): Promise<IDbBrand | false> {
logger.error("Invalid brand ID");
return false;
}
const brand = await MysqlService.Brand.getById(DbHandler, brandId);
const brand = await MysqlService.Brand.getById(
DbHandler,
brandId,
);
if (!brand) {
logger.error(`Brand not found (${brandId})`);
return false;
}
logger.info(`Retrieved brand by ID successfully (${brandId})`);
logger.info(
`Retrieved brand by ID successfully (${brandId})`,
);
return brand;
}
@ -144,11 +185,14 @@ async function deleteBrand(brandId: string): Promise<boolean> {
return false;
}
//TODO verify if as models linked
const deletedBrand = await MysqlService.Brand.delete(DbHandler, brandId);
if (!deletedBrand) {
const deletedBrand = await MysqlService.Brand.delete(
DbHandler,
brandId,
);
if (!deletedBrand) {
logger.error(`Failed to delete brand (${brandId})`);
return false;
}
}
logger.info(`Brand deleted successfully (${brandId})`);
return true;
}
@ -160,6 +204,6 @@ const BrandService = {
getBySlug: getBySlugBrand,
getById: getByIdBrand,
delete: deleteBrand,
}
};
export default BrandService;
export default BrandService;

View File

@ -1,12 +1,12 @@
import type { IDbCategory } from "@interfaces/database/IDbCategory";
import MysqlService from "@services/mysql.service";
import {Logger} from "tslog";
import { v4 as uuidv4 } from 'uuid';
const DbHandler = new MysqlService.Handler('CategoryService')
const logger = new Logger({name: 'CategoryService'})
import { Logger } from "tslog";
import { v4 as uuidv4 } from "uuid";
const DbHandler = new MysqlService.Handler("CategoryService");
const logger = new Logger({
name: "CategoryService",
});
/**
* Creates a new category with the given data.
@ -15,19 +15,23 @@ const logger = new Logger({name: 'CategoryService'})
* @returns {Promise<boolean>} A promise that resolves with the created category.
* If an error occurs, the promise will reject with the error.
*/
async function createCategory(data: IDbCategory): Promise<boolean> {
logger.info(`Creating a new category... (${data.display_name})`)
async function createCategory(
data: IDbCategory,
): Promise<boolean> {
logger.info(
`Creating a new category... (${data.display_name})`,
);
try {
await MysqlService.Category.insert(DbHandler, {
id: uuidv4(),
display_name: data.display_name,
slug_name: data.slug_name
})
slug_name: data.slug_name,
});
//TODO Return the new id
return true;
} catch (error) {
logger.error(`Error creating category: ${error}`);
return false;
return false;
}
}
@ -43,19 +47,19 @@ async function createCategory(data: IDbCategory): Promise<boolean> {
*/
async function updateCategory(data: IDbCategory) {
if (!data.id) {
logger.error("Category id is missing.")
return false
logger.error("Category id is missing.");
return false;
}
try {
await MysqlService.Category.update(DbHandler, {
id: data.id,
slug_name: data.slug_name,
display_name: data.display_name
display_name: data.display_name,
});
//TODO Return id
return true;
} catch (err) {
logger.error(err)
logger.error(err);
return false;
}
}
@ -65,31 +69,37 @@ 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.
*/
async function getAll(): Promise<Promise<Array<IDbCategory>> | null> {
async function getAll(): Promise<Promise<
Array<IDbCategory>
> | null> {
try {
logger.info("Getting all categories...");
return await MysqlService.Category.getAll(DbHandler);
} catch (error) {
logger.error(`Error getting all categories: ${error}`);
return null;
}
logger.info("Getting all categories...");
return await MysqlService.Category.getAll(DbHandler);
} catch (error) {
logger.error(`Error getting all categories: ${error}`);
return null;
}
}
/**
* Gets a category by its slug
*
* @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
*/
async function getBySlug(slug: string): Promise<IDbCategory | null> {
async function getBySlug(
slug: string,
): Promise<IDbCategory | null> {
try {
logger.info(`Getting category by slug... (${slug})`);
return await MysqlService.Category.getBySlug(DbHandler, slug);
} catch (error) {
logger.error(`Error getting category by slug: ${error}`);
return null;
}
logger.info(`Getting category by slug... (${slug})`);
return await MysqlService.Category.getBySlug(
DbHandler,
slug,
);
} catch (error) {
logger.error(`Error getting category by slug: ${error}`);
return null;
}
}
/**
@ -98,35 +108,36 @@ async function getBySlug(slug: string): Promise<IDbCategory | null> {
* @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.
*/
async function getById(id: string):Promise<IDbCategory | null> {
async function getById(
id: string,
): Promise<IDbCategory | null> {
try {
logger.info(`Getting category by id... (${id})`);
return await MysqlService.Category.getById(DbHandler, id);
} catch (error) {
logger.error(`Error getting category by id: ${error}`);
return null;
}
logger.info(`Getting category by id... (${id})`);
return await MysqlService.Category.getById(DbHandler, id);
} catch (error) {
logger.error(`Error getting category by id: ${error}`);
return null;
}
}
//FEAT Get all models in category (slug)
/**
* Deletes a category with the given ID from the database.
*
* @param {string} id - The ID of the category to delete.
* @return {Promise} - A Promise that resolves to the deleted category if successful, or null if an error occurs.
*/
async function deleteCategory(id:string): Promise<unknown> {
async function deleteCategory(id: string): Promise<unknown> {
//TODO Verify if exist
//TODO Verify if element linked to category
try {
logger.info(`Deleting category... (${id})`);
return await MysqlService.Category.delete(DbHandler, id);
} catch (error) {
logger.error(`Error deleting category: ${error}`);
return null;
}
logger.info(`Deleting category... (${id})`);
return await MysqlService.Category.delete(DbHandler, id);
} catch (error) {
logger.error(`Error deleting category: ${error}`);
return null;
}
}
const CategoryService = {
@ -135,7 +146,7 @@ const CategoryService = {
update: updateCategory,
getAll,
getBySlug,
getById
}
getById,
};
export default CategoryService;
export default CategoryService;

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,16 @@
import {Logger} from "tslog";
import MySqlService from "@services/mysql.service";
import type { IReqLogin } from "@interfaces/requests/IReqLogin";
import type { IReqRegister } from "@interfaces/requests/IReqRegister";
import CredentialService from "@services/credential.service";
import JwtService from "@services/jwt.service";
import MySqlService from "@services/mysql.service";
import MysqlService from "@services/mysql.service";
import type {IReqRegister} from "@interfaces/requests/IReqRegister";
import {IReqLogin} from "@interfaces/requests/IReqLogin";
import { Logger } from "tslog";
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.
@ -17,55 +18,84 @@ const DbHandler = new MySqlService.Handler('UserService')
* @param {string} username - The username of the user to retrieve.
* @returns {Promise<Object | null>} - The user object if found, or null if not found.
*/
async function getUserFromUsername(username: string): Promise<object | null> {
const dbUser = await MySqlService.User.getByUsername(DbHandler, username)
async function getUserFromUsername(
username: string,
): Promise<object | null> {
const dbUser = await MySqlService.User.getByUsername(
DbHandler,
username,
);
if (dbUser === undefined) return null;
return dbUser;
}
async function getUserFromIdService(id: string | undefined) {
const dbUser = await MySqlService.User.getById(DbHandler, id);
if (dbUser === undefined) return null;
return dbUser;
if (dbUser === undefined) return null;
return dbUser;
}
async function register(ReqData: IReqRegister) {
if (ReqData.password.length < 6) {
logger.info(`REGISTER :> Invalid password (${ReqData.username})`)
return { error: "invalidPassword" };
logger.info(
`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 ?
if (ReqData.gdpr !== true) {
logger.info(`REGISTER :> GDPR not validated (${ReqData.username})`)
return { error: "gdprNotApproved" }
logger.info(
`REGISTER :> GDPR not validated (${ReqData.username})`,
);
return {
error: "gdprNotApproved",
};
}
// Check if exist and return
const dbUserIfExist = await getUserFromUsername(ReqData.username)
const dbUserIfExist = await getUserFromUsername(
ReqData.username,
);
if (dbUserIfExist) {
logger.info(`REGISTER :> User exist (${dbUserIfExist.username})\n ID:${dbUserIfExist.id}`)
return { error: "exist" }
logger.info(
`REGISTER :> User exist (${dbUserIfExist.username})\n ID:${dbUserIfExist.id}`,
);
return {
error: "exist",
};
}
const currentDate = new Date();
// 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.setLastName(ReqData.lastName);
// JWT
const alg = 'HS512'
const token = await JwtService.sign({
sub: NewUser.id
}, alg,
'1d',
'user')
const alg = "HS512";
const token = await JwtService.sign(
{
sub: NewUser.id,
},
alg,
"1d",
"user",
);
const userData = {
error: "none",
@ -75,45 +105,74 @@ async function register(ReqData: IReqRegister) {
username: NewUser.username,
displayName: NewUser.displayName,
firstName: NewUser.firstName,
lastName: NewUser.lastName
}};
logger.info(userData)
lastName: NewUser.lastName,
},
};
logger.info(userData);
await Db.collection("users").insertOne(NewUser);
logger.info(`REGISTER :> Inserted new user (${NewUser.username})`)
return userData
logger.info(
`REGISTER :> Inserted new user (${NewUser.username})`,
);
return userData;
}
async function login(ReqData: IReqLogin) {
//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) {
console.log(`LoginService :> User does not exist (${ReqData.username})`);
return { error: "userNotFound" };
console.log(
`LoginService :> User does not exist (${ReqData.username})`,
);
return {
error: "userNotFound",
};
}
if (ReqData.password.length < 6) {
console.log('X')
console.log(`LoginService :> Invalid password (${ReqData.username})`);
return { error: "invalidPassword" };
console.log("X");
console.log(
`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) {
console.log(isPasswordValid)
console.log(`LoginService :> Invalid password (${ReqData.username})`);
return { error: "invalidPassword" };
console.log(isPasswordValid);
console.log(
`LoginService :> Invalid password (${ReqData.username})`,
);
return {
error: "invalidPassword",
};
}
// biome-ignore lint/style/useConst: <explanation>
let userData = {
error: "none",
jwt: '',
jwt: "",
user: {
id: dbUser.id,
username: dbUser.username,
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);
@ -130,17 +189,17 @@ async function login(ReqData: IReqLogin) {
async function getAllUsersService() {
const users = await Db.collection("users").find().toArray();
// biome-ignore lint/complexity/noForEach: <explanation>
users.forEach(user => {
delete user.passwordHash
delete user._id
delete user.gdpr
users.forEach((user) => {
delete user.passwordHash;
delete user._id;
delete user.gdpr;
});
logger.info(`Query ${users.length} user(s)`)
logger.info(`Query ${users.length} user(s)`);
return {
iat: Date.now(),
users: users,
length: users.length
}
length: users.length,
};
}
/**
@ -154,19 +213,34 @@ async function getAllUsersService() {
*/
async function editUserService(targetId, sanitizedData) {
if (sanitizedData.password) {
const passwordHash = await getHashFromPassword(sanitizedData.password)
delete sanitizedData.password
logger.info(`Changing password for user "${targetId}"`)
sanitizedData.passwordHash = passwordHash
const passwordHash = await getHashFromPassword(
sanitizedData.password,
);
delete sanitizedData.password;
logger.info(`Changing password for user "${targetId}"`);
sanitizedData.passwordHash = passwordHash;
}
const updatedUserResult = await Db.collection("users").updateOne({id: targetId}, {$set: sanitizedData});
const updatedUserResult = await Db.collection(
"users",
).updateOne(
{
id: targetId,
},
{
$set: sanitizedData,
},
);
if (updatedUserResult.modifiedCount === 0) {
logger.info(`EDIT :> User not found (${targetId})`);
return { error: "userNotFound" };
return {
error: "userNotFound",
};
}
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.
*/
async function deleteUserService(targetId) {
logger.info(`Deleting user ${targetId}`)
logger.info(`Deleting user ${targetId}`);
try {
await Db.collection("users").deleteOne({id: targetId});
return true
await Db.collection("users").deleteOne({
id: targetId,
});
return true;
} catch (e) {
logger.warn(e)
return false
logger.warn(e);
return false;
}
}
@ -192,7 +268,7 @@ const UserService = {
getAll: getAllUsersService,
getFromId: getUserFromIdService,
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 type {NextFunction, Request, Response} from "express";
import MySqlService from "@services/mysql.service";
import MysqlService from "@services/mysql.service";
import {Logger} from "tslog";
import type { NextFunction, Request, Response } from "express";
import { Logger } from "tslog";
const DbHandler = new MySqlService.Handler('AdminGuard')
const logger = new Logger({name: 'AdminGuard'})
const DbHandler = new MySqlService.Handler("AdminGuard");
const logger = new Logger({
name: "AdminGuard",
});
const UNAUTHORIZED = 401;
const FORBIDDEN = 403;
const UNAUTH_MESSAGE = 'Missing Authorization Header';
const INVALID_TOKEN_MESSAGE = 'Invalid or expired token.';
const PERMISSON_NOT_VALID = 'You are missing the required permission.'
const UNAUTH_MESSAGE = "Missing Authorization Header";
const INVALID_TOKEN_MESSAGE = "Invalid or expired token.";
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;
if (!authHeader) {
logger.warn(`Invalid header (${req.ip})`)
return res.status(UNAUTHORIZED).json({message: UNAUTH_MESSAGE});
logger.warn(`Invalid header (${req.ip})`);
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);
if (token) {
// @ts-ignore
const isSourceAdmin = await MysqlService.User.getAdminStateForId(DbHandler, token.sub)
const isSourceAdmin =
await MysqlService.User.getAdminStateForId(
DbHandler,
token.sub,
);
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 type {NextFunction, Request, Response} from "express";
import MySqlService from "@services/mysql.service";
import {Logger} from "tslog";
import type { NextFunction, Request, Response } from "express";
import { Logger } from "tslog";
const DbHandler = new MySqlService.Handler('UserGuard')
const logger = new Logger({name: 'UserGuard'})
const DbHandler = new MySqlService.Handler("UserGuard");
const logger = new Logger({
name: "UserGuard",
});
const UNAUTHORIZED = 401;
const FORBIDDEN = 403;
const UNAUTH_MESSAGE = 'Missing Authorization Header';
const INVALID_TOKEN_MESSAGE = 'Invalid or expired token.';
const USER_NOT_EXIST = 'You dont exist anymore'
const UNAUTH_MESSAGE = "Missing Authorization Header";
const INVALID_TOKEN_MESSAGE = "Invalid or expired token.";
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;
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);
@ -29,16 +40,25 @@ async function UserGuard(req: Request, res: Response, next: NextFunction) {
const userId = token.sub;
if (!userId) {
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);
if (user) {
logger.info(`An user do a request. (${user?.username})`)
next()
const user = await MySqlService.User.getById(
DbHandler,
userId,
);
if (user) {
logger.info(`An user do a request. (${user?.username})`);
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;