From e2a8b208bc137073a7262baa4ee69e550d9cc37b Mon Sep 17 00:00:00 2001 From: sianida26 Date: Tue, 27 Feb 2024 00:40:52 +0700 Subject: [PATCH] Move create user to service --- prisma/seeds/permissionSeed.ts | 2 +- src/modules/auth/actions/createUser.ts | 76 ++----------------- .../auth/formSchemas/CreateUserFormSchema.ts | 23 ++++++ src/modules/auth/services/createUser.ts | 54 +++++++++++++ 4 files changed, 85 insertions(+), 70 deletions(-) create mode 100644 src/modules/auth/formSchemas/CreateUserFormSchema.ts create mode 100644 src/modules/auth/services/createUser.ts diff --git a/prisma/seeds/permissionSeed.ts b/prisma/seeds/permissionSeed.ts index 2050aeb..167add4 100644 --- a/prisma/seeds/permissionSeed.ts +++ b/prisma/seeds/permissionSeed.ts @@ -94,7 +94,7 @@ export default async function permissionSeed(prisma: PrismaClient) { isActive: true } ]; - + await Promise.all( permissionData.map(async (permission) => { await prisma.permission.upsert({ diff --git a/src/modules/auth/actions/createUser.ts b/src/modules/auth/actions/createUser.ts index 2df4d5d..e52b685 100644 --- a/src/modules/auth/actions/createUser.ts +++ b/src/modules/auth/actions/createUser.ts @@ -5,30 +5,7 @@ import { cookies } from "next/headers"; import { redirect } from "next/navigation"; import { hashPassword } from "../utils/hashPassword"; import { createJwtToken } from "../utils/createJwtToken"; - -/** - * Interface for the schema of a new user. - */ -interface CreateUserSchema { - name: string; - email: string; - password: string; -} - -/** - * Validation schema for creating a user. - */ -const createUserSchema = z - .object({ - name: z.string(), - email: z.string().email(), - password: z.string().min(6), - passwordConfirmation: z.string().optional(), - }) - .refine((data) => data.password === data.passwordConfirmation, { - message: "Password confirmation must match the password", - path: ["passwordConfirmation"], - }); +import createUser from "../services/createUser"; /** * Creates a new user in the system. @@ -36,7 +13,7 @@ const createUserSchema = z * @param formData - The form data containing user details. * @returns An object indicating the result of the operation. */ -export default async function createUser(formData: FormData) { +export default async function createUserAction(formData: FormData) { //TODO: Add Throttling //TODO: Add validation check if the user is already logged in @@ -44,49 +21,12 @@ export default async function createUser(formData: FormData) { const parsedData = { email: formData.get("email")?.toString() ?? "", name: formData.get("name")?.toString() ?? "", - password: formData.get("password")?.toString() ?? "", - passwordConfirmation: formData - .get("passwordConfirmation") - ?.toString(), + plainPassword: formData.get("password")?.toString() ?? "", + plainPasswordConfirmation: + formData.get("passwordConfirmation")?.toString() ?? "", }; - const validatedFields = createUserSchema.safeParse(parsedData); - - if (!validatedFields.success) { - return { - success: false, - error: { - message: "", - errors: validatedFields.error.flatten().fieldErrors, - }, - }; - } - - const existingUser = await prisma.user.findUnique({ - where: { email: validatedFields.data.email }, - }); - - if (existingUser) { - return { - success: false, - error: { - message: "", - errors: { - email: ["Email already exists"], - }, - }, - }; - } - - const user = await prisma.user.create({ - data: { - name: validatedFields.data.name, - email: validatedFields.data.email, - passwordHash: await hashPassword(validatedFields.data.password), - }, - }); - - const token = createJwtToken({ id: user.id }); - cookies().set("token", token); + await createUser(parsedData); + redirect("/dashboard"); } catch (e: unknown) { // Handle unexpected errors console.error(e); @@ -100,6 +40,4 @@ export default async function createUser(formData: FormData) { }, }; } - - redirect("/dashboard"); } diff --git a/src/modules/auth/formSchemas/CreateUserFormSchema.ts b/src/modules/auth/formSchemas/CreateUserFormSchema.ts new file mode 100644 index 0000000..0885c2c --- /dev/null +++ b/src/modules/auth/formSchemas/CreateUserFormSchema.ts @@ -0,0 +1,23 @@ +import {z} from "zod" + +/** + * Interface for the schema of a new user. + */ +export interface CreateUserSchema { + name: string; + email: string; + plainPassword: string; + plainPasswordConfirmation: string; +} + +export const createUserSchema = z + .object({ + name: z.string(), + email: z.string().email(), + password: z.string().min(6), + passwordConfirmation: z.string().optional(), + }) + .refine((data) => data.password === data.passwordConfirmation, { + message: "Password confirmation must match the password", + path: ["passwordConfirmation"], + }); \ No newline at end of file diff --git a/src/modules/auth/services/createUser.ts b/src/modules/auth/services/createUser.ts new file mode 100644 index 0000000..a903658 --- /dev/null +++ b/src/modules/auth/services/createUser.ts @@ -0,0 +1,54 @@ +import DashboardError from "@/modules/dashboard/errors/DashboardError"; +import { + CreateUserSchema, + createUserSchema, +} from "../formSchemas/CreateUserFormSchema"; +import mapObjectToFirstValue from "@/utils/mapObjectToFirstValue"; +import db from "@/core/db"; +import AuthError from "../error/AuthError"; +import hashPassword from "../utils/hashPassword"; +import { createJwtToken } from "../utils/createJwtToken"; +import { cookies } from "next/headers"; + +export default async function createUser(userData: CreateUserSchema) { + const validatedFields = createUserSchema.safeParse(userData); + + //Validate form input + if (!validatedFields.success) { + throw new DashboardError({ + errorCode: "INVALID_FORM_DATA", + formErrors: mapObjectToFirstValue( + validatedFields.error.flatten().fieldErrors + ), + }); + } + + //Check email exists + if ( + await db.user.findFirst({ + where: { email: validatedFields.data.email }, + }) + ) { + throw new AuthError({ + errorCode: "USER_ALREADY_EXISTS", + message: "This email already exists", + }); + } + + //Create user + const user = await db.user.create({ + data: { + name: validatedFields.data.name, + email: validatedFields.data.email, + passwordHash: await hashPassword(validatedFields.data.password), + }, + }); + + //Set token + const token = createJwtToken({ id: user.id }); + cookies().set("token", token); + + return { + token, + }; +}