From ad86bc8e120e571268cffbb45fe3c8253c1207fe Mon Sep 17 00:00:00 2001 From: Darcy Ye Date: Tue, 21 Jun 2022 23:26:23 +0800 Subject: [PATCH] fix(core,console): delete specific user identities by target (#1176) --- .../UserDetails/components/UserConnectors.tsx | 6 ++-- packages/core/src/routes/admin-user.test.ts | 29 +++++-------------- packages/core/src/routes/admin-user.ts | 10 ++----- 3 files changed, 13 insertions(+), 32 deletions(-) diff --git a/packages/console/src/pages/UserDetails/components/UserConnectors.tsx b/packages/console/src/pages/UserDetails/components/UserConnectors.tsx index 6e82114be..60328109e 100644 --- a/packages/console/src/pages/UserDetails/components/UserConnectors.tsx +++ b/packages/console/src/pages/UserDetails/components/UserConnectors.tsx @@ -35,7 +35,7 @@ const UserConnectors = ({ userId, connectors, onDelete }: Props) => { const isLoading = !connectorGroups && !error; const [isSubmitting, setIsSubmitting] = useState(false); - const handleDelete = async (connectorId: string) => { + const handleDelete = async (target: string) => { if (isSubmitting) { return; } @@ -43,8 +43,8 @@ const UserConnectors = ({ userId, connectors, onDelete }: Props) => { setIsSubmitting(true); try { - await api.delete(`/api/users/${userId}/identities/${connectorId}`); - onDelete?.(connectorId); + await api.delete(`/api/users/${userId}/identities/${target}`); + onDelete?.(target); } finally { setIsSubmitting(false); } diff --git a/packages/core/src/routes/admin-user.test.ts b/packages/core/src/routes/admin-user.test.ts index e321070b4..f43ee66ef 100644 --- a/packages/core/src/routes/admin-user.test.ts +++ b/packages/core/src/routes/admin-user.test.ts @@ -2,7 +2,6 @@ import { CreateUser, Role, User, userInfoSelectFields } from '@logto/schemas'; import pick from 'lodash.pick'; import { mockUser, mockUserList, mockUserListResponse, mockUserResponse } from '@/__mocks__'; -import { getConnectorInstanceById } from '@/connectors'; import { encryptUserPassword } from '@/lib/user'; import { findRolesByRoleNames } from '@/queries/roles'; import { @@ -23,10 +22,6 @@ const filterUsersWithSearch = (users: User[], search: string) => ) ); -jest.mock('@/connectors', () => ({ - getConnectorInstanceById: jest.fn(), -})); - jest.mock('@/queries/user', () => ({ countUsers: jest.fn(async (search) => ({ count: search ? filterUsersWithSearch(mockUserList, search).length : mockUserList.length, @@ -292,9 +287,9 @@ describe('adminUserRoutes', () => { expect(deleteUserById).not.toHaveBeenCalled(); }); - it('DELETE /users/:userId/identities/:connectorId should throw if user not found', async () => { + it('DELETE /users/:userId/identities/:target should throw if user not found', async () => { const notExistedUserId = 'notExisitedUserId'; - const arbitraryConnectorId = 'arbitraryConnectorId'; + const arbitraryTarget = 'arbitraryTarget'; const mockedFindUserById = findUserById as jest.Mock; mockedFindUserById.mockImplementationOnce((userId) => { if (userId === notExistedUserId) { @@ -302,14 +297,13 @@ describe('adminUserRoutes', () => { } }); await expect( - userRequest.delete(`/users/${notExistedUserId}/identities/${arbitraryConnectorId}`) + userRequest.delete(`/users/${notExistedUserId}/identities/${arbitraryTarget}`) ).resolves.toHaveProperty('status', 500); expect(deleteUserIdentity).not.toHaveBeenCalled(); }); - it('DELETE /users/:userId/identities/:connectorId should throw if user found and connector is not found', async () => { + it('DELETE /users/:userId/identities/:target should throw if user found and connector is not found', async () => { const arbitraryUserId = 'arbitraryUserId'; - const nonexistentConnectorId = 'nonexistentConnectorId'; const nonexistentTarget = 'nonexistentTarget'; const mockedFindUserById = findUserById as jest.Mock; mockedFindUserById.mockImplementationOnce((userId) => { @@ -317,19 +311,14 @@ describe('adminUserRoutes', () => { return { identities: { connector1: {}, connector2: {} } }; } }); - const mockGetConnectorInstanceById = getConnectorInstanceById as jest.Mock; - mockGetConnectorInstanceById.mockResolvedValueOnce({ - metadata: { target: nonexistentTarget }, - }); await expect( - userRequest.delete(`/users/${arbitraryUserId}/identities/${nonexistentConnectorId}`) + userRequest.delete(`/users/${arbitraryUserId}/identities/${nonexistentTarget}`) ).resolves.toHaveProperty('status', 404); expect(deleteUserIdentity).not.toHaveBeenCalled(); }); - it('DELETE /users/:userId/identities/:connectorId', async () => { + it('DELETE /users/:userId/identities/:target', async () => { const arbitraryUserId = 'arbitraryUserId'; - const arbitraryConnectorId = 'arbitraryConnectorId'; const arbitraryTarget = 'arbitraryTarget'; const mockedFindUserById = findUserById as jest.Mock; mockedFindUserById.mockImplementationOnce((userId) => { @@ -337,11 +326,7 @@ describe('adminUserRoutes', () => { return { identities: { connectorTarget1: {}, connectorTarget2: {}, arbitraryTarget: {} } }; } }); - const mockGetConnectorInstanceById = getConnectorInstanceById as jest.Mock; - mockGetConnectorInstanceById.mockResolvedValueOnce({ - metadata: { target: arbitraryTarget }, - }); - await userRequest.delete(`/users/${arbitraryUserId}/identities/${arbitraryConnectorId}`); + await userRequest.delete(`/users/${arbitraryUserId}/identities/${arbitraryTarget}`); expect(deleteUserIdentity).toHaveBeenCalledWith(arbitraryUserId, arbitraryTarget); }); }); diff --git a/packages/core/src/routes/admin-user.ts b/packages/core/src/routes/admin-user.ts index 9e02df7e1..0526150ca 100644 --- a/packages/core/src/routes/admin-user.ts +++ b/packages/core/src/routes/admin-user.ts @@ -5,7 +5,6 @@ import pick from 'lodash.pick'; import { InvalidInputError } from 'slonik'; import { object, string } from 'zod'; -import { getConnectorInstanceById } from '@/connectors'; import RequestError from '@/errors/RequestError'; import { encryptUserPassword, generateUserId } from '@/lib/user'; import koaGuard from '@/middleware/koa-guard'; @@ -199,17 +198,14 @@ export default function adminUserRoutes(router: T) { ); router.delete( - '/users/:userId/identities/:connectorId', - koaGuard({ params: object({ userId: string(), connectorId: string() }) }), + '/users/:userId/identities/:target', + koaGuard({ params: object({ userId: string(), target: string() }) }), async (ctx, next) => { const { - params: { userId, connectorId }, + params: { userId, target }, } = ctx.guard; const { identities } = await findUserById(userId); - const { - metadata: { target }, - } = await getConnectorInstanceById(connectorId); if (!has(identities, target)) { throw new RequestError({ code: 'user.identity_not_exists', status: 404 });