Merge pull request #4 from digitalsolutiongroup/feat/register

Develop API Register
This commit is contained in:
sianida26 2024-08-20 16:36:18 +07:00 committed by GitHub
commit 6e8c3cbdf8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 142 additions and 1 deletions

View File

@ -17,10 +17,18 @@ const roleData: RoleData[] = [
name: "Super Admin", name: "Super Admin",
permissions: permissionsData.map((permission) => permission.code), permissions: permissionsData.map((permission) => permission.code),
}, },
{
code: "user",
description:
"User with standard access rights for general usage of the application.",
isActive: true,
name: "User",
permissions: permissionsData.map((permission) => permission.code),
},
]; ];
// Manually specify the union of role codes // Manually specify the union of role codes
export type RoleCode = "super-admin" | "*"; export type RoleCode = "super-admin" | "user" | "*";
const exportedRoleData = roleData; const exportedRoleData = roleData;

View File

@ -3,6 +3,7 @@ import { configDotenv } from "dotenv";
import { Hono } from "hono"; import { Hono } from "hono";
import authRoutes from "./routes/auth/route"; import authRoutes from "./routes/auth/route";
import usersRoute from "./routes/users/route"; import usersRoute from "./routes/users/route";
import respondentsRoute from "./routes/register/route";
import { verifyAccessToken } from "./utils/authUtils"; import { verifyAccessToken } from "./utils/authUtils";
import permissionRoutes from "./routes/permissions/route"; import permissionRoutes from "./routes/permissions/route";
import { cors } from "hono/cors"; import { cors } from "hono/cors";
@ -80,6 +81,7 @@ const routes = app
.route("/roles", rolesRoute) .route("/roles", rolesRoute)
.route("/dev", devRoutes) .route("/dev", devRoutes)
.route("/questions", questionsRoute) .route("/questions", questionsRoute)
.route("/register", respondentsRoute)
.onError((err, c) => { .onError((err, c) => {
if (err instanceof DashboardError) { if (err instanceof DashboardError) {
return c.json( return c.json(

View File

@ -0,0 +1,131 @@
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<HonoEnv>()
.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;