Skip to content

Commit

Permalink
add getMember and getPagedMember to teamsInfo (#1833)
Browse files Browse the repository at this point in the history
* add getMember and getPagedMember to teamsInfo

* abstract options object

* examples

* fix test

* add missing awaits

Co-authored-by: Steven Ickman <stevenic@microsoft.com>
  • Loading branch information
clearab and Stevenic authored Mar 3, 2020
1 parent c2eebb7 commit 5b16410
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 15 deletions.
84 changes: 81 additions & 3 deletions libraries/botbuilder/src/teamsInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import {
TeamsChannelAccount,
TeamsChannelData,
TeamDetails,
TurnContext
TurnContext,
PagedMembersResult,
TeamsPagedMembersResult
} from 'botbuilder-core';
import { ConnectorClient, TeamsConnectorClient } from 'botframework-connector';
import { ConnectorClient, TeamsConnectorClient, TeamsConnectorModels} from 'botframework-connector';

import { BotFrameworkAdapter } from './botFrameworkAdapter';

Expand Down Expand Up @@ -50,12 +52,59 @@ export class TeamsInfo {
}
}

public static async getPagedMembers(context: TurnContext, pageSize?: number, continuationToken?: string): Promise<TeamsPagedMembersResult> {
const teamId = this.getTeamId(context);
const options: TeamsConnectorModels.ConversationsGetConversationPagedMembersOptionalParams = {
"continuationToken" : continuationToken,
"pageSize": pageSize
}
if (teamId) {
return await this.getPagedTeamMembers(context, teamId, pageSize, continuationToken);
} else {
const conversation = context.activity.conversation;
const conversationId = conversation && conversation.id ? conversation.id : undefined;
return await this.getPagedMembersInternal(this.getConnectorClient(context), conversationId, options);
}
}

public static async getMember(context: TurnContext, userId: string): Promise<TeamsChannelAccount> {
const teamId = this.getTeamId(context);
if (teamId) {
return await this.getTeamMember(context, teamId, userId);
} else {
const conversation = context.activity.conversation;
const conversationId = conversation && conversation.id ? conversation.id : undefined;
return await this.getMemberInternal(this.getConnectorClient(context), conversationId, userId);
}
}

public static async getTeamMembers(context: TurnContext, teamId?: string): Promise<TeamsChannelAccount[]> {
const t = teamId || this.getTeamId(context);
if (!t) {
throw new Error('This method is only valid within the scope of a MS Teams Team.');
}
return this.getMembersInternal(this.getConnectorClient(context), t);
return await this.getMembersInternal(this.getConnectorClient(context), t);
}

public static async getPagedTeamMembers(context: TurnContext, teamId?: string, pageSize?: number, continuationToken?: string): Promise<TeamsPagedMembersResult> {
const t = teamId || this.getTeamId(context);
if (!t) {
throw new Error('This method is only valid within the scope of a MS Teams Team.');
}

const options: TeamsConnectorModels.ConversationsGetConversationPagedMembersOptionalParams = {
"continuationToken" : continuationToken,
"pageSize": pageSize
}
return await this.getPagedMembersInternal(this.getConnectorClient(context), t, options);
}

public static async getTeamMember(context: TurnContext, teamId?: string, userId?: string): Promise<TeamsChannelAccount> {
const t = teamId || this.getTeamId(context);
if (!t) {
throw new Error('This method is only valid within the scope of a MS Teams Team.');
}
return await this.getMemberInternal(this.getConnectorClient(context), t, userId);
}

