0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-31 22:51:25 -05:00

fix(core,console): delete specific user identities by target (#1176)

This commit is contained in:
Darcy Ye 2022-06-21 23:26:23 +08:00 committed by GitHub
parent 43711f234d
commit ad86bc8e12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 13 additions and 32 deletions

View file

@ -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);
}

View file

@ -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);
});
});

View file

@ -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<T extends AuthedRouter>(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 });