push de la fleme

This commit is contained in:
2024-04-17 16:55:04 +02:00
parent 66e402cbf6
commit f7fcc0d051
28 changed files with 2042 additions and 131 deletions

View File

@@ -0,0 +1,343 @@
const {
RegisterService,
LoginService,
getAllUsersService,
getUserFromIdService,
editUserService,
deleteUserService
} = require("../services/UserService");
const {JwtVerify} = require("../services/JwtService");
const { Logger } = require('tslog');
const logger = new Logger({ name: "Auth Controller" });
/**
* Registers a user.
*
* @async
* @param {Object} req - The request object.
* @param {Object} res - The response object.
* @return {Object} The response object containing the result of the registration.
* If successful, it will contain the registered user's data.
* If there is an error, it will contain an error name and message.
*/
async function registerUser(req, res) {
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' });
}
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' });
}
// sanitize data
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}`,
};
/**
* Represents the result of the registration service.
*
* @typedef {Object} RegisterServiceResult
* @property {Promise} promise - The promise that resolves when the service registration is complete.
*/
const RegisterServiceResult = await RegisterService(sanitizeData)
if (RegisterServiceResult.error === "gdprNotApproved") {
logger.warn(`GDPR not approved (${req.ip})`);
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."
});
}
// SUCCESS
logger.info(`User registered successfully (${req.ip})`);
return res
.type('application/json')
.status(201)
.json(RegisterServiceResult);
}
/**
* Logs in a user with the provided username and password.
*
* @param {Object} req - The request object containing the body data.
* @param {Object} res - The response object to send the result.
* @returns {Promise<void>} - A promise that resolves once the login process is complete.
*/
async function loginUser(req, res) {
const body = req.body;
if (!body) {
return res
.type('application/json')
.status(400)
.json({ error: 'Invalid input data' });
}
if (!body.password || !body.username) {
logger.warn(`Field(s) missing (${req.ip})`);
return res
.type('application/json')
.status(400)
.json({ error: 'Field(s) missing' });
}
const loginData = {
username: `${body.username}`,
password: `${body.password}`
};
console.log(body)
const LoginServiceResult = await LoginService(loginData);
console.log(LoginServiceResult)
if (LoginServiceResult.error === "userNotFound") {
console.log('POOL')
return res
.type('application/json')
.status(404)
.json({
error: LoginServiceResult.error,
message: "User not found."
});
}
if (LoginServiceResult.error === "invalidPassword") {
return res
.type('application/json')
.status(401)
.json({
error: LoginServiceResult.error,
message: "Invalid password."
});
}
return res
.type('application/json')
.status(200)
.json(LoginServiceResult);
}
//TODO - To test
async function getAllUsers(req, res) {
const authHeader = req.headers.authorization;
const bearerToken = authHeader.split(' ')[1];
const payload = await JwtVerify(bearerToken);
const sourceUser = await getUserFromIdService(payload.sub)
if (!sourceUser) {
return res
.type('application/json')
.status(404)
.json({ error: 'You dont exist anymore' });
}
if (!sourceUser.isAdmin) {
return res
.type('application/json')
.status(403)
.json({ error: 'Unauthorized' });
}
const AllUserResponse = await getAllUsersService()
if (!AllUserResponse.users) {
return res
.type('application/json')
.status(500)
.json({ error: 'Internal server error' });
}
return res
.type('application/json')
.status(200)
.json(AllUserResponse);
}
//TODO - To test
/**
* Get user from the database based on the provided user ID and return it as a response.
*
* @async
* @param {object} req - The request object containing the user ID as a parameter.
* @param {object} res - The response object to be used for sending the user data or error.
* @return {Promise<void>} - A Promise that resolves when the user data is sent to the client or an error occurred.
*/
async function getUser(req, res) {
const userId = req.params.userId;
const dbUser = await getUserFromIdService(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(200)
.json(dbUser);
}
//TODO - To test
async function editUser(req, res) {
const body = req.body;
if (!body) {
return res
.type('application/json')
.status(400)
.json({ error: 'Field(s) missing' });
}
const authHeader = req.headers.authorization;
const bearerToken = authHeader.split(' ')[1];
const payload = await JwtVerify(bearerToken);
const sourceUser = await getUserFromIdService(payload.sub)
/**
* Represents the user ID that is the target for a specific operation.
*
* @type {string|number}
*/
const targetUserId = body.targetId | payload.sub
if (!sourceUser) {
logger.warn(`Unauthorized access attempt (${req.ip})`);
return res
.type('application/json')
.status(404)
.json({ error: 'You dont exist anymore' });
}
if (sourceUser.isAdmin || sourceUser.id === payload.sub) {
if (sourceUser.isAdmin) {
logger.info(`EDIT :> Source user is an admin (${sourceUser.displayName})`)
} else {
logger.info(`EDIT :> Source user modify itself (${sourceUser.displayName})`)
}
// biome-ignore lint/style/useConst: <explanation>
let modifiedData= {}
if (body.firstName) modifiedData.firstName = `${body.firstName}`;
if (body.lastName) modifiedData.lastName = `${body.lastName}`;
if (body.displayName) modifiedData.displayName = `${body.displayName}`;
if (body.password) modifiedData.password = `${body.password}`;
//Call service
const EditUserServiceResult = await editUserService(`${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' });
}
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')
.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' });
}
//TODO - To test
async function deleteUser(req, res) {
const body = req.body;
const authHeader = req.headers.authorization;
const bearerToken = authHeader.split(' ')[1];
const payload = await JwtVerify(bearerToken);
const sourceUser = await getUserFromIdService(payload.sub)
const targetUserId = body.targetId | payload.sub
if (!sourceUser) {
logger.warn(`Unauthorized access attempt (${req.ip})`);
return res
.type('application/json')
.status(404)
.json({ error: 'You dont exist anymore' });
}
if (sourceUser.isAdmin || sourceUser.id === payload.sub) {
const deleteUserServiceResult = await deleteUserService(`${targetUserId}`);
if (!deleteUserServiceResult) {
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' });
}
}
/**
* Retrieves the user's information.
*
* @param {object} req - The incoming request object.
* @param {object} res - The outgoing response object.
*/
async function getSelf(req, res) {
const authHeader = req.headers.authorization;
const bearerToken = authHeader.split(' ')[1];
const payload = await JwtVerify(bearerToken);
console.log(payload)
const dbUser = await getUserFromIdService(payload.sub)
if (!dbUser) {
return res
.type('application/json')
.status(404)
.json({ error: 'User not found' });
}
return res
.type('application/json')
.status(200)
.json({
username: dbUser.username,
displayName: dbUser.displayName,
firstName: dbUser.firstName,
lastName: dbUser.lastName
});
}
module.exports = {
registerUser,
loginUser,
getAllUsers,
getUser,
editUser,
deleteUser,
getSelf
}

View File

@@ -0,0 +1,180 @@
const {
getUserFromIdService
} = require("../services/UserService");
const {
JwtVerify
} = require("../services/JwtService");
const {
getAllEventsService,
getEventFromIdService, alterUserSubscribedEventStateService, getUserSubscribedEventService
} = require("../services/EventService");
//TODO - To test
/**
* Retrieves all events.
*
* @param {Object} req - The request object.
* @param {Object} res - The response object.
* @return {Object} The response object containing all events or an error message if events not found.
*/
async function getAllEvents(req, res) {
const events = await getAllEventsService('public');
if (!events) {
return res.status(404).json({ message: "Events not found" });
}
return res.status(200).json(events);
}
//TODO - To test
/**
* Retrieves an event by ID.
*
* @param {object} req - The request object.
* @param {object} res - The response object.
*
* @return {object} Returns a response with the retrieved event.
*
* @throws {Error} Throws an error if the event ID is missing or if the event is not found.
*/
async function getEvent(req, res) {
const authHeader = req.headers.authorization;
const bearerToken = authHeader.split(' ')[1];
const payload = await JwtVerify(bearerToken);
const sourceUser = await getUserFromIdService(payload.sub)
const targetId = req.params.id;
if (!targetId) {
return res.status(400).json({ message: "Event ID is missing" });
}
const result = await getEventFromIdService(targetId)
if (!result) {
return res.status(404).json({ message: "Event not found" });
}
return res.status(200).json(result);
}
//TODO Owner user, admin user ===
async function editEvent(req, res) {
const body = req.body;
const authHeader = req.headers.authorization;
const bearerToken = authHeader.split(' ')[1];
const payload = await JwtVerify(bearerToken);
const sourceUser = await getUserFromIdService(payload.sub)
const targetId = body.targetId || sourceUser.id;
const eventTargetId = req.params.id
if (targetId !== sourceUser.id && !sourceUser.isAdmin) {
res.status(403).json({ message: "Unauthorized request" });
}
if (!eventTargetId) {
res.status(400).json({ message: "Event target ID is missing" });
}
}
//TODO Owner user, admin user ===
async function deleteEvent(req, res) {
const authHeader = req.headers.authorization;
const bearerToken = authHeader.split(' ')[1];
const payload = await JwtVerify(bearerToken);
const sourceUser = await getUserFromIdService(payload.sub)
}
//TODO Event creation by logged user ===
async function createNewEvent(req, res) {
const authHeader = req.headers.authorization;
const bearerToken = authHeader.split(' ')[1];
const payload = await JwtVerify(bearerToken);
const sourceUser = await getUserFromIdService(payload.sub)
}
//TODO - To test
/**
* Retrieves the subscribed event for the specified user.
*
* @param {Object} req - The request object.
* @param {Object} res - The response object.
* @returns {Object} The subscribed event information.
*/
async function getSubscribedEvent(req, res) {
const authHeader = req.headers.authorization;
const bearerToken = authHeader.split(' ')[1];
const payload = await JwtVerify(bearerToken);
const sourceUser = await getUserFromIdService(payload.sub)
const targetId = body.targetId || sourceUser.id;
if (targetId !== sourceUser.id && !sourceUser.isAdmin) {
res.status(403).json({ message: "Unauthorized request" });
}
const subscribedEventResult = await getUserSubscribedEventService(targetId);
if (subscribedEventResult.error === 'noSubscribedEventFound') {
return res
.type('application/json')
.status(404)
.json({
error: 'noSubscribedEventFound',
message: 'No subscribed event found'
});
}
return res
.type('application/json')
.status(200)
.json(subscribedEventResult);
}
//TODO - To test
/**
* Alter the subscription state of an event for a user.
* @param {Object} req
* - The request object.
* @param {Object} req.body
* - The body of the request containing the desired subscription state.
* @param {string} req.headers.authorization
* - The authorization header containing the bearer token.
* @param {string} req.params.id
* - The ID of the target event.
* @param {Object} res
* - The response object.
* @returns {Object} The response object.
*/
async function alterSubscribedEventState(req, res) {
const body = req.body
const authHeader = req.headers.authorization;
const bearerToken = authHeader.split(' ')[1];
const payload = await JwtVerify(bearerToken);
const sourceUser = await getUserFromIdService(payload.sub)
const eventTargetId = req.params.id;
const userTargetId = body.userId || sourceUser.id
const wantedState = body.subscribed === true
if (!eventTargetId) {
return res.status(400).json({ message: "Event target ID is missing" });
}
if (userTargetId !== sourceUser.id && !sourceUser.isAdmin) {
return res.status(403).json({ message: "Unauthorized request" });
}
const alterEventSubStateResult = await alterUserSubscribedEventStateService(
userTargetId,
eventTargetId,
wantedState
)
if (alterEventSubStateResult.error === 'none') {
return res.status(200).json({
message: "Event subscription state altered"
});
}
return res.status(400).json({
error: alterEventSubStateResult.error,
message: "Event subscription state not altered"
});
}
module.exports = {
getAllEvent: getAllEvents,
getEvent,
editEvent,
deleteEvent,
createNewEvent,
getSubscribedEvent,
alterSubscribedEventState
}

View File

@@ -0,0 +1,22 @@
//TODO Logged user, size limit, format type
async function addNewImage(req, res) {
}
//TODO Admin user
async function GetAllImages(req, res) {
}
//TODO Logged and non logged
async function getImage(req, res) {
}
//TODO Owner user and admin user
async function deleteImage(req, res) {
}
module.exports = {
addNewImage,
GetAllImages,
getImage,
deleteImage
}

View File

@@ -0,0 +1,281 @@
const {JwtVerify} = require("../services/JwtService");
const {
CreateThreadService,
GetAllThreadService,
GetThreadByIdService,
UpdateThreadService,
DeleteThreadService,
GetUserThreadService
} = require("../services/ThreadService");
const req = require("express/lib/request");
/**
* Retrieves the payload of a JWT token from the request headers.
* @param {Object} req - The HTTP request object.
* @return {Promise<Object|boolean>} - The payload of the JWT token if it exists, otherwise false.
*/
async function getJwtPayload(req) {
const authHeader = req.headers.authorization;
const bearerToken = authHeader.split(' ')[1];
const jwtPayload = await JwtVerify(bearerToken);
if (jwtPayload) {
return jwtPayload;
}
console.log(`AUTH :> Invalid jwt (${req.ip})`)
return false
}
/**
* CreateThreadController - Controller function for creating a thread
*
* @param {Object} req - The request object
* @param {Object} res - The response object
*
* @return {Promise} - A Promise that resolves to the response object with appropriate status and JSON payload
*/
async function CreateThreadController(req, res) {
console.log(`CTRL :> Thread creation (${req.ip})`)
const payload = await getJwtPayload(req)
if (payload) {
const body = req.body;
if (!body) {
return res
.type('application/json')
.status(400)
.json({ error: 'Invalid input data' });
}
if (!body.title || !body.subTitle || !body.base64Banner || !body.desc || !body.price) {
return res
.type('application/json')
.status(400)
.json({ error: 'Field(s) missing' });
}
const userId = payload.sub
const sanitizedData = {
userId: `${userId}`,
title: `${body.title}`,
subTitle: `${body.subTitle}`,
base64Banner: `${body.base64Banner}`,
desc: `${body.desc}`,
price: Number.parseFloat(body.price)
}
const CreateThreadServiceResult = await CreateThreadService(sanitizedData)
if (!CreateThreadServiceResult) {
return res
.type('application/json')
.status(500)
.json({ error: 'Failed to create thread' });
}
return res
.type('application/json')
.status(200)
.json({ success: 'Thread created successfully' });
}
}
/**
* Retrieves a thread by its ID.
* @async
* @function GetThreadByIdController
* @param {Object} req - The request object containing the parameters and body.
* @param {Object} res - The response object used to send the response.
* @return {Promise<void>} - A promise that resolves once the thread is retrieved and the response is sent.
*/
async function GetThreadByIdController(req, res) {
const payload = await getJwtPayload(req)
const body = req.body;
if (payload) {
if (!req.params.id) {
return res
.type('application/json')
.status(400)
.json({ error: 'Field(s) missing' });
}
const threadId = req.params.id;
const GetThreadByIdServiceResult = await GetThreadByIdService(threadId);
if (GetThreadByIdServiceResult.error === 'ThreadNotFound') {
return res
.type('application/json')
.status(404)
.json({ message: `${GetThreadByIdServiceResult.message}` });
}
return res
.type('application/json')
.status(200)
.json(GetThreadByIdServiceResult);
}
}
/**
* Retrieve all threads for a user.
*
* @param {Object} req - The request object.
* @param {Object} req.ip - The IP address of the requesting client.
* @param {Object} res - The response object.
* @returns {Promise} A promise that resolves with the JSON response containing all threads, or rejects with an error.
*/
async function GetAllThreadController(req, res) {
console.log(`CTRL :> Query all threads (${req.ip})`)
const payload = await getJwtPayload(req)
if (payload) {
const ServiceResult = await GetAllThreadService({userId: payload.sub})
if (!ServiceResult) {
return res
.type('application/json')
.status(200)
.json({ error: 'No threads found' });
}
if (ServiceResult.error) {
return res
.type('application/json')
.status(500)
.json({ error: ServiceResult.message });
}
return res
.type('application/json')
.status(200)
.json(ServiceResult);
}
}
/**
* Retrieves a user's thread from the server.
*
* @param {Object} req - The request object.
* @param {Object} res - The response object.
* @return {Object} The response object containing the retrieved user thread.
* @throws {Error} If an error occurs while retrieving the user thread.
*/
async function GetUserThreadController(req, res) {
const payload = await getJwtPayload(req)
const GetUserThreadServiceResult = await GetUserThreadService(payload.sub);
if (GetUserThreadServiceResult.error === 'ThreadNotFound') {
return res
.type('application/json')
.status(200)
.json({ error: 'No threads found' });
}
if (GetUserThreadServiceResult.error) {
return res
.type('application/json')
.status(500)
.json({ error: GetUserThreadServiceResult.message });
}
return res
.type('application/json')
.status(200)
.json(GetUserThreadServiceResult);
}
/**
* UpdateThreadController is an asynchronous function that handles the logic for updating a thread.
*
* @param {Object} req - The request object.
* @param {Object} res - The response object.
* @return {Object} - The response object.
*/
async function UpdateThreadController(req, res) {
const payload = await getJwtPayload(req)
if (payload) {
const body = req.body;
if (!body) {
return res
.type('application/json')
.status(400)
.json({ error: 'Invalid input data' });
}
if (!req.params.id) {
return res
.type('application/json')
.status(400)
.json({ error: 'Missing identifier' });
}
const threadId = req.params.id;
if (!body) {
return res
.type('application/json')
.status(400)
.json({ error: 'Invalid input data' });
}
if (!body.title || !body.subTitle || !body.base64Banner || !body.desc || !body.price || !body.userId) {
return res
.type('application/json')
.status(400)
.json({ error: 'Field(s) missing' });
}
const sanitizedData = {
title: `${body.title}`,
subTitle: `${body.subTitle}`,
base64Banner: `${body.base64Banner}`,
desc: `${body.desc}`,
price: Number.parseFloat(body.price)
}
const UpdateThreadServiceResult = await UpdateThreadService(threadId, sanitizedData);
if (UpdateThreadServiceResult.error === 'ThreadNotFound') {
return res
.type('application/json')
.status(404)
.json({ message: `${UpdateThreadServiceResult.message}` });
}
return res
.type('application/json')
.status(200)
.json({ message: 'Thread updated successfully' });
}
}
/**
* Deletes a thread.
* @param {Object} req - The request object.
* @param {Object} res - The response object.
* @return {Promise} - A promise that resolves with the response.
*/
async function DeleteThreadController(req, res) {
const payload = await getJwtPayload(req)
if (payload) {
const body = req.body;
if (!body) {
return res
.type('application/json')
.status(400)
.json({ error: 'Invalid input data' });
}
if (!req.params.id) {
return res
.type('application/json')
.status(400)
.json({ error: 'Field(s) missing' });
}
const threadId = `${body.id}`;
const DeleteThreadServiceResult = await DeleteThreadService(threadId);
if (!DeleteThreadServiceResult) {
return res
.type('application/json')
.status(500)
.json({ error: 'Failed to delete thread' });
}
if (DeleteThreadServiceResult.error === 'ThreadNotFound') {
return res
.type('application/json')
.status(404)
.json({ message: `${DeleteThreadServiceResult.message}` });
}
return res
.type('application/json')
.status(200)
.json({ message: 'Thread deleted successfully' });
}
}
module.exports = {
CreateThreadController,
GetThreadByIdController,
GetAllThreadController,
GetUserThreadController,
UpdateThreadController,
DeleteThreadController
}

View File

@@ -0,0 +1,23 @@
const express = require("express");
const router = express.Router()
const {
getSelf,
loginUser,
registerUser,
getUser,
editUser,
deleteUser
} = require("../../AuthController");
const {validateJWT} = require("../../../middlewares/AuthorizationMiddleware");
router.route("/login").post(loginUser)
router.route("/register").post(registerUser)
router.route("/me").get(validateJWT, getSelf)
router.route("/:id").get(validateJWT, getUser)
router.route("/:id").patch(validateJWT, editUser)
router.route("/:id").delete(validateJWT, deleteUser)
module.exports = router

View File

@@ -0,0 +1,24 @@
const express = require("express");
const router = express.Router()
const {
getSubscribedEvent,
getEvent,
getAllEvent,
alterSubscribedEventState,
createNewEvent,
deleteEvent,
editEvent
} = require("../../EventController");
const {validateJWT} = require("../../../middlewares/AuthorizationMiddleware");
router.route("/all").get(getAllEvent)
router.route("/subscribed").get(validateJWT, getSubscribedEvent)
router.route("/subscribed").post(validateJWT, alterSubscribedEventState)
router.route("/new").post(validateJWT, createNewEvent)
router.route("/:id").get(validateJWT, getEvent)
router.route("/:id").patch(validateJWT, editEvent)
router.route("/:id").delete(validateJWT, deleteEvent)
module.exports = router

View File

@@ -0,0 +1,13 @@
const express = require("express");
const router = express.Router()
const {} = require("../../EventController");
const {isAdmin, validateJWT} = require("../../../middlewares/AuthorizationMiddleware");
router.route("/all").get(isAdmin)
router.route("/new").post(validateJWT)
router.route("/:id").get(validateJWT)
router.route("/:id").delete(validateJWT)
module.exports = router

View File

@@ -0,0 +1,28 @@
const express = require("express");
const {
CreateThreadController,
GetThreadByIdController,
GetAllThreadController,
UpdateThreadController,
DeleteThreadController,
GetUserThreadController
} = require("../../ThreadController");
const {validateJWT} = require("../../../middlewares/AuthorizationMiddleware");
const router = express.Router()
// CREATE
router.route("/new").post(validateJWT, CreateThreadController)
// READ
router.route("/all").get(validateJWT, GetAllThreadController)
router.route("/user").get(validateJWT, GetUserThreadController)
router.route("/:id").get(validateJWT, GetThreadByIdController)
// UPDATE
router.route("/:id").patch(validateJWT, UpdateThreadController)
// DELETE
router.route("/:id").delete(validateJWT, DeleteThreadController)
module.exports = router