UNPKG

@microsoft/agents-hosting-teams

Version:

Microsoft 365 Agents SDK for JavaScript

1,192 lines (1,079 loc) 43.2 kB
/** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ import { ReadReceiptInfo } from './message-read-info/readReceipInfo' import * as z from 'zod' import { FileConsentCardResponse } from './file/fileConsentCardResponse' import { TaskModuleRequest } from './task/taskModuleRequest' import { TabRequest } from './tab/tabRequest' import { TabSubmit } from './tab/tabSubmit' import { TabResponse } from './tab/tabResponse' import { TaskModuleResponse } from './task/taskModuleResponse' import { TeamsChannelAccount } from './connector-client/teamsChannelAccount' import { MeetingStartEventDetails } from './meeting/meetingStartEventDetails' import { MeetingEndEventDetails } from './meeting/meetingEndEventDetails' import { MeetingParticipantsEventDetails } from './meeting/meetingParticipantsEventDetails' import { TeamsMeetingMember } from './meeting/teamsMeetingMember' import { O365ConnectorCardActionQuery } from './query/o365ConnectorCardActionQuery' import { AppBasedLinkQuery } from './query/appBasedLinkQuery' import { SigninStateVerificationQuery } from './query/signinStateVerificationQuery' import { ConfigResponse } from './agent-config/configResponse' import { MessagingExtensionAction } from './messaging-extension/messagingExtensionAction' import { MessagingExtensionResponse } from './messaging-extension/messagingExtensionResponse' import { MessagingExtensionActionResponse } from './messaging-extension/messagingExtensionActionResponse' import { ActivityHandler, InvokeResponse, TurnContext } from '@microsoft/agents-hosting' import { Channels } from '@microsoft/agents-activity' import { ChannelInfo, TeamInfo } from './channel-data' import { parseValueMessagingExtensionQuery } from './parsers/activityValueParsers' import { parseTeamsChannelData } from './parsers/teamsChannelDataParser' import { MessagingExtensionQuery } from './messaging-extension' import { TeamsConnectorClient } from './connector-client/teamsConnectorClient' const TeamsMeetingStartT = z .object({ Id: z.string(), JoinUrl: z.string(), MeetingType: z.string(), Title: z.string(), StartTime: z.string() }) const TeamsMeetingEndT = z .object({ Id: z.string(), JoinUrl: z.string(), MeetingType: z.string(), Title: z.string(), EndTime: z.string() }) /** * A handler for processing Microsoft Teams-specific activities. * Extends the ActivityHandler class to provide additional Teams-specific functionality. * This class includes methods for handling various Teams events, such as message updates, channel events, and meeting events. */ export class TeamsActivityHandler extends ActivityHandler { /** * Handles invoke activities. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<InvokeResponse>} The invoke response. */ protected async onInvokeActivity (context: TurnContext): Promise<InvokeResponse> { let runEvents = true try { if (!context.activity.name && context.activity.channelId === 'msteams') { return await this.handleTeamsCardActionInvoke(context) } else { switch (context.activity.name) { case 'config/fetch': return ActivityHandler.createInvokeResponse( await this.handleTeamsConfigFetch(context, context.activity.value) ) case 'config/submit': return ActivityHandler.createInvokeResponse( await this.handleTeamsConfigSubmit(context, context.activity.value) ) case 'fileConsent/invoke': return ActivityHandler.createInvokeResponse( await this.handleTeamsFileConsent(context, context.activity.value as FileConsentCardResponse) ) case 'actionableMessage/executeAction': await this.handleTeamsO365ConnectorCardAction(context, context.activity.value as O365ConnectorCardActionQuery) return ActivityHandler.createInvokeResponse() case 'composeExtension/queryLink': return ActivityHandler.createInvokeResponse( await this.handleTeamsAppBasedLinkQuery(context, context.activity.value as AppBasedLinkQuery) ) case 'composeExtension/anonymousQueryLink': return ActivityHandler.createInvokeResponse( await this.handleTeamsAnonymousAppBasedLinkQuery(context, context.activity.value as AppBasedLinkQuery) ) case 'composeExtension/query': return ActivityHandler.createInvokeResponse( await this.handleTeamsMessagingExtensionQuery(context, parseValueMessagingExtensionQuery(context.activity.value)) ) case 'composeExtension/selectItem': return ActivityHandler.createInvokeResponse( await this.handleTeamsMessagingExtensionSelectItem(context, context.activity.value) ) case 'composeExtension/submitAction': return ActivityHandler.createInvokeResponse( await this.handleTeamsMessagingExtensionSubmitActionDispatch( context, context.activity.value as MessagingExtensionAction ) ) case 'composeExtension/fetchTask': return ActivityHandler.createInvokeResponse( await this.handleTeamsMessagingExtensionFetchTask(context, context.activity.value as MessagingExtensionAction) ) case 'composeExtension/querySettingUrl': return ActivityHandler.createInvokeResponse( await this.handleTeamsMessagingExtensionConfigurationQuerySettingUrl( context, context.activity.value as MessagingExtensionQuery ) ) case 'composeExtension/setting': await this.handleTeamsMessagingExtensionConfigurationSetting(context, context.activity.value) return ActivityHandler.createInvokeResponse() case 'composeExtension/onCardButtonClicked': await this.handleTeamsMessagingExtensionCardButtonClicked(context, context.activity.value) return ActivityHandler.createInvokeResponse() case 'task/fetch': return ActivityHandler.createInvokeResponse( await this.handleTeamsTaskModuleFetch(context, context.activity.value as TaskModuleRequest) ) case 'task/submit': return ActivityHandler.createInvokeResponse( await this.handleTeamsTaskModuleSubmit(context, context.activity.value as TaskModuleRequest) ) case 'tab/fetch': return ActivityHandler.createInvokeResponse( await this.handleTeamsTabFetch(context, context.activity.value as TabRequest) ) case 'tab/submit': return ActivityHandler.createInvokeResponse( await this.handleTeamsTabSubmit(context, context.activity.value as TabSubmit) ) default: runEvents = false return await super.onInvokeActivity(context) } } } catch (err: any) { if (err.message === 'NotImplemented') { return { status: 501 } } else if (err.message === 'BadRequest') { return { status: 400 } } throw err } finally { if (runEvents) { this.defaultNextEvent(context)() } } } /** * Handles card action invoke. * @param {TurnContext} _context - The context object for the turn. * @returns {Promise<InvokeResponse>} The invoke response. */ protected async handleTeamsCardActionInvoke (_context: TurnContext): Promise<InvokeResponse> { throw new Error('NotImplemented') } /** * Handles config fetch. * @param {TurnContext} _context - The context object for the turn. * @param {any} _configData - The config data. * @returns {Promise<ConfigResponse>} The config response. */ protected async handleTeamsConfigFetch (_context: TurnContext, _configData: any): Promise<ConfigResponse> { throw new Error('NotImplemented') } /** * Handles config submit. * @param {TurnContext} _context - The context object for the turn. * @param {any} _configData - The config data. * @returns {Promise<ConfigResponse>} The config response. */ protected async handleTeamsConfigSubmit (_context: TurnContext, _configData: any): Promise<ConfigResponse> { throw new Error('NotImplemented') } /** * Handles file consent. * @param {TurnContext} context - The context object for the turn. * @param {FileConsentCardResponse} fileConsentCardResponse - The file consent card response. * @returns {Promise<void>} */ protected async handleTeamsFileConsent ( context: TurnContext, fileConsentCardResponse: FileConsentCardResponse ): Promise<void> { switch (fileConsentCardResponse.action) { case 'accept': return await this.handleTeamsFileConsentAccept(context, fileConsentCardResponse) case 'decline': return await this.handleTeamsFileConsentDecline(context, fileConsentCardResponse) default: throw new Error('BadRequest') } } /** * Handles file consent accept. * @param {TurnContext} _context - The context object for the turn. * @param {FileConsentCardResponse} _fileConsentCardResponse - The file consent card response. * @returns {Promise<void>} */ protected async handleTeamsFileConsentAccept ( _context: TurnContext, _fileConsentCardResponse: FileConsentCardResponse ): Promise<void> { throw new Error('NotImplemented') } /** * Handles file consent decline. * @param {TurnContext} _context - The context object for the turn. * @param {FileConsentCardResponse} _fileConsentCardResponse - The file consent card response. * @returns {Promise<void>} */ protected async handleTeamsFileConsentDecline ( _context: TurnContext, _fileConsentCardResponse: FileConsentCardResponse ): Promise<void> { throw new Error('NotImplemented') } /** * Handles O365 connector card action. * @param {TurnContext} _context - The context object for the turn. * @param {O365ConnectorCardActionQuery} _query - The O365 connector card action query. * @returns {Promise<void>} */ protected async handleTeamsO365ConnectorCardAction ( _context: TurnContext, _query: O365ConnectorCardActionQuery ): Promise<void> { throw new Error('NotImplemented') } /** * Handles sign-in verify state. * @param {TurnContext} _context - The context object for the turn. * @param {SigninStateVerificationQuery} _query - The sign-in state verification query. * @returns {Promise<void>} */ protected async handleTeamsSigninVerifyState ( _context: TurnContext, _query: SigninStateVerificationQuery ): Promise<void> { throw new Error('NotImplemented') } /** * Handles sign-in token exchange. * @param {TurnContext} _context - The context object for the turn. * @param {SigninStateVerificationQuery} _query - The sign-in state verification query. * @returns {Promise<void>} */ protected async handleTeamsSigninTokenExchange ( _context: TurnContext, _query: SigninStateVerificationQuery ): Promise<void> { throw new Error('NotImplemented') } /** * Handles messaging extension card button clicked. * @param {TurnContext} _context - The context object for the turn. * @param {any} _cardData - The card data. * @returns {Promise<void>} */ protected async handleTeamsMessagingExtensionCardButtonClicked ( _context: TurnContext, _cardData: any ): Promise<void> { throw new Error('NotImplemented') } /** * Handles task module fetch. * @param {TurnContext} _context - The context object for the turn. * @param {TaskModuleRequest} _taskModuleRequest - The task module request. * @returns {Promise<TaskModuleResponse>} The task module response. */ protected async handleTeamsTaskModuleFetch ( _context: TurnContext, _taskModuleRequest: TaskModuleRequest ): Promise<TaskModuleResponse> { throw new Error('NotImplemented') } /** * Handles task module submit. * @param {TurnContext} _context - The context object for the turn. * @param {TaskModuleRequest} _taskModuleRequest - The task module request. * @returns {Promise<TaskModuleResponse>} The task module response. */ protected async handleTeamsTaskModuleSubmit ( _context: TurnContext, _taskModuleRequest: TaskModuleRequest ): Promise<TaskModuleResponse> { throw new Error('NotImplemented') } /** * Handles tab fetch. * @param {TurnContext} _context - The context object for the turn. * @param {TabRequest} _tabRequest - The tab request. * @returns {Promise<TabResponse>} The tab response. */ protected async handleTeamsTabFetch (_context: TurnContext, _tabRequest: TabRequest): Promise<TabResponse> { throw new Error('NotImplemented') } /** * Handles tab submit. * @param {TurnContext} _context - The context object for the turn. * @param {TabSubmit} _tabSubmit - The tab submit. * @returns {Promise<TabResponse>} The tab response. */ protected async handleTeamsTabSubmit (_context: TurnContext, _tabSubmit: TabSubmit): Promise<TabResponse> { throw new Error('NotImplemented') } /** * Handles app-based link query. * @param {TurnContext} _context - The context object for the turn. * @param {AppBasedLinkQuery} _query - The app-based link query. * @returns {Promise<MessagingExtensionResponse>} The messaging extension response. */ protected async handleTeamsAppBasedLinkQuery ( _context: TurnContext, _query: AppBasedLinkQuery ): Promise<MessagingExtensionResponse> { throw new Error('NotImplemented') } /** * Handles anonymous app-based link query. * @param {TurnContext} _context - The context object for the turn. * @param {AppBasedLinkQuery} _query - The app-based link query. * @returns {Promise<MessagingExtensionResponse>} The messaging extension response. */ protected async handleTeamsAnonymousAppBasedLinkQuery ( _context: TurnContext, _query: AppBasedLinkQuery ): Promise<MessagingExtensionResponse> { throw new Error('NotImplemented') } /** * Handles messaging extension query. * @param {TurnContext} _context - The context object for the turn. * @param {MessagingExtensionQuery} _query - The messaging extension query. * @returns {Promise<MessagingExtensionResponse>} The messaging extension response. */ protected async handleTeamsMessagingExtensionQuery ( _context: TurnContext, _query: MessagingExtensionQuery ): Promise<MessagingExtensionResponse> { throw new Error('NotImplemented') } /** * Handles messaging extension select item. * @param {TurnContext} _context - The context object for the turn. * @param {any} _query - The query. * @returns {Promise<MessagingExtensionResponse>} The messaging extension response. */ protected async handleTeamsMessagingExtensionSelectItem ( _context: TurnContext, _query: any ): Promise<MessagingExtensionResponse> { throw new Error('NotImplemented') } /** * Handles messaging extension submit action dispatch. * @param {TurnContext} context - The context object for the turn. * @param {MessagingExtensionAction} action - The messaging extension action. * @returns {Promise<MessagingExtensionActionResponse>} The messaging extension action response. */ protected async handleTeamsMessagingExtensionSubmitActionDispatch ( context: TurnContext, action: MessagingExtensionAction ): Promise<MessagingExtensionActionResponse> { if (action.messagePreviewAction) { switch (action.messagePreviewAction) { case 'edit': return await this.handleTeamsMessagingExtensionMessagePreviewEdit(context, action) case 'send': return await this.handleTeamsMessagingExtensionMessagePreviewSend(context, action) default: throw new Error('BadRequest') } } else { return await this.handleTeamsMessagingExtensionSubmitAction(context, action) } } /** * Handles messaging extension submit action. * @param {TurnContext} _context - The context object for the turn. * @param {MessagingExtensionAction} _action - The messaging extension action. * @returns {Promise<MessagingExtensionActionResponse>} The messaging extension action response. */ protected async handleTeamsMessagingExtensionSubmitAction ( _context: TurnContext, _action: MessagingExtensionAction ): Promise<MessagingExtensionActionResponse> { throw new Error('NotImplemented') } /** * Handles messaging extension message preview edit. * @param {TurnContext} _context - The context object for the turn. * @param {MessagingExtensionAction} _action - The messaging extension action. * @returns {Promise<MessagingExtensionActionResponse>} The messaging extension action response. */ protected async handleTeamsMessagingExtensionMessagePreviewEdit ( _context: TurnContext, _action: MessagingExtensionAction ): Promise<MessagingExtensionActionResponse> { throw new Error('NotImplemented') } /** * Handles messaging extension message preview send. * @param {TurnContext} _context - The context object for the turn. * @param {MessagingExtensionAction} _action - The messaging extension action. * @returns {Promise<MessagingExtensionActionResponse>} The messaging extension action response. */ protected async handleTeamsMessagingExtensionMessagePreviewSend ( _context: TurnContext, _action: MessagingExtensionAction ): Promise<MessagingExtensionActionResponse> { throw new Error('NotImplemented') } /** * Handles messaging extension fetch task. * @param {TurnContext} _context - The context object for the turn. * @param {MessagingExtensionAction} _action - The messaging extension action. * @returns {Promise<MessagingExtensionActionResponse>} The messaging extension action response. */ protected async handleTeamsMessagingExtensionFetchTask ( _context: TurnContext, _action: MessagingExtensionAction ): Promise<MessagingExtensionActionResponse> { throw new Error('NotImplemented') } /** * Handles messaging extension configuration query setting URL. * @param {TurnContext} _context - The context object for the turn. * @param {MessagingExtensionQuery} _query - The messaging extension query. * @returns {Promise<MessagingExtensionResponse>} The messaging extension response. */ protected async handleTeamsMessagingExtensionConfigurationQuerySettingUrl ( _context: TurnContext, _query: MessagingExtensionQuery ): Promise<MessagingExtensionResponse> { throw new Error('NotImplemented') } /** * Handles messaging extension configuration setting. * @param {TurnContext} _context - The context object for the turn. * @param {any} _settings - The settings. * @returns {Promise<void>} */ protected async handleTeamsMessagingExtensionConfigurationSetting (_context: TurnContext, _settings: any): Promise<void> { throw new Error('NotImplemented') } /** * Dispatches conversation update activity. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async dispatchConversationUpdateActivity (context: TurnContext): Promise<void> { if (context.activity.channelId === 'msteams') { const channelData = parseTeamsChannelData(context.activity.channelData) if ((context.activity.membersAdded != null) && context.activity.membersAdded.length > 0) { return await this.onTeamsMembersAdded(context) } if ((context.activity.membersRemoved != null) && context.activity.membersRemoved.length > 0) { return await this.onTeamsMembersRemoved(context) } if (!channelData || !channelData.eventType) { return await super.dispatchConversationUpdateActivity(context) } switch (channelData.eventType) { case 'channelCreated': return await this.onTeamsChannelCreated(context) case 'channelDeleted': return await this.onTeamsChannelDeleted(context) case 'channelRenamed': return await this.onTeamsChannelRenamed(context) case 'teamArchived': return await this.onTeamsTeamArchived(context) case 'teamDeleted': return await this.onTeamsTeamDeleted(context) case 'teamHardDeleted': return await this.onTeamsTeamHardDeleted(context) case 'channelRestored': return await this.onTeamsChannelRestored(context) case 'teamRenamed': return await this.onTeamsTeamRenamed(context) case 'teamRestored': return await this.onTeamsTeamRestored(context) case 'teamUnarchived': return await this.onTeamsTeamUnarchived(context) default: return await super.dispatchConversationUpdateActivity(context) } } else { return await super.dispatchConversationUpdateActivity(context) } } /** * Dispatches message update activity. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async dispatchMessageUpdateActivity (context: TurnContext): Promise<void> { if (context.activity.channelId === 'msteams') { const channelData = parseTeamsChannelData(context.activity.channelData) switch (channelData.eventType) { case 'undeleteMessage': return await this.onTeamsMessageUndelete(context) case 'editMessage': return await this.onTeamsMessageEdit(context) default: return await super.dispatchMessageUpdateActivity(context) } } else { return await super.dispatchMessageUpdateActivity(context) } } /** * Dispatches message delete activity. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async dispatchMessageDeleteActivity (context: TurnContext): Promise<void> { if (context.activity.channelId === 'msteams') { const channelData = parseTeamsChannelData(context.activity.channelData) switch (channelData.eventType) { case 'softDeleteMessage': return await this.onTeamsMessageSoftDelete(context) default: return await super.dispatchMessageDeleteActivity(context) } } else { return await super.dispatchMessageDeleteActivity(context) } } /** * Handles Teams message undelete. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsMessageUndelete (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsMessageUndelete', this.defaultNextEvent(context)) } /** * Handles Teams message edit. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsMessageEdit (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsMessageEdit', this.defaultNextEvent(context)) } /** * Handles Teams message soft delete. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsMessageSoftDelete (context: TurnContext): Promise<void> { await this.handle(context, 'onTeamsMessageSoftDelete', this.defaultNextEvent(context)) } /** * Handles Teams members added. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsMembersAdded (context: TurnContext): Promise<void> { if ('TeamsMembersAdded' in this.handlers && this.handlers.TeamsMembersAdded.length > 0) { if (!context.activity || (context.activity.membersAdded == null)) { throw new Error('OnTeamsMemberAdded: context.activity is undefined') } for (let i = 0; i < context.activity.membersAdded.length; i++) { const channelAccount = context.activity.membersAdded[i] if ( 'givenName' in channelAccount || 'surname' in channelAccount || 'email' in channelAccount || 'userPrincipalName' in channelAccount || ((context.activity.recipient != null) && context.activity.recipient.id === channelAccount.id) ) { continue } try { context.activity.membersAdded[i] = await TeamsConnectorClient.getMember(context.activity, channelAccount.id!) } catch (err: any) { const errCode: string = err.body && err.body.error && err.body.error.code if (errCode === 'ConversationNotFound') { const teamsChannelAccount: TeamsChannelAccount = { id: channelAccount.id, name: channelAccount.name, aadObjectId: channelAccount.aadObjectId, role: channelAccount.role } context.activity.membersAdded[i] = teamsChannelAccount } else { throw err } } } await this.handle(context, 'TeamsMembersAdded', this.defaultNextEvent(context)) } else { await this.handle(context, 'MembersAdded', this.defaultNextEvent(context)) } } /** * Handles Teams members removed. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsMembersRemoved (context: TurnContext): Promise<void> { if ('TeamsMembersRemoved' in this.handlers && this.handlers.TeamsMembersRemoved.length > 0) { await this.handle(context, 'TeamsMembersRemoved', this.defaultNextEvent(context)) } else { await this.handle(context, 'MembersRemoved', this.defaultNextEvent(context)) } } /** * Handles Teams channel created. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsChannelCreated (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsChannelCreated', this.defaultNextEvent(context)) } /** * Handles Teams channel deleted. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsChannelDeleted (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsChannelDeleted', this.defaultNextEvent(context)) } /** * Handles Teams channel renamed. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsChannelRenamed (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsChannelRenamed', this.defaultNextEvent(context)) } /** * Handles Teams team archived. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsTeamArchived (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsTeamArchived', this.defaultNextEvent(context)) } /** * Handles Teams team deleted. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsTeamDeleted (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsTeamDeleted', this.defaultNextEvent(context)) } /** * Handles Teams team hard deleted. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsTeamHardDeleted (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsTeamHardDeleted', this.defaultNextEvent(context)) } /** * Handles Teams channel restored. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsChannelRestored (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsChannelRestored', this.defaultNextEvent(context)) } /** * Handles Teams team renamed. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsTeamRenamed (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsTeamRenamed', this.defaultNextEvent(context)) } /** * Handles Teams team restored. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsTeamRestored (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsTeamRestored', this.defaultNextEvent(context)) } /** * Handles Teams team unarchived. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsTeamUnarchived (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsTeamUnarchived', this.defaultNextEvent(context)) } /** * Registers a handler for Teams message undelete event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsMessageUndeleteEvent (handler: (context: TurnContext, next: () => Promise<void>) => Promise<void>): this { return this.on('TeamsMessageUndelete', async (context, next) => { await handler(context, next) }) } /** * Registers a handler for Teams message edit event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsMessageEditEvent (handler: (context: TurnContext, next: () => Promise<void>) => Promise<void>): this { return this.on('TeamsMessageEdit', async (context, next) => { await handler(context, next) }) } /** * Registers a handler for Teams message soft delete event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsMessageSoftDeleteEvent (handler: (context: TurnContext, next: () => Promise<void>) => Promise<void>): this { return this.on('onTeamsMessageSoftDelete', async (context, next) => { await handler(context, next) }) } /** * Registers a handler for Teams members added event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsMembersAddedEvent ( handler: ( membersAdded: TeamsChannelAccount[], teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void> ) => Promise<void> ): this { return this.on('TeamsMembersAdded', async (context, next) => { const teamsChannelData = parseTeamsChannelData(context.activity.channelData) await handler(context.activity.membersAdded || [], teamsChannelData.team as TeamInfo, context, next) }) } /** * Registers a handler for Teams members removed event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsMembersRemovedEvent ( handler: ( membersRemoved: TeamsChannelAccount[], teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void> ) => Promise<void> ): this { return this.on('TeamsMembersRemoved', async (context, next) => { const teamsChannelData = parseTeamsChannelData(context.activity.channelData) await handler(context.activity.membersRemoved || [], teamsChannelData.team as TeamInfo, context, next) }) } /** * Registers a handler for Teams channel created event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsChannelCreatedEvent ( handler: ( channelInfo: ChannelInfo, teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void> ) => Promise<void> ): this { return this.on('TeamsChannelCreated', async (context, next) => { const teamsChannelData = parseTeamsChannelData(context.activity.channelData) await handler(teamsChannelData.channel as ChannelInfo, teamsChannelData.team as TeamInfo, context, next) }) } /** * Registers a handler for Teams channel deleted event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsChannelDeletedEvent ( handler: ( channelInfo: ChannelInfo, teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void> ) => Promise<void> ): this { return this.on('TeamsChannelDeleted', async (context, next) => { const teamsChannelData = parseTeamsChannelData(context.activity.channelData) await handler(teamsChannelData.channel as ChannelInfo, teamsChannelData.team as TeamInfo, context, next) }) } /** * Registers a handler for Teams channel renamed event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsChannelRenamedEvent ( handler: ( channelInfo: ChannelInfo, teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void> ) => Promise<void> ): this { return this.on('TeamsChannelRenamed', async (context, next) => { const teamsChannelData = parseTeamsChannelData(context.activity.channelData) await handler(teamsChannelData.channel as ChannelInfo, teamsChannelData.team as TeamInfo, context, next) }) } /** * Registers a handler for Teams team archived event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsTeamArchivedEvent ( handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void> ): this { return this.on('TeamsTeamArchived', async (context, next) => { const teamsChannelData = parseTeamsChannelData(context.activity.channelData) await handler(teamsChannelData.team as TeamInfo, context, next) }) } /** * Registers a handler for Teams team deleted event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsTeamDeletedEvent ( handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void> ): this { return this.on('TeamsTeamDeleted', async (context, next) => { const teamsChannelData = parseTeamsChannelData(context.activity.channelData) await handler(teamsChannelData.team as TeamInfo, context, next) }) } /** * Registers a handler for Teams team hard deleted event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsTeamHardDeletedEvent ( handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void> ): this { return this.on('TeamsTeamHardDeleted', async (context, next) => { const teamsChannelData = parseTeamsChannelData(context.activity.channelData) await handler(teamsChannelData.team as TeamInfo, context, next) }) } /** * Registers a handler for Teams channel restored event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsChannelRestoredEvent ( handler: ( channelInfo: ChannelInfo, teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void> ) => Promise<void> ): this { return this.on('TeamsChannelRestored', async (context, next) => { const teamsChannelData = parseTeamsChannelData(context.activity.channelData) await handler(teamsChannelData.channel as ChannelInfo, teamsChannelData.team as TeamInfo, context, next) }) } /** * Registers a handler for Teams team renamed event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsTeamRenamedEvent ( handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void> ): this { return this.on('TeamsTeamRenamed', async (context, next) => { const teamsChannelData = parseTeamsChannelData(context.activity.channelData) await handler(teamsChannelData.team as TeamInfo, context, next) }) } /** * Registers a handler for Teams team restored event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsTeamRestoredEvent ( handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void> ): this { return this.on('TeamsTeamRestored', async (context, next) => { const teamsChannelData = parseTeamsChannelData(context.activity.channelData) await handler(teamsChannelData.team as TeamInfo, context, next) }) } /** * Registers a handler for Teams team unarchived event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsTeamUnarchivedEvent ( handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void> ): this { return this.on('TeamsTeamUnarchived', async (context, next) => { const teamsChannelData = parseTeamsChannelData(context.activity.channelData) await handler(teamsChannelData.team as TeamInfo, context, next) }) } /** * Dispatches event activity. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async dispatchEventActivity (context: TurnContext): Promise<void> { if (context.activity.channelId === Channels.Msteams) { switch (context.activity.name) { case 'application/vnd.microsoft.readReceipt': return await this.onTeamsReadReceipt(context) case 'application/vnd.microsoft.meetingStart': return await this.onTeamsMeetingStart(context) case 'application/vnd.microsoft.meetingEnd': return await this.onTeamsMeetingEnd(context) case 'application/vnd.microsoft.meetingParticipantJoin': return await this.onTeamsMeetingParticipantsJoin(context) case 'application/vnd.microsoft.meetingParticipantLeave': return await this.onTeamsMeetingParticipantsLeave(context) } } return await super.dispatchEventActivity(context) } /** * Handles Teams meeting start. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsMeetingStart (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsMeetingStart', this.defaultNextEvent(context)) } /** * Handles Teams meeting end. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsMeetingEnd (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsMeetingEnd', this.defaultNextEvent(context)) } /** * Handles Teams read receipt. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsReadReceipt (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsReadReceipt', this.defaultNextEvent(context)) } /** * Handles Teams meeting participants join. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsMeetingParticipantsJoin (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsMeetingParticipantsJoin', this.defaultNextEvent(context)) } /** * Handles Teams meeting participants leave. * @param {TurnContext} context - The context object for the turn. * @returns {Promise<void>} */ protected async onTeamsMeetingParticipantsLeave (context: TurnContext): Promise<void> { await this.handle(context, 'TeamsMeetingParticipantsLeave', this.defaultNextEvent(context)) } /** * Registers a handler for Teams meeting start event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsMeetingStartEvent ( handler: (meeting: MeetingStartEventDetails, context: TurnContext, next: () => Promise<void>) => Promise<void> ): this { return this.on('TeamsMeetingStart', async (context, next) => { const meeting = TeamsMeetingStartT.parse(context.activity.value) await handler( { id: meeting.Id, joinUrl: meeting.JoinUrl, meetingType: meeting.MeetingType, startTime: new Date(meeting.StartTime), title: meeting.Title }, context, next ) }) } /** * Registers a handler for Teams meeting end event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsMeetingEndEvent ( handler: (meeting: MeetingEndEventDetails, context: TurnContext, next: () => Promise<void>) => Promise<void> ): this { return this.on('TeamsMeetingEnd', async (context, next) => { const meeting = TeamsMeetingEndT.parse(context.activity.value) await handler( { id: meeting.Id, joinUrl: meeting.JoinUrl, meetingType: meeting.MeetingType, endTime: new Date(meeting.EndTime), title: meeting.Title }, context, next ) }) } /** * Registers a handler for Teams read receipt event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsReadReceiptEvent ( handler: (receiptInfo: ReadReceiptInfo, context: TurnContext, next: () => Promise<void>) => Promise<void> ): this { return this.on('TeamsReadReceipt', async (context, next) => { const receiptInfo = context.activity.value as { lastReadMessageId: string } await handler(new ReadReceiptInfo(receiptInfo.lastReadMessageId), context, next) }) } /** * Registers a handler for Teams meeting participants join event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsMeetingParticipantsJoinEvent ( handler: ( meeting: MeetingParticipantsEventDetails, context: TurnContext, next: () => Promise<void> ) => Promise<void> ): this { return this.on('TeamsMeetingParticipantsJoin', async (context, next) => { const meeting = TeamsMeetingStartT.parse(context.activity.value) await handler( { members: (meeting as unknown as { members: TeamsMeetingMember[] }).members }, context, next ) }) } /** * Registers a handler for Teams meeting participants leave event. * @param {function} handler - The handler function. * @returns {this} */ onTeamsMeetingParticipantsLeaveEvent ( handler: ( meeting: MeetingParticipantsEventDetails, context: TurnContext, next: () => Promise<void> ) => Promise<void> ): this { return this.on('TeamsMeetingParticipantsLeave', async (context, next) => { const meeting = TeamsMeetingEndT.parse(context.activity.value) await handler( { members: (meeting as unknown as { members: TeamsMeetingMember[] }).members }, context, next ) }) } }