Skip to content

Commit

Permalink
port: [microsoft#4527][#6655] Implementation of Teams batch APIs (mic…
Browse files Browse the repository at this point in the history
…rosoft#4535)

* add teams batch operations

* update teamsInfo logic

* add unit tests for batch operations

* fix retry logic

* apply code feedback

* Fix lint issue

---------

Co-authored-by: JhontSouth <[email protected]>
  • Loading branch information
ceciliaavila and JhontSouth authored Oct 3, 2023
1 parent 843c847 commit 901b06a
Show file tree
Hide file tree
Showing 12 changed files with 1,568 additions and 6 deletions.
12 changes: 12 additions & 0 deletions libraries/botbuilder/etc/botbuilder.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ import { AppBasedLinkQuery } from 'botbuilder-core';
import { AppCredentials } from 'botframework-connector';
import { AttachmentData } from 'botbuilder-core';
import { AuthenticationConfiguration } from 'botframework-connector';
import { BatchFailedEntriesResponse } from 'botbuilder-core';
import { BatchOperationResponse } from 'botbuilder-core';
import { BatchOperationStateResponse } from 'botbuilder-core';
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';
import { BotState } from 'botbuilder-core';
import { CancelOperationResponse } from 'botframework-connector';
import { ChannelAccount } from 'botbuilder-core';
import { ChannelInfo } from 'botbuilder-core';
import { ClaimsIdentity } from 'botframework-connector';
Expand Down Expand Up @@ -78,6 +82,7 @@ import { TeamInfo } from 'botbuilder-core';
import { TeamsChannelAccount } from 'botbuilder-core';
import { TeamsMeetingInfo } from 'botbuilder-core';
import { TeamsMeetingParticipant } from 'botbuilder-core';
import { TeamsMember } from 'botbuilder-core';
import { TeamsPagedMembersResult } from 'botbuilder-core';
import { TenantInfo } from 'botbuilder-core';
import { TokenApiClient } from 'botframework-connector';
Expand Down Expand Up @@ -460,11 +465,14 @@ export function teamsGetTenant(activity: Activity): TenantInfo | null;

// @public
export class TeamsInfo {
static cancelOperation(context: TurnContext, operationId: string): Promise<CancelOperationResponse>;
static getFailedEntries(context: TurnContext, operationId: string): Promise<BatchFailedEntriesResponse>;
static getMeetingInfo(context: TurnContext, meetingId?: string): Promise<TeamsMeetingInfo>;
static getMeetingParticipant(context: TurnContext, meetingId?: string, participantId?: string, tenantId?: string): Promise<TeamsMeetingParticipant>;
static getMember(context: TurnContext, userId: string): Promise<TeamsChannelAccount>;
// @deprecated
static getMembers(context: TurnContext): Promise<TeamsChannelAccount[]>;
static getOperationState(context: TurnContext, operationId: string): Promise<BatchOperationStateResponse>;
static getPagedMembers(context: TurnContext, pageSize?: number, continuationToken?: string): Promise<TeamsPagedMembersResult>;
static getPagedTeamMembers(context: TurnContext, teamId?: string, pageSize?: number, continuationToken?: string): Promise<TeamsPagedMembersResult>;
static getTeamChannels(context: TurnContext, teamId?: string): Promise<ChannelInfo[]>;
Expand All @@ -473,6 +481,10 @@ export class TeamsInfo {
// @deprecated
static getTeamMembers(context: TurnContext, teamId?: string): Promise<TeamsChannelAccount[]>;
static sendMeetingNotification(context: TurnContext, notification: MeetingNotification, meetingId?: string): Promise<MeetingNotificationResponse>;
static sendMessageToAllUsersInTeam(context: TurnContext, activity: Activity, tenantId: string, teamId: string): Promise<BatchOperationResponse>;
static sendMessageToAllUsersInTenant(context: TurnContext, activity: Activity, tenantId: string): Promise<BatchOperationResponse>;
static sendMessageToListOfChannels(context: TurnContext, activity: Activity, tenantId: string, members: TeamsMember[]): Promise<BatchOperationResponse>;
static sendMessageToListOfUsers(context: TurnContext, activity: Activity, tenantId: string, members: TeamsMember[]): Promise<BatchOperationResponse>;
static sendMessageToTeamsChannel(context: TurnContext, activity: Activity, teamsChannelId: string, botAppId?: string): Promise<[ConversationReference, string]>;
}

Expand Down
171 changes: 170 additions & 1 deletion libraries/botbuilder/src/teamsInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,17 @@ import {
Channels,
MeetingNotification,
MeetingNotificationResponse,
TeamsMember,
BatchOperationResponse,
BatchOperationStateResponse,
BatchFailedEntriesResponse,
} from 'botbuilder-core';
import { ConnectorClient, TeamsConnectorClient, TeamsConnectorModels } from 'botframework-connector';
import {
CancelOperationResponse,
ConnectorClient,
TeamsConnectorClient,
TeamsConnectorModels,
} from 'botframework-connector';

import { BotFrameworkAdapter } from './botFrameworkAdapter';
import { CloudAdapter } from './cloudAdapter';
Expand Down Expand Up @@ -364,6 +373,166 @@ export class TeamsInfo {
return await this.getTeamsConnectorClient(context).teams.sendMeetingNotification(meetingId, notification);
}

/**
* Sends a message to the provided users in the list of Teams members.
*
* @param context The [TurnContext](xref:botbuilder-core.TurnContext) for this turn.
* @param activity The activity to send.
* @param tenantId The tenant ID.
* @param members The list of users recipients for the message.
* @returns Promise with operationId.
*/
static async sendMessageToListOfUsers(
context: TurnContext,
activity: Activity,
tenantId: string,
members: TeamsMember[]
): Promise<BatchOperationResponse> {
if (!activity) {
throw new Error('activity is required.');
}
if (!tenantId) {
throw new Error('tenantId is required.');
}
if (!members || members.length == 0) {
throw new Error('members list is required.');
}

return await this.getTeamsConnectorClient(context).teams.sendMessageToListOfUsers(activity, tenantId, members);
}

/**
* Sends a message to all the users in a tenant.
*
* @param context The [TurnContext](xref:botbuilder-core.TurnContext) for this turn.
* @param activity The activity to send.
* @param tenantId The tenant ID.
* @returns Promise with operationId.
*/
static async sendMessageToAllUsersInTenant(
context: TurnContext,
activity: Activity,
tenantId: string
): Promise<BatchOperationResponse> {
if (!activity) {
throw new Error('activity is required.');
}
if (!tenantId) {
throw new Error('tenantId is required.');
}

return await this.getTeamsConnectorClient(context).teams.sendMessageToAllUsersInTenant(activity, tenantId);
}

/**
* Sends a message to all the users in a team.
*
* @param context The [TurnContext](xref:botbuilder-core.TurnContext) for this turn.
* @param activity The activity to send.
* @param tenantId The tenant ID.
* @param teamId The team ID.
* @returns Promise with operationId.
*/
static async sendMessageToAllUsersInTeam(
context: TurnContext,
activity: Activity,
tenantId: string,
teamId: string
): Promise<BatchOperationResponse> {
if (!activity) {
throw new Error('activity is required.');
}
if (!tenantId) {
throw new Error('tenantId is required.');
}
if (!teamId) {
throw new Error('teamId is required.');
}

return await this.getTeamsConnectorClient(context).teams.sendMessageToAllUsersInTeam(
activity,
tenantId,
teamId
);
}

/**
* Sends a message to the provided list of Teams channels.
*
* @param context The [TurnContext](xref:botbuilder-core.TurnContext) for this turn.
* @param activity The activity to send.
* @param tenantId The tenant ID.
* @param members The list of channels recipients for the message.
* @returns Promise with operationId.
*/
static async sendMessageToListOfChannels(
context: TurnContext,
activity: Activity,
tenantId: string,
members: TeamsMember[]
): Promise<BatchOperationResponse> {
if (!activity) {
throw new Error('activity is required.');
}
if (!tenantId) {
throw new Error('tenantId is required.');
}
if (!members || members.length == 0) {
throw new Error('members list is required.');
}

return await this.getTeamsConnectorClient(context).teams.sendMessageToListOfChannels(
activity,
tenantId,
members
);
}

/**
* Gets the operation state.
*
* @param context The [TurnContext](xref:botbuilder-core.TurnContext) for this turn.
* @param operationId The operationId to get the state of.
* @returns Promise with The state and responses of the operation.
*/
static async getOperationState(context: TurnContext, operationId: string): Promise<BatchOperationStateResponse> {
if (!operationId) {
throw new Error('operationId is required.');
}

return await this.getTeamsConnectorClient(context).teams.getOperationState(operationId);
}

/**
* Gets the failed entries of an executed operation.
*
* @param context The [TurnContext](xref:botbuilder-core.TurnContext) for this turn.
* @param operationId The operationId to get the failed entries of.
* @returns Promise with the list of failed entries of the operation.
*/
static async getFailedEntries(context: TurnContext, operationId: string): Promise<BatchFailedEntriesResponse> {
if (!operationId) {
throw new Error('operationId is required.');
}

return await this.getTeamsConnectorClient(context).teams.getOperationFailedEntries(operationId);
}

/**
* Cancels a pending operation.
*
* @param context The [TurnContext](xref:botbuilder-core.TurnContext) for this turn.
* @param operationId The id of the operation to cancel.
* @returns Promise representing the asynchronous operation.
*/
static async cancelOperation(context: TurnContext, operationId: string): Promise<CancelOperationResponse> {
if (!operationId) {
throw new Error('operationId is required.');
}

return await this.getTeamsConnectorClient(context).teams.cancelOperation(operationId);
}

/**
* @private
*/
Expand Down
Loading

0 comments on commit 901b06a

Please sign in to comment.