private static async getMembersInternal(connectorClient: ConnectorClient, conversationId: string): Promise<TeamsChannelAccount[]> {
Expand All @@ -71,6 +120,35 @@ export class TeamsInfo {
return teamMembers as TeamsChannelAccount[];
}

private static async getPagedMembersInternal(connectorClient: ConnectorClient, conversationId: string, options: TeamsConnectorModels.ConversationsGetConversationPagedMembersOptionalParams): Promise<TeamsPagedMembersResult> {
if (!conversationId) {
throw new Error('The getPagedMembers operation needs a valid conversationId.');
}

const pagedMembersResult: PagedMembersResult = await connectorClient.conversations.getConversationPagedMembers(conversationId, options)

const teamsPagedMembersResult: TeamsPagedMembersResult = {
"continuationToken": pagedMembersResult.continuationToken,
"members": pagedMembersResult.members as TeamsChannelAccount[]
}

return teamsPagedMembersResult;
}

private static async getMemberInternal(connectorClient: ConnectorClient, conversationId: string, userId: string): Promise<TeamsChannelAccount> {
if (!conversationId) {
throw new Error('The getMember operation needs a valid conversationId.');
}

if (!userId) {
throw new Error('The getMember operation needs a valid conversationId.');
}

const teamMember: ChannelAccount = await connectorClient.conversations.getConversationMember(conversationId, userId);

return teamMember as TeamsChannelAccount;
}

private static getTeamId(context: TurnContext): string {
if (!context) {
throw new Error('Missing context parameter');
Expand Down
18 changes: 14 additions & 4 deletions libraries/botbuilder/tests/teams/roster/src/rosterBot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export class RosterBot extends TeamsActivityHandler {
await this.showDetails(context);
break;

case "show member":
await this.showMember(context);
break;

default:
await context.sendActivity(
'Invalid command. Type "Show channels" to see a channel list. Type "Show members" to see a list of members in a team. ' +
Expand All @@ -59,23 +63,29 @@ export class RosterBot extends TeamsActivityHandler {
}

private async showMembers(context: TurnContext): Promise<void> {
let teamsChannelAccounts = await TeamsInfo.getMembers(context);
let options = {"continuationToken": null, "pageSize": 2};
let teamsChannelAccounts = await (await TeamsInfo.getPagedMembers(context, 5)).members;
await context.sendActivity(MessageFactory.text(`Total of ${teamsChannelAccounts.length} members are currently in team`));
let messages = teamsChannelAccounts.map(function(teamsChannelAccount) {
return `${teamsChannelAccount.aadObjectId} --> ${teamsChannelAccount.name} --> ${teamsChannelAccount.userPrincipalName}`;
});
await this.sendInBatches(context, messages);
}
private async showChannels(context: TurnContext): Promise<void> {

private async showChannels(context: TurnContext): Promise<void> {
let channels = await TeamsInfo.getTeamChannels(context);
await context.sendActivity(MessageFactory.text(`Total of ${channels.length} channels are currently in team`));
let messages = channels.map(function(channel) {
return `${channel.id} --> ${channel.name ? channel.name : 'General'}`;
});
await this.sendInBatches(context, messages);
}


private async showMember(context: TurnContext): Promise<void> {
let member = await TeamsInfo.getMember(context, context.activity.from.id);
await context.sendActivity(MessageFactory.text("You are: " + member.name));
}

private async showDetails(context: TurnContext): Promise<void> {
let teamDetails = await TeamsInfo.getTeamDetails(context);
await context.sendActivity(MessageFactory.text(`The team name is ${teamDetails.name}. The team ID is ${teamDetails.id}. The AAD GroupID is ${teamDetails.aadGroupId}.`));
Expand Down
20 changes: 20 additions & 0 deletions libraries/botframework-connector/src/connectorApi/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,26 @@ export type ConversationsGetConversationMembersResponse = Array<ChannelAccount>
};
};

/**
* Contains response data for the getConversationMember operation.
*/
export type ConversationsGetConversationMemberResponse = ChannelAccount & {
/**
* The underlying HTTP response.
*/
_response: msRest.HttpResponse & {
/**
* The response body as text (string format)
*/
bodyAsText: string;

/**
* The response body as parsed JSON or XML
*/
parsedBody: ChannelAccount;
};
};

/**
* Contains response data for the getConversationPagedMembers operation.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,23 @@ export class Conversations {
callback) as Promise<Models.ConversationsGetConversationMembersResponse>;
}

/**
* @param conversationId Conversation ID
* @param memberId MemberId for the user
* @param options The optional parameters
* @param callback The callback
*/
getConversationMember(conversationId: string, memberId: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback<Models.ChannelAccount[]>, callback?: msRest.ServiceCallback<Models.ChannelAccount[]>): Promise<Models.ConversationsGetConversationMemberResponse> {
return this.client.sendOperationRequest(
{
conversationId,
memberId,
options
},
getConversationMemberOperationSpec,
callback) as Promise<Models.ConversationsGetConversationMemberResponse>;
}

/**
* Enumerate the members of a conversation one page at a time.
*
Expand Down Expand Up @@ -696,13 +713,13 @@ const getConversationMembersOperationSpec: msRest.OperationSpec = {
bodyMapper: {
serializedName: "parsedResponse",
type: {
name: "Sequence",
element: {
type: {
name: "Composite",
className: "ChannelAccount"
name: "Sequence",
element: {
type: {
name: "Composite",
className: "ChannelAccount"
}
}
}
}
}
},
Expand All @@ -713,6 +730,24 @@ const getConversationMembersOperationSpec: msRest.OperationSpec = {
serializer
};

const getConversationMemberOperationSpec: msRest.OperationSpec = {
httpMethod: "GET",
path: "v3/conversations/{conversationId}/members/{memberId}",
urlParameters: [
Parameters.conversationId,
Parameters.memberId
],
responses: {
200: {
bodyMapper: Mappers.ChannelAccount,
},
default: {
bodyMapper: Mappers.ErrorResponse
}
},
serializer
};

const getConversationPagedMembersOperationSpec: msRest.OperationSpec = {
httpMethod: "GET",
path: "v3/conversations/{conversationId}/pagedmembers",
Expand Down
17 changes: 15 additions & 2 deletions libraries/botframework-connector/src/teams/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@


/*
* Code generated by Microsoft (R) AutoRest Code Generator.
* Changes may cause incorrect behavior and will be lost if the code is
Expand All @@ -6,7 +8,7 @@
// This code has been manually edited to reflect the integration of the Teams schemas into botframework-schema
// and the botframework-connector libraries.

import { HttpResponse, ServiceClientOptions } from '@azure/ms-rest-js';
import { HttpResponse, ServiceClientOptions, RequestOptionsBase } from '@azure/ms-rest-js';
import { ConversationList, TeamDetails } from 'botframework-schema';

/**
Expand Down Expand Up @@ -57,4 +59,15 @@ export type TeamsFetchTeamDetailsResponse = TeamDetails & {
*/
parsedBody: TeamDetails;
};
};
};

export interface ConversationsGetConversationPagedMembersOptionalParams extends RequestOptionsBase {
/**
* Suggested page size
*/
pageSize: number;
/**
* Continuation Token
*/
continuationToken: string;
}
11 changes: 11 additions & 0 deletions libraries/botframework-schema/src/teams/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,17 @@ export interface TeamsChannelAccount extends ChannelAccount {
userPrincipalName?: string;
}

export interface TeamsPagedMembersResult {
/**
* Paging token
*/
continuationToken: string;
/**
* The Channel Accounts.
*/
members: TeamsChannelAccount[];
}

/**
* @interface
* An interface representing O365ConnectorCardFact.
Expand Down

0 comments on commit 5b16410

Please sign in to comment.