From 93b7f56337676e5feb80b1544c5237fc067be77f Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Fri, 20 Sep 2024 13:30:38 +0800 Subject: [PATCH] misc: migrated groups API to use ids instead of slug --- backend/src/ee/routes/v1/group-router.ts | 43 ++++++++++--------- .../src/ee/services/group/group-service.ts | 42 ++++++++---------- backend/src/ee/services/group/group-types.ts | 10 ++--- backend/src/lib/api-docs/constants.ts | 9 ++-- frontend/src/hooks/api/groups/mutations.tsx | 34 +++++++++++---- frontend/src/hooks/api/groups/queries.tsx | 16 ++++--- .../OrgGroupsSection/OrgGroupMembersModal.tsx | 4 ++ .../OrgGroupsSection/OrgGroupModal.tsx | 2 +- .../OrgGroupsSection/OrgGroupsSection.tsx | 6 +-- .../OrgGroupsSection/OrgGroupsTable.tsx | 11 ++--- 10 files changed, 99 insertions(+), 78 deletions(-) diff --git a/backend/src/ee/routes/v1/group-router.ts b/backend/src/ee/routes/v1/group-router.ts index d267564f2..11c5d6fba 100644 --- a/backend/src/ee/routes/v1/group-router.ts +++ b/backend/src/ee/routes/v1/group-router.ts @@ -10,7 +10,7 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { server.route({ url: "/", method: "POST", - onRequest: verifyAuth([AuthMode.JWT]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { body: z.object({ name: z.string().trim().min(1).max(50).describe(GROUPS.CREATE.name), @@ -43,12 +43,12 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { }); server.route({ - url: "/:currentSlug", + url: "/:id", method: "PATCH", - onRequest: verifyAuth([AuthMode.JWT]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { params: z.object({ - currentSlug: z.string().trim().describe(GROUPS.UPDATE.currentSlug) + id: z.string().trim().describe(GROUPS.UPDATE.id) }), body: z .object({ @@ -70,7 +70,7 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { }, handler: async (req) => { const group = await server.services.group.updateGroup({ - currentSlug: req.params.currentSlug, + id: req.params.id, actor: req.permission.type, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, @@ -83,12 +83,12 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { }); server.route({ - url: "/:slug", + url: "/:id", method: "DELETE", - onRequest: verifyAuth([AuthMode.JWT]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { params: z.object({ - slug: z.string().trim().describe(GROUPS.DELETE.slug) + id: z.string().trim().describe(GROUPS.DELETE.id) }), response: { 200: GroupsSchema @@ -96,7 +96,7 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { }, handler: async (req) => { const group = await server.services.group.deleteGroup({ - groupSlug: req.params.slug, + id: req.params.id, actor: req.permission.type, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, @@ -109,11 +109,11 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:slug/users", - onRequest: verifyAuth([AuthMode.JWT]), + url: "/:id/users", + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { params: z.object({ - slug: z.string().trim().describe(GROUPS.LIST_USERS.slug) + id: z.string().trim().describe(GROUPS.LIST_USERS.id) }), querystring: z.object({ offset: z.coerce.number().min(0).max(100).default(0).describe(GROUPS.LIST_USERS.offset), @@ -141,24 +141,25 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { }, handler: async (req) => { const { users, totalCount } = await server.services.group.listGroupUsers({ - groupSlug: req.params.slug, + id: req.params.id, actor: req.permission.type, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, ...req.query }); + return { users, totalCount }; } }); server.route({ method: "POST", - url: "/:slug/users/:username", - onRequest: verifyAuth([AuthMode.JWT]), + url: "/:id/users/:username", + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { params: z.object({ - slug: z.string().trim().describe(GROUPS.ADD_USER.slug), + id: z.string().trim().describe(GROUPS.ADD_USER.id), username: z.string().trim().describe(GROUPS.ADD_USER.username) }), response: { @@ -173,7 +174,7 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { }, handler: async (req) => { const user = await server.services.group.addUserToGroup({ - groupSlug: req.params.slug, + id: req.params.id, username: req.params.username, actor: req.permission.type, actorId: req.permission.id, @@ -187,11 +188,11 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { server.route({ method: "DELETE", - url: "/:slug/users/:username", - onRequest: verifyAuth([AuthMode.JWT]), + url: "/:id/users/:username", + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { params: z.object({ - slug: z.string().trim().describe(GROUPS.DELETE_USER.slug), + id: z.string().trim().describe(GROUPS.DELETE_USER.id), username: z.string().trim().describe(GROUPS.DELETE_USER.username) }), response: { @@ -206,7 +207,7 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { }, handler: async (req) => { const user = await server.services.group.removeUserFromGroup({ - groupSlug: req.params.slug, + id: req.params.id, username: req.params.username, actor: req.permission.type, actorId: req.permission.id, diff --git a/backend/src/ee/services/group/group-service.ts b/backend/src/ee/services/group/group-service.ts index e6a151bf7..05fafe180 100644 --- a/backend/src/ee/services/group/group-service.ts +++ b/backend/src/ee/services/group/group-service.ts @@ -95,7 +95,7 @@ export const groupServiceFactory = ({ }; const updateGroup = async ({ - currentSlug, + id, name, slug, role, @@ -121,8 +121,10 @@ export const groupServiceFactory = ({ message: "Failed to update group due to plan restrictio Upgrade plan to update group." }); - const group = await groupDAL.findOne({ orgId: actorOrgId, slug: currentSlug }); - if (!group) throw new BadRequestError({ message: `Failed to find group with slug ${currentSlug}` }); + const group = await groupDAL.findOne({ orgId: actorOrgId, id }); + if (!group) { + throw new BadRequestError({ message: `Failed to find group with ID ${id}` }); + } let customRole: TOrgRoles | undefined; if (role) { @@ -140,8 +142,7 @@ export const groupServiceFactory = ({ const [updatedGroup] = await groupDAL.update( { - orgId: actorOrgId, - slug: currentSlug + id: group.id }, { name, @@ -158,7 +159,7 @@ export const groupServiceFactory = ({ return updatedGroup; }; - const deleteGroup = async ({ groupSlug, actor, actorId, actorAuthMethod, actorOrgId }: TDeleteGroupDTO) => { + const deleteGroup = async ({ id, actor, actorId, actorAuthMethod, actorOrgId }: TDeleteGroupDTO) => { if (!actorOrgId) throw new BadRequestError({ message: "Failed to create group without organization" }); const { permission } = await permissionService.getOrgPermission( @@ -178,15 +179,15 @@ export const groupServiceFactory = ({ }); const [group] = await groupDAL.delete({ - orgId: actorOrgId, - slug: groupSlug + id, + orgId: actorOrgId }); return group; }; const listGroupUsers = async ({ - groupSlug, + id, offset, limit, username, @@ -208,12 +209,12 @@ export const groupServiceFactory = ({ const group = await groupDAL.findOne({ orgId: actorOrgId, - slug: groupSlug + id }); if (!group) throw new BadRequestError({ - message: `Failed to find group with slug ${groupSlug}` + message: `Failed to find group with ID ${id}` }); const users = await groupDAL.findAllGroupMembers({ @@ -229,14 +230,7 @@ export const groupServiceFactory = ({ return { users, totalCount: count }; }; - const addUserToGroup = async ({ - groupSlug, - username, - actor, - actorId, - actorAuthMethod, - actorOrgId - }: TAddUserToGroupDTO) => { + const addUserToGroup = async ({ id, username, actor, actorId, actorAuthMethod, actorOrgId }: TAddUserToGroupDTO) => { if (!actorOrgId) throw new BadRequestError({ message: "Failed to create group without organization" }); const { permission } = await permissionService.getOrgPermission( @@ -251,12 +245,12 @@ export const groupServiceFactory = ({ // check if group with slug exists const group = await groupDAL.findOne({ orgId: actorOrgId, - slug: groupSlug + id }); if (!group) throw new BadRequestError({ - message: `Failed to find group with slug ${groupSlug}` + message: `Failed to find group with ID ${id}` }); const { permission: groupRolePermission } = await permissionService.getOrgPermissionByRole(group.role, actorOrgId); @@ -285,7 +279,7 @@ export const groupServiceFactory = ({ }; const removeUserFromGroup = async ({ - groupSlug, + id, username, actor, actorId, @@ -306,12 +300,12 @@ export const groupServiceFactory = ({ // check if group with slug exists const group = await groupDAL.findOne({ orgId: actorOrgId, - slug: groupSlug + id }); if (!group) throw new BadRequestError({ - message: `Failed to find group with slug ${groupSlug}` + message: `Failed to find group with ID ${id}` }); const { permission: groupRolePermission } = await permissionService.getOrgPermissionByRole(group.role, actorOrgId); diff --git a/backend/src/ee/services/group/group-types.ts b/backend/src/ee/services/group/group-types.ts index ca9831ffb..125765a1c 100644 --- a/backend/src/ee/services/group/group-types.ts +++ b/backend/src/ee/services/group/group-types.ts @@ -17,7 +17,7 @@ export type TCreateGroupDTO = { } & TGenericPermission; export type TUpdateGroupDTO = { - currentSlug: string; + id: string; } & Partial<{ name: string; slug: string; @@ -26,23 +26,23 @@ export type TUpdateGroupDTO = { TGenericPermission; export type TDeleteGroupDTO = { - groupSlug: string; + id: string; } & TGenericPermission; export type TListGroupUsersDTO = { - groupSlug: string; + id: string; offset: number; limit: number; username?: string; } & TGenericPermission; export type TAddUserToGroupDTO = { - groupSlug: string; + id: string; username: string; } & TGenericPermission; export type TRemoveUserFromGroupDTO = { - groupSlug: string; + id: string; username: string; } & TGenericPermission; diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index 5ed7ed8f2..9b64900a1 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -5,26 +5,27 @@ export const GROUPS = { role: "The role of the group to create." }, UPDATE: { - currentSlug: "The current slug of the group to update.", + id: "The id of the group to update", name: "The new name of the group to update to.", slug: "The new slug of the group to update to.", role: "The new role of the group to update to." }, DELETE: { + id: "The id of the group to delete", slug: "The slug of the group to delete" }, LIST_USERS: { - slug: "The slug of the group to list users for", + id: "The id of the group to list users for", offset: "The offset to start from. If you enter 10, it will start from the 10th user.", limit: "The number of users to return.", username: "The username to search for." }, ADD_USER: { - slug: "The slug of the group to add the user to.", + id: "The id of the group to add the user to.", username: "The username of the user to add to the group." }, DELETE_USER: { - slug: "The slug of the group to remove the user from.", + id: "The id of the group to remove the user from.", username: "The username of the user to remove from the group." } } as const; diff --git a/frontend/src/hooks/api/groups/mutations.tsx b/frontend/src/hooks/api/groups/mutations.tsx index ad8d83597..445ae10bc 100644 --- a/frontend/src/hooks/api/groups/mutations.tsx +++ b/frontend/src/hooks/api/groups/mutations.tsx @@ -38,17 +38,17 @@ export const useUpdateGroup = () => { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ - currentSlug, + id, name, slug, role }: { - currentSlug: string; + id: string; name?: string; slug?: string; role?: string; }) => { - const { data: group } = await apiRequest.patch(`/api/v1/groups/${currentSlug}`, { + const { data: group } = await apiRequest.patch(`/api/v1/groups/${id}`, { name, slug, role @@ -65,8 +65,8 @@ export const useUpdateGroup = () => { export const useDeleteGroup = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ slug }: { slug: string }) => { - const { data: group } = await apiRequest.delete(`/api/v1/groups/${slug}`); + mutationFn: async ({ id }: { id: string }) => { + const { data: group } = await apiRequest.delete(`/api/v1/groups/${id}`); return group; }, @@ -79,8 +79,15 @@ export const useDeleteGroup = () => { export const useAddUserToGroup = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ slug, username }: { slug: string; username: string }) => { - const { data } = await apiRequest.post(`/api/v1/groups/${slug}/users/${username}`); + mutationFn: async ({ + groupId, + username + }: { + groupId: string; + username: string; + slug: string; + }) => { + const { data } = await apiRequest.post(`/api/v1/groups/${groupId}/users/${username}`); return data; }, @@ -93,8 +100,17 @@ export const useAddUserToGroup = () => { export const useRemoveUserFromGroup = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ slug, username }: { slug: string; username: string }) => { - const { data } = await apiRequest.delete(`/api/v1/groups/${slug}/users/${username}`); + mutationFn: async ({ + username, + groupId + }: { + slug: string; + username: string; + groupId: string; + }) => { + const { data } = await apiRequest.delete( + `/api/v1/groups/${groupId}/users/${username}` + ); return data; }, diff --git a/frontend/src/hooks/api/groups/queries.tsx b/frontend/src/hooks/api/groups/queries.tsx index ba0543135..9012d2dcf 100644 --- a/frontend/src/hooks/api/groups/queries.tsx +++ b/frontend/src/hooks/api/groups/queries.tsx @@ -4,7 +4,8 @@ import { apiRequest } from "@app/config/request"; export const groupKeys = { allGroupUserMemberships: () => ["group-user-memberships"] as const, - forGroupUserMemberships: (slug: string) => [...groupKeys.allGroupUserMemberships(), slug] as const, + forGroupUserMemberships: (slug: string) => + [...groupKeys.allGroupUserMemberships(), slug] as const, specificGroupUserMemberships: ({ slug, offset, @@ -28,11 +29,13 @@ type TUser = { }; export const useListGroupUsers = ({ + id, groupSlug, offset = 0, limit = 10, username }: { + id: string; groupSlug: string; offset: number; limit: number; @@ -52,14 +55,15 @@ export const useListGroupUsers = ({ limit: String(limit), username }); - - const { data } = await apiRequest.get<{ users: TUser[]; totalCount: number; }>( - `/api/v1/groups/${groupSlug}/users`, { + + const { data } = await apiRequest.get<{ users: TUser[]; totalCount: number }>( + `/api/v1/groups/${id}/users`, + { params } ); - + return data; - }, + } }); }; diff --git a/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupMembersModal.tsx b/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupMembersModal.tsx index d6b1c515f..78b805df9 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupMembersModal.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupMembersModal.tsx @@ -35,10 +35,12 @@ export const OrgGroupMembersModal = ({ popUp, handlePopUpToggle }: Props) => { const [searchMemberFilter, setSearchMemberFilter] = useState(""); const popUpData = popUp?.groupMembers?.data as { + groupId: string; slug: string; }; const { data, isLoading } = useListGroupUsers({ + id: popUpData?.groupId, groupSlug: popUpData?.slug, offset: (page - 1) * perPage, limit: perPage, @@ -54,11 +56,13 @@ export const OrgGroupMembersModal = ({ popUp, handlePopUpToggle }: Props) => { if (assign) { await assignMutateAsync({ + groupId: popUpData.groupId, username, slug: popUpData.slug }); } else { await unassignMutateAsync({ + groupId: popUpData.groupId, username, slug: popUpData.slug }); diff --git a/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupModal.tsx b/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupModal.tsx index 85a5c0c23..4ea4516de 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupModal.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupModal.tsx @@ -85,7 +85,7 @@ export const OrgGroupModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: Pr if (group) { await updateMutateAsync({ - currentSlug: group.slug, + id: group.groupId, name, slug, role: role || undefined diff --git a/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupsSection.tsx b/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupsSection.tsx index 2df78fe5f..7738d1353 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupsSection.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupsSection.tsx @@ -34,10 +34,10 @@ export const OrgGroupsSection = () => { } }; - const onDeleteGroupSubmit = async ({ name, slug }: { name: string; slug: string }) => { + const onDeleteGroupSubmit = async ({ name, groupId }: { name: string; groupId: string }) => { try { await deleteMutateAsync({ - slug + id: groupId }); createNotification({ text: `Successfully deleted the group named ${name}`, @@ -87,7 +87,7 @@ export const OrgGroupsSection = () => { onChange={(isOpen) => handlePopUpToggle("deleteGroup", isOpen)} deleteKey="confirm" onDeleteApproved={() => - onDeleteGroupSubmit(popUp?.deleteGroup?.data as { name: string; slug: string }) + onDeleteGroupSubmit(popUp?.deleteGroup?.data as { name: string; groupId: string }) } /> { const { data: roles } = useGetOrgRoles(orgId); - const handleChangeRole = async ({ currentSlug, role }: { currentSlug: string; role: string }) => { + const handleChangeRole = async ({ id, role }: { id: string; role: string }) => { try { await updateMutateAsync({ - currentSlug, + id, role }); @@ -112,7 +112,7 @@ export const OrgGroupsTable = ({ handlePopUpOpen }: Props) => { dropdownContainerClassName="border border-mineshaft-600 bg-mineshaft-800" onValueChange={(selectedRole) => handleChangeRole({ - currentSlug: slug, + id, role: selectedRole }) } @@ -147,6 +147,7 @@ export const OrgGroupsTable = ({ handlePopUpOpen }: Props) => { onClick={(e) => { e.stopPropagation(); handlePopUpOpen("groupMembers", { + groupId: id, slug }); }} @@ -195,7 +196,7 @@ export const OrgGroupsTable = ({ handlePopUpOpen }: Props) => { onClick={(e) => { e.stopPropagation(); handlePopUpOpen("deleteGroup", { - slug, + groupId: id, name }); }}