Compare commits

...

7 Commits

Author SHA1 Message Date
65a6ae2e3c
feat(routes): update rent related routes
- The "/affected" route has been updated to now use the `RentController.getAssignedToUser` method.
- The "/affected/all" route, which was previously not implemented, now utilizes the `RentController.getAll` function.
- These changes will help facilitate the retrieval of individual and all rented vehicles.

Signed-off-by: Mathis <yidhra@tuta.io>
2024-05-03 13:18:46 +02:00
83d07a2812
feat(services): add availability check in rent service
A new condition was added in `rent.service.ts` to check if a vehicle is available before executing the rent operation. It also logs an error if the vehicle is not available.

Signed-off-by: Mathis <yidhra@tuta.io>
2024-05-03 13:18:33 +02:00
e8acfd7b30
feat(services): update condition checks in model.service.ts
Updated the condition checks in the 'delete' and 'fetch' methods of the `model.service.ts`. Now, it properly checks if the model exists by examining the first item of the result array, instead of considering the result array itself. This resolves issues where fetching or deleting a model with a non-existent slug would incorrectly attempt to perform operations considering the empty array as valid input.

Signed-off-by: Mathis <yidhra@tuta.io>
2024-05-03 13:18:15 +02:00
438ae4b5d0
fix(controllers): update model slug in updateModel function
The model slug has been updated to use `req.params["modelSlug"]` instead of `body.slug_name` in the `updateModel` function, ensuring the correct slug is used when checking if the model exists.

Signed-off-by: Mathis <yidhra@tuta.io>
2024-05-03 13:17:58 +02:00
6ccc899320
feat(interfaces): add isAvailable field to IDbVehicle interface
The IDbVehicle interface has been updated to include an optional `isAvailable` field. This field can be used to check the availability status of a vehicle.

Signed-off-by: Mathis <yidhra@tuta.io>
2024-05-03 13:17:47 +02:00
5afb6e22bf
feat(services): update getBySlug function in MySQL services
The `getBySlug` function originally returned a single database model by slug from the MySQL handler. It has been updated to return a list of database models by slug name. Error handling for failed query executions is also included.

Signed-off-by: Mathis <yidhra@tuta.io>
2024-05-03 13:17:37 +02:00
bdba2f6e29
feat(controllers): add rent controller
- Implemented functionality for creating, updating, and getting rent information.
- Created `createRent`, `updateRent`, `getAllAssigned`, and `getAssignedToUser` functions in the `rent.controller.ts` file.
- These functions handle all the interactions related to renting vehicles.

Issue: #25
Signed-off-by: Mathis <yidhra@tuta.io>
2024-05-03 13:17:25 +02:00
7 changed files with 173 additions and 15 deletions

View File

