From 79398b77725773c5f2bc97f9ec39201c094c232c Mon Sep 17 00:00:00 2001 From: Bruce Tian Date: Tue, 4 Mar 2025 11:20:54 -0800 Subject: [PATCH 1/3] chore: deprecate RemoveOrgUserMutation in favor of RemoveOrgUsersMutation --- .../LeaveOrgModal/LeaveOrgModal.tsx | 14 ++++++++----- .../components/OrgBilling/BillingLeader.tsx | 21 +++++++++++++++---- .../components/OrgUserRow/OrgMemberRow.tsx | 21 +++++++++++++++---- .../RemoveFromOrgModal/RemoveFromOrgModal.tsx | 18 +++++++++++++--- 4 files changed, 58 insertions(+), 16 deletions(-) diff --git a/packages/client/modules/userDashboard/components/LeaveOrgModal/LeaveOrgModal.tsx b/packages/client/modules/userDashboard/components/LeaveOrgModal/LeaveOrgModal.tsx index 5944f544985..978d8434869 100644 --- a/packages/client/modules/userDashboard/components/LeaveOrgModal/LeaveOrgModal.tsx +++ b/packages/client/modules/userDashboard/components/LeaveOrgModal/LeaveOrgModal.tsx @@ -7,7 +7,7 @@ import PrimaryButton from '../../../../components/PrimaryButton' import useAtmosphere from '../../../../hooks/useAtmosphere' import useMutationProps from '../../../../hooks/useMutationProps' import useRouter from '../../../../hooks/useRouter' -import RemoveOrgUserMutation from '../../../../mutations/RemoveOrgUserMutation' +import RemoveOrgUsersMutation from '../../../../mutations/RemoveOrgUsersMutation' const StyledButton = styled(PrimaryButton)({ margin: '1.5rem auto 0' @@ -15,6 +15,7 @@ const StyledButton = styled(PrimaryButton)({ interface Props { orgId: string + closePortal: () => void } const StyledDialogContainer = styled(DialogContainer)({ @@ -22,20 +23,23 @@ const StyledDialogContainer = styled(DialogContainer)({ }) const LeaveOrgModal = (props: Props) => { - const {orgId} = props + const {orgId, closePortal} = props const atmosphere = useAtmosphere() const {history} = useRouter() const {onCompleted, onError, submitMutation, submitting} = useMutationProps() const handleClick = () => { if (submitting) return submitMutation() - RemoveOrgUserMutation( + RemoveOrgUsersMutation( atmosphere, - {orgId, userId: atmosphere.viewerId}, + {orgId, userIds: [atmosphere.viewerId]}, { history, onError, - onCompleted + onCompleted: () => { + onCompleted() + closePortal() + } } ) } diff --git a/packages/client/modules/userDashboard/components/OrgBilling/BillingLeader.tsx b/packages/client/modules/userDashboard/components/OrgBilling/BillingLeader.tsx index 9cd6c11f043..ed0678f099f 100644 --- a/packages/client/modules/userDashboard/components/OrgBilling/BillingLeader.tsx +++ b/packages/client/modules/userDashboard/components/OrgBilling/BillingLeader.tsx @@ -72,8 +72,16 @@ const BillingLeader = (props: Props) => { isOrgAdmin: isViewerOrgAdmin, isBillingLeader: isViewerBillingLeader } = organization - const {togglePortal: toggleLeave, modalPortal: leaveModal} = useModal() - const {togglePortal: toggleRemove, modalPortal: removeModal} = useModal() + const { + togglePortal: toggleLeave, + modalPortal: leaveModal, + closePortal: closeLeaveModal + } = useModal() + const { + togglePortal: toggleRemove, + modalPortal: removeModal, + closePortal: closeRemoveModal + } = useModal() const {user: billingLeaderUser, role} = billingLeader const {id: userId, preferredName, picture} = billingLeaderUser const canEdit = isViewerOrgAdmin || (isViewerBillingLeader && role === 'BILLING_LEADER') @@ -100,9 +108,14 @@ const BillingLeader = (props: Props) => { )} - {leaveModal()} + {leaveModal()} {removeModal( - + )} ) diff --git a/packages/client/modules/userDashboard/components/OrgUserRow/OrgMemberRow.tsx b/packages/client/modules/userDashboard/components/OrgUserRow/OrgMemberRow.tsx index e9bcc5db714..2dac16ee932 100644 --- a/packages/client/modules/userDashboard/components/OrgUserRow/OrgMemberRow.tsx +++ b/packages/client/modules/userDashboard/components/OrgUserRow/OrgMemberRow.tsx @@ -108,8 +108,16 @@ const UserActions: React.FC = ({ const { user: {id: userId} } = organizationUser - const {togglePortal: toggleLeave, modalPortal: leaveModal} = useModal() - const {togglePortal: toggleRemove, modalPortal: removeModal} = useModal() + const { + togglePortal: toggleLeave, + modalPortal: leaveModal, + closePortal: closeLeaveModal + } = useModal() + const { + togglePortal: toggleRemove, + modalPortal: removeModal, + closePortal: closeRemoveModal + } = useModal() return ( @@ -119,9 +127,14 @@ const UserActions: React.FC = ({ toggleLeave={toggleLeave} toggleRemove={toggleRemove} /> - {leaveModal()} + {leaveModal()} {removeModal( - + )} diff --git a/packages/client/modules/userDashboard/components/RemoveFromOrgModal/RemoveFromOrgModal.tsx b/packages/client/modules/userDashboard/components/RemoveFromOrgModal/RemoveFromOrgModal.tsx index 13d2fd81df3..9ee4be487e6 100644 --- a/packages/client/modules/userDashboard/components/RemoveFromOrgModal/RemoveFromOrgModal.tsx +++ b/packages/client/modules/userDashboard/components/RemoveFromOrgModal/RemoveFromOrgModal.tsx @@ -7,7 +7,7 @@ import PrimaryButton from '../../../../components/PrimaryButton' import useAtmosphere from '../../../../hooks/useAtmosphere' import useMutationProps from '../../../../hooks/useMutationProps' import useRouter from '../../../../hooks/useRouter' -import RemoveOrgUserMutation from '../../../../mutations/RemoveOrgUserMutation' +import RemoveOrgUsersMutation from '../../../../mutations/RemoveOrgUsersMutation' const StyledButton = styled(PrimaryButton)({ margin: '1.5rem auto 0' @@ -17,6 +17,7 @@ interface Props { orgId: string userId: string preferredName: string + closePortal: () => void } const StyledDialogContainer = styled(DialogContainer)({ @@ -24,13 +25,24 @@ const StyledDialogContainer = styled(DialogContainer)({ }) const RemoveFromOrgModal = (props: Props) => { - const {orgId, preferredName, userId} = props + const {orgId, preferredName, userId, closePortal} = props const atmosphere = useAtmosphere() const {history} = useRouter() const {onCompleted, onError, submitMutation, submitting} = useMutationProps() const handleClick = () => { submitMutation() - RemoveOrgUserMutation(atmosphere, {orgId, userId}, {history, onError, onCompleted}) + RemoveOrgUsersMutation( + atmosphere, + {orgId, userIds: [userId]}, + { + history, + onError, + onCompleted: () => { + onCompleted() + closePortal() + } + } + ) } return ( From fd3f4a834be3d30068898b76fdfb4a7024a12371 Mon Sep 17 00:00:00 2001 From: Bruce Tian Date: Tue, 4 Mar 2025 11:28:51 -0800 Subject: [PATCH 2/3] Delete RemoveOrgUserMutation --- .../client/mutations/RemoveOrgUserMutation.ts | 258 ------------------ .../subscriptions/NotificationSubscription.ts | 9 - .../subscriptions/OrganizationSubscription.ts | 9 - .../client/subscriptions/TaskSubscription.ts | 5 - .../client/subscriptions/TeamSubscription.ts | 6 - .../server/graphql/mutations/removeOrgUser.ts | 75 ----- .../graphql/public/typeDefs/Mutation.graphql | 15 - .../NotificationSubscriptionPayload.graphql | 1 - .../OrganizationSubscriptionPayload.graphql | 1 - .../typeDefs/RemoveOrgUserPayload.graphql | 39 --- .../typeDefs/TaskSubscriptionPayload.graphql | 1 - .../typeDefs/TeamSubscriptionPayload.graphql | 1 - packages/server/graphql/rootMutation.ts | 2 - .../graphql/types/RemoveOrgUserPayload.ts | 84 ------ 14 files changed, 506 deletions(-) delete mode 100644 packages/client/mutations/RemoveOrgUserMutation.ts delete mode 100644 packages/server/graphql/mutations/removeOrgUser.ts delete mode 100644 packages/server/graphql/public/typeDefs/RemoveOrgUserPayload.graphql delete mode 100644 packages/server/graphql/types/RemoveOrgUserPayload.ts diff --git a/packages/client/mutations/RemoveOrgUserMutation.ts b/packages/client/mutations/RemoveOrgUserMutation.ts deleted file mode 100644 index 6545e3399a5..00000000000 --- a/packages/client/mutations/RemoveOrgUserMutation.ts +++ /dev/null @@ -1,258 +0,0 @@ -import graphql from 'babel-plugin-relay/macro' -import {commitLocalUpdate, commitMutation} from 'react-relay' -import {RemoveOrgUserMutation as TRemoveOrgUserMutation} from '~/__generated__/RemoveOrgUserMutation.graphql' -import {RemoveOrgUserMutation_team$data} from '~/__generated__/RemoveOrgUserMutation_team.graphql' -import {RemoveOrgUserMutation_notification$data} from '../__generated__/RemoveOrgUserMutation_notification.graphql' -import {RemoveOrgUserMutation_organization$data} from '../__generated__/RemoveOrgUserMutation_organization.graphql' -import {RemoveOrgUserMutation_task$data} from '../__generated__/RemoveOrgUserMutation_task.graphql' -import { - HistoryLocalHandler, - OnNextHandler, - OnNextHistoryContext, - SharedUpdater, - StandardMutation -} from '../types/relayMutations' -import findStageById from '../utils/meetings/findStageById' -import onExOrgRoute from '../utils/onExOrgRoute' -import onMeetingRoute from '../utils/onMeetingRoute' -import onTeamRoute from '../utils/onTeamRoute' -import {setLocalStageAndPhase} from '../utils/relay/updateLocalStage' -import handleAddNotifications from './handlers/handleAddNotifications' -import handleRemoveOrgMembers from './handlers/handleRemoveOrgMembers' -import handleRemoveOrganization from './handlers/handleRemoveOrganization' -import handleRemoveTeamMembers from './handlers/handleRemoveTeamMembers' -import handleRemoveTeams from './handlers/handleRemoveTeams' -import handleTasksForRemovedUsers from './handlers/handleTasksForRemovedUsers' - -graphql` - fragment RemoveOrgUserMutation_organization on RemoveOrgUserPayload { - organization { - id - } - user { - id - } - organizationUserId - } -` - -graphql` - fragment RemoveOrgUserMutation_notification on RemoveOrgUserPayload { - organization { - id - name - } - kickOutNotifications { - id - type - team { - id - name - activeMeetings { - id - } - } - ...KickedOut_notification - } - } -` - -graphql` - fragment RemoveOrgUserMutation_team on RemoveOrgUserPayload { - teamMembers { - id - } - user { - id - } - teams { - ...RemoveTeamMemberMutation_teamTeam @relay(mask: false) - activeMeetings { - id - } - } - user { - id - } - } -` - -graphql` - fragment RemoveOrgUserMutation_task on RemoveOrgUserPayload { - updatedTasks { - ...CompleteTaskFrag @relay(mask: false) - } - user { - id - } - } -` - -const mutation = graphql` - mutation RemoveOrgUserMutation($userId: ID!, $orgId: ID!) { - removeOrgUser(userId: $userId, orgId: $orgId) { - error { - message - } - ...RemoveOrgUserMutation_organization @relay(mask: false) - ...RemoveOrgUserMutation_team @relay(mask: false) - ...RemoveOrgUserMutation_task @relay(mask: false) - } - } -` - -export const removeOrgUserOrganizationUpdater: SharedUpdater< - RemoveOrgUserMutation_organization$data -> = (payload, {atmosphere, store}) => { - const {viewerId} = atmosphere - const removedUserId = payload.getLinkedRecord('user').getValue('id') - const removedOrgUserId = payload.getValue('organizationUserId') - const orgId = payload.getLinkedRecord('organization').getValue('id') - if (removedUserId === viewerId) { - handleRemoveOrganization(orgId, store) - } else { - handleRemoveOrgMembers(orgId, removedOrgUserId, store) - } -} - -export const removeOrgUserNotificationUpdater: SharedUpdater< - RemoveOrgUserMutation_notification$data -> = (payload, {store}) => { - const kickOutNotifications = payload.getLinkedRecords('kickOutNotifications') - handleAddNotifications(kickOutNotifications, store) -} - -export const removeOrgUserTeamUpdater: SharedUpdater = ( - payload, - {atmosphere, store} -) => { - const removedUserId = payload.getLinkedRecord('user').getValue('id') - const {viewerId} = atmosphere - - if (removedUserId === viewerId) { - const teams = payload.getLinkedRecords('teams') - const teamIds = teams.map((team) => team.getValue('id')) - handleRemoveTeams(teamIds, store) - } else { - const teamMembers = payload.getLinkedRecords('teamMembers') - const teamMemberIds = teamMembers?.map((teamMember) => teamMember.getValue('id')) - handleRemoveTeamMembers(teamMemberIds, store) - } -} - -export const removeOrgUserTaskUpdater: SharedUpdater = ( - payload, - {atmosphere, store} -) => { - const removedUserId = payload.getLinkedRecord('user').getValue('id') - const tasks = payload.getLinkedRecords('updatedTasks') - if (!tasks) return - const {viewerId} = atmosphere - handleTasksForRemovedUsers(tasks, [removedUserId], viewerId, store) -} - -export const removeOrgUserTeamOnNext: OnNextHandler = ( - payload, - context -) => { - const {atmosphere} = context - const {teams} = payload - if (!teams) return - teams.forEach((team) => { - const {activeMeetings} = team - activeMeetings.forEach((newMeeting) => { - const {id: meetingId, facilitatorStageId, phases} = newMeeting - // a meeting is going on, see if the are on the removed user's phase & if so, redirect them - commitLocalUpdate(atmosphere, (store) => { - const meetingProxy = store.get(meetingId) - if (!meetingProxy) return - const localStage = meetingProxy.getLinkedRecord('localStage') - if (!localStage) return - const viewerStageId = localStage.getValue('id') as string - const stageRes = findStageById(phases, viewerStageId) - if (!stageRes) { - setLocalStageAndPhase(store, meetingId, facilitatorStageId) - } - }) - }) - }) -} - -export const removeOrgUserOrganizationOnNext: OnNextHandler< - RemoveOrgUserMutation_organization$data, - OnNextHistoryContext -> = (payload, context) => { - // FIXME currently, the server doesn't send this to the user in other tabs, so they don't get redirected in their other tabs - const { - atmosphere: {viewerId}, - history - } = context - const {pathname} = history.location - const {user, organization} = payload - const userId = user?.id - const orgId = organization?.id ?? '' - if (userId === viewerId && onExOrgRoute(pathname, orgId)) { - history.push('/meetings') - } -} - -export const removeOrgUserNotificationOnNext: OnNextHandler< - RemoveOrgUserMutation_notification$data, - OnNextHistoryContext -> = (payload, {atmosphere, history}) => { - if (!payload) return - const {organization, kickOutNotifications} = payload - if (!organization || !kickOutNotifications) return - const {name: orgName, id: orgId} = organization - const teams = kickOutNotifications.map((notification) => notification && notification.team) - atmosphere.eventEmitter.emit('addSnackbar', { - key: `removedFromOrg:${orgId}`, - autoDismiss: 10, - message: `You have been removed from ${orgName} and all its teams` - }) - - for (let ii = 0; ii < teams.length; ii++) { - const team = teams[ii] - if (!team) continue - const {activeMeetings, id: teamId} = team - const meetingIds = activeMeetings.map(({id}) => id) - if ( - onTeamRoute(window.location.pathname, teamId) || - onMeetingRoute(window.location.pathname, meetingIds) - ) { - history.push('/meetings') - return - } - } -} - -const RemoveOrgUserMutation: StandardMutation = ( - atmosphere, - variables, - {history, onError, onCompleted} -) => { - return commitMutation(atmosphere, { - mutation, - variables, - updater: (store) => { - const payload = store.getRootField('removeOrgUser') - if (!payload) return - removeOrgUserOrganizationUpdater(payload, {atmosphere, store}) - removeOrgUserTeamUpdater(payload, {atmosphere, store}) - removeOrgUserTaskUpdater(payload, {atmosphere, store}) - }, - onCompleted: (res, errors) => { - if (onCompleted) { - onCompleted(res, errors) - } - if (!res.removeOrgUser) return - removeOrgUserOrganizationOnNext(res.removeOrgUser, { - history, - atmosphere - }) - }, - onError - }) -} - -export default RemoveOrgUserMutation diff --git a/packages/client/subscriptions/NotificationSubscription.ts b/packages/client/subscriptions/NotificationSubscription.ts index 1d5898adb1a..54cc8b2b822 100644 --- a/packages/client/subscriptions/NotificationSubscription.ts +++ b/packages/client/subscriptions/NotificationSubscription.ts @@ -20,10 +20,6 @@ import { inviteToTeamNotificationOnNext, inviteToTeamNotificationUpdater } from '../mutations/InviteToTeamMutation' -import { - removeOrgUserNotificationOnNext, - removeOrgUserNotificationUpdater -} from '../mutations/RemoveOrgUserMutation' import { removeOrgUsersNotificationOnNext, removeOrgUsersNotificationUpdater @@ -116,9 +112,6 @@ const subscription = graphql` InviteToTeamPayload { ...InviteToTeamMutation_notification @relay(mask: false) } - RemoveOrgUserPayload { - ...RemoveOrgUserMutation_notification @relay(mask: false) - } RemoveOrgUsersSuccess { ...RemoveOrgUsersMutation_notification @relay(mask: false) } @@ -290,7 +283,6 @@ const updateHandlers = { EndRetrospectiveSuccess: endRetrospectiveNotificationUpdater, InviteToTeamPayload: inviteToTeamNotificationUpdater, MeetingStageTimeLimitPayload: meetingStageTimeLimitUpdater, - RemoveOrgUserPayload: removeOrgUserNotificationUpdater, RemoveOrgUsersSuccess: removeOrgUsersNotificationUpdater, StripeFailPaymentPayload: stripeFailPaymentNotificationUpdater, ArchiveTimelineEventSuccess: archiveTimelineEventNotificationUpdater @@ -300,7 +292,6 @@ const onNextHandlers = { AuthTokenPayload: authTokenNotificationOnNext, CreateTaskPayload: createTaskNotificationOnNext, InviteToTeamPayload: inviteToTeamNotificationOnNext, - RemoveOrgUserPayload: removeOrgUserNotificationOnNext, RemoveOrgUsersSuccess: removeOrgUsersNotificationOnNext, StripeFailPaymentPayload: stripeFailPaymentNotificationOnNext, MeetingStageTimeLimitPayload: meetingStageTimeLimitOnNext, diff --git a/packages/client/subscriptions/OrganizationSubscription.ts b/packages/client/subscriptions/OrganizationSubscription.ts index 8359ff5207b..67aac7ed259 100644 --- a/packages/client/subscriptions/OrganizationSubscription.ts +++ b/packages/client/subscriptions/OrganizationSubscription.ts @@ -11,10 +11,6 @@ import { } from '~/mutations/ArchiveOrganizationMutation' import Atmosphere from '../Atmosphere' import {addOrgMutationOrganizationUpdater} from '../mutations/AddOrgMutation' -import { - removeOrgUserOrganizationOnNext, - removeOrgUserOrganizationUpdater -} from '../mutations/RemoveOrgUserMutation' import { removeOrgUsersOrganizationOnNext, removeOrgUsersOrganizationUpdater @@ -49,9 +45,6 @@ const subscription = graphql` RemoveIntegrationProviderSuccess { ...RemoveIntegrationProviderMutation_organization @relay(mask: false) } - RemoveOrgUserPayload { - ...RemoveOrgUserMutation_organization @relay(mask: false) - } RemoveOrgUsersSuccess { ...RemoveOrgUsersMutation_organization @relay(mask: false) } @@ -70,7 +63,6 @@ const subscription = graphql` const onNextHandlers = { ArchiveOrganizationPayload: archiveOrganizationOrganizationOnNext, - RemoveOrgUserPayload: removeOrgUserOrganizationOnNext, RemoveOrgUsersSuccess: removeOrgUsersOrganizationOnNext, SetOrgUserRoleSuccess: setOrgUserRoleAddedOrganizationOnNext } as const @@ -78,7 +70,6 @@ const onNextHandlers = { const updateHandlers = { AddOrgPayload: addOrgMutationOrganizationUpdater, ArchiveOrganizationPayload: archiveOrganizationOrganizationUpdater, - RemoveOrgUserPayload: removeOrgUserOrganizationUpdater, RemoveOrgUsersSuccess: removeOrgUsersOrganizationUpdater, SetOrgUserRoleSuccess: setOrgUserRoleAddedOrganizationUpdater, UpdateTemplateScopeSuccess: updateTemplateScopeOrganizationUpdater diff --git a/packages/client/subscriptions/TaskSubscription.ts b/packages/client/subscriptions/TaskSubscription.ts index eb247fb878a..a0fc88317a1 100644 --- a/packages/client/subscriptions/TaskSubscription.ts +++ b/packages/client/subscriptions/TaskSubscription.ts @@ -10,7 +10,6 @@ import {changeTaskTeamTaskUpdater} from '../mutations/ChangeTaskTeamMutation' import {createTaskTaskUpdater} from '../mutations/CreateTaskMutation' import {deleteTaskTaskUpdater} from '../mutations/DeleteTaskMutation' import {editTaskTaskUpdater} from '../mutations/EditTaskMutation' -import {removeOrgUserTaskUpdater} from '../mutations/RemoveOrgUserMutation' import {removeOrgUsersTaskUpdater} from '../mutations/RemoveOrgUsersMutation' import {updateTaskTaskOnNext, updateTaskTaskUpdater} from '../mutations/UpdateTaskMutation' import subscriptionOnNext from './subscriptionOnNext' @@ -38,9 +37,6 @@ const subscription = graphql` EditTaskPayload { ...EditTaskMutation_task @relay(mask: false) } - RemoveOrgUserPayload { - ...RemoveOrgUserMutation_task @relay(mask: false) - } RemoveOrgUsersSuccess { ...RemoveOrgUsersMutation_task @relay(mask: false) } @@ -63,7 +59,6 @@ const updateHandlers = { CreateTaskPayload: createTaskTaskUpdater, DeleteTaskPayload: deleteTaskTaskUpdater, EditTaskPayload: editTaskTaskUpdater, - RemoveOrgUserPayload: removeOrgUserTaskUpdater, RemoveOrgUsersSuccess: removeOrgUsersTaskUpdater, UpdateTaskPayload: updateTaskTaskUpdater } as const diff --git a/packages/client/subscriptions/TeamSubscription.ts b/packages/client/subscriptions/TeamSubscription.ts index d7cc2fda82c..68028213e16 100644 --- a/packages/client/subscriptions/TeamSubscription.ts +++ b/packages/client/subscriptions/TeamSubscription.ts @@ -32,7 +32,6 @@ import {endTeamPromptTeamUpdater} from '../mutations/EndTeamPromptMutation' import {moveReflectTemplatePromptTeamUpdater} from '../mutations/MoveReflectTemplatePromptMutation' import {pushInvitationTeamOnNext} from '../mutations/PushInvitationMutation' import {removeAgendaItemUpdater} from '../mutations/RemoveAgendaItemMutation' -import {removeOrgUserTeamOnNext, removeOrgUserTeamUpdater} from '../mutations/RemoveOrgUserMutation' import { removeOrgUsersTeamOnNext, removeOrgUsersTeamUpdater @@ -126,9 +125,6 @@ const subscription = graphql` RemoveAgendaItemPayload { ...RemoveAgendaItemMutation_team @relay(mask: false) } - RemoveOrgUserPayload { - ...RemoveOrgUserMutation_team @relay(mask: false) - } RemoveOrgUsersSuccess { ...RemoveOrgUsersMutation_team @relay(mask: false) } @@ -200,7 +196,6 @@ const onNextHandlers = { EndCheckInSuccess: endCheckInTeamOnNext, EndRetrospectiveSuccess: endRetrospectiveTeamOnNext, EndSprintPokerSuccess: endSprintPokerTeamOnNext, - RemoveOrgUserPayload: removeOrgUserTeamOnNext, RemoveOrgUsersSuccess: removeOrgUsersTeamOnNext, RemoveTeamMemberPayload: removeTeamMemberTeamOnNext, PushInvitationPayload: pushInvitationTeamOnNext @@ -223,7 +218,6 @@ const updateHandlers = { EndTeamPromptSuccess: endTeamPromptTeamUpdater, MoveReflectTemplatePromptPayload: moveReflectTemplatePromptTeamUpdater, NavigateMeetingPayload: navigateMeetingTeamUpdater, - RemoveOrgUserPayload: removeOrgUserTeamUpdater, RemoveOrgUsersSuccess: removeOrgUsersTeamUpdater, RemoveReflectTemplatePayload: removeReflectTemplateTeamUpdater, RemoveReflectTemplatePromptPayload: removeReflectTemplatePromptTeamUpdater, diff --git a/packages/server/graphql/mutations/removeOrgUser.ts b/packages/server/graphql/mutations/removeOrgUser.ts deleted file mode 100644 index 1e3b6a6c2a0..00000000000 --- a/packages/server/graphql/mutations/removeOrgUser.ts +++ /dev/null @@ -1,75 +0,0 @@ -import {GraphQLID, GraphQLNonNull} from 'graphql' -import {SubscriptionChannel} from 'parabol-client/types/constEnums' -import {getUserId, isUserBillingLeader, isUserOrgAdmin} from '../../utils/authorization' -import publish from '../../utils/publish' -import standardError from '../../utils/standardError' -import {GQLContext} from '../graphql' -import isValid from '../isValid' -import RemoveOrgUserPayload from '../types/RemoveOrgUserPayload' -import removeFromOrg from './helpers/removeFromOrg' - -const removeOrgUser = { - type: RemoveOrgUserPayload, - description: 'Remove a user from an org', - args: { - userId: { - type: new GraphQLNonNull(GraphQLID), - description: 'the user to remove' - }, - orgId: { - type: new GraphQLNonNull(GraphQLID), - description: 'the org that does not want them anymore' - } - }, - async resolve( - _source: unknown, - {orgId, userId}: {orgId: string; userId: string}, - {authToken, dataLoader, socketId: mutatorId}: GQLContext - ) { - const operationId = dataLoader.share() - const subOptions = {mutatorId, operationId} - - // AUTH - const viewerId = getUserId(authToken) - if (viewerId !== userId) { - if ( - !(await isUserOrgAdmin(viewerId, orgId, dataLoader)) && - !(await isUserBillingLeader(viewerId, orgId, dataLoader)) - ) { - return standardError(new Error('Must be the organization leader'), {userId: viewerId}) - } - } - - const {tms, taskIds, kickOutNotificationIds, teamIds, teamMemberIds, organizationUserId} = - await removeFromOrg(userId, orgId, viewerId, dataLoader) - - publish(SubscriptionChannel.NOTIFICATION, userId, 'AuthTokenPayload', {tms}) - - const data = { - orgId, - kickOutNotificationIds, - teamIds, - teamMemberIds, - taskIds, - userId, - organizationUserId - } - - publish(SubscriptionChannel.ORGANIZATION, orgId, 'RemoveOrgUserPayload', data, subOptions) - publish(SubscriptionChannel.NOTIFICATION, userId, 'RemoveOrgUserPayload', data, subOptions) - teamIds.forEach((teamId) => { - publish(SubscriptionChannel.TEAM, teamId, 'RemoveOrgUserPayload', data, subOptions) - }) - - const remainingTeamMembers = (await dataLoader.get('teamMembersByTeamId').loadMany(teamIds)) - .filter(isValid) - .flat() - remainingTeamMembers.forEach((teamMember) => { - if (teamMemberIds.includes(teamMember.id)) return - publish(SubscriptionChannel.TASK, teamMember.userId, 'RemoveOrgUserPayload', data, subOptions) - }) - return data - } -} - -export default removeOrgUser diff --git a/packages/server/graphql/public/typeDefs/Mutation.graphql b/packages/server/graphql/public/typeDefs/Mutation.graphql index b3a42b5e369..982e436fe0d 100644 --- a/packages/server/graphql/public/typeDefs/Mutation.graphql +++ b/packages/server/graphql/public/typeDefs/Mutation.graphql @@ -600,21 +600,6 @@ type Mutation { teamId: ID! ): RemoveGitHubAuthPayload! - """ - Remove a user from an org - """ - removeOrgUser( - """ - the user to remove - """ - userId: ID! - - """ - the org that does not want them anymore - """ - orgId: ID! - ): RemoveOrgUserPayload - """ Remove multiple users from an org """ diff --git a/packages/server/graphql/public/typeDefs/NotificationSubscriptionPayload.graphql b/packages/server/graphql/public/typeDefs/NotificationSubscriptionPayload.graphql index 6bce9131818..6c20a563deb 100644 --- a/packages/server/graphql/public/typeDefs/NotificationSubscriptionPayload.graphql +++ b/packages/server/graphql/public/typeDefs/NotificationSubscriptionPayload.graphql @@ -14,7 +14,6 @@ type NotificationSubscriptionPayload { InvalidateSessionsPayload: InvalidateSessionsPayload InviteToTeamPayload: InviteToTeamPayload MeetingStageTimeLimitPayload: MeetingStageTimeLimitPayload - RemoveOrgUserPayload: RemoveOrgUserPayload RemoveOrgUsersSuccess: RemoveOrgUsersSuccess StripeFailPaymentPayload: StripeFailPaymentPayload PersistJiraSearchQuerySuccess: PersistJiraSearchQuerySuccess diff --git a/packages/server/graphql/public/typeDefs/OrganizationSubscriptionPayload.graphql b/packages/server/graphql/public/typeDefs/OrganizationSubscriptionPayload.graphql index 2ba8836cff8..66ea70a1250 100644 --- a/packages/server/graphql/public/typeDefs/OrganizationSubscriptionPayload.graphql +++ b/packages/server/graphql/public/typeDefs/OrganizationSubscriptionPayload.graphql @@ -5,7 +5,6 @@ type OrganizationSubscriptionPayload { ArchiveOrganizationPayload: ArchiveOrganizationPayload DowngradeToStarterPayload: DowngradeToStarterPayload RemoveIntegrationProviderSuccess: RemoveIntegrationProviderSuccess - RemoveOrgUserPayload: RemoveOrgUserPayload RemoveOrgUsersSuccess: RemoveOrgUsersSuccess ToggleAIFeaturesSuccess: ToggleAIFeaturesSuccess SetOrgUserRoleSuccess: SetOrgUserRoleSuccess diff --git a/packages/server/graphql/public/typeDefs/RemoveOrgUserPayload.graphql b/packages/server/graphql/public/typeDefs/RemoveOrgUserPayload.graphql deleted file mode 100644 index a2e659914be..00000000000 --- a/packages/server/graphql/public/typeDefs/RemoveOrgUserPayload.graphql +++ /dev/null @@ -1,39 +0,0 @@ -type RemoveOrgUserPayload { - error: StandardMutationError - - """ - The organization the user was removed from - """ - organization: Organization - - """ - The teams the user was removed from - """ - teams: [Team!] - - """ - The teamMembers removed - """ - teamMembers: [TeamMember!] - - """ - The tasks that were archived or reassigned - """ - updatedTasks: [Task!] - - """ - The user removed from the organization - """ - user: User - - """ - The notifications for each team the user was kicked out of - """ - kickOutNotifications: [NotifyKickedOut!] - - """ - The organization member that got removed - """ - removedOrgMember: OrganizationUser - organizationUserId: String -} diff --git a/packages/server/graphql/public/typeDefs/TaskSubscriptionPayload.graphql b/packages/server/graphql/public/typeDefs/TaskSubscriptionPayload.graphql index 7db16ada9ef..cfc879e219f 100644 --- a/packages/server/graphql/public/typeDefs/TaskSubscriptionPayload.graphql +++ b/packages/server/graphql/public/typeDefs/TaskSubscriptionPayload.graphql @@ -5,7 +5,6 @@ type TaskSubscriptionPayload { CreateTaskPayload: CreateTaskPayload DeleteTaskPayload: DeleteTaskPayload EditTaskPayload: EditTaskPayload - RemoveOrgUserPayload: RemoveOrgUserPayload RemoveOrgUsersSuccess: RemoveOrgUsersSuccess RemoveTeamMemberPayload: RemoveTeamMemberPayload UpdateTaskPayload: UpdateTaskPayload diff --git a/packages/server/graphql/public/typeDefs/TeamSubscriptionPayload.graphql b/packages/server/graphql/public/typeDefs/TeamSubscriptionPayload.graphql index 0799063f09b..c87502c6ebf 100644 --- a/packages/server/graphql/public/typeDefs/TeamSubscriptionPayload.graphql +++ b/packages/server/graphql/public/typeDefs/TeamSubscriptionPayload.graphql @@ -18,7 +18,6 @@ type TeamSubscriptionPayload { PushInvitationPayload: PushInvitationPayload PromoteToTeamLeadPayload: PromoteToTeamLeadPayload RemoveAgendaItemPayload: RemoveAgendaItemPayload - RemoveOrgUserPayload: RemoveOrgUserPayload RemoveOrgUsersSuccess: RemoveOrgUsersSuccess RemoveTeamMemberPayload: RemoveTeamMemberPayload RenameMeetingSuccess: RenameMeetingSuccess diff --git a/packages/server/graphql/rootMutation.ts b/packages/server/graphql/rootMutation.ts index 5b457bf14ee..ff9571c52c8 100644 --- a/packages/server/graphql/rootMutation.ts +++ b/packages/server/graphql/rootMutation.ts @@ -53,7 +53,6 @@ import pushInvitation from './mutations/pushInvitation' import removeAtlassianAuth from './mutations/removeAtlassianAuth' import removeGitHubAuth from './mutations/removeGitHubAuth' import removeIntegrationProvider from './mutations/removeIntegrationProvider' -import removeOrgUser from './mutations/removeOrgUser' import removePokerTemplateDimension from './mutations/removePokerTemplateDimension' import removePokerTemplateScale from './mutations/removePokerTemplateScale' import removePokerTemplateScaleValue from './mutations/removePokerTemplateScaleValue' @@ -145,7 +144,6 @@ export default new GraphQLObjectType({ pokerTemplateDimensionUpdateDescription, removeAtlassianAuth, removeGitHubAuth, - removeOrgUser, removeReflectTemplate, removePokerTemplateDimension, renameMeeting, diff --git a/packages/server/graphql/types/RemoveOrgUserPayload.ts b/packages/server/graphql/types/RemoveOrgUserPayload.ts deleted file mode 100644 index 1f840c53419..00000000000 --- a/packages/server/graphql/types/RemoveOrgUserPayload.ts +++ /dev/null @@ -1,84 +0,0 @@ -import {GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLString} from 'graphql' -import {getUserId} from '../../utils/authorization' -import {GQLContext} from '../graphql' -import isValid from '../isValid' -import { - resolveFilterByTeam, - resolveOrganization, - resolveTasks, - resolveTeamMembers, - resolveTeams, - resolveUser -} from '../resolvers' -import Organization from './Organization' -import OrganizationUser from './OrganizationUser' -import StandardMutationError from './StandardMutationError' -import Task from './Task' -import Team from './Team' -import TeamMember from './TeamMember' -import User from './User' - -const RemoveOrgUserPayload = new GraphQLObjectType({ - name: 'RemoveOrgUserPayload', - fields: () => ({ - error: { - type: StandardMutationError - }, - organization: { - type: Organization, - resolve: resolveOrganization, - description: 'The organization the user was removed from' - }, - teams: { - type: new GraphQLList(new GraphQLNonNull(Team)), - description: 'The teams the user was removed from', - resolve: resolveFilterByTeam(resolveTeams as any, ({id}) => id) - }, - teamMembers: { - type: new GraphQLList(new GraphQLNonNull(TeamMember)), - description: 'The teamMembers removed', - resolve: resolveFilterByTeam(resolveTeamMembers as any, ({teamId}) => teamId) - }, - updatedTasks: { - type: new GraphQLList(new GraphQLNonNull(Task)), - description: 'The tasks that were archived or reassigned', - resolve: resolveFilterByTeam(resolveTasks, ({teamId}) => teamId) - }, - user: { - type: User, - description: 'The user removed from the organization', - resolve: resolveUser - }, - kickOutNotifications: { - type: new GraphQLList( - new GraphQLNonNull( - new GraphQLObjectType({ - name: 'NotifyKickedOut', - fields: {} - }) - ) - ), - description: 'The notifications for each team the user was kicked out of', - resolve: async ({kickOutNotificationIds}, _args: unknown, {authToken, dataLoader}) => { - if (!kickOutNotificationIds) return null - const viewerId = getUserId(authToken) - const notifications = ( - await dataLoader.get('notifications').loadMany(kickOutNotificationIds) - ).filter(isValid) - return notifications.filter((notification) => notification.userId === viewerId) - } - }, - removedOrgMember: { - type: OrganizationUser, - description: 'The organization member that got removed', - resolve: async ({organizationUserId}, _args: unknown, {dataLoader}) => { - return dataLoader.get('organizationUsers').load(organizationUserId) - } - }, - organizationUserId: { - type: GraphQLString - } - }) -}) - -export default RemoveOrgUserPayload From 0e916be8639eba960931efb99e849cadbf4cb732 Mon Sep 17 00:00:00 2001 From: Bruce Tian Date: Wed, 5 Mar 2025 10:28:17 -0800 Subject: [PATCH 3/3] Manually add OrganizationUser type in rootTypes --- packages/server/graphql/rootTypes.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/server/graphql/rootTypes.ts b/packages/server/graphql/rootTypes.ts index b974f7f054d..a6892a5fd31 100644 --- a/packages/server/graphql/rootTypes.ts +++ b/packages/server/graphql/rootTypes.ts @@ -1,4 +1,5 @@ import JiraDimensionField from './types/JiraDimensionField' +import OrganizationUser from './types/OrganizationUser' import RenamePokerTemplatePayload from './types/RenamePokerTemplatePayload' import SetMeetingSettingsPayload from './types/SetMeetingSettingsPayload' import TimelineEventCompletedActionMeeting from './types/TimelineEventCompletedActionMeeting' @@ -17,6 +18,7 @@ const rootTypes = [ TimelineEventPokerComplete, JiraDimensionField, RenamePokerTemplatePayload, - UserTiersCount + UserTiersCount, + OrganizationUser ] export default rootTypes