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),
phoneNumber: z.string().min(1).max(13),
isEnabled: z.string().default("false"),
roles: z
.string()
.refine(
(data) => {
console.log(data);
try {
const parsed = JSON.parse(data);
return Array.isArray(parsed);
} catch {
return false;
}
},
{
message: "Roles must be an array",
}
)
.optional(),
// roles: z
// .string()
// .refine(
// (data) => {
// console.log(data);
// try {
// const parsed = JSON.parse(data);
// return Array.isArray(parsed);
// } catch {
// return false;
// }
// },
// {
// message: "Roles must be an array",
// }
// )
// .optional(),
roles: z.array(z.string()).optional(),
});
export const userUpdateSchema = userFormSchema.extend({
@ -58,6 +59,7 @@ const usersRoute = new Hono<HonoEnv>()
* - includeTrashed: boolean (default: false)\
* - withMetadata: boolean
*/
.get(
"/",
checkPermission("users.readAll"),
@ -73,13 +75,14 @@ const usersRoute = new Hono<HonoEnv>()
.optional()
.transform((v) => v?.toLowerCase() === "true"),
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(""),
})
),
async (c) => {
const { includeTrashed, page, limit, q } = c.req.valid("query");
// Total count for pagination
const totalCountQuery = includeTrashed
? sql<number>`(SELECT count(*) FROM ${users})`
: sql<number>`(SELECT count(*) FROM ${users} WHERE ${users.deletedAt} IS NULL)`;
@ -95,7 +98,10 @@ const usersRoute = new Hono<HonoEnv>()
updatedAt: users.updatedAt,
...(includeTrashed ? { deletedAt: users.deletedAt } : {}),
company: respondents.companyName,
roles: rolesSchema.name,
role: {
name: rolesSchema.name,
id: rolesSchema.id,
},
fullCount: totalCountQuery,
})
.from(users)
@ -118,8 +124,47 @@ const usersRoute = new Hono<HonoEnv>()
.offset(page * 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({
data: result.map((d) => ({ ...d, fullCount: undefined })),
data: groupedData.map((d) => ({ ...d, fullCount: undefined })),
_metadata: {
currentPage: page,
totalPages: Math.ceil(
@ -131,6 +176,7 @@ const usersRoute = new Hono<HonoEnv>()
});
}
)
//get user by id
.get(
"/: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
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 = (
await trx
.select()
.from(rolesSchema)
.where(eq(rolesSchema.code, roleCode))
.where(eq(rolesSchema.id, roleId))
.limit(1)
)[0];
@ -312,7 +344,7 @@ const usersRoute = new Hono<HonoEnv>()
});
} else {
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
if (userData.roles) {
const roles = JSON.parse(userData.roles) as string[];
const roles = userData.roles;
// Remove existing roles for the user
await trx.delete(rolesToUsers).where(eq(rolesToUsers.userId, userId));
// Assign new roles
for (let roleCode of roles) {
for (let roleId of roles) {
const role = (
await trx
.select()
.from(rolesSchema)
.where(eq(rolesSchema.code, roleCode))
.where(eq(rolesSchema.id, roleId))
.limit(1)
)[0];
@ -422,7 +454,7 @@ const usersRoute = new Hono<HonoEnv>()
});
} else {
throw new HTTPException(404, {
message: `Role ${roleCode} does not exist`,
message: `Role ${roleId} does not exist`,
});
}
}