feat(services): improve UserService with enhanced error handling and data validation
This commit includes updates to `user.service.ts` that enhance error handling and data validation. The `getUserFromUsername` function has been renamed to `getUserByEmail` reflecting the new identifier being used to retrieve users. Both `getUserByEmail` and `getUserFromIdService` have been revised to include error handling and logging capability. The `register` function now incorporates stronger validation checks and proper GDPR verification. It is also updated to return JWT token on successful registration. Issue: #18 Signed-off-by: Mathis <yidhra@tuta.io>
This commit is contained in:
parent
9225337e95
commit
3232e5fac1
@ -1,10 +1,14 @@
|
|||||||
import type { IReqLogin } from "@interfaces/requests/IReqLogin";
|
import type {IDbUser} from "@interfaces/database/IDbUser";
|
||||||
import type { IReqRegister } from "@interfaces/requests/IReqRegister";
|
import type {IReqLogin} from "@interfaces/requests/IReqLogin";
|
||||||
|
import type {IReqRegister} from "@interfaces/requests/IReqRegister";
|
||||||
|
import {ErrorType, type ISError} from "@interfaces/services/ISError";
|
||||||
import CredentialService from "@services/credential.service";
|
import CredentialService from "@services/credential.service";
|
||||||
import JwtService from "@services/jwt.service";
|
import JwtService from "@services/jwt.service";
|
||||||
import MySqlService from "@services/mysql.service";
|
import MySqlService from "@services/mysql.service";
|
||||||
import MysqlService from "@services/mysql.service";
|
import MysqlService from "@services/mysql.service";
|
||||||
import { Logger } from "tslog";
|
import {Logger} from "tslog";
|
||||||
|
import {v4} from "uuid";
|
||||||
|
|
||||||
|
|
||||||
const logger = new Logger({
|
const logger = new Logger({
|
||||||
name: "UserService",
|
name: "UserService",
|
||||||
@ -13,92 +17,124 @@ const logger = new Logger({
|
|||||||
const DbHandler = new MySqlService.Handler("UserService");
|
const DbHandler = new MySqlService.Handler("UserService");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a user object from the database based on the given username.
|
* Retrieves a user from the database by the given email address.
|
||||||
*
|
*
|
||||||
* @param {string} username - The username of the user to retrieve.
|
* @param {string} targetEmail - The email address of the user to retrieve.
|
||||||
* @returns {Promise<Object | null>} - The user object if found, or null if not found.
|
* @returns {Promise<IDbUser | ISError>}
|
||||||
|
* - A promise that resolves with the user.
|
||||||
|
* - If the user is not found, an error object is returned.
|
||||||
|
* - If an error occurs during the database operation, an error object is returned.
|
||||||
*/
|
*/
|
||||||
async function getUserFromUsername(username: string): Promise<object | null> {
|
async function getUserByEmail(targetEmail: string): Promise<IDbUser | ISError> {
|
||||||
const dbUser = await MySqlService.User.getByUsername(DbHandler, username);
|
try {
|
||||||
if (dbUser === undefined) return null;
|
const dbUser = await MySqlService.User.getByEmail(DbHandler, targetEmail);
|
||||||
return dbUser;
|
if (dbUser === undefined) {
|
||||||
}
|
logger.info(`User not found (${targetEmail})`);
|
||||||
|
return {
|
||||||
async function getUserFromIdService(id: string | undefined) {
|
error: ErrorType.NotFound,
|
||||||
const dbUser = await MySqlService.User.getById(DbHandler, id);
|
message: "The user was not fund.",
|
||||||
if (dbUser === undefined) return null;
|
};
|
||||||
return dbUser;
|
}
|
||||||
}
|
return dbUser;
|
||||||
|
} catch (err) {
|
||||||
async function register(ReqData: IReqRegister) {
|
logger.error(err);
|
||||||
if (ReqData.password.length < 6) {
|
|
||||||
logger.info(`REGISTER :> Invalid password (${ReqData.username})`);
|
|
||||||
return {
|
return {
|
||||||
error: "invalidPassword",
|
error: ErrorType.DatabaseError,
|
||||||
|
message: "An unknown error occurred.",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const passwordHash = await CredentialService.hash(ReqData.password);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a user from the database based on the provided ID.
|
||||||
|
*
|
||||||
|
* @param {string} id - The ID of the user to retrieve.
|
||||||
|
* @returns {Promise<IDbUser | ISError>} - A promise that resolves with the user object if found, or an error object if not.
|
||||||
|
*/
|
||||||
|
async function getUserFromIdService(id: string): Promise<IDbUser | ISError> {
|
||||||
|
try {
|
||||||
|
if (!id || id.length !== 36) {
|
||||||
|
logger.info(`Invalid ID (${id})`);
|
||||||
|
return {
|
||||||
|
error: ErrorType.InvalidData,
|
||||||
|
message: "Invalid ID length.",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const dbUser = await MySqlService.User.getById(DbHandler, id);
|
||||||
|
if (dbUser === undefined) {
|
||||||
|
logger.info(`User not found (${id})`);
|
||||||
|
return {
|
||||||
|
error: ErrorType.NotFound,
|
||||||
|
message: "The user was not found.",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return dbUser;
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
error: ErrorType.DatabaseError,
|
||||||
|
message: "An unknown error occurred.",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function register(ReqData: IReqRegister): Promise<ISError | string> {
|
||||||
|
if (ReqData.password.length < 6) {
|
||||||
|
return {
|
||||||
|
error: ErrorType.InvalidData,
|
||||||
|
message: "Password must be at least 6 characters long.",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const passwordHash = await CredentialService.hash(`${ReqData.password}`);
|
||||||
|
|
||||||
// Does the new user has accepted GDPR ?
|
// Does the new user has accepted GDPR ?
|
||||||
if (ReqData.gdpr !== true) {
|
if (ReqData.gdpr !== true) {
|
||||||
logger.info(`REGISTER :> GDPR not validated (${ReqData.username})`);
|
|
||||||
return {
|
return {
|
||||||
error: "gdprNotApproved",
|
error: ErrorType.InvalidData,
|
||||||
|
message: "GDPR acceptance is required.",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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();
|
const currentDate = new Date();
|
||||||
|
|
||||||
// New UserService (class)
|
// Check if exist and return
|
||||||
|
const dbUserIfExist: IDbUser | ISError = await getUserByEmail(ReqData.email);
|
||||||
|
if ("error" in dbUserIfExist) {
|
||||||
|
return {
|
||||||
|
error: dbUserIfExist.error,
|
||||||
|
message: dbUserIfExist.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const NewUser = new User(
|
const NewUser = await MySqlService.User.insert(DbHandler, {
|
||||||
ReqData.username,
|
id: v4(),
|
||||||
ReqData.displayName,
|
email: ReqData.email,
|
||||||
passwordHash,
|
username: ReqData.username,
|
||||||
currentDate,
|
firstname: ReqData.firstName,
|
||||||
);
|
lastname: ReqData.lastName,
|
||||||
NewUser.setFirstName(ReqData.firstName);
|
dob: ReqData.dob,
|
||||||
NewUser.setLastName(ReqData.lastName);
|
hash: passwordHash,
|
||||||
|
gdpr: currentDate,
|
||||||
|
is_admin: false,
|
||||||
|
is_mail_verified: false,
|
||||||
|
});
|
||||||
|
if ("error" in NewUser || !NewUser.id) {
|
||||||
|
return {
|
||||||
|
error: ErrorType.DatabaseError,
|
||||||
|
message: 'Error when inserting user in database.'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// JWT
|
// JWT
|
||||||
|
|
||||||
const alg = "HS512";
|
|
||||||
const token = await JwtService.sign(
|
const token = await JwtService.sign(
|
||||||
{
|
{
|
||||||
sub: NewUser.id,
|
sub: NewUser.id,
|
||||||
},
|
},
|
||||||
alg,
|
{
|
||||||
|
alg: "HS512",
|
||||||
|
},
|
||||||
"1d",
|
"1d",
|
||||||
"user",
|
"user",
|
||||||
);
|
);
|
||||||
|
return token;
|
||||||
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) {
|
async function login(ReqData: IReqLogin) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user