From 3f68d835fee856aa4197b9d2e72c75c7e64a3cc0 Mon Sep 17 00:00:00 2001 From: i701 Date: Wed, 27 Nov 2024 14:17:06 +0500 Subject: [PATCH] Refactor authentication actions and add user verification functionality - Updated signin and signup actions to correctly handle phone number redirection and date of birth formatting. - Introduced a new user-actions file to implement user verification logic. - Added an auth guard to restrict access based on user roles. - Enhanced the auth configuration to include user roles and language settings. - Improved validation schemas for user input in the signup form. --- actions/auth-actions.ts | 13 ++++++++----- actions/user-actions.ts | 25 +++++++++++++++++++++++++ lib/auth-guard.ts | 13 +++++++++++++ lib/auth.ts | 15 +++++++++++++++ lib/schemas.ts | 10 ++++++++-- 5 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 actions/user-actions.ts create mode 100644 lib/auth-guard.ts diff --git a/actions/auth-actions.ts b/actions/auth-actions.ts index 8281e72..76e6901 100644 --- a/actions/auth-actions.ts +++ b/actions/auth-actions.ts @@ -44,7 +44,9 @@ export async function signin(previousState: ActionState, formData: FormData) { await authClient.phoneNumber.sendOtp({ phoneNumber: NUMBER_WITH_COUNTRY_CODE, }); - redirect(`/verify-otp?phone_number=${encodeURIComponent(phoneNumber)}`); + redirect( + `/verify-otp?phone_number=${encodeURIComponent(NUMBER_WITH_COUNTRY_CODE)}`, + ); } type ActionState = { @@ -112,16 +114,17 @@ export async function signup(_actionState: ActionState, formData: FormData) { atollId: parsedData.data.atoll_id, house_name: parsedData.data.house_name, id_card: parsedData.data.id_card, - dob: parsedData.data.dob, + dob: new Date(parsedData.data.dob), + role: "USER", phoneNumber: NUMBER_WITH_COUNTRY_CODE, }, }); await authClient.phoneNumber.sendOtp({ phoneNumber: newUser.phoneNumber, }); - // redirect( - // `/verify-otp?phone_number=${encodeURIComponent(newUser.phoneNumber)}`, - // ); + redirect( + `/verify-otp?phone_number=${encodeURIComponent(newUser.phoneNumber)}`, + ); return { message: "Post created" }; } diff --git a/actions/user-actions.ts b/actions/user-actions.ts new file mode 100644 index 0000000..5367085 --- /dev/null +++ b/actions/user-actions.ts @@ -0,0 +1,25 @@ +"use server"; + +import prisma from "@/lib/db"; +import { revalidatePath } from "next/cache"; + +export async function VerifyUser(userId: string) { + const user = await prisma.user.findUnique({ + where: { + id: userId, + }, + }); + if (!user) { + throw new Error("User not found"); + } + user.verified = true; + await prisma.user.update({ + where: { + id: userId, + }, + data: { + verified: true, + }, + }); + revalidatePath("/users"); +} diff --git a/lib/auth-guard.ts b/lib/auth-guard.ts new file mode 100644 index 0000000..9880ee7 --- /dev/null +++ b/lib/auth-guard.ts @@ -0,0 +1,13 @@ +import { auth } from "@/lib/auth"; +import { redirect } from "next/navigation"; +import { headers } from "next/headers"; + +const session = await auth.api.getSession({ + headers: await headers(), +}); +export async function AdminAuthGuard() { + if (session?.user.role !== "ADMIN") { + return redirect("/login"); + } + return true; +} diff --git a/lib/auth.ts b/lib/auth.ts index 6dfcf88..c0a31e6 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -6,6 +6,21 @@ import { phoneNumber } from "better-auth/plugins"; const prisma = new PrismaClient(); export const auth = betterAuth({ + user: { + additionalFields: { + role: { + type: "string", + required: false, + defaultValue: "USER", + input: false, // don't allow user to set role + }, + lang: { + type: "string", + required: false, + defaultValue: "en", + }, + }, + }, database: prismaAdapter(prisma, { provider: "sqlite", // or "mysql", "postgresql", ...etc }), diff --git a/lib/schemas.ts b/lib/schemas.ts index 21181b4..400d90c 100644 --- a/lib/schemas.ts +++ b/lib/schemas.ts @@ -6,8 +6,14 @@ export const signUpFormSchema = z.object({ .min(2, { message: "ID Card is required" }) .regex(/^[A][0-9]{6}$/, "Please enter a valid ID Card number."), atoll_id: z.string().min(2, { message: "Atoll is required." }), - island_id: z.string().min(2, { message: "Island is required." }), + island_id: z + .string({ required_error: "Island is required." }) + .min(2, { message: "Island is required." }), house_name: z.string().min(2, { message: "House name is required." }), dob: z.coerce.date({ message: "Date of birth is required." }), - phone_number: z.string().min(7, { message: "Phone number is required." }).regex(/^[79][0-9]{2}[0-9]{4}$/, "Please enter a valid phone number").transform((val) => val.replace(/\D/g, "")), + phone_number: z + .string() + .min(7, { message: "Phone number is required." }) + .regex(/^[79][0-9]{2}[0-9]{4}$/, "Please enter a valid phone number") + .transform((val) => val.replace(/\D/g, "")), });