diff --git a/backend/src/ee/routes/v1/scim-router.ts b/backend/src/ee/routes/v1/scim-router.ts index 0a45486ef..3fdcabc8a 100644 --- a/backend/src/ee/routes/v1/scim-router.ts +++ b/backend/src/ee/routes/v1/scim-router.ts @@ -475,10 +475,13 @@ export const registerScimRouter = async (server: FastifyZodProvider) => { }), z.object({ op: z.literal("add"), - value: z.object({ - value: z.string().trim(), - display: z.string().trim().optional() - }) + path: z.string().trim(), + value: z.array( + z.object({ + value: z.string().trim(), + display: z.string().trim().optional() + }) + ) }) ]) ) diff --git a/backend/src/ee/services/scim/scim-service.ts b/backend/src/ee/services/scim/scim-service.ts index dc175f15b..4d15676b8 100644 --- a/backend/src/ee/services/scim/scim-service.ts +++ b/backend/src/ee/services/scim/scim-service.ts @@ -2,7 +2,7 @@ import { ForbiddenError } from "@casl/ability"; import slugify from "@sindresorhus/slugify"; import jwt from "jsonwebtoken"; -import { OrgMembershipRole, OrgMembershipStatus, TableName, TGroups, TOrgMemberships, TUsers } from "@app/db/schemas"; +import { OrgMembershipRole, OrgMembershipStatus, TableName, TOrgMemberships, TUsers } from "@app/db/schemas"; import { TGroupDALFactory } from "@app/ee/services/group/group-dal"; import { addUsersToGroupByUserIds, removeUsersFromGroupByUserIds } from "@app/ee/services/group/group-fns"; import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal"; @@ -66,7 +66,7 @@ type TScimServiceFactoryDep = { projectMembershipDAL: Pick; groupDAL: Pick< TGroupDALFactory, - "create" | "findOne" | "findAllGroupMembers" | "update" | "delete" | "findGroups" | "transaction" + "create" | "findOne" | "findAllGroupMembers" | "delete" | "findGroups" | "transaction" | "updateById" | "update" >; groupProjectDAL: Pick; userGroupMembershipDAL: Pick< @@ -817,7 +817,6 @@ export const scimServiceFactory = ({ }); }; - // TODO: add support for add/remove op const updateScimGroupNamePatch = async ({ groupId, orgId, operations }: TUpdateScimGroupNamePatchDTO) => { const plan = await licenseService.getPlan(orgId); if (!plan.groups) @@ -840,23 +839,45 @@ export const scimServiceFactory = ({ status: 403 }); - let group: TGroups | undefined; + let group = await groupDAL.findOne({ + id: groupId, + orgId + }); + + if (!group) { + throw new ScimRequestError({ + detail: "Group Not Found", + status: 404 + }); + } + for await (const operation of operations) { switch (operation.op) { case "replace": { - await groupDAL.update( - { - id: groupId, - orgId - }, - { - name: operation.value.displayName - } - ); + group = await groupDAL.updateById(group.id, { + name: operation.value.displayName + }); break; } case "add": { - // TODO + const orgMemberships = await orgMembershipDAL.find({ + $in: { + id: operation.value.map((member) => member.value) + } + }); + + await addUsersToGroupByUserIds({ + group, + userIds: orgMemberships.map((membership) => membership.userId as string), + userDAL, + userGroupMembershipDAL, + orgDAL, + groupProjectDAL, + projectKeyDAL, + projectDAL, + projectBotDAL + }); + break; } case "remove": { @@ -872,13 +893,6 @@ export const scimServiceFactory = ({ } } - if (!group) { - throw new ScimRequestError({ - detail: "Group Not Found", - status: 404 - }); - } - return buildScimGroup({ groupId: group.id, name: group.name, diff --git a/backend/src/ee/services/scim/scim-types.ts b/backend/src/ee/services/scim/scim-types.ts index cffc80407..f00336fd2 100644 --- a/backend/src/ee/services/scim/scim-types.ts +++ b/backend/src/ee/services/scim/scim-types.ts @@ -125,10 +125,11 @@ type TRemoveOp = { type TAddOp = { op: "add"; + path: string; value: { value: string; display?: string; - }; + }[]; }; export type TDeleteScimGroupDTO = {