Pull Request branch dev-clone to main #1
|
|
@ -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`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user