From 307c5e2d688669865ac7d136d22a1247791258eb Mon Sep 17 00:00:00 2001 From: rafiarrafif Date: Sun, 11 May 2025 01:41:05 +0700 Subject: [PATCH] fixing in user and authentication --- bun.lockb | Bin 63698 -> 63698 bytes src/helpers/error/handler/index.ts | 63 +++++++++++++++--- src/helpers/error/instances/app.ts | 13 ++++ .../loginWithPassword.controller.ts | 11 +-- .../services/loginWithPassword.service.ts | 12 +++- .../user/controller/createUser.controller.ts | 6 +- .../user/controller/getAllUser.controller.ts | 5 +- .../repositories/createUser.repository.ts | 17 +++++ .../findUserByEmailOrUsername.repository.ts | 2 +- .../repositories/getAllUser.repository.ts | 15 +++++ .../user/services/createUser.service.ts | 11 ++- .../user/services/getAllUser.service.ts | 8 +-- .../controller/createUserRole.controller.ts | 2 +- .../createUserSession.controller.ts | 2 +- src/utils/databases/prisma/error/handler.ts | 51 -------------- 15 files changed, 122 insertions(+), 96 deletions(-) create mode 100644 src/helpers/error/instances/app.ts create mode 100644 src/modules/user/repositories/createUser.repository.ts create mode 100644 src/modules/user/repositories/getAllUser.repository.ts delete mode 100644 src/utils/databases/prisma/error/handler.ts diff --git a/bun.lockb b/bun.lockb index 81df191ba123638aa7d759c7bdf4c08368ac99f8..53faf6ed546c964e53c5f5f39d7606bd9b7f6faa 100644 GIT binary patch delta 38 rcmccgk@?a`<_*s4*_jx?VDh}}GLzHRYqK-Pnd+J88E&4j-pUgI4D$@? delta 38 rcmccgk@?a`<_*s4*%{+Z^$hh4C(qk1GdXR&Haimo7;K)g-pUgIA { + if (error instanceof AppError) { + return returnErrorResponse( + set, + error.statusCode, + error.message, + error.details + ); } -} + + if (error instanceof Prisma.PrismaClientKnownRequestError) { + const errorInfo = PrismaErrorCodeList[error.code]; + + if (errorInfo) + return returnErrorResponse( + set, + errorInfo.status, + errorInfo.message, + error.meta ?? {} + ); + } + + if (error instanceof Prisma.PrismaClientUnknownRequestError) { + return returnErrorResponse(set, 500, "Unknown database error"); + } + + if (error instanceof Prisma.PrismaClientRustPanicError) { + return returnErrorResponse( + set, + 500, + "Database engine crashed unexpectedly" + ); + } + + if (error instanceof Prisma.PrismaClientInitializationError) { + return returnErrorResponse(set, 500, "Database initialization failed"); + } + + if (error instanceof Prisma.PrismaClientValidationError) { + return returnErrorResponse( + set, + 400, + "Invalid input to query", + error.message + ); + } + + return returnErrorResponse(set, 500, "Internal server error"); +}; diff --git a/src/helpers/error/instances/app.ts b/src/helpers/error/instances/app.ts new file mode 100644 index 0000000..0d80636 --- /dev/null +++ b/src/helpers/error/instances/app.ts @@ -0,0 +1,13 @@ +export class AppError extends Error { + public readonly statusCode: number; + public readonly details?: any; + + constructor(statusCode = 400, message: string, details?: any) { + super(message); + this.name = "AppError"; + this.statusCode = statusCode; + this.details = details; + + Object.setPrototypeOf(this, AppError.prototype); + } +} diff --git a/src/modules/auth/controller/loginWithPassword.controller.ts b/src/modules/auth/controller/loginWithPassword.controller.ts index f415d36..21266c7 100644 --- a/src/modules/auth/controller/loginWithPassword.controller.ts +++ b/src/modules/auth/controller/loginWithPassword.controller.ts @@ -3,7 +3,7 @@ import { loginWithPasswordService } from "../services/loginWithPassword.service" import { loginWithPasswordSchema } from "../auth.schema"; import { returnErrorResponse } from "../../../helpers/callback/httpResponse"; import { LoginWithPasswordRequest } from "../auth.types"; -import { AppError } from "../../../helpers/error/handler"; +import { mainErrorHandler } from "../../../helpers/error/handler"; export const loginWithPassword = async ( ctx: Context & { body: LoginWithPasswordRequest } @@ -16,13 +16,6 @@ export const loginWithPassword = async ( const result = await loginWithPasswordService(ctx.body); return result; } catch (error) { - if (error instanceof AppError) { - return returnErrorResponse( - ctx.set, - error.statusCode, - error.message, - error.details - ); - } + return mainErrorHandler(ctx.set, error); } }; diff --git a/src/modules/auth/services/loginWithPassword.service.ts b/src/modules/auth/services/loginWithPassword.service.ts index 9cd0f86..e63f891 100644 --- a/src/modules/auth/services/loginWithPassword.service.ts +++ b/src/modules/auth/services/loginWithPassword.service.ts @@ -1,11 +1,19 @@ +import bcrypt from "bcrypt"; import { findUserByEmailOrUsernameService } from "../../user/services/findUserByEmailOrUsername.service"; import { LoginWithPasswordRequest } from "../auth.types"; +import { AppError } from "../../../helpers/error/instances/app"; export const loginWithPasswordService = async ( - data: LoginWithPasswordRequest + request: LoginWithPasswordRequest ) => { try { - const userData = await findUserByEmailOrUsernameService(data.identifier); + // search for user data using an identifier (username or email) + const userData = await findUserByEmailOrUsernameService(request.identifier); + + // Validate the password in the request with the existing one + if (!(await bcrypt.compare(request.password, userData.password))) + throw new AppError(401, "Password incorrect"); + return userData; } catch (error) { throw error; diff --git a/src/modules/user/controller/createUser.controller.ts b/src/modules/user/controller/createUser.controller.ts index 3c61bdf..1e1a6f7 100644 --- a/src/modules/user/controller/createUser.controller.ts +++ b/src/modules/user/controller/createUser.controller.ts @@ -2,11 +2,11 @@ import { Prisma } from "@prisma/client"; import { Context } from "elysia"; import { createUserSchema } from "../user.schema"; import { createUserService } from "../services/createUser.service"; -import { handlePrismaError } from "../../../utils/databases/prisma/error/handler"; import { returnErrorResponse, returnWriteResponse, } from "../../../helpers/callback/httpResponse"; +import { mainErrorHandler } from "../../../helpers/error/handler"; /** * @function createUser @@ -45,8 +45,6 @@ export const createUser = async ( newUser ); } catch (error) { - // Handle any errors that occur during user creation - const { status, message, details } = handlePrismaError(error); - return returnErrorResponse(ctx.set, status, message, details); + return mainErrorHandler(ctx.set, error); } }; diff --git a/src/modules/user/controller/getAllUser.controller.ts b/src/modules/user/controller/getAllUser.controller.ts index e729997..3eca0c8 100644 --- a/src/modules/user/controller/getAllUser.controller.ts +++ b/src/modules/user/controller/getAllUser.controller.ts @@ -1,10 +1,10 @@ -import { handlePrismaError } from "../../../utils/databases/prisma/error/handler"; import { returnErrorResponse, returnReadResponse, } from "../../../helpers/callback/httpResponse"; import { Context } from "elysia"; import { getAllUsersService } from "../services/getAllUser.service"; +import { mainErrorHandler } from "../../../helpers/error/handler"; export const getAllUser = async (ctx: Context) => { try { @@ -16,7 +16,6 @@ export const getAllUser = async (ctx: Context) => { allUser ); } catch (error) { - const { status, message, details } = handlePrismaError(error); - return returnErrorResponse(ctx.set, status, message, details); + return mainErrorHandler(ctx.set, error); } }; diff --git a/src/modules/user/repositories/createUser.repository.ts b/src/modules/user/repositories/createUser.repository.ts new file mode 100644 index 0000000..d421cd0 --- /dev/null +++ b/src/modules/user/repositories/createUser.repository.ts @@ -0,0 +1,17 @@ +import { Prisma } from "@prisma/client"; +import { userModel } from "../user.model"; + +export const createUserRepo = async (data: Prisma.UserCreateInput) => { + try { + const userData = await userModel.create({ + data, + omit: { + password: true, + }, + }); + + return userData; + } catch (error) { + throw error; + } +}; diff --git a/src/modules/user/repositories/findUserByEmailOrUsername.repository.ts b/src/modules/user/repositories/findUserByEmailOrUsername.repository.ts index 5dce67e..9ed0060 100644 --- a/src/modules/user/repositories/findUserByEmailOrUsername.repository.ts +++ b/src/modules/user/repositories/findUserByEmailOrUsername.repository.ts @@ -1,4 +1,4 @@ -import { AppError } from "../../../helpers/error/handler"; +import { AppError } from "../../../helpers/error/instances/app"; import { userModel } from "../user.model"; export const findUserByEmailOrUsernameRepo = async (identifier: string) => { diff --git a/src/modules/user/repositories/getAllUser.repository.ts b/src/modules/user/repositories/getAllUser.repository.ts new file mode 100644 index 0000000..66a2cdd --- /dev/null +++ b/src/modules/user/repositories/getAllUser.repository.ts @@ -0,0 +1,15 @@ +import { userModel } from "../user.model"; + +export const getAllUserRepo = async () => { + try { + const data = await userModel.findMany({ + where: { + deletedAt: null, + }, + }); + + return data; + } catch (error) { + throw error; + } +}; diff --git a/src/modules/user/services/createUser.service.ts b/src/modules/user/services/createUser.service.ts index fe03020..bbc1245 100644 --- a/src/modules/user/services/createUser.service.ts +++ b/src/modules/user/services/createUser.service.ts @@ -1,18 +1,15 @@ import { Prisma } from "@prisma/client"; import { hashPassword } from "../../../helpers/security/password/hash"; -import { userModel } from "../user.model"; +import { createUserRepo } from "../repositories/createUser.repository"; export const createUserService = async (userData: Prisma.UserCreateInput) => { const { password, ...rest } = userData; // Destructure the password and the rest of the user data const hashedPassword = await hashPassword(password); // Hash the password before saving to the database - // Create the user in the database using Prisma try { - const newUser = await userModel.create({ - data: { - ...rest, - password: hashedPassword, - }, + const newUser = await createUserRepo({ + ...rest, + password: hashedPassword, }); return newUser; } catch (error) { diff --git a/src/modules/user/services/getAllUser.service.ts b/src/modules/user/services/getAllUser.service.ts index 0c8443b..509522a 100644 --- a/src/modules/user/services/getAllUser.service.ts +++ b/src/modules/user/services/getAllUser.service.ts @@ -1,12 +1,8 @@ -import { userModel } from "../user.model"; +import { getAllUserRepo } from "../repositories/getAllUser.repository"; export const getAllUsersService = async () => { try { - const allUser = await userModel.findMany({ - where: { - deletedAt: null, - }, - }); + const allUser = await getAllUserRepo(); return allUser; } catch (error) { throw error; diff --git a/src/modules/userRole/controller/createUserRole.controller.ts b/src/modules/userRole/controller/createUserRole.controller.ts index bc603f9..6beaedc 100644 --- a/src/modules/userRole/controller/createUserRole.controller.ts +++ b/src/modules/userRole/controller/createUserRole.controller.ts @@ -6,7 +6,7 @@ import { } from "../../../helpers/callback/httpResponse"; import { createUserRoleSchema } from "../userRole.schema"; import { createUserRoleService } from "../services/createUserRole.service"; -import { handlePrismaError } from "../../../utils/databases/prisma/error/handler"; +import { handlePrismaError } from "../../../helpers/error/instances/prisma"; import { JWTDecodeToken } from "../../../helpers/cookies/jwt/decodeToken"; /** diff --git a/src/modules/userSession/controller/createUserSession.controller.ts b/src/modules/userSession/controller/createUserSession.controller.ts index e15ba58..85a9f53 100644 --- a/src/modules/userSession/controller/createUserSession.controller.ts +++ b/src/modules/userSession/controller/createUserSession.controller.ts @@ -1,7 +1,7 @@ import { Context } from "elysia"; import { createUserSessionService } from "../services/createUserSession.service"; import { getUserHeaderInformation } from "../../../helpers/cookies/userHeader/getUserHeaderInformation"; -import { handlePrismaError } from "../../../utils/databases/prisma/error/handler"; +import { handlePrismaError } from "../../../helpers/error/instances/prisma"; import { returnErrorResponse, returnWriteResponse, diff --git a/src/utils/databases/prisma/error/handler.ts b/src/utils/databases/prisma/error/handler.ts deleted file mode 100644 index 25adb47..0000000 --- a/src/utils/databases/prisma/error/handler.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Prisma } from "@prisma/client"; -import { PrismaErrorCodeList } from "./codeList"; -import { PrismaErrorTypes } from "./types"; - -/** - * Handles Prisma-specific errors and returns a structured response. - * - * This helper is designed to standardize error handling for Prisma operations - * and provide clear differentiation between client-side and server-side errors. - * - * It maps known Prisma errors to HTTP status codes and human-readable messages, - * allowing consistent and centralized error handling across the application. - * - * ### Supported Error Codes: - * - P2002: Duplicate field detected. - * - P2025: Record not found. - * - P2003: Foreign key constraint failed - * - Validation errors handled via `PrismaClientValidationError`. - * - * @param {unknown} error - The error thrown by a Prisma operation. - * @returns {ErrorResponse} A structured error response object. - */ -export const handlePrismaError = (error: unknown): PrismaErrorTypes => { - // Check for Prisma known request errors (e.g., P2002, P2025) - if (error instanceof Prisma.PrismaClientKnownRequestError) { - const mappedError = PrismaErrorCodeList[error.code]; - if (mappedError) { - return { - status: mappedError.status, - message: mappedError.message, - details: error.meta, - }; - } - } - - // Handle Prisma validation errors - if (error instanceof Prisma.PrismaClientValidationError) { - return { - status: 400, - message: "Validation failed", - details: error.message, - }; - } - - // Fallback for unknown errors (typically server errors) - return { - status: 500, - message: "An unexpected error occurred", - details: error, - }; -};