From 385c75c543101ace8c19057d56ff63450beb7c25 Mon Sep 17 00:00:00 2001 From: Carlos Monastyrski Date: Mon, 11 Aug 2025 21:23:05 -0700 Subject: [PATCH] Add machine identities to /organization endpoint --- .../server/routes/v1/organization-router.ts | 30 +++++++++++++------ backend/src/services/org/org-dal.ts | 22 +++++++++++++- backend/src/services/org/org-service.ts | 10 +++++++ 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/backend/src/server/routes/v1/organization-router.ts b/backend/src/server/routes/v1/organization-router.ts index 323354bc1..dfd87fa11 100644 --- a/backend/src/server/routes/v1/organization-router.ts +++ b/backend/src/server/routes/v1/organization-router.ts @@ -29,18 +29,30 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { }, schema: { response: { - 200: z.object({ - organizations: sanitizedOrganizationSchema - .extend({ - orgAuthMethod: z.string(), - userRole: z.string() - }) - .array() - }) + 200: z.union([ + z.object({ + id: z.string(), + name: z.string(), + slug: z.string(), + role: z.string() + }), + z.object({ + organizations: sanitizedOrganizationSchema + .extend({ + orgAuthMethod: z.string(), + userRole: z.string() + }) + .array() + }) + ]) } }, - onRequest: verifyAuth([AuthMode.JWT], { requireOrg: false }), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN], { requireOrg: false }), handler: async (req) => { + if (req.permission.type === ActorType.IDENTITY) { + const organization = await server.services.org.findIdentityOrganization(req.permission.id); + return organization; + } const organizations = await server.services.org.findAllOrganizationOfUser(req.permission.id); return { organizations }; } diff --git a/backend/src/services/org/org-dal.ts b/backend/src/services/org/org-dal.ts index b46efc46c..b4246adaa 100644 --- a/backend/src/services/org/org-dal.ts +++ b/backend/src/services/org/org-dal.ts @@ -630,6 +630,25 @@ export const orgDALFactory = (db: TDbClient) => { } }; + const findIdentityOrganization = async ( + identityId: string + ): Promise<{ id: string; name: string; slug: string; role: string }> => { + try { + const org = await db + .replicaNode()(TableName.IdentityOrgMembership) + .where({ identityId }) + .join(TableName.Organization, `${TableName.IdentityOrgMembership}.orgId`, `${TableName.Organization}.id`) + .select(db.ref("id").withSchema(TableName.Organization).as("id")) + .select(db.ref("name").withSchema(TableName.Organization).as("name")) + .select(db.ref("slug").withSchema(TableName.Organization).as("slug")) + .select(db.ref("role").withSchema(TableName.IdentityOrgMembership).as("role")); + + return org?.[0]; + } catch (error) { + throw new DatabaseError({ error, name: "Find all org by user id" }); + } + }; + return withTransaction(db, { ...orgOrm, findOrgByProjectId, @@ -652,6 +671,7 @@ export const orgDALFactory = (db: TDbClient) => { updateMembershipById, deleteMembershipById, deleteMembershipsById, - updateMembership + updateMembership, + findIdentityOrganization }); }; diff --git a/backend/src/services/org/org-service.ts b/backend/src/services/org/org-service.ts index 5779fa7d3..ba76d0a93 100644 --- a/backend/src/services/org/org-service.ts +++ b/backend/src/services/org/org-service.ts @@ -198,6 +198,15 @@ export const orgServiceFactory = ({ // Filter out orgs where the membership object is an invitation return orgs.filter((org) => org.userStatus !== "invited"); }; + + /* + * Get all organization an identity is part of + * */ + const findIdentityOrganization = async (identityId: string) => { + const org = await orgDAL.findIdentityOrganization(identityId); + + return org; + }; /* * Get all workspace members * */ @@ -1403,6 +1412,7 @@ export const orgServiceFactory = ({ findOrganizationById, findAllOrgMembers, findAllOrganizationOfUser, + findIdentityOrganization, inviteUserToOrganization, verifyUserToOrg, updateOrg,