diff --git a/packages/server/graphql/mutations/helpers/notifications/MSTeamsNotifier.ts b/packages/server/graphql/mutations/helpers/notifications/MSTeamsNotifier.ts index 99b6f77670b..a8b4fe0d02c 100644 --- a/packages/server/graphql/mutations/helpers/notifications/MSTeamsNotifier.ts +++ b/packages/server/graphql/mutations/helpers/notifications/MSTeamsNotifier.ts @@ -13,8 +13,7 @@ import sendToSentry from '../../../../utils/sendToSentry' import {DataLoaderWorker} from '../../../graphql' import getSummaryText from './getSummaryText' import {NotificationIntegrationHelper} from './NotificationIntegrationHelper' -import {Notifier} from './Notifier' -import {getTeamPromptResponsesByMeetingId} from '../../../../postgres/queries/getTeamPromptResponsesByMeetingIds' +import {createNotifier} from './Notifier' import {analytics} from '../../../../utils/analytics/analytics' const notifyMSTeams = async ( @@ -346,87 +345,16 @@ async function getMSTeams(dataLoader: DataLoaderWorker, teamId: string, userId: .get('bestTeamIntegrationProviders') .load({service: 'msTeams', teamId, userId}) return provider - ? MSTeamsNotificationHelper({ - ...(provider as IntegrationProviderMSTeams), - userId - }) - : null + ? [ + MSTeamsNotificationHelper({ + ...(provider as IntegrationProviderMSTeams), + userId + }) + ] + : [] } -async function loadMeetingTeam(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { - const [team, meeting] = await Promise.all([ - dataLoader.get('teams').load(teamId), - dataLoader.get('newMeetings').load(meetingId) - ]) - return { - meeting, - team - } -} - -export const MSTeamsNotifier: Notifier = { - async startMeeting(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { - const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) - if (!meeting || !team) return - ;(await getMSTeams(dataLoader, team.id, meeting.facilitatorUserId))?.startMeeting(meeting, team) - }, - - async endMeeting(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { - const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) - if (!meeting || !team) return - ;(await getMSTeams(dataLoader, team.id, meeting.facilitatorUserId))?.endMeeting( - meeting, - team, - null - ) - }, - - async startTimeLimit( - dataLoader: DataLoaderWorker, - scheduledEndTime: Date, - meetingId: string, - teamId: string - ) { - const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) - if (!meeting || !team) return - ;(await getMSTeams(dataLoader, team.id, meeting.facilitatorUserId))?.startTimeLimit( - scheduledEndTime, - meeting, - team - ) - }, - - async endTimeLimit(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { - const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) - if (!meeting || !team) return - ;(await getMSTeams(dataLoader, team.id, meeting.facilitatorUserId))?.endTimeLimit(meeting, team) - }, - - async integrationUpdated(dataLoader: DataLoaderWorker, teamId: string, userId: string) { - ;(await getMSTeams(dataLoader, teamId, userId))?.integrationUpdated() - }, - - async standupResponseSubmitted( - dataLoader: DataLoaderWorker, - meetingId: string, - teamId: string, - userId: string - ) { - const [{meeting, team}, user, responses] = await Promise.all([ - loadMeetingTeam(dataLoader, meetingId, teamId), - dataLoader.get('users').load(userId), - getTeamPromptResponsesByMeetingId(meetingId) - ]) - const response = responses.find(({userId: responseUserId}) => responseUserId === userId) - if (!meeting || !team || !response || !user) return - ;(await getMSTeams(dataLoader, teamId, userId))?.standupResponseSubmitted( - meeting, - team, - user, - response - ) - } -} +export const MSTeamsNotifier = createNotifier(getMSTeams) function GenerateACMeetingTitle(meetingTitle: string) { const titleTextBlock = new AdaptiveCards.TextBlock(meetingTitle) diff --git a/packages/server/graphql/mutations/helpers/notifications/MattermostNotifier.ts b/packages/server/graphql/mutations/helpers/notifications/MattermostNotifier.ts index afe69f2e1c2..21c1e9966f3 100644 --- a/packages/server/graphql/mutations/helpers/notifications/MattermostNotifier.ts +++ b/packages/server/graphql/mutations/helpers/notifications/MattermostNotifier.ts @@ -21,8 +21,7 @@ import { makeHackedFieldButtonValue } from './makeMattermostAttachments' import {NotificationIntegrationHelper} from './NotificationIntegrationHelper' -import {Notifier} from './Notifier' -import {getTeamPromptResponsesByMeetingId} from '../../../../postgres/queries/getTeamPromptResponsesByMeetingIds' +import {createNotifier} from './Notifier' import {analytics} from '../../../../utils/analytics/analytics' const notifyMattermost = async ( @@ -322,90 +321,13 @@ async function getMattermost(dataLoader: DataLoaderWorker, teamId: string, userI .get('bestTeamIntegrationProviders') .load({service: 'mattermost', teamId, userId}) return provider - ? MattermostNotificationHelper({ - ...(provider as IntegrationProviderMattermost), - userId - }) - : null -} - -async function loadMeetingTeam(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { - const [team, meeting] = await Promise.all([ - dataLoader.get('teams').load(teamId), - dataLoader.get('newMeetings').load(meetingId) - ]) - return { - meeting, - team - } + ? [ + MattermostNotificationHelper({ + ...(provider as IntegrationProviderMattermost), + userId + }) + ] + : [] } -export const MattermostNotifier: Notifier = { - async startMeeting(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { - const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) - if (!meeting || !team) return - ;(await getMattermost(dataLoader, team.id, meeting.facilitatorUserId))?.startMeeting( - meeting, - team - ) - }, - - async endMeeting(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { - const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) - if (!meeting || !team) return - ;(await getMattermost(dataLoader, team.id, meeting.facilitatorUserId))?.endMeeting( - meeting, - team, - null - ) - }, - - async startTimeLimit( - dataLoader: DataLoaderWorker, - scheduledEndTime: Date, - meetingId: string, - teamId: string - ) { - const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) - if (!meeting || !team) return - ;(await getMattermost(dataLoader, team.id, meeting.facilitatorUserId))?.startTimeLimit( - scheduledEndTime, - meeting, - team - ) - }, - - async endTimeLimit(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { - const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) - if (!meeting || !team) return - ;(await getMattermost(dataLoader, team.id, meeting.facilitatorUserId))?.endTimeLimit( - meeting, - team - ) - }, - - async integrationUpdated(dataLoader: DataLoaderWorker, teamId: string, userId: string) { - ;(await getMattermost(dataLoader, teamId, userId))?.integrationUpdated() - }, - - async standupResponseSubmitted( - dataLoader: DataLoaderWorker, - meetingId: string, - teamId: string, - userId: string - ) { - const [{meeting, team}, user, responses] = await Promise.all([ - loadMeetingTeam(dataLoader, meetingId, teamId), - dataLoader.get('users').load(userId), - getTeamPromptResponsesByMeetingId(meetingId) - ]) - const response = responses.find(({userId: responseUserId}) => responseUserId === userId) - if (!meeting || !team || !response || !user) return - ;(await getMattermost(dataLoader, teamId, userId))?.standupResponseSubmitted( - meeting, - team, - user, - response - ) - } -} +export const MattermostNotifier = createNotifier(getMattermost) diff --git a/packages/server/graphql/mutations/helpers/notifications/Notifier.ts b/packages/server/graphql/mutations/helpers/notifications/Notifier.ts index 20448ce9bca..3e222e23e4e 100644 --- a/packages/server/graphql/mutations/helpers/notifications/Notifier.ts +++ b/packages/server/graphql/mutations/helpers/notifications/Notifier.ts @@ -1,5 +1,7 @@ +import {SlackNotificationEvent} from '../../../../database/types/SlackNotification' +import {getTeamPromptResponsesByMeetingId} from '../../../../postgres/queries/getTeamPromptResponsesByMeetingIds' import {DataLoaderWorker} from '../../../graphql' -import {NotifyResponse} from './NotificationIntegrationHelper' +import {NotificationIntegration, NotifyResponse} from './NotificationIntegrationHelper' export type Notifier = { startMeeting(dataLoader: DataLoaderWorker, meetingId: string, teamId: string): Promise @@ -34,3 +36,112 @@ export type Notifier = { userId: string ): Promise } + +export type NotificationIntegrationLoader = ( + dataLoader: DataLoaderWorker, + teamId: string, + userId: string, + event: SlackNotificationEvent +) => Promise + +async function loadMeetingTeam(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { + const [team, meeting] = await Promise.all([ + dataLoader.get('teams').load(teamId), + dataLoader.get('newMeetings').load(meetingId) + ]) + return { + meeting, + team + } +} + +export const createNotifier = (loader: NotificationIntegrationLoader): Notifier => ({ + async startMeeting(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { + const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) + if (!meeting || !team) return + const notifiers = await loader(dataLoader, team.id, meeting.facilitatorUserId, 'meetingStart') + notifiers.forEach((notifier) => notifier.startMeeting(meeting, team)) + }, + + async updateMeeting(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { + const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) + if (!meeting || !team) return + const notifiers = await loader(dataLoader, team.id, meeting.facilitatorUserId, 'meetingStart') + notifiers.forEach((notifier) => notifier.updateMeeting?.(meeting, team)) + }, + + async endMeeting(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { + const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) + if (!meeting || !team) return + const meetingResponses = await getTeamPromptResponsesByMeetingId(meetingId) + const standupResponses = await Promise.all( + meetingResponses.map(async (response) => { + const user = await dataLoader.get('users').loadNonNull(response.userId) + return { + user, + response + } + }) + ) + const notifiers = await loader(dataLoader, team.id, meeting.facilitatorUserId, 'meetingEnd') + notifiers.forEach((notifier) => notifier.endMeeting(meeting, team, standupResponses)) + }, + + async startTimeLimit( + dataLoader: DataLoaderWorker, + scheduledEndTime: Date, + meetingId: string, + teamId: string + ) { + const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) + if (!meeting || !team) return + const notifiers = await loader( + dataLoader, + team.id, + meeting.facilitatorUserId, + 'MEETING_STAGE_TIME_LIMIT_START' + ) + notifiers.forEach((notifier) => notifier.startTimeLimit(scheduledEndTime, meeting, team)) + }, + + async endTimeLimit(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { + const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) + if (!meeting || !team) return + const notifiers = await loader( + dataLoader, + team.id, + meeting.facilitatorUserId, + 'MEETING_STAGE_TIME_LIMIT_END' + ) + notifiers.forEach((notifier) => notifier.endTimeLimit(meeting, team)) + }, + + async integrationUpdated(dataLoader: DataLoaderWorker, teamId: string, userId: string) { + const notifiers = await loader(dataLoader, teamId, userId, 'meetingEnd') + notifiers.forEach((notifier) => notifier.integrationUpdated()) + }, + + async standupResponseSubmitted( + dataLoader: DataLoaderWorker, + meetingId: string, + teamId: string, + userId: string + ) { + const [{meeting, team}, user, responses] = await Promise.all([ + loadMeetingTeam(dataLoader, meetingId, teamId), + dataLoader.get('users').load(userId), + getTeamPromptResponsesByMeetingId(meetingId) + ]) + const response = responses.find(({userId: responseUserId}) => responseUserId === userId) + if (!meeting || !team || !response || !user) return + const notifiers = await loader( + dataLoader, + team.id, + meeting.facilitatorUserId, + 'STANDUP_RESPONSE_SUBMITTED' + ) + notifiers.forEach((notifier) => + notifier.standupResponseSubmitted(meeting, team, user, response) + ) + } +}) diff --git a/packages/server/graphql/mutations/helpers/notifications/SlackNotifier.ts b/packages/server/graphql/mutations/helpers/notifications/SlackNotifier.ts index 14656a2b938..22a6a96701b 100644 --- a/packages/server/graphql/mutations/helpers/notifications/SlackNotifier.ts +++ b/packages/server/graphql/mutations/helpers/notifications/SlackNotifier.ts @@ -17,7 +17,7 @@ import {DataLoaderWorker} from '../../../graphql' import getSummaryText from './getSummaryText' import {makeButtons, makeHeader, makeSection, makeSections} from './makeSlackBlocks' import {NotificationIntegrationHelper} from './NotificationIntegrationHelper' -import {Notifier} from './Notifier' +import {createNotifier} from './Notifier' import SlackAuth from '../../../../database/types/SlackAuth' import {getTeamPromptResponsesByMeetingId} from '../../../../postgres/queries/getTeamPromptResponsesByMeetingIds' import {ErrorResponse, PostMessageResponse} from '../../../../../client/utils/SlackManager' @@ -456,8 +456,9 @@ export const SlackSingleChannelNotifier: NotificationIntegrationHelper notifier.startMeeting(meeting, team)) - }, - - async updateMeeting(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { - const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) - if (!meeting || !team) return - const notifiers = await getSlack(dataLoader, 'meetingStart', team.id) - notifiers.forEach((notifier) => notifier.updateMeeting?.(meeting, team)) - }, - - async endMeeting(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { - const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) - const meetingResponses = await getTeamPromptResponsesByMeetingId(meetingId) - // const standupResponses: Array<{user: User; response: TeamPromptResponse}> = [] - const standupResponses = await Promise.all( - meetingResponses.map(async (response) => { - const user = await dataLoader.get('users').loadNonNull(response.userId) - return { - user, - response - } - }) - ) - if (!meeting || !team) return - const notifiers = await getSlack(dataLoader, 'meetingEnd', team.id) - notifiers.forEach((notifier) => notifier.endMeeting(meeting, team, standupResponses)) - }, - - async startTimeLimit( - dataLoader: DataLoaderWorker, - scheduledEndTime: Date, - meetingId: string, - teamId: string - ) { - const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) - if (!meeting || !team) return - const notifiers = await getSlack(dataLoader, 'MEETING_STAGE_TIME_LIMIT_START', team.id) - notifiers.forEach((notifier) => notifier.startTimeLimit(scheduledEndTime, meeting, team)) - }, - - async endTimeLimit(dataLoader: DataLoaderWorker, meetingId: string, teamId: string) { - const {meeting, team} = await loadMeetingTeam(dataLoader, meetingId, teamId) - if (!meeting || !team) return - const notifiers = await getSlack(dataLoader, 'MEETING_STAGE_TIME_LIMIT_END', team.id) - notifiers.forEach((notifier) => notifier.endTimeLimit(meeting, team)) - }, - - async integrationUpdated() { - // Slack sends a system message on its own - }, - - async standupResponseSubmitted( - dataLoader: DataLoaderWorker, - meetingId: string, - teamId: string, - userId: string - ) { - const [{meeting, team}, user, responses] = await Promise.all([ - loadMeetingTeam(dataLoader, meetingId, teamId), - dataLoader.get('users').load(userId), - getTeamPromptResponsesByMeetingId(meetingId) - ]) - const response = responses.find(({userId: responseUserId}) => responseUserId === userId) - if (!meeting || !team || !response || !user) { - return - } - - const notifiers = await getSlack(dataLoader, 'STANDUP_RESPONSE_SUBMITTED', team.id) - notifiers.forEach((notifier) => - notifier.standupResponseSubmitted(meeting, team, user, response) - ) - }, - +export const SlackNotifier = { + ...createNotifier(getSlack), async shareTopic( dataLoader: DataLoaderWorker, userId: string,