From 653ac6b130384440f83c104b8e0fd70694e11096 Mon Sep 17 00:00:00 2001 From: McPizza0 Date: Wed, 21 Aug 2024 12:16:39 +0200 Subject: [PATCH] change emailIdentity lookup to check based on spaces --- .../trpc/routers/convoRouter/convoRouter.ts | 68 ++++++++++---- .../orgRouter/mail/emailIdentityRouter.ts | 94 ++++++++++++------- .../convo/[convoId]/_components/reply-box.tsx | 3 +- 3 files changed, 113 insertions(+), 52 deletions(-) diff --git a/apps/platform/trpc/routers/convoRouter/convoRouter.ts b/apps/platform/trpc/routers/convoRouter/convoRouter.ts index 8827953e..583027ae 100644 --- a/apps/platform/trpc/routers/convoRouter/convoRouter.ts +++ b/apps/platform/trpc/routers/convoRouter/convoRouter.ts @@ -542,16 +542,7 @@ export const convoRouter = router({ lastUpdatedAt: newConvoTimestamp }); - // add the conversation to the space - - // const convoToSpacesInsertValues = spacesToAddConvoTo.map((spaceId) => ({ - // publicId: typeIdGenerator('convoToSpaces'), - // convoId: Number(insertConvoResponse.insertId), - // spaceId: spaceId, - // orgId: orgId - // })); - - // await db.insert(convoToSpaces).values(convoToSpacesInsertValues); + // add the conversation to the space(s) for (const spaceToAdd of spacesToAddConvoTo) { await addConvoToSpace({ @@ -953,6 +944,18 @@ export const convoRouter = router({ publicId: true }, with: { + spaces: { + columns: { + id: true + }, + with: { + space: { + columns: { + id: true + } + } + } + }, participants: { columns: { id: true, @@ -983,6 +986,11 @@ export const convoRouter = router({ }); } + const allSpaceIdsWhereConvoAlreadyExists = + convoEntryToReplyToQueryResponse.convo.spaces.map( + (space) => space.space.id + ); + // get the email identity the user wants to email from let emailIdentityId: number | null = null; @@ -1082,7 +1090,8 @@ export const convoRouter = router({ authorizedSenders: { columns: { orgMemberId: true, - teamId: true + teamId: true, + spaceId: true }, with: { team: { @@ -1102,15 +1111,36 @@ export const convoRouter = router({ } }); - const userIsAuthorized = - sendAsEmailIdentityResponse?.authorizedSenders.some( - (authorizedOrgMember) => - authorizedOrgMember.orgMemberId === accountOrgMemberId || - authorizedOrgMember.team?.members.some( - (teamMember) => teamMember.orgMemberId === accountOrgMemberId - ) + const authedOrgMemberIds = + sendAsEmailIdentityResponse?.authorizedSenders?.map( + (authorizedOrgMember) => authorizedOrgMember.orgMemberId + ) ?? []; + const authedTeamMemberIds: number[] = []; + sendAsEmailIdentityResponse?.authorizedSenders?.map( + (authorizedSender) => + authorizedSender.team?.members.map((teamMember) => + authedTeamMemberIds.push(teamMember.orgMemberId) + ) + ); + const authedSpacedIds = + sendAsEmailIdentityResponse?.authorizedSenders?.map( + (authorizedOrgMember) => authorizedOrgMember.spaceId + ) ?? []; + + const orgMemberIsAuthorizedToUseEmailIdentity = + authedOrgMemberIds.some( + (authedOrgMemberId) => authedOrgMemberId === accountOrgMemberId + ) || + authedTeamMemberIds?.some( + (authedTeamMemberId) => authedTeamMemberId === accountOrgMemberId + ) || + authedSpacedIds.some( + (authedSpacedId) => + authedSpacedId && + allSpaceIdsWhereConvoAlreadyExists.includes(authedSpacedId) ); - if (!userIsAuthorized) { + + if (!orgMemberIsAuthorizedToUseEmailIdentity) { throw new TRPCError({ code: 'UNAUTHORIZED', message: 'User is not authorized to send as this email identity' diff --git a/apps/platform/trpc/routers/orgRouter/mail/emailIdentityRouter.ts b/apps/platform/trpc/routers/orgRouter/mail/emailIdentityRouter.ts index 6dfd8bfa..5a62e9c9 100644 --- a/apps/platform/trpc/routers/orgRouter/mail/emailIdentityRouter.ts +++ b/apps/platform/trpc/routers/orgRouter/mail/emailIdentityRouter.ts @@ -7,7 +7,8 @@ import { emailIdentities, teamMembers, spaces, - emailIdentitiesAuthorizedSenders + emailIdentitiesAuthorizedSenders, + convos } from '@u22n/database/schema'; import { and, @@ -531,14 +532,15 @@ export const emailIdentityRouter = router({ getUserEmailIdentities: orgProcedure .input( z.object({ - spaceShortcode: z.string().min(1).max(64).nullable().optional() + spaceShortcode: z.string().min(1).max(64).nullable().optional(), + convoPublicId: typeIdValidator('convos').optional() }) ) .query(async ({ ctx, input }) => { const { db, org } = ctx; const orgId = org.id; const orgMemberId = org?.memberId || 0; - let spaceId: number | undefined; + const authorizedSpaceIds: number[] = []; if (input.spaceShortcode) { const spaceQueryResponse = await db.query.spaces.findFirst({ @@ -551,32 +553,61 @@ export const emailIdentityRouter = router({ } }); if (spaceQueryResponse?.id) { - spaceId = spaceQueryResponse.id; + authorizedSpaceIds.push(spaceQueryResponse.id); } } - // get all space memberships for the orgMember - const spaceMemberships = await db.query.spaceMembers.findMany({ - where: eq(spaceMembers.orgMemberId, orgMemberId), - columns: { - spaceId: true - } - }); - const orgOpenSpaces = await db.query.spaces.findMany({ - where: and(eq(spaces.orgId, orgId), eq(spaces.type, 'open')), - columns: { - id: true + if (input.convoPublicId) { + const convoQueryResponse = await db.query.convos.findFirst({ + where: and( + eq(convos.publicId, input.convoPublicId), + eq(convos.orgId, orgId) + ), + columns: { + id: true + }, + with: { + spaces: { + columns: { + id: true, + spaceId: true + } + } + } + }); + + if (convoQueryResponse?.spaces) { + convoQueryResponse.spaces.map((space) => { + authorizedSpaceIds.push(space.id); + }); } - }); + } - // create an array with unique spaceIds - const allUniqueSpaceIds = Array.from( - new Set( - spaceMemberships - .map((spaceMembership) => spaceMembership.spaceId) - .concat(orgOpenSpaces.map((space) => space.id)) - ) - ); + // get all space memberships for the orgMember + if (!input.spaceShortcode) { + const spaceMemberships = await db.query.spaceMembers.findMany({ + where: eq(spaceMembers.orgMemberId, orgMemberId), + columns: { + spaceId: true + } + }); + const orgOpenSpaces = await db.query.spaces.findMany({ + where: and(eq(spaces.orgId, orgId), eq(spaces.type, 'open')), + columns: { + id: true + } + }); + + // create an array with unique spaceIds + const allUniqueSpaceIds = Array.from( + new Set( + spaceMemberships + .map((spaceMembership) => spaceMembership.spaceId) + .concat(orgOpenSpaces.map((space) => space.id)) + ) + ); + authorizedSpaceIds.push(...allUniqueSpaceIds); + } // search for user org team memberships, get id of org team @@ -614,15 +645,14 @@ export const emailIdentityRouter = router({ const authorizedEmailIdentities = await db.query.emailIdentitiesAuthorizedSenders.findMany({ where: or( - inArray( - emailIdentitiesAuthorizedSenders.spaceId, - allUniqueSpaceIds - ), + authorizedSpaceIds.length && authorizedSpaceIds.length > 0 + ? inArray( + emailIdentitiesAuthorizedSenders.spaceId, + authorizedSpaceIds + ) + : undefined, eq(emailIdentitiesAuthorizedSenders.orgMemberId, orgMemberId), - inArray(emailIdentitiesAuthorizedSenders.teamId, uniqueUserTeamIds), - spaceId - ? eq(emailIdentitiesAuthorizedSenders.spaceId, spaceId) - : undefined + inArray(emailIdentitiesAuthorizedSenders.teamId, uniqueUserTeamIds) ), columns: { orgMemberId: true, diff --git a/apps/web/src/app/[orgShortcode]/convo/[convoId]/_components/reply-box.tsx b/apps/web/src/app/[orgShortcode]/convo/[convoId]/_components/reply-box.tsx index b6e3d651..d637b5c1 100644 --- a/apps/web/src/app/[orgShortcode]/convo/[convoId]/_components/reply-box.tsx +++ b/apps/web/src/app/[orgShortcode]/convo/[convoId]/_components/reply-box.tsx @@ -98,7 +98,8 @@ export function ReplyBox({ platform.org.mail.emailIdentities.getUserEmailIdentities.useQuery( { orgShortcode, - spaceShortcode + spaceShortcode, + convoPublicId: convoId }, { staleTime: ms('1 hour')