import { Hono } from "hono"; import { HTTPException } from "hono/http-exception"; import db from "../../drizzle"; import { respondents } from "../../drizzle/schema/respondents"; import { users } from "../../drizzle/schema/users"; import { rolesSchema } from "../../drizzle/schema/roles"; import { rolesToUsers } from "../../drizzle/schema/rolesToUsers"; import { hashPassword } from "../../utils/passwordUtils"; import requestValidator from "../../utils/requestValidator"; import authInfo from "../../middlewares/authInfo"; import { or, eq } from "drizzle-orm"; import { z } from "zod"; import HonoEnv from "../../types/HonoEnv"; import { notFound } from "../../errors/DashboardError"; const registerFormSchema = z.object({ name: z.string().min(1).max(255), username: z.string().min(1).max(255), email: z.string().email(), password: z.string().min(6), companyName: z.string().min(1).max(255), position: z.string().min(1).max(255), workExperience: z.string().min(1).max(255), address: z.string().min(1), phoneNumber: z.string().min(1).max(13), isEnabled: z.string().default("false"), }); const respondentsRoute = new Hono() .use(authInfo) //post user .post("/", requestValidator("json", registerFormSchema), async (c) => { const formData = c.req.valid("json"); // Check if the provided email or username is already exists in database const conditions = []; if (formData.email) { conditions.push(eq(users.email, formData.email)); } conditions.push(eq(users.username, formData.username)); const existingUser = await db .select() .from(users) .where( or( eq(users.email, formData.email), eq(users.username, formData.username) ) ); const existingRespondent = await db .select() .from(respondents) .where(eq(respondents.phoneNumber, formData.phoneNumber)); if (existingUser.length > 0) { throw new HTTPException(400, { message: "Email or username has been registered", }); } if (existingRespondent.length > 0) { throw new HTTPException(400, { message: "Phone number has been registered", }); } // Hash the password const hashedPassword = await hashPassword(formData.password); // Start a transaction const result = await db.transaction(async (trx) => { // Create user const [newUser] = await trx .insert(users) .values({ name: formData.name, username: formData.username, email: formData.email, password: hashedPassword, isEnabled: formData.isEnabled?.toLowerCase() === "true" || true, }) .returning() .catch(() => { throw new HTTPException(500, { message: "Error creating user" }); }); // Create respondent await trx .insert(respondents) .values({ companyName: formData.companyName, position: formData.position, workExperience: formData.workExperience, address: formData.address, phoneNumber: formData.phoneNumber, userId: newUser.id, }) .catch(() => { throw new HTTPException(500, { message: "Error creating respondent", }); }); // Automatically assign "user" role to the new user const [role] = await trx .select() .from(rolesSchema) .where(eq(rolesSchema.code, "user")) .limit(1); if (!role) throw notFound(); await trx.insert(rolesToUsers).values({ userId: newUser.id, roleId: role.id, }); return newUser; }); return c.json( { message: "User created successfully", }, 201 ); }); export default respondentsRoute;