Update : API for users (get, post, patch)

This commit is contained in:
percyfikri 2024-09-13 10:33:09 +07:00
parent 22eb64d611
commit 5bebf337db

View File

@ -26,23 +26,24 @@ export const userFormSchema = z.object({
address: z.string().min(1), address: z.string().min(1),
phoneNumber: z.string().min(1).max(13), phoneNumber: z.string().min(1).max(13),
isEnabled: z.string().default("false"), isEnabled: z.string().default("false"),
roles: z // roles: z
.string() // .string()
.refine( // .refine(
(data) => { // (data) => {
console.log(data); // console.log(data);
try { // try {
const parsed = JSON.parse(data); // const parsed = JSON.parse(data);
return Array.isArray(parsed); // return Array.isArray(parsed);
} catch { // } catch {
return false; // return false;
} // }
}, // },
{ // {
message: "Roles must be an array", // message: "Roles must be an array",
} // }
) // )
.optional(), // .optional(),
roles: z.array(z.string()).optional(),
}); });
export const userUpdateSchema = userFormSchema.extend({ export const userUpdateSchema = userFormSchema.extend({
@ -58,6 +59,7 @@ const usersRoute = new Hono<HonoEnv>()
* - includeTrashed: boolean (default: false)\ * - includeTrashed: boolean (default: false)\
* - withMetadata: boolean * - withMetadata: boolean
*/ */
.get( .get(
"/", "/",
checkPermission("users.readAll"), checkPermission("users.readAll"),
@ -73,13 +75,14 @@ const usersRoute = new Hono<HonoEnv>()
.optional() .optional()
.transform((v) => v?.toLowerCase() === "true"), .transform((v) => v?.toLowerCase() === "true"),
page: z.coerce.number().int().min(0).default(0), page: z.coerce.number().int().min(0).default(0),
limit: z.coerce.number().int().min(1).max(1000).default(1), limit: z.coerce.number().int().min(1).max(1000).default(100),
q: z.string().default(""), q: z.string().default(""),
}) })
), ),
async (c) => { async (c) => {
const { includeTrashed, page, limit, q } = c.req.valid("query"); const { includeTrashed, page, limit, q } = c.req.valid("query");
// Total count for pagination
const totalCountQuery = includeTrashed const totalCountQuery = includeTrashed
? sql<number>`(SELECT count(*) FROM ${users})` ? sql<number>`(SELECT count(*) FROM ${users})`
: sql<number>`(SELECT count(*) FROM ${users} WHERE ${users.deletedAt} IS NULL)`; : sql<number>`(SELECT count(*) FROM ${users} WHERE ${users.deletedAt} IS NULL)`;
@ -95,7 +98,10 @@ const usersRoute = new Hono<HonoEnv>()
updatedAt: users.updatedAt, updatedAt: users.updatedAt,
...(includeTrashed ? { deletedAt: users.deletedAt } : {}), ...(includeTrashed ? { deletedAt: users.deletedAt } : {}),
company: respondents.companyName, company: respondents.companyName,
roles: rolesSchema.name, role: {
name: rolesSchema.name,
id: rolesSchema.id,
},
fullCount: totalCountQuery, fullCount: totalCountQuery,
}) })
.from(users) .from(users)
@ -118,8 +124,47 @@ const usersRoute = new Hono<HonoEnv>()
.offset(page * limit) .offset(page * limit)
.limit(limit); .limit(limit);
// Group roles for each user to prevent duplication
const userMap = new Map<string, {
id: string;
name: string;
email: string | null;
username: string;
isEnabled: boolean;
createdAt: Date;
updatedAt: Date;
deletedAt?: Date;
company: string | null;
roles: { id: string; name: string }[];
}>();
result.forEach((item) => {
if (!userMap.has(item.id)) {
userMap.set(item.id, {
id: item.id,
name: item.name,
email: item.email ?? null,
username: item.username,
isEnabled: item.isEnabled ?? false,
createdAt: item.createdAt ?? new Date(),
updatedAt: item.updatedAt ?? new Date(),
deletedAt: item.deletedAt ?? undefined,
company: item.company,
roles: item.role ? [{ id: item.role.id, name: item.role.name }] : [],
});
} else {
const existingUser = userMap.get(item.id);
if (item.role) {
existingUser?.roles.push({ id: item.role.id, name: item.role.name });
}
}
});
// Return user data without duplication and roles in array form
const groupedData = Array.from(userMap.values());
return c.json({ return c.json({
data: result.map((d) => ({ ...d, fullCount: undefined })), data: groupedData.map((d) => ({ ...d, fullCount: undefined })),
_metadata: { _metadata: {
currentPage: page, currentPage: page,
totalPages: Math.ceil( totalPages: Math.ceil(
@ -131,6 +176,7 @@ const usersRoute = new Hono<HonoEnv>()
}); });
} }
) )
//get user by id //get user by id
.get( .get(
"/:id", "/:id",
@ -278,30 +324,16 @@ const usersRoute = new Hono<HonoEnv>()
}); });
}); });
// 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,
});
// Add other roles if provided // Add other roles if provided
if (userData.roles) { if (userData.roles) {
const roles = JSON.parse(userData.roles) as string[]; const roles = userData.roles;
for (let roleCode of roles) { for (let roleId of roles) {
const role = ( const role = (
await trx await trx
.select() .select()
.from(rolesSchema) .from(rolesSchema)
.where(eq(rolesSchema.code, roleCode)) .where(eq(rolesSchema.id, roleId))
.limit(1) .limit(1)
)[0]; )[0];
@ -312,7 +344,7 @@ const usersRoute = new Hono<HonoEnv>()
}); });
} else { } else {
throw new HTTPException(404, { throw new HTTPException(404, {
message: `Role ${roleCode} does not exists`, message: `Role ${roleId} does not exists`,
}); });
} }
} }
@ -400,18 +432,18 @@ const usersRoute = new Hono<HonoEnv>()
// Update roles if provided // Update roles if provided
if (userData.roles) { if (userData.roles) {
const roles = JSON.parse(userData.roles) as string[]; const roles = userData.roles;
// Remove existing roles for the user // Remove existing roles for the user
await trx.delete(rolesToUsers).where(eq(rolesToUsers.userId, userId)); await trx.delete(rolesToUsers).where(eq(rolesToUsers.userId, userId));
// Assign new roles // Assign new roles
for (let roleCode of roles) { for (let roleId of roles) {
const role = ( const role = (
await trx await trx
.select() .select()
.from(rolesSchema) .from(rolesSchema)
.where(eq(rolesSchema.code, roleCode)) .where(eq(rolesSchema.id, roleId))
.limit(1) .limit(1)
)[0]; )[0];
@ -422,7 +454,7 @@ const usersRoute = new Hono<HonoEnv>()
}); });
} else { } else {
throw new HTTPException(404, { throw new HTTPException(404, {
message: `Role ${roleCode} does not exist`, message: `Role ${roleId} does not exist`,
}); });
} }
} }