diff --git a/src/app/api/approveEmployees/route.ts b/src/app/api/approveEmployees/route.ts index 24ca5f3..6208191 100644 --- a/src/app/api/approveEmployees/route.ts +++ b/src/app/api/approveEmployees/route.ts @@ -3,23 +3,25 @@ import { db } from "../../../server/db/index"; import { users } from "../../../server/db/schema"; import { eq } from "drizzle-orm"; import { auth } from "@clerk/nextjs/server"; -import * as console from "console"; - -type PostBody = { - employeeId: string; -} +import { validateRequestBody, EmployeeIdSchema } from "~/lib/validation"; export async function POST(request: Request) { try { + // Validate request body first + const validation = await validateRequestBody(request, EmployeeIdSchema); + if (!validation.success) { + return validation.response; + } + const { userId } = await auth(); - + if (!userId) { return NextResponse.json({ success: false, message: "Unauthorized" }, { status: 401 }); - } + } const [userInfo] = await db .select() @@ -38,20 +40,24 @@ export async function POST(request: Request) { }, { status: 401 }); } - const { employeeId } = (await request.json()) as PostBody; + // Use validated data + const { employeeId } = validation.data; await db .update(users) .set({ status: "verified" }) - .where(eq(users.id, Number(employeeId))); + .where(eq(users.id, employeeId)); - return NextResponse.json({ status: 200 }); + return NextResponse.json({ + success: true, + message: "Employee approved successfully" + }); } catch (error: unknown) { - console.error("Error fetching documents:", error); + console.error("Error approving employee:", error); return NextResponse.json( - { error: "Unable to fetch documents" }, + { success: false, error: "Failed to approve employee" }, { status: 500 } ); } diff --git a/src/app/api/removeEmployees/route.ts b/src/app/api/removeEmployees/route.ts index fe7a70c..f4e9d24 100644 --- a/src/app/api/removeEmployees/route.ts +++ b/src/app/api/removeEmployees/route.ts @@ -2,49 +2,55 @@ import { NextResponse } from "next/server"; import { db } from "../../../server/db/index"; import { users } from "../../../server/db/schema"; import { eq } from "drizzle-orm"; -import * as console from "console"; import { auth } from "@clerk/nextjs/server"; - -type PostBody = { - employeeId: string; -} +import { validateRequestBody, EmployeeIdSchema } from "~/lib/validation"; export async function POST(request: Request) { - const { userId } = await auth(); - if (!userId) { - return NextResponse.json({ - success: false, - message: "Unauthorized" - }, { status: 401 }); - } + try { + // Validate request body first + const validation = await validateRequestBody(request, EmployeeIdSchema); + if (!validation.success) { + return validation.response; + } - const [userInfo] = await db - .select() - .from(users) - .where(eq(users.userId, userId)); + const { userId } = await auth(); + if (!userId) { + return NextResponse.json({ + success: false, + message: "Unauthorized" + }, { status: 401 }); + } - if (!userInfo) { - return NextResponse.json({ - success: false, - message: "Invalid user." - }, { status: 400 }); - } else if (userInfo.role !== "employer" && userInfo.role !== "owner") { - return NextResponse.json({ - success: false, - message: "Unauthorized" - }, { status: 401 }); - } - - try { - const { employeeId } = (await request.json()) as PostBody; + const [userInfo] = await db + .select() + .from(users) + .where(eq(users.userId, userId)); - await db.delete(users).where(eq(users.id, Number(employeeId))); + if (!userInfo) { + return NextResponse.json({ + success: false, + message: "Invalid user." + }, { status: 400 }); + } else if (userInfo.role !== "employer" && userInfo.role !== "owner") { + return NextResponse.json({ + success: false, + message: "Unauthorized" + }, { status: 401 }); + } - return NextResponse.json( { status: 200 }); + // Use validated data + const { employeeId } = validation.data; + + await db.delete(users).where(eq(users.id, employeeId)); + + return NextResponse.json({ + success: true, + message: "Employee removed successfully" + }); } catch (error: unknown) { - console.error("Error fetching documents:", error); + console.error("Error removing employee:", error); return NextResponse.json( - { error: "Unable to fetch documents" }, + { success: false, error: "Failed to remove employee" }, { status: 500 } ); } diff --git a/src/app/api/signup/employee/route.ts b/src/app/api/signup/employee/route.ts index d64497f..c30c921 100644 --- a/src/app/api/signup/employee/route.ts +++ b/src/app/api/signup/employee/route.ts @@ -2,18 +2,17 @@ import { NextResponse } from "next/server"; import { db } from "~/server/db/index"; import { users, company } from "~/server/db/schema"; import { and, eq } from "drizzle-orm"; - -type PostBody = { - userId: string; - name: string; - email: string; - employeePasskey: string; - companyName: string; -}; +import { validateRequestBody, SignupEmployeeSchema } from "~/lib/validation"; export async function POST(request: Request) { try { - const { userId, name, email, employeePasskey, companyName } = (await request.json()) as PostBody; + // Validate request body + const validation = await validateRequestBody(request, SignupEmployeeSchema); + if (!validation.success) { + return validation.response; + } + + const { userId, name, email, employeePasskey, companyName } = validation.data; // Find company by company name const [existingCompany] = await db @@ -28,7 +27,11 @@ export async function POST(request: Request) { if (!existingCompany) { return NextResponse.json( - { error: "Invalid company name or passkey." }, + { + success: false, + error: "Validation Error", + message: "Invalid company name or employee passkey. Please check your credentials." + }, { status: 400 } ); } @@ -36,16 +39,26 @@ export async function POST(request: Request) { // Insert new user await db.insert(users).values({ userId, - name: name, - email: email, + name, + email, companyId: existingCompany.id.toString(), status: "pending", role: "employee", }); - return NextResponse.json({ success: true }); + return NextResponse.json({ + success: true, + message: "Employee account created successfully. Awaiting approval." + }); } catch (error: unknown) { - console.error(error); - return NextResponse.json({ error: error }, { status: 500 }); + console.error("Error during employee signup:", error); + return NextResponse.json( + { + success: false, + error: "Registration failed", + message: "An error occurred during registration. Please try again." + }, + { status: 500 } + ); } } \ No newline at end of file diff --git a/src/app/api/signup/employer/route.ts b/src/app/api/signup/employer/route.ts index adac6c5..e0c9afa 100644 --- a/src/app/api/signup/employer/route.ts +++ b/src/app/api/signup/employer/route.ts @@ -1,23 +1,20 @@ import { NextResponse } from "next/server"; import { db } from "~/server/db/index"; import { users, company } from "~/server/db/schema"; -import {and, eq} from "drizzle-orm"; -import * as console from "console"; - -type PostBody = { - userId: string; - name: string; - email: string; - employerPasskey: string; - companyName: string; -} +import { and, eq } from "drizzle-orm"; +import { validateRequestBody, SignupEmployerSchema } from "~/lib/validation"; export async function POST(request: Request) { try { - const {userId, name, email, employerPasskey, companyName} = (await request.json()) as PostBody; + // Validate request body + const validation = await validateRequestBody(request, SignupEmployerSchema); + if (!validation.success) { + return validation.response; + } + + const { userId, name, email, employerPasskey, companyName } = validation.data; - let companyId: string; const [existingCompany] = await db .select() .from(company) @@ -30,13 +27,16 @@ export async function POST(request: Request) { if (!existingCompany) { return NextResponse.json( - {error: "Invalid company name or passkey."}, - {status: 400} + { + success: false, + error: "Validation Error", + message: "Invalid company name or employer passkey. Please check your credentials." + }, + { status: 400 } ); } - // eslint-disable-next-line prefer-const - companyId = existingCompany.id.toString(); + const companyId = existingCompany.id.toString(); await db.insert(users).values({ userId, @@ -47,9 +47,19 @@ export async function POST(request: Request) { role: "employer", }); - } - catch (error: unknown) { - console.error(error); - return NextResponse.json({ error: error}, { status: 500 }); + return NextResponse.json({ + success: true, + message: "Employer account created successfully. Awaiting approval." + }); + } catch (error: unknown) { + console.error("Error during employer signup:", error); + return NextResponse.json( + { + success: false, + error: "Registration failed", + message: "An error occurred during registration. Please try again." + }, + { status: 500 } + ); } } \ No newline at end of file diff --git a/src/lib/validation.ts b/src/lib/validation.ts index eef1ae8..7c0321d 100644 --- a/src/lib/validation.ts +++ b/src/lib/validation.ts @@ -127,3 +127,29 @@ export const EmployerAuthSchema = z.object({ userId: z.string().min(1, "User ID is required"), companyPasskey: z.string().min(1, "Company passkey is required"), }); + +export const EmployeeIdSchema = z.object({ + employeeId: z.coerce + .number({ + required_error: "Employee ID is required", + invalid_type_error: "Employee ID must be a number" + }) + .int("Employee ID must be an integer") + .positive("Employee ID must be a positive number"), +}); + +export const SignupEmployeeSchema = z.object({ + userId: z.string().min(1, "User ID is required").max(256, "User ID is too long").trim(), + name: z.string().min(1, "Name is required").max(256, "Name is too long").trim(), + email: z.string().email("Invalid email address").max(256, "Email is too long").trim(), + employeePasskey: z.string().min(1, "Employee passkey is required").max(256, "Employee passkey is too long"), + companyName: z.string().min(1, "Company name is required").max(256, "Company name is too long").trim(), +}); + +export const SignupEmployerSchema = z.object({ + userId: z.string().min(1, "User ID is required").max(256, "User ID is too long").trim(), + name: z.string().min(1, "Name is required").max(256, "Name is too long").trim(), + email: z.string().email("Invalid email address").max(256, "Email is too long").trim(), + employerPasskey: z.string().min(1, "Employer passkey is required").max(256, "Employer passkey is too long"), + companyName: z.string().min(1, "Company name is required").max(256, "Company name is too long").trim(), +});