diff --git a/libraries/botbuilder/src/teamsActivityHandler.ts b/libraries/botbuilder/src/teamsActivityHandler.ts index d9ab475921..d71a30733b 100644 --- a/libraries/botbuilder/src/teamsActivityHandler.ts +++ b/libraries/botbuilder/src/teamsActivityHandler.ts @@ -388,12 +388,27 @@ export class TeamsActivityHandler extends ActivityHandler { 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); } @@ -499,6 +514,38 @@ export class TeamsActivityHandler extends ActivityHandler { } /** + * Invoked when a Team Archived event activity is received from the connector. + * Team Archived correspond to the user archiving a team. + * @param context The context for this turn. + * @returns A promise that represents the work queued. + */ + protected async onTeamsTeamArchived(context): Promise { + await this.handle(context, 'TeamsTeamArchived', this.defaultNextEvent(context)); + } + + /** + * Invoked when a Team Deleted event activity is received from the connector. + * Team Deleted correspond to the user deleting a team. + * @param context The context for this turn. + * @returns A promise that represents the work queued. + */ + protected async onTeamsTeamDeleted(context): Promise { + await this.handle(context, 'TeamsTeamDeleted', this.defaultNextEvent(context)); + } + + /** + * Invoked when a Team Hard Deleted event activity is received from the connector. + * Team Hard Deleted correspond to the user hard-deleting a team. + * @param context The context for this turn. + * @returns A promise that represents the work queued. + */ + protected async onTeamsTeamHardDeleted(context): Promise { + await this.handle(context, 'TeamsTeamHardDeleted', this.defaultNextEvent(context)); + } + + /** + * + * @param context * Invoked when a Channel Restored event activity is received from the connector. * Channel Restored correspond to the user restoring a previously deleted channel. * @param context The context for this turn. @@ -519,6 +566,27 @@ export class TeamsActivityHandler extends ActivityHandler { } /** + * Invoked when a Team Restored event activity is received from the connector. + * Team Restored correspond to the user restoring a team. + * @param context The context for this turn. + * @returns A promise that represents the work queued. + */ + protected async onTeamsTeamRestored(context): Promise { + await this.handle(context, 'TeamsTeamRestored', this.defaultNextEvent(context)); + } + + /** + * Invoked when a Team Unarchived event activity is received from the connector. + * Team Unarchived correspond to the user unarchiving a team. + * @param context The context for this turn. + * @returns A promise that represents the work queued. + */ + protected async onTeamsTeamUnarchived(context): Promise { + await this.handle(context, 'TeamsTeamUnarchived', this.defaultNextEvent(context)); + } + + /** + * * Override this in a derived class to provide logic for when members other than the bot * join the channel, such as your bot's welcome logic. * @param handler @@ -580,6 +648,42 @@ export class TeamsActivityHandler extends ActivityHandler { }); } + /** + * Override this in a derived class to provide logic for when a team is archived. + * @param handler + * @returns A promise that represents the work queued. + */ + public onTeamsTeamArchivedEvent(handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise) => Promise): this { + return this.on('TeamsTeamArchived', async (context, next) => { + const teamsChannelData = context.activity.channelData as TeamsChannelData; + await handler(teamsChannelData.team, context, next); + }); + } + + /** + * Override this in a derived class to provide logic for when a team is deleted. + * @param handler + * @returns A promise that represents the work queued. + */ + public onTeamsTeamDeletedEvent(handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise) => Promise): this { + return this.on('TeamsTeamDeleted', async (context, next) => { + const teamsChannelData = context.activity.channelData as TeamsChannelData; + await handler(teamsChannelData.team, context, next); + }); + } + + /** + * Override this in a derived class to provide logic for when a team is hard-deleted. + * @param handler + * @returns A promise that represents the work queued. + */ + public onTeamsTeamHardDeletedEvent(handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise) => Promise): this { + return this.on('TeamsTeamHardDeleted', async (context, next) => { + const teamsChannelData = context.activity.channelData as TeamsChannelData; + await handler(teamsChannelData.team, context, next); + }); + } + /** * Override this in a derived class to provide logic for when a channel is restored. * @param handler @@ -603,4 +707,28 @@ export class TeamsActivityHandler extends ActivityHandler { await handler(teamsChannelData.team, context, next); }); } -} \ No newline at end of file + + /** + * Override this in a derived class to provide logic for when a team is restored. + * @param handler + * @returns A promise that represents the work queued. + */ + public onTeamsTeamRestoredEvent(handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise) => Promise): this { + return this.on('TeamsTeamRestored', async (context, next) => { + const teamsChannelData = context.activity.channelData as TeamsChannelData; + await handler(teamsChannelData.team, context, next); + }); + } + + /** + * Override this in a derived class to provide logic for when a team is unarchived. + * @param handler + * @returns A promise that represents the work queued. + */ + public onTeamsTeamUnarchivedEvent(handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise) => Promise): this { + return this.on('TeamsTeamUnarchived', async (context, next) => { + const teamsChannelData = context.activity.channelData as TeamsChannelData; + await handler(teamsChannelData.team, context, next); + }); + } +} diff --git a/libraries/botbuilder/tests/teamsActivityHandler.test.js b/libraries/botbuilder/tests/teamsActivityHandler.test.js index 780f1c5424..93f1af5e58 100644 --- a/libraries/botbuilder/tests/teamsActivityHandler.test.js +++ b/libraries/botbuilder/tests/teamsActivityHandler.test.js @@ -1574,6 +1574,231 @@ describe('TeamsActivityHandler', () => { .catch(err => done(err)); }); + it('onTeamsTeamArchived routed activity', done => { + const bot = new TeamsActivityHandler(); + + let onTeamsTeamArchivedEventCalled = false; + + const team = { id: 'team' }; + const activity = createConvUpdateActivity({ team, eventType: 'teamArchived' }); + + bot.onConversationUpdate(async (context, next) => { + assert(context, 'context not found'); + assert(next, 'next not found'); + onConversationUpdateCalled = true; + await next(); + }); + + bot.onTeamsTeamArchivedEvent(async (teamInfo, context, next) => { + assert(teamInfo, 'teamsInfo not found'); + assert(context, 'context not found'); + assert(next, 'next not found'); + assert.strictEqual(teamInfo, team); + onTeamsTeamArchivedEventCalled = true; + await next(); + }); + + bot.onDialog(async (context, next) => { + assert(context, 'context not found'); + assert(next, 'next not found'); + onDialogCalled = true; + await next(); + }); + + const adapter = new TestAdapter(async context => { + await bot.run(context); + }); + + adapter.send(activity) + .then(() => { + assert(onTeamsTeamArchivedEventCalled, 'onTeamsTeamArchivedEvent handler not called'); + assert(onConversationUpdateCalled, 'onConversationUpdate handler not called'); + assert(onDialogCalled, 'onDialog handler not called'); + done(); + }) + .catch(err => done(err)); + }); + + it('onTeamsTeamDeleted routed activity', done => { + const bot = new TeamsActivityHandler(); + + let onTeamsTeamDeletedEventCalled = false; + + const team = { id: 'team' }; + const activity = createConvUpdateActivity({ team, eventType: 'teamDeleted' }); + + bot.onConversationUpdate(async (context, next) => { + assert(context, 'context not found'); + assert(next, 'next not found'); + onConversationUpdateCalled = true; + await next(); + }); + + bot.onTeamsTeamDeletedEvent(async (teamInfo, context, next) => { + assert(teamInfo, 'teamsInfo not found'); + assert(context, 'context not found'); + assert(next, 'next not found'); + assert.strictEqual(teamInfo, team); + onTeamsTeamDeletedEventCalled = true; + await next(); + }); + + bot.onDialog(async (context, next) => { + assert(context, 'context not found'); + assert(next, 'next not found'); + onDialogCalled = true; + await next(); + }); + + const adapter = new TestAdapter(async context => { + await bot.run(context); + }); + + adapter.send(activity) + .then(() => { + assert(onTeamsTeamDeletedEventCalled, 'onTeamsTeamDeletedEvent handler not called'); + assert(onConversationUpdateCalled, 'onConversationUpdate handler not called'); + assert(onDialogCalled, 'onDialog handler not called'); + done(); + }) + .catch(err => done(err)); + }); + + it('onTeamsTeamHardDeleted routed activity', done => { + const bot = new TeamsActivityHandler(); + + let onTeamsTeamHardDeletedEventCalled = false; + + const team = { id: 'team' }; + const activity = createConvUpdateActivity({ team, eventType: 'teamHardDeleted' }); + + bot.onConversationUpdate(async (context, next) => { + assert(context, 'context not found'); + assert(next, 'next not found'); + onConversationUpdateCalled = true; + await next(); + }); + + bot.onTeamsTeamHardDeletedEvent(async (teamInfo, context, next) => { + assert(teamInfo, 'teamsInfo not found'); + assert(context, 'context not found'); + assert(next, 'next not found'); + assert.strictEqual(teamInfo, team); + onTeamsTeamHardDeletedEventCalled = true; + await next(); + }); + + bot.onDialog(async (context, next) => { + assert(context, 'context not found'); + assert(next, 'next not found'); + onDialogCalled = true; + await next(); + }); + + const adapter = new TestAdapter(async context => { + await bot.run(context); + }); + + adapter.send(activity) + .then(() => { + assert(onTeamsTeamHardDeletedEventCalled, 'onTeamsTeamHardDeletedEvent handler not called'); + assert(onConversationUpdateCalled, 'onConversationUpdate handler not called'); + assert(onDialogCalled, 'onDialog handler not called'); + done(); + }) + .catch(err => done(err)); + }); + + it('onTeamsTeamRestored routed activity', done => { + const bot = new TeamsActivityHandler(); + + let onTeamsTeamRestoredEventCalled = false; + + const team = { id: 'team' }; + const activity = createConvUpdateActivity({ team, eventType: 'teamRestored' }); + + bot.onConversationUpdate(async (context, next) => { + assert(context, 'context not found'); + assert(next, 'next not found'); + onConversationUpdateCalled = true; + await next(); + }); + + bot.onTeamsTeamRestoredEvent(async (teamInfo, context, next) => { + assert(teamInfo, 'teamsInfo not found'); + assert(context, 'context not found'); + assert(next, 'next not found'); + assert.strictEqual(teamInfo, team); + onTeamsTeamRestoredEventCalled = true; + await next(); + }); + + bot.onDialog(async (context, next) => { + assert(context, 'context not found'); + assert(next, 'next not found'); + onDialogCalled = true; + await next(); + }); + + const adapter = new TestAdapter(async context => { + await bot.run(context); + }); + + adapter.send(activity) + .then(() => { + assert(onTeamsTeamRestoredEventCalled, 'onTeamsTeamRestoredEvent handler not called'); + assert(onConversationUpdateCalled, 'onConversationUpdate handler not called'); + assert(onDialogCalled, 'onDialog handler not called'); + done(); + }) + .catch(err => done(err)); + }); + + it('onTeamsTeamUnarchived routed activity', done => { + const bot = new TeamsActivityHandler(); + + let onTeamsTeamUnarchivedEventCalled = false; + + const team = { id: 'team' }; + const activity = createConvUpdateActivity({ team, eventType: 'teamUnarchived' }); + + bot.onConversationUpdate(async (context, next) => { + assert(context, 'context not found'); + assert(next, 'next not found'); + onConversationUpdateCalled = true; + await next(); + }); + + bot.onTeamsTeamUnarchivedEvent(async (teamInfo, context, next) => { + assert(teamInfo, 'teamsInfo not found'); + assert(context, 'context not found'); + assert(next, 'next not found'); + assert.strictEqual(teamInfo, team); + onTeamsTeamUnarchivedEventCalled = true; + await next(); + }); + + bot.onDialog(async (context, next) => { + assert(context, 'context not found'); + assert(next, 'next not found'); + onDialogCalled = true; + await next(); + }); + + const adapter = new TestAdapter(async context => { + await bot.run(context); + }); + + adapter.send(activity) + .then(() => { + assert(onTeamsTeamUnarchivedEventCalled, 'onTeamsTeamUnarchivedEvent handler not called'); + assert(onConversationUpdateCalled, 'onConversationUpdate handler not called'); + assert(onDialogCalled, 'onDialog handler not called'); + done(); + }) + .catch(err => done(err)); + }); + it('signin/verifyState routed activity', done => { onDialogCalled = false; handleTeamsSigninVerifyStateCalled = false;