@ -42,7 +42,7 @@ async function createModel(req: Request, res: Response): Promise<Response> {
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(`${req.params["modelSlug"]}`);
if (!doesExist) { if (!doesExist) {
logger.error("Model does not exist"); logger.error("Model does not exist");
return res.status(404).json({ return res.status(404).json({

View File

@ -0,0 +1,150 @@
import { isDebugMode } from "@utils/debugState";
import type { Request, Response } from "express";
import { Logger } from "tslog";
import RentService from "@services/rent.service";
import {HttpStatusCode} from "@interfaces/requests/HttpStatusCode";
import type IDbRent from "@interfaces/database/IDbRent";
import JwtService from "@services/jwt.service";
import UserService from "@services/user.service";
const logger = new Logger({
name: "RentController",
});
async function createRent(req: Request, res: Response): Promise<Response> {
try {
const rentData: IDbRent = req.body;
if (!rentData.active || !rentData.need_survey || !rentData.eat || !rentData.iat || !rentData.user_id || !rentData.vehicle_id || !rentData.km_at_start || !rentData.active) {
logger.error("Invalid rent data");
return res.status(HttpStatusCode.BadRequest).json({
error: "Invalid rent data",
});
}
const rent = await RentService.create(rentData);
logger.info(`\n\n> Rent created successfully! (ID: ${rentData.vehicle_id})\n`);
return res.status(201).json({
message: "Rent created successfully",
rent,
});
} catch (error) {
logger.error(`\n\n> Failed to create rent !\n${error}\n`);
return res.status(500).json({
error: "Failed to create rent",
});
}
}
async function updateRent(req: Request, res: Response): Promise<Response> {
const body: IDbRent = req.body;
if (!body.vehicle_id || !body.user_id || !body.active || !body.need_survey || !body.eat || !body.iat || !body.km_at_start) {
logger.error("Invalid rent data");
return res.status(HttpStatusCode.BadRequest).json({
error: "Invalid rent data",
});
}
const rentId = req.params["rentId"];
if (!rentId || rentId.length !== 36) {
logger.error("Invalid rent ID");
return res.status(HttpStatusCode.BadRequest).json({
error: "Invalid rent ID",
});
}
const result = await RentService.update({
id: rentId,
vehicle_id: ``,
user_id: ``,
active: !!body.active,
need_survey: !!body.need_survey,
eat: body.eat,
iat: body.iat,
km_at_start: body.km_at_start,
})
if (!result) {
logger.error(`Failed to update rent with ID: ${rentId}`);
return res.status(HttpStatusCode.InternalServerError).json({
error: `Failed to update rent with ID: ${rentId}`,
});
}
logger.info(`Rent with ID: ${rentId} updated successfully`);
return res.status(HttpStatusCode.Ok).json({
message: `Rent with ID: ${rentId} updated successfully`,
});
}
async function getAllAssigned(res: Response): Promise<Response> {
const rents = await RentService.getAll();
if (rents.length === 0) {
return res.status(HttpStatusCode.NotFound).json({
error: "No assigned rents found",
});
}
return res.status(HttpStatusCode.Ok).json({
iat: Date.now(),
rents: rents,
total: rents.length
});
}
async function getAssignedToUser(req: Request, res: Response): Promise<Response> {
const authHeader = req.headers.authorization;
const bearerToken = authHeader?.split(" ")[1];
if (!bearerToken) {
logger.warn(`Bearer token not provided (${req.ip})`);
return res
.type("application/json")
.status(HttpStatusCode.Unauthorized)
.json({
error: "Unauthorized",
});
}
const payload = await JwtService.verify(bearerToken);
if (!payload || !payload.sub) {
logger.warn(`Unauthorized access attempt (${req.ip})`);
return res
.type("application/json")
.status(HttpStatusCode.Unauthorized)
.json({
error: "Unauthorized",
});
}
const sourceUser = await UserService.getFromId(payload.sub);
if (!sourceUser) {
return res.type("application/json").status(HttpStatusCode.ImATeapot).json({
error: "You dont exist anymore",
});
}
const userId: string = payload.sub;
if (!userId || userId.length !== 36) {
logger.error("Invalid user ID");
return res.status(HttpStatusCode.BadRequest).json({
error: "Invalid user ID",
});
}
let targetId = userId
if ("is_admin" in sourceUser && sourceUser.is_admin) {
targetId = req.body.targetId || userId
}
const rents = await RentService.getUserRent(targetId);
if (!rents) {
return res.status(HttpStatusCode.NotFound).json({
error: "No assigned rents found for the user",
});
}
return res.status(HttpStatusCode.Ok).json({
iat: Date.now(),
rents: rents,
total: rents.length,
});
}
if (isDebugMode()) logger.debug("\nController loaded.");
const RentController = {
create: createRent,
update: updateRent,
getAll: getAllAssigned,
getAssignedToUser,
};
export default RentController;

View File

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

View File

@ -2,14 +2,15 @@ import AdminGuard from "@validators/AdminGuard";
import UserGuard from "@validators/UserGuard"; import UserGuard from "@validators/UserGuard";
import express, { type Router } from "express"; import express, { type Router } from "express";
import VehicleController from "@controllers/vehicle.controller"; import VehicleController from "@controllers/vehicle.controller";
import RentController from "@controllers/rent.controller";
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").get(UserGuard); RentRouter.route("/affected").get(UserGuard, RentController.getAssignedToUser);
// Get all vehicle in rent (admin only) //TODO Non implemented yet // Get all vehicle in rent (admin only)
RentRouter.route("/affected/all").get(AdminGuard); RentRouter.route("/affected/all").get(AdminGuard, RentController.getAll);
// Add a new vehicle (admin only) // Add a new vehicle (admin only)
RentRouter.route("/veh/new").post(AdminGuard, VehicleController.create); RentRouter.route("/veh/new").post(AdminGuard, VehicleController.create);

View File

@ -80,12 +80,14 @@ async function deleteModel(modelSlug: string): Promise<boolean> {
} }
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[0]) {
logger.warn(`Model with slug ${modelSlug} not found`); logger.warn(`Model with slug ${modelSlug} not found`);
return false; return false;
} }
const target = doesExist[0]
if (!target.id) return false;
try { try {
await MysqlService.Model.delete(DbHandler, doesExist.id); await MysqlService.Model.delete(DbHandler, target.id);
logger.info("Deletion Successful !"); logger.info("Deletion Successful !");
return true; return true;
} catch (error) { } catch (error) {
@ -104,11 +106,11 @@ 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[0]) {
logger.warn(`Model with slug ${modelSlug} not found`); logger.warn(`Model with slug ${modelSlug} not found`);
return null; return null;
} }
return model; return model[0];
} catch (error) { } catch (error) {
logger.error(`Error fetching model by slug: ${error}`); logger.error(`Error fetching model by slug: ${error}`);
return null; return null;

View File

@ -569,20 +569,20 @@ const MySqlService = {
}, },
/** /**
* Retrieves a database model by slug from a given MySQL handler. * Retrieves a list of database models by slug name.
* *
* @param {MysqlHandler} handler - The MySQL handler instance. * @param {MysqlHandler} handler - The MySQL handler used to execute the query.
* @param {string} modelSlug - The slug of the model to retrieve. * @param {string} modelSlug - The slug name of the model to retrieve.
* @return {Promise<IDbModel>} A promise that resolves with the retrieved model. * @return {Promise<Array<IDbModel>>} - A promise that resolves to an array of database models.
* @throws {Error} If there was an error executing the query. * @throws {Error} - If an error occurs during the execution of the query.
*/ */
getBySlug(handler: MysqlHandler, modelSlug: string): Promise<IDbModel> { getBySlug(handler: MysqlHandler, modelSlug: string): Promise<Array<IDbModel>> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const _sql = "SELECT * FROM models WHERE slug_name VALUES(?)"; const _sql = "SELECT * FROM models WHERE slug_name VALUES(?)";
const _values = [modelSlug]; const _values = [modelSlug];
try { try {
handler.execute(_sql, _values).then((result) => { handler.execute(_sql, _values).then((result) => {
return resolve(result as unknown as IDbModel); return resolve(result as unknown as Array<IDbModel>);
}); });
} catch (err: unknown) { } catch (err: unknown) {
reject(err as Error); reject(err as Error);

View File

@ -32,6 +32,10 @@ async function createRentService(data: IDbRent): Promise<boolean> {
return false; return false;
} }
const vehicleId = vehicleIfExist[0].id const vehicleId = vehicleIfExist[0].id
if (!vehicleIfExist[0].isAvailable) {
logger.error(`Vehicle is not available`);
return false;
}
try { try {
const result = await MySqlService.Rent.insert(DbHandler, { const result = await MySqlService.Rent.insert(DbHandler, {
id: v4(), id: v4(),