diff --git a/packages/builder/src/pages/builder/portal/users/groups/[groupId].svelte b/packages/builder/src/pages/builder/portal/users/groups/[groupId].svelte index d0eb50c8dd..5cb88149d5 100644 --- a/packages/builder/src/pages/builder/portal/users/groups/[groupId].svelte +++ b/packages/builder/src/pages/builder/portal/users/groups/[groupId].svelte @@ -49,7 +49,8 @@ $: group = $groups.find(x => x._id === groupId) $: isScimGroup = group?.scimInfo?.isSync - $: readonly = !sdk.users.isAdmin($auth.user) || isScimGroup + $: isAdmin = sdk.users.isAdmin($auth.user) + $: readonly = !isAdmin || isScimGroup $: groupApps = $apps .filter(app => groups.actions @@ -123,14 +124,18 @@ - editModal.show()}> + editModal.show()} + disabled={!isAdmin} + > Edit
deleteModal.show()} - disabled={isScimGroup} + disabled={readonly} > Delete @@ -139,7 +144,7 @@
- + diff --git a/packages/builder/src/pages/builder/portal/users/groups/_components/GroupUsers.svelte b/packages/builder/src/pages/builder/portal/users/groups/_components/GroupUsers.svelte index 438feecc07..9f6703964a 100644 --- a/packages/builder/src/pages/builder/portal/users/groups/_components/GroupUsers.svelte +++ b/packages/builder/src/pages/builder/portal/users/groups/_components/GroupUsers.svelte @@ -13,6 +13,7 @@ export let groupId export let readonly + export let isScimGroup let emailSearch let fetchGroupUsers @@ -61,10 +62,10 @@
- {#if !readonly} - - {:else} + {#if isScimGroup} + {:else if !readonly} + {/if}
diff --git a/packages/builder/src/stores/portal/groups.js b/packages/builder/src/stores/portal/groups.js index 34fe0f9231..1edc8a461c 100644 --- a/packages/builder/src/stores/portal/groups.js +++ b/packages/builder/src/stores/portal/groups.js @@ -35,7 +35,9 @@ export function createGroupsStore() { get: getGroup, save: async group => { - const { _scimInfo, ...dataToSave } = group + const { ...dataToSave } = group + delete dataToSave.scimInfo + delete dataToSave.userGroups const response = await API.saveGroup(dataToSave) group._id = response._id group._rev = response._rev diff --git a/packages/pro b/packages/pro index e565db07f6..c4c98ae70f 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit e565db07f6c51868087e88dfebde0328493443e6 +Subproject commit c4c98ae70f2e936009250893898ecf11f4ddf2c3 diff --git a/packages/worker/src/api/routes/global/tests/groups.spec.ts b/packages/worker/src/api/routes/global/tests/groups.spec.ts index b69c4781c4..414518d763 100644 --- a/packages/worker/src/api/routes/global/tests/groups.spec.ts +++ b/packages/worker/src/api/routes/global/tests/groups.spec.ts @@ -104,17 +104,79 @@ describe("/api/global/groups", () => { expect(events.group.permissionsEdited).not.toBeCalled() }) - describe("destroy", () => { - it("should be able to delete a basic group", async () => { - const group = structures.groups.UserGroup() - let oldGroup = await config.api.groups.saveGroup(group) - await config.api.groups.deleteGroup( - oldGroup.body._id, - oldGroup.body._rev - ) + describe("scim", () => { + async function createScimGroup() { + mocks.licenses.useScimIntegration() + await config.setSCIMConfig(true) - expect(events.group.deleted).toBeCalledTimes(1) + const scimGroup = await config.api.scimGroupsAPI.post({ + body: structures.scim.createGroupRequest({ + displayName: generator.word(), + }), + }) + + const { body: group } = await config.api.groups.find(scimGroup.id) + + expect(group).toBeDefined() + return group + } + + it("update will not allow sending SCIM fields", async () => { + const group = await createScimGroup() + + const updatedGroup: UserGroup = { + ...group, + name: generator.word(), + } + await config.api.groups.saveGroup(updatedGroup, { + expect: { + message: 'Invalid body - "scimInfo" is not allowed', + status: 400, + }, + }) + + expect(events.group.updated).not.toBeCalled() }) + + it("update will not amend the SCIM fields", async () => { + const group: UserGroup = await createScimGroup() + + const updatedGroup: UserGroup = { + ...group, + name: generator.word(), + scimInfo: undefined, + } + + await config.api.groups.saveGroup(updatedGroup, { + expect: 200, + }) + + expect(events.group.updated).toBeCalledTimes(1) + expect( + ( + await config.api.groups.find(group._id!, { + expect: 200, + }) + ).body + ).toEqual( + expect.objectContaining({ + ...group, + name: updatedGroup.name, + scimInfo: group.scimInfo, + _rev: expect.any(String), + }) + ) + }) + }) + }) + + describe("destroy", () => { + it("should be able to delete a basic group", async () => { + const group = structures.groups.UserGroup() + let oldGroup = await config.api.groups.saveGroup(group) + await config.api.groups.deleteGroup(oldGroup.body._id, oldGroup.body._rev) + + expect(events.group.deleted).toBeCalledTimes(1) }) }) @@ -147,7 +209,7 @@ describe("/api/global/groups", () => { await Promise.all( Array.from({ length: 30 }).map(async (_, i) => { - const email = `user${i}@example.com` + const email = `user${i}+${generator.guid()}@example.com` const user = await config.api.users.saveUser({ ...structures.users.user(), email, @@ -257,12 +319,16 @@ describe("/api/global/groups", () => { }) }) - it("update should return 200", async () => { + it("update should return forbidden", async () => { await config.withUser(builder, async () => { - await config.api.groups.updateGroupUsers(group._id!, { - add: [builder._id!], - remove: [], - }) + await config.api.groups.updateGroupUsers( + group._id!, + { + add: [builder._id!], + remove: [], + }, + { expect: 403 } + ) }) }) }) diff --git a/packages/worker/src/tests/api/groups.ts b/packages/worker/src/tests/api/groups.ts index 0b9081cc92..5153c19db0 100644 --- a/packages/worker/src/tests/api/groups.ts +++ b/packages/worker/src/tests/api/groups.ts @@ -7,7 +7,10 @@ export class GroupsAPI extends TestAPI { super(config) } - saveGroup = (group: UserGroup, { expect } = { expect: 200 }) => { + saveGroup = ( + group: UserGroup, + { expect }: { expect: number | object } = { expect: 200 } + ) => { return this.request .post(`/api/global/groups`) .send(group) @@ -44,14 +47,15 @@ export class GroupsAPI extends TestAPI { updateGroupUsers = ( id: string, - body: { add: string[]; remove: string[] } + body: { add: string[]; remove: string[] }, + { expect } = { expect: 200 } ) => { return this.request .post(`/api/global/groups/${id}/users`) .send(body) .set(this.config.defaultHeaders()) .expect("Content-Type", /json/) - .expect(200) + .expect(expect) } fetch = ({ expect } = { expect: 200 }) => { @@ -61,4 +65,12 @@ export class GroupsAPI extends TestAPI { .expect("Content-Type", /json/) .expect(expect) } + + find = (id: string, { expect } = { expect: 200 }) => { + return this.request + .get(`/api/global/groups/${id}`) + .set(this.config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(expect) + } }