diff --git a/bun.lockb b/bun.lockb index e4fd7e6..9e8bf1e 100644 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index cfd7221..b677444 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ }, "dependencies": { "@prisma/client": "^6.7.0", + "@types/bcrypt": "^5.0.2", "@types/jsonwebtoken": "^9.0.9", + "bcrypt": "^5.1.1", "cookie": "^1.0.2", "elysia": "latest", "joi": "^17.13.3", diff --git a/src/helpers/security/password/hash.ts b/src/helpers/security/password/hash.ts new file mode 100644 index 0000000..de949d2 --- /dev/null +++ b/src/helpers/security/password/hash.ts @@ -0,0 +1,6 @@ +import bcrypt from "bcrypt"; + +export const hashPassword = async (password: string): Promise => { + const saltRounds = Number(process.env.SALT_ROUNDS); + return await bcrypt.hash(password, saltRounds); +}; diff --git a/src/modules/user/controller/createUser.controller.ts b/src/modules/user/controller/createUser.controller.ts index e69de29..c3387d4 100644 --- a/src/modules/user/controller/createUser.controller.ts +++ b/src/modules/user/controller/createUser.controller.ts @@ -0,0 +1,56 @@ +import { Prisma } from "@prisma/client"; +import { Context } from "elysia"; +import { createUserSchema } from "../user.schema"; +import { createUserService } from "../services/createUser.service"; +import { PrismaErrorTypes } from "../../../utils/databases/prisma/error/types"; +import { + returnErrorResponse, + returnWriteResponse, +} from "../../../helpers/callback/httpResponse"; + +/** + * @function createUser + * @description Creates a new user in the database. + * + * @param {Context & { body: Prisma.UserCreateInput }} ctx - The context object containing the request body. + * @param {Prisma.UserCreateInput} ctx.body - The user data to be created. + * + * @returns {Promise} A response object indicating success or failure. + * @throws {Object} An error response object if validation fails or an error occurs during user creation. + * + * @example + * Request route: POST /users + * Request body: + * { + * "username": "john_doe", + * "email": "john@example.com", + * "password": "password123" + * } + */ +export const createUser = async ( + ctx: Context & { body: Prisma.UserCreateInput } +) => { + // Validate the user input using a validation schema + const { error } = createUserSchema.validate(ctx.body); + if (error) + return returnErrorResponse(ctx.set, 400, "Invalid user input", error); + + // Create the user in the database using the service + createUserService(ctx.body) + .then((result) => { + return returnWriteResponse( + ctx.set, + 201, + "User created successfully", + result + ); + }) + .catch((error: PrismaErrorTypes) => { + return returnErrorResponse( + ctx.set, + error.status, + error.message, + error.details + ); + }); +}; diff --git a/src/modules/user/index.ts b/src/modules/user/index.ts index 3a2b134..6a4e208 100644 --- a/src/modules/user/index.ts +++ b/src/modules/user/index.ts @@ -1,6 +1,7 @@ import Elysia from "elysia"; import { getAllUser } from "./controller/getAllUser.controller"; +import { createUser } from "./controller/createUser.controller"; export const userModule = new Elysia({ prefix: "/users" }) - .get("/", () => "Hello User Module") - .post("/", () => getAllUser); + .get("/", () => getAllUser) + .post("/", () => createUser); diff --git a/src/modules/user/services/createUser.service.ts b/src/modules/user/services/createUser.service.ts index e69de29..a31b225 100644 --- a/src/modules/user/services/createUser.service.ts +++ b/src/modules/user/services/createUser.service.ts @@ -0,0 +1,22 @@ +import { Prisma } from "@prisma/client"; +import { hashPassword } from "../../../helpers/security/password/hash"; +import { userModel } from "../user.model"; +import { handlePrismaError } from "../../../utils/databases/prisma/error/handler"; + +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, + }, + }); + return newUser; + } catch (error) { + return handlePrismaError(error); + } +}; diff --git a/src/modules/user/user.model.ts b/src/modules/user/user.model.ts index e69de29..80f0114 100644 --- a/src/modules/user/user.model.ts +++ b/src/modules/user/user.model.ts @@ -0,0 +1,3 @@ +import { prisma } from "../../utils/databases/prisma/connection"; + +export const userModel = prisma.user; diff --git a/src/modules/user/user.schema.ts b/src/modules/user/user.schema.ts index e69de29..3021ddf 100644 --- a/src/modules/user/user.schema.ts +++ b/src/modules/user/user.schema.ts @@ -0,0 +1,15 @@ +import Joi from "joi"; + +export const createUserSchema = Joi.object({ + name: Joi.string().min(4).max(255).required(), + username: Joi.string().min(4).max(255).required(), + email: Joi.string().email().required(), + password: Joi.string().min(8).max(255).required(), + birthdate: Joi.date(), + gender: Joi.string().valid("male", "female"), + phoneCC: Joi.string().min(2).max(2), + phoneNumber: Joi.string().min(7).max(15), + bioProfile: Joi.string().max(300), + profilePicture: Joi.string().uri(), + commentPicture: Joi.string().uri(), +}); diff --git a/src/modules/userRole/controller/createUserRole.controller.ts b/src/modules/userRole/controller/createUserRole.controller.ts index 97d596a..ba5167f 100644 --- a/src/modules/userRole/controller/createUserRole.controller.ts +++ b/src/modules/userRole/controller/createUserRole.controller.ts @@ -4,10 +4,8 @@ import { returnErrorResponse, returnWriteResponse, } from "../../../helpers/callback/httpResponse"; -import { handlePrismaError } from "../../../utils/databases/prisma/error/handler"; import { createUserRoleSchema } from "../userRole.schema"; import { JWTDecodeToken } from "../../../helpers/jwt/decodeToken"; -import { prisma } from "../../../utils/databases/prisma/connection"; import { createUserRoleService } from "../services/createUserRole.service"; import { PrismaErrorTypes } from "../../../utils/databases/prisma/error/types"; @@ -72,10 +70,15 @@ export const createUserRole = async ( }; createUserRoleService(dataPayload) - .then((result) => - returnWriteResponse(ctx.set, 201, "User role created", result) - ) - .catch((error: PrismaErrorTypes) => - returnErrorResponse(ctx.set, error.status, error.message, error.details) - ); + .then((result) => { + return returnWriteResponse(ctx.set, 201, "User role created", result); + }) + .catch((error: PrismaErrorTypes) => { + return returnErrorResponse( + ctx.set, + error.status, + error.message, + error.details + ); + }); };