mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
feat(core): added a new endpoint to replace user roles (#3203)
This commit is contained in:
parent
dde0ae1ae7
commit
1db6177f3a
3 changed files with 66 additions and 1 deletions
|
@ -6,6 +6,7 @@ import type {
|
||||||
Resource,
|
Resource,
|
||||||
Role,
|
Role,
|
||||||
Scope,
|
Scope,
|
||||||
|
UsersRole,
|
||||||
} from '@logto/schemas';
|
} from '@logto/schemas';
|
||||||
import { ApplicationType } from '@logto/schemas';
|
import { ApplicationType } from '@logto/schemas';
|
||||||
|
|
||||||
|
@ -72,6 +73,13 @@ export const mockRole: Role = {
|
||||||
description: 'admin',
|
description: 'admin',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const mockRole2: Role = {
|
||||||
|
tenantId: 'fake_tenant',
|
||||||
|
id: 'role_id2',
|
||||||
|
name: 'admin2',
|
||||||
|
description: 'admin2',
|
||||||
|
};
|
||||||
|
|
||||||
export const mockAdminConsoleData: AdminConsoleData = {
|
export const mockAdminConsoleData: AdminConsoleData = {
|
||||||
demoChecked: false,
|
demoChecked: false,
|
||||||
applicationCreated: false,
|
applicationCreated: false,
|
||||||
|
@ -93,3 +101,10 @@ export const mockPasscode: Passcode = {
|
||||||
tryCount: 2,
|
tryCount: 2,
|
||||||
createdAt: 10,
|
createdAt: 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const mockUserRole: UsersRole = {
|
||||||
|
tenantId: 'fake_tenant',
|
||||||
|
id: 'user_role_id',
|
||||||
|
userId: 'foo',
|
||||||
|
roleId: 'role_id',
|
||||||
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { pickDefault } from '@logto/shared/esm';
|
import { pickDefault } from '@logto/shared/esm';
|
||||||
|
|
||||||
import { mockRole, mockUser } from '#src/__mocks__/index.js';
|
import { mockRole, mockUser, mockRole2, mockUserRole } from '#src/__mocks__/index.js';
|
||||||
import { mockId, mockStandardId } from '#src/test-utils/nanoid.js';
|
import { mockId, mockStandardId } from '#src/test-utils/nanoid.js';
|
||||||
import { MockTenant } from '#src/test-utils/tenant.js';
|
import { MockTenant } from '#src/test-utils/tenant.js';
|
||||||
import { createRequester } from '#src/utils/test-utils.js';
|
import { createRequester } from '#src/utils/test-utils.js';
|
||||||
|
@ -50,6 +50,18 @@ describe('user role routes', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('PUT /users/:id/roles', async () => {
|
||||||
|
findUsersRolesByUserId.mockResolvedValueOnce([mockUserRole]);
|
||||||
|
const response = await roleRequester.put(`/users/${mockUser.id}/roles`).send({
|
||||||
|
roleIds: [mockRole2.id],
|
||||||
|
});
|
||||||
|
expect(response.status).toEqual(200);
|
||||||
|
expect(deleteUsersRolesByUserIdAndRoleId).toHaveBeenCalledWith(mockUser.id, mockRole.id);
|
||||||
|
expect(insertUsersRoles).toHaveBeenCalledWith([
|
||||||
|
{ id: mockId, userId: mockUser.id, roleId: mockRole2.id },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('DELETE /users/:id/roles/:roleId', async () => {
|
it('DELETE /users/:id/roles/:roleId', async () => {
|
||||||
const response = await roleRequester.delete(`/users/${mockUser.id}/roles/${mockRole.id}`);
|
const response = await roleRequester.delete(`/users/${mockUser.id}/roles/${mockRole.id}`);
|
||||||
expect(response.status).toEqual(204);
|
expect(response.status).toEqual(204);
|
||||||
|
|
|
@ -99,6 +99,44 @@ export default function adminUserRoleRoutes<T extends AuthedRouter>(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
router.put(
|
||||||
|
'/users/:userId/roles',
|
||||||
|
koaGuard({
|
||||||
|
params: object({ userId: string() }),
|
||||||
|
body: object({ roleIds: string().min(1).array() }),
|
||||||
|
}),
|
||||||
|
async (ctx, next) => {
|
||||||
|
const {
|
||||||
|
params: { userId },
|
||||||
|
body: { roleIds },
|
||||||
|
} = ctx.guard;
|
||||||
|
|
||||||
|
await findUserById(userId);
|
||||||
|
const usersRoles = await findUsersRolesByUserId(userId);
|
||||||
|
|
||||||
|
// Only add the ones that doesn't exist
|
||||||
|
const roleIdsToAdd = roleIds.filter(
|
||||||
|
(roleId) => !usersRoles.some(({ roleId: _roleId }) => _roleId === roleId)
|
||||||
|
);
|
||||||
|
// Remove existing roles that isn't wanted by user anymore
|
||||||
|
const roleIdsToRemove = usersRoles
|
||||||
|
.filter(({ roleId }) => !roleIds.includes(roleId))
|
||||||
|
.map(({ roleId }) => roleId);
|
||||||
|
|
||||||
|
await Promise.all(roleIdsToAdd.map(async (roleId) => findRoleById(roleId)));
|
||||||
|
await Promise.all(
|
||||||
|
roleIdsToRemove.map(async (roleId) => deleteUsersRolesByUserIdAndRoleId(userId, roleId))
|
||||||
|
);
|
||||||
|
await insertUsersRoles(
|
||||||
|
roleIdsToAdd.map((roleId) => ({ id: generateStandardId(), userId, roleId }))
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.status = 200;
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
router.delete(
|
router.delete(
|
||||||
'/users/:userId/roles/:roleId',
|
'/users/:userId/roles/:roleId',
|
||||||
koaGuard({
|
koaGuard({
|
||||||
|
|
Loading…
Reference in a new issue