brief-05-back/src/services/user.service.ts
Mathis 789d62ea62
feat(services): refactor register and login functions in UserService
- Removed extraneous comments and updated function parameters to use interface types in `register` and `login` methods.
- Renamed `RegisterService` and `LoginService` to `register` and `login` respectively.
- This update enhances readability and maintains the consistency in code by leveraging TypeScript's type-checking feature.

Signed-off-by: Mathis <yidhra@tuta.io>
2024-04-25 16:57:21 +02:00

198 lines
5.9 KiB
TypeScript

import {Logger} from "tslog";
import MySqlService from "@services/mysql.service";
import CredentialService from "@services/credential.service";
import JwtService from "@services/jwt.service";
import MysqlService from "@services/mysql.service";
import type {IReqRegister} from "@interfaces/requests/IReqRegister";
import {IReqLogin} from "@interfaces/requests/IReqLogin";
const logger = new Logger({ name: "UserService" });
const DbHandler = new MySqlService.Handler('UserService')
/**
* Retrieves a user object from the database based on the given username.
*
* @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)
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;
}
async function register(ReqData: IReqRegister) {
if (ReqData.password.length < 6) {
logger.info(`REGISTER :> Invalid password (${ReqData.username})`)
return { error: "invalidPassword" };
}
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" }
}
// Check if exist and return
const dbUserIfExist = await getUserFromUsername(ReqData.username)
if (dbUserIfExist) {
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);
NewUser.setFirstName(ReqData.firstName);
NewUser.setLastName(ReqData.lastName);
// JWT
const alg = 'HS512'
const token = await JwtService.sign({
sub: NewUser.id
}, alg,
'1d',
'user')
const userData = {
error: "none",
jwt: token,
user: {
id: NewUser.id,
username: NewUser.username,
displayName: NewUser.displayName,
firstName: NewUser.firstName,
lastName: NewUser.lastName
}};
logger.info(userData)
await Db.collection("users").insertOne(NewUser);
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);
if (!dbUser) {
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" };
}
const isPasswordValid = await CredentialService.compare(ReqData.password, dbUser.hash)
if (!isPasswordValid) {
console.log(isPasswordValid)
console.log(`LoginService :> Invalid password (${ReqData.username})`);
return { error: "invalidPassword" };
}
// biome-ignore lint/style/useConst: <explanation>
let userData = {
error: "none",
jwt: '',
user: {
id: dbUser.id,
username: dbUser.username,
displayName: dbUser.displayName,
}
};
userData.jwt = await JwtService.sign({sub: dbUser.id}, {alg: 'HS512'}, '7d', 'user')
console.log("USERDATA :>");
console.log(userData);
return userData;
}
/**
* Retrieves all users from the database.
*
* @async
* @function getAllUsersService
* @returns {Promise<{iat: number, users: Array<user>, length: number}>} - The response object containing the users array and its length.
*/
async function getAllUsersService() {
const users = await Db.collection("users").find().toArray();
// biome-ignore lint/complexity/noForEach: <explanation>
users.forEach(user => {
delete user.passwordHash
delete user._id
delete user.gdpr
});
logger.info(`Query ${users.length} user(s)`)
return {
iat: Date.now(),
users: users,
length: users.length
}
}
/**
* Edits a user in the database.
*
* @param {string} targetId - The ID of the user to be edited.
* @param {object} sanitizedData - The sanitized data to update the user with.
* @returns {object} - An object indicating the result of the operation.
* If the user is not found, the error property will be a string "userNotFound".
* Otherwise, the error property will be a string "none".
*/
async function editUserService(targetId, sanitizedData) {
if (sanitizedData.password) {
const passwordHash = await getHashFromPassword(sanitizedData.password)
delete sanitizedData.password
logger.info(`Changing password for user "${targetId}"`)
sanitizedData.passwordHash = passwordHash
}
const updatedUserResult = await Db.collection("users").updateOne({id: targetId}, {$set: sanitizedData});
if (updatedUserResult.modifiedCount === 0) {
logger.info(`EDIT :> User not found (${targetId})`);
return { error: "userNotFound" };
}
logger.info(`EDIT :> User updated (${targetId})`);
return { error: "none" };
}
/**
* Delete a user from the database.
*
* @param {string} targetId - The ID of the user to be deleted.
* @return {Promise<boolean>} - A promise that resolves to true if the user is successfully deleted, or false if an error occurs.
*/
async function deleteUserService(targetId) {
logger.info(`Deleting user ${targetId}`)
try {
await Db.collection("users").deleteOne({id: targetId});
return true
} catch (e) {
logger.warn(e)
return false
}
}
const UserService = {
register: register,
login: login,
getAll: getAllUsersService,
getFromId: getUserFromIdService,
edit: editUserService,
delete: deleteUserService
}
export default UserService;