Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for config auth type (fetch & submit) #4485

Merged
merged 9 commits into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions libraries/botbuilder/etc/botbuilder.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { AppCredentials } from 'botframework-connector';
import { AttachmentData } from 'botbuilder-core';
import { AuthenticationConfiguration } from 'botframework-connector';
import { BotAdapter } from 'botbuilder-core';
import { BotConfigAuth } from 'botbuilder-core';
import { BotFrameworkAuthentication } from 'botframework-connector';
import { BotFrameworkClient } from 'botbuilder-core';
import { BotFrameworkSkill } from 'botbuilder-core';
Expand All @@ -20,6 +21,8 @@ import { ChannelAccount } from 'botbuilder-core';
import { ChannelInfo } from 'botbuilder-core';
import { ClaimsIdentity } from 'botframework-connector';
import { CloudAdapterBase } from 'botbuilder-core';
import { ConfigResponse } from 'botbuilder-core';
import { ConfigTaskResponse } from 'botbuilder-core';
import { ConnectorClient } from 'botframework-connector';
import { ConnectorClientOptions } from 'botframework-connector';
import { ConversationAccount } from 'botbuilder-core';
Expand Down Expand Up @@ -367,6 +370,8 @@ export class TeamsActivityHandler extends ActivityHandler {
protected handleTeamsAnonymousAppBasedLinkQuery(_context: TurnContext, _query: AppBasedLinkQuery): Promise<MessagingExtensionResponse>;
protected handleTeamsAppBasedLinkQuery(_context: TurnContext, _query: AppBasedLinkQuery): Promise<MessagingExtensionResponse>;
protected handleTeamsCardActionInvoke(_context: TurnContext): Promise<InvokeResponse>;
protected handleTeamsConfigFetch(_context: TurnContext, _configData: any): Promise<ConfigResponse<BotConfigAuth | ConfigTaskResponse>>;
protected handleTeamsConfigSubmit(_context: TurnContext, _configData: any): Promise<ConfigResponse<BotConfigAuth | ConfigTaskResponse>>;
protected handleTeamsFileConsent(context: TurnContext, fileConsentCardResponse: FileConsentCardResponse): Promise<void>;
protected handleTeamsFileConsentAccept(_context: TurnContext, _fileConsentCardResponse: FileConsentCardResponse): Promise<void>;
protected handleTeamsFileConsentDecline(_context: TurnContext, _fileConsentCardResponse: FileConsentCardResponse): Promise<void>;
Expand All @@ -389,13 +394,13 @@ export class TeamsActivityHandler extends ActivityHandler {
protected handleTeamsTaskModuleSubmit(_context: TurnContext, _taskModuleRequest: TaskModuleRequest): Promise<TaskModuleResponse>;
protected onInvokeActivity(context: TurnContext): Promise<InvokeResponse>;
protected onSignInInvoke(context: TurnContext): Promise<void>;
protected onTeamsChannelCreated(context: any): Promise<void>;
protected onTeamsChannelCreated(context: TurnContext): Promise<void>;
onTeamsChannelCreatedEvent(handler: (channelInfo: ChannelInfo, teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void>): this;
protected onTeamsChannelDeleted(context: any): Promise<void>;
protected onTeamsChannelDeleted(context: TurnContext): Promise<void>;
onTeamsChannelDeletedEvent(handler: (channelInfo: ChannelInfo, teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void>): this;
protected onTeamsChannelRenamed(context: any): Promise<void>;
protected onTeamsChannelRenamed(context: TurnContext): Promise<void>;
onTeamsChannelRenamedEvent(handler: (channelInfo: ChannelInfo, teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void>): this;
protected onTeamsChannelRestored(context: any): Promise<void>;
protected onTeamsChannelRestored(context: TurnContext): Promise<void>;
onTeamsChannelRestoredEvent(handler: (channelInfo: ChannelInfo, teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void>): this;
protected onTeamsMeetingEnd(context: TurnContext): Promise<void>;
onTeamsMeetingEndEvent(handler: (meeting: MeetingEndEventDetails, context: TurnContext, next: () => Promise<void>) => Promise<void>): this;
Expand All @@ -413,17 +418,17 @@ export class TeamsActivityHandler extends ActivityHandler {
onTeamsMessageUndeleteEvent(handler: (context: TurnContext, next: () => Promise<void>) => Promise<void>): this;
protected onTeamsReadReceipt(context: TurnContext): Promise<void>;
onTeamsReadReceiptEvent(handler: (receiptInfo: ReadReceiptInfo, context: TurnContext, next: () => Promise<void>) => Promise<void>): this;
protected onTeamsTeamArchived(context: any): Promise<void>;
protected onTeamsTeamArchived(context: TurnContext): Promise<void>;
onTeamsTeamArchivedEvent(handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void>): this;
protected onTeamsTeamDeleted(context: any): Promise<void>;
protected onTeamsTeamDeleted(context: TurnContext): Promise<void>;
onTeamsTeamDeletedEvent(handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void>): this;
protected onTeamsTeamHardDeleted(context: any): Promise<void>;
protected onTeamsTeamHardDeleted(context: TurnContext): Promise<void>;
onTeamsTeamHardDeletedEvent(handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void>): this;
protected onTeamsTeamRenamed(context: any): Promise<void>;
protected onTeamsTeamRenamed(context: TurnContext): Promise<void>;
onTeamsTeamRenamedEvent(handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void>): this;
protected onTeamsTeamRestored(context: any): Promise<void>;
protected onTeamsTeamRestored(context: TurnContext): Promise<void>;
onTeamsTeamRestoredEvent(handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void>): this;
protected onTeamsTeamUnarchived(context: any): Promise<void>;
protected onTeamsTeamUnarchived(context: TurnContext): Promise<void>;
onTeamsTeamUnarchivedEvent(handler: (teamInfo: TeamInfo, context: TurnContext, next: () => Promise<void>) => Promise<void>): this;
}

Expand Down
76 changes: 59 additions & 17 deletions libraries/botbuilder/src/teamsActivityHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
import {
ActivityHandler,
AppBasedLinkQuery,
BotConfigAuth,
corinagum marked this conversation as resolved.
Show resolved Hide resolved
ChannelInfo,
Channels,
ConfigResponse,
ConfigTaskResponse,
FileConsentCardResponse,
InvokeResponse,
MeetingStartEventDetails,
MeetingEndEventDetails,
MeetingStartEventDetails,
MessagingExtensionAction,
MessagingExtensionActionResponse,
MessagingExtensionQuery,
Expand All @@ -26,11 +29,11 @@ import {
TabSubmit,
TaskModuleRequest,
TaskModuleResponse,
TeamsChannelData,
TeamsChannelAccount,
TeamInfo,
TurnContext,
TeamsChannelAccount,
TeamsChannelData,
tokenExchangeOperationName,
TurnContext,
verifyStateOperationName,
} from 'botbuilder-core';
import { ReadReceiptInfo } from 'botframework-connector';
Expand Down Expand Up @@ -86,6 +89,14 @@ export class TeamsActivityHandler extends ActivityHandler {
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)
Expand Down Expand Up @@ -169,7 +180,7 @@ export class TeamsActivityHandler extends ActivityHandler {
return super.onInvokeActivity(context);
}
}
} catch (err) {
} catch (err: any) {
if (err.message === 'NotImplemented') {
return { status: 501 };
} else if (err.message === 'BadRequest') {
Expand All @@ -193,6 +204,34 @@ export class TeamsActivityHandler extends ActivityHandler {
throw new Error('NotImplemented');
}

/**
* Handles a config/fetch invoke activity.
*
* @param _context A context object for this turn.
* @param _configData The object representing the configuration.
* @returns An Invoke Response for the activity.
corinagum marked this conversation as resolved.
Show resolved Hide resolved
*/
protected async handleTeamsConfigFetch(
_context: TurnContext,
_configData: any
): Promise<ConfigResponse<BotConfigAuth | ConfigTaskResponse>> {
throw new Error('NotImplemented');
}

/**
* Handles a config/submit invoke activity.
*
* @param _context A context object for this turn.
* @param _configData The object representing the configuration.
* @returns An Invoke Response for the activity.
corinagum marked this conversation as resolved.
Show resolved Hide resolved
*/
protected async handleTeamsConfigSubmit(
_context: TurnContext,
_configData: any
): Promise<ConfigResponse<BotConfigAuth | ConfigTaskResponse>> {
throw new Error('NotImplemented');
}

/**
* Receives invoke activities with Activity name of 'fileConsent/invoke'. Handlers registered here run before
* `handleTeamsFileConsentAccept` and `handleTeamsFileConsentDecline`.
Expand Down Expand Up @@ -424,7 +463,7 @@ export class TeamsActivityHandler extends ActivityHandler {
* @remarks
* Used in creating a Search-based Message Extension.
* @param _context A context object for this turn.
* @param _query he object representing the query.
* @param _query The object representing the query.
* @returns The Messaging Extension Response for the query.
*/
protected async handleTeamsMessagingExtensionSelectItem(
Expand Down Expand Up @@ -700,6 +739,9 @@ export class TeamsActivityHandler extends ActivityHandler {
*/
protected async onTeamsMembersAdded(context: TurnContext): Promise<void> {
if ('TeamsMembersAdded' in this.handlers && this.handlers['TeamsMembersAdded'].length > 0) {
if (!context.activity || !context.activity.membersAdded) {
throw new Error('OnTeamsMemberAdded: context.activity is undefined');
}
for (let i = 0; i < context.activity.membersAdded.length; i++) {
const channelAccount = context.activity.membersAdded[i];

Expand All @@ -717,7 +759,7 @@ export class TeamsActivityHandler extends ActivityHandler {

try {
context.activity.membersAdded[i] = await TeamsInfo.getMember(context, channelAccount.id);
} catch (err) {
} catch (err: any) {
const errCode: string = err.body && err.body.error && err.body.error.code;
if (errCode === 'ConversationNotFound') {
// unable to find the member added in ConversationUpdate Activity in the response from the getMember call
Expand Down Expand Up @@ -767,7 +809,7 @@ export class TeamsActivityHandler extends ActivityHandler {
* @param context A context object for this turn.
* @returns A promise that represents the work queued.
*/
protected async onTeamsChannelCreated(context): Promise<void> {
protected async onTeamsChannelCreated(context: TurnContext): Promise<void> {
await this.handle(context, 'TeamsChannelCreated', this.defaultNextEvent(context));
}

Expand All @@ -779,7 +821,7 @@ export class TeamsActivityHandler extends ActivityHandler {
* @param context A context object for this turn.
* @returns A promise that represents the work queued.
*/
protected async onTeamsChannelDeleted(context): Promise<void> {
protected async onTeamsChannelDeleted(context: TurnContext): Promise<void> {
corinagum marked this conversation as resolved.
Show resolved Hide resolved
await this.handle(context, 'TeamsChannelDeleted', this.defaultNextEvent(context));
}

Expand All @@ -791,7 +833,7 @@ export class TeamsActivityHandler extends ActivityHandler {
* @param context A context object for this turn.
* @returns A promise that represents the work queued.
*/
protected async onTeamsChannelRenamed(context): Promise<void> {
protected async onTeamsChannelRenamed(context: TurnContext): Promise<void> {
await this.handle(context, 'TeamsChannelRenamed', this.defaultNextEvent(context));
}

Expand All @@ -803,7 +845,7 @@ export class TeamsActivityHandler extends ActivityHandler {
* @param context The context for this turn.
* @returns A promise that represents the work queued.
*/
protected async onTeamsTeamArchived(context): Promise<void> {
protected async onTeamsTeamArchived(context: TurnContext): Promise<void> {
await this.handle(context, 'TeamsTeamArchived', this.defaultNextEvent(context));
}

Expand All @@ -815,7 +857,7 @@ export class TeamsActivityHandler extends ActivityHandler {
* @param context The context for this turn.
* @returns A promise that represents the work queued.
*/
protected async onTeamsTeamDeleted(context): Promise<void> {
protected async onTeamsTeamDeleted(context: TurnContext): Promise<void> {
await this.handle(context, 'TeamsTeamDeleted', this.defaultNextEvent(context));
}

Expand All @@ -827,7 +869,7 @@ export class TeamsActivityHandler extends ActivityHandler {
* @param context The context for this turn.
* @returns A promise that represents the work queued.
*/
protected async onTeamsTeamHardDeleted(context): Promise<void> {
protected async onTeamsTeamHardDeleted(context: TurnContext): Promise<void> {
await this.handle(context, 'TeamsTeamHardDeleted', this.defaultNextEvent(context));
}

Expand All @@ -840,7 +882,7 @@ export class TeamsActivityHandler extends ActivityHandler {
* @param context The context for this turn.
* @returns A promise that represents the work queued.
*/
protected async onTeamsChannelRestored(context): Promise<void> {
protected async onTeamsChannelRestored(context: TurnContext): Promise<void> {
await this.handle(context, 'TeamsChannelRestored', this.defaultNextEvent(context));
}

Expand All @@ -852,7 +894,7 @@ export class TeamsActivityHandler extends ActivityHandler {
* @param context The context for this turn.
* @returns A promise that represents the work queued.
*/
protected async onTeamsTeamRenamed(context): Promise<void> {
protected async onTeamsTeamRenamed(context: TurnContext): Promise<void> {
await this.handle(context, 'TeamsTeamRenamed', this.defaultNextEvent(context));
}

Expand All @@ -864,7 +906,7 @@ export class TeamsActivityHandler extends ActivityHandler {
* @param context The context for this turn.
* @returns A promise that represents the work queued.
*/
protected async onTeamsTeamRestored(context): Promise<void> {
protected async onTeamsTeamRestored(context: TurnContext): Promise<void> {
await this.handle(context, 'TeamsTeamRestored', this.defaultNextEvent(context));
}

Expand All @@ -876,7 +918,7 @@ export class TeamsActivityHandler extends ActivityHandler {
* @param context The context for this turn.
* @returns A promise that represents the work queued.
*/
protected async onTeamsTeamUnarchived(context): Promise<void> {
protected async onTeamsTeamUnarchived(context: TurnContext): Promise<void> {
await this.handle(context, 'TeamsTeamUnarchived', this.defaultNextEvent(context));
}

Expand Down
36 changes: 36 additions & 0 deletions libraries/botbuilder/tests/teamsActivityHandler.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,42 @@ describe('TeamsActivityHandler', function () {
});

describe('should send a NotImplemented status code if', function () {
it('handleTeamsBotConfigFetch is not overridden', async function () {
const bot = new TeamsActivityHandler();

const adapter = new TestAdapter(async (context) => {
await bot.run(context);
});

const taskSubmitActivity = createInvokeActivity('config/fetch');
await adapter
.send(taskSubmitActivity)
.assertReply((activity) => {
assert.strictEqual(activity.type, 'invokeResponse');
assert.strictEqual(activity.value.status, 501);
assert.strictEqual(activity.value.body, undefined);
})
.startTest();
});

it('handleTeamsBotConfigSubmit is not overridden', async function () {
const bot = new TeamsActivityHandler();

const adapter = new TestAdapter(async (context) => {
await bot.run(context);
});

const taskSubmitActivity = createInvokeActivity('config/submit');
await adapter
.send(taskSubmitActivity)
.assertReply((activity) => {
assert.strictEqual(activity.type, 'invokeResponse');
assert.strictEqual(activity.value.status, 501);
assert.strictEqual(activity.value.body, undefined);
})
.startTest();
});

it('handleTeamsMessagingExtensionSubmitAction is not overridden', async function () {
const bot = new TeamsActivityHandler();

Expand Down
24 changes: 24 additions & 0 deletions libraries/botframework-schema/etc/botframework-schema.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,15 @@ export interface BasicCard {
title: string;
}

// @public
export interface BotConfigAuth {
corinagum marked this conversation as resolved.
Show resolved Hide resolved
suggestedActions?: SuggestedActions;
type: 'auth';
}

// @public
export type BotConfigAuthType = 'auth' | 'task';

// @public
export type BotMessagePreviewActionType = 'edit' | 'send';

Expand Down Expand Up @@ -484,6 +493,21 @@ export interface CommandValue<T = unknown> {
data?: T;
}

// @public (undocumented)
export interface ConfigAuthResponse extends ConfigResponse<BotConfigAuth> {
}

// @public
export interface ConfigResponse<T> {
cacheInfo: CacheInfo;
config: T;
responseType: string;
}

// @public (undocumented)
export interface ConfigTaskResponse extends ConfigResponse<TaskModuleResponse> {
}

// @public
export enum ContactRelationUpdateActionTypes {
// (undocumented)
Expand Down
Loading