diff --git a/libraries/botbuilder/tests/teams/adaptiveCards/.env b/libraries/botbuilder/tests/teams/adaptiveCards/.env new file mode 100644 index 0000000000..660828e3e8 --- /dev/null +++ b/libraries/botbuilder/tests/teams/adaptiveCards/.env @@ -0,0 +1,2 @@ +MicrosoftAppId= +MicrosoftAppPassword= \ No newline at end of file diff --git a/libraries/botbuilder/tests/teams/adaptiveCards/package.json b/libraries/botbuilder/tests/teams/adaptiveCards/package.json new file mode 100644 index 0000000000..a821090aa9 --- /dev/null +++ b/libraries/botbuilder/tests/teams/adaptiveCards/package.json @@ -0,0 +1,30 @@ +{ + "name": "adaptive-cards-bot", + "version": "1.0.0", + "description": "", + "main": "./lib/index.js", + "scripts": { + "start": "tsc --build && node ./lib/index.js", + "build": "tsc --build", + "watch": "nodemon --watch ./src -e ts --exec \"npm run start\"" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "botbuilder": "file:../../../", + "dotenv": "^8.1.0", + "node-fetch": "^2.6.0", + "restify": "^8.4.0", + "uuid": "^3.3.3" + }, + "devDependencies": { + "@types/node": "^12.7.1", + "@types/node-fetch": "^2.5.0", + "@types/request": "^2.48.1", + "@types/restify": "^7.2.7", + "nodemon": "^1.19.1", + "ts-node": "^7.0.1", + "typescript": "^3.2.4" + } +} diff --git a/libraries/botbuilder/tests/teams/adaptiveCards/src/adaptiveCardsBot.ts b/libraries/botbuilder/tests/teams/adaptiveCards/src/adaptiveCardsBot.ts new file mode 100644 index 0000000000..3d706cbe23 --- /dev/null +++ b/libraries/botbuilder/tests/teams/adaptiveCards/src/adaptiveCardsBot.ts @@ -0,0 +1,234 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { + Activity, + ActionTypes, + Attachment, + CardFactory, + InvokeResponse, + MessageFactory, + TaskModuleRequest, + TaskModuleResponseBase, + TaskModuleMessageResponse, + TaskModuleTaskInfo, + TeamsActivityHandler, + TurnContext +} from 'botbuilder'; + +// +// You can @mention the bot the text "1", "2", or "3". "1" will send back adaptive cards. "2" will send back a +// task module that contains an adpative card. "3" will return an adpative card that contains BF card actions. +// +export class AdaptiveCardsBot extends TeamsActivityHandler { + constructor() { + super(); + + // See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types. + this.onMessage(async (context, next) => { + TurnContext.removeRecipientMention(context.activity); + let text = context.activity.text; + if (text && text.length > 0) { + text = text.trim(); + if (text == '1') + { + await this.sendAdaptiveCard1(context); + } + else if (text == '2') + { + await this.sendAdaptiveCard2(context); + } + else if (text == '3') + { + await this.sendAdaptiveCard3(context); + } + else + { + await context.sendActivity(`You said: ${text}`); + } + } + else { + await context.sendActivity('App sent a message with empty text'); + const activityValue = context.activity.value; + if (activityValue) { + await context.sendActivity(`but with value ${JSON.stringify(activityValue)}`); + } + } + await next(); + }); + + this.onMembersAdded(async (context, next) => { + const membersAdded = context.activity.membersAdded; + for (const member of membersAdded) { + if (member.id !== context.activity.recipient.id) { + await context.sendActivity('Hello and welcome!'); + } + } + + // By calling next() you ensure that the next BotHandler is run. + await next(); + }); + } + + protected async onTeamsTaskModuleFetch(context: TurnContext, taskModuleRequest: TaskModuleRequest): Promise { + await context.sendActivity(MessageFactory.text(`OnTeamsTaskModuleFetchAsync TaskModuleRequest: ${JSON.stringify(taskModuleRequest)}`)); + + const card = CardFactory.adaptiveCard({ + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.0", + "body": [ + { + "type": "TextBlock", + "text": "This is an Adaptive Card within a Task Module" + } + ], + "actions": [ + { + "type": "Action.Submit", + "title": "Action.Submit", + "data": { + "submitLocation": "taskModule" + } + } + ] + }); + + return { + card: card, + height: 200, + width: 400, + title: 'Task Module Example' + }; + } + + protected async onTeamsTaskModuleSubmit(context: TurnContext, taskModuleRequest: TaskModuleRequest): Promise { + await context.sendActivity(MessageFactory.text(`OnTeamsTaskModuleSubmit value: ${ JSON.stringify(taskModuleRequest) }`)); + return { type: 'message', value: 'Thanks!' }; + } + + protected async onTeamsCardActionInvoke(context: TurnContext): Promise { + await context.sendActivity(MessageFactory.text(`OnTeamsCardActionInvoke value: ${JSON.stringify(context.activity.value)}`)); + return { status: 200 }; + } + + private async sendAdaptiveCard1(context: TurnContext): Promise { + const card = CardFactory.adaptiveCard({ + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.0", + "body": [ + { + "type": "TextBlock", + "text": "Bot Builder actions" + } + ], + "actions": [ + { + "type": "Action.Submit", + "title": "imBack", + "data": { + "msteams": { + "type": "imBack", + "value": "text" + } + } + }, + { + "type": "Action.Submit", + "title": "message back", + "data": { + "msteams": { + "type": "messageBack", + "value": { "key": "value" } + } + } + }, + { + "type": "Action.Submit", + "title": "message back local echo", + "data": { + "msteams": { + "type": "messageBack", + "text": "text received by bots", + "displayText": "display text message back", + "value": { "key": "value" } + } + }, + }, + { + "type": "Action.Submit", + "title": "invoke", + "data": { + "msteams": { + "type": "invoke", + "value": { "key": "value" } + } + } + } + ] + }); + + await context.sendActivity(MessageFactory.attachment(card)); + } + + private async sendAdaptiveCard2(context: TurnContext): Promise { + const card = CardFactory.adaptiveCard({ + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.0", + "body": [ + { + "type": "TextBlock", + "text": "Task Module Adaptive Card" + } + ], + "actions": [ + { + "type": "Action.Submit", + "title": "Launch Task Module", + "data": { + "msteams": { + "type": "invoke", + "value": { + "hiddenKey": "hidden value from task module launcher", + "type": "task/fetch" + } + } + } + } + ] + }); + + await context.sendActivity(MessageFactory.attachment(card)); + } + + private async sendAdaptiveCard3(context: TurnContext): Promise { + const card = CardFactory.adaptiveCard({ + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.0", + "body": [ + { + "type": "TextBlock", + "text": "Bot Builder actions" + }, + { + "type": "Input.Text", + "id": "x" + } + ], + "actions": [ + { + "type": "Action.Submit", + "title": "Action.Submit", + "data": { + "key": "value" + } + } + ] + }); + + await context.sendActivity(MessageFactory.attachment(card)); + } +} diff --git a/libraries/botbuilder/tests/teams/adaptiveCards/src/index.ts b/libraries/botbuilder/tests/teams/adaptiveCards/src/index.ts new file mode 100644 index 0000000000..d5633612af --- /dev/null +++ b/libraries/botbuilder/tests/teams/adaptiveCards/src/index.ts @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { config } from 'dotenv'; +import * as path from 'path'; +import * as restify from 'restify'; + +// Import required bot services. +// See https://aka.ms/bot-services to learn more about the different parts of a bot. +import { BotFrameworkAdapter } from 'botbuilder'; + +// This bot's main dialog. +import { AdaptiveCardsBot } from './adaptiveCardsBot'; + +const ENV_FILE = path.join(__dirname, '..', '.env'); +config({ path: ENV_FILE }); + +// Create HTTP server. +const server = restify.createServer(); +server.listen(process.env.port || process.env.PORT || 3978, () => { + console.log(`\n${server.name} listening to ${server.url}`); + console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`); + console.log(`\nTo test your bot, see: https://aka.ms/debug-with-emulator`); +}); + +// Create adapter. +// See https://aka.ms/about-bot-adapter to learn more about adapters. +const adapter = new BotFrameworkAdapter({ + appId: process.env.MicrosoftAppId, + appPassword: process.env.MicrosoftAppPassword +}); + +// adapter.use(new TranscriptLoggerMiddleware(new FileTranscriptStore('./transcripts'))); + +// Catch-all for errors. +adapter.onTurnError = async (context, error) => { + // This check writes out errors to console log .vs. app insights. + console.error('[onTurnError]:'); + console.error(error); + // Send a message to the user + await context.sendActivity(`Oops. Something went wrong in the bot!\n ${error.message}`); +}; + +// Create the main dialog. +const myBot = new AdaptiveCardsBot(); + +// Listen for incoming requests. +server.post('/api/messages', (req, res) => { + adapter.processActivity(req, res, async (context) => { + // Route to main dialog. + await myBot.run(context); + }); +}); diff --git a/libraries/botbuilder/tests/teams/adaptiveCards/teams-app-manifest/color.png b/libraries/botbuilder/tests/teams/adaptiveCards/teams-app-manifest/color.png new file mode 100644 index 0000000000..48a2de1330 Binary files /dev/null and b/libraries/botbuilder/tests/teams/adaptiveCards/teams-app-manifest/color.png differ diff --git a/libraries/botbuilder/tests/teams/adaptiveCards/teams-app-manifest/manifest.json b/libraries/botbuilder/tests/teams/adaptiveCards/teams-app-manifest/manifest.json new file mode 100644 index 0000000000..5b8e9d9dec --- /dev/null +++ b/libraries/botbuilder/tests/teams/adaptiveCards/teams-app-manifest/manifest.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.3/MicrosoftTeams.schema.json", + "manifestVersion": "1.3", + "version": "1.0.0", + "id": "<>", + "packageName": "com.teams.sample.echobot", + "developer": { + "name": "CardActionsBotJS", + "websiteUrl": "https://www.microsoft.com", + "privacyUrl": "https://www.teams.com/privacy", + "termsOfUseUrl": "https://www.teams.com/termsofuser" + }, + "icons": { + "color": "color.png", + "outline": "outline.png" + }, + "name": { + "short": "CardActionsBot", + "full": "CardActionsBot" + }, + "description": { + "short": "CardActionsBot", + "full": "CardActionsBot" + }, + "accentColor": "#FFFFFF", + "bots": [ + { + "botId": "<>", + "scopes": [ + "groupchat", + "team" + ], + "supportsFiles": false, + "isNotificationOnly": false + } + ], + "permissions": [ + "identity", + "messageTeamMembers" + ], + "validDomains": [] +} \ No newline at end of file diff --git a/libraries/botbuilder/tests/teams/adaptiveCards/teams-app-manifest/outline.png b/libraries/botbuilder/tests/teams/adaptiveCards/teams-app-manifest/outline.png new file mode 100644 index 0000000000..dbfa927729 Binary files /dev/null and b/libraries/botbuilder/tests/teams/adaptiveCards/teams-app-manifest/outline.png differ diff --git a/libraries/botbuilder/tests/teams/adaptiveCards/tsconfig.json b/libraries/botbuilder/tests/teams/adaptiveCards/tsconfig.json new file mode 100644 index 0000000000..a168d60662 --- /dev/null +++ b/libraries/botbuilder/tests/teams/adaptiveCards/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "es2016", + "module": "commonjs", + "composite": true, + "declaration": true, + "sourceMap": true, + "outDir": "./lib", + "rootDir": "./src", + } +} \ No newline at end of file diff --git a/libraries/botbuilder/tests/teams/fileUpload/package.json b/libraries/botbuilder/tests/teams/fileUpload/package.json index 1179cde90f..395c5279d3 100644 --- a/libraries/botbuilder/tests/teams/fileUpload/package.json +++ b/libraries/botbuilder/tests/teams/fileUpload/package.json @@ -1,5 +1,5 @@ { - "name": "messaging-extension-action", + "name": "teams-file-bot", "version": "1.0.0", "description": "", "main": "./lib/index.js", diff --git a/libraries/botbuilder/tests/teams/fileUpload/src/fileUploadBot.ts b/libraries/botbuilder/tests/teams/fileUpload/src/fileUploadBot.ts index 21a8c282d0..8e0670145f 100644 --- a/libraries/botbuilder/tests/teams/fileUpload/src/fileUploadBot.ts +++ b/libraries/botbuilder/tests/teams/fileUpload/src/fileUploadBot.ts @@ -18,7 +18,12 @@ export class FileUploadBot extends TeamsActivityHandler { // See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types. this.onMessage(async (context, next) => { - await context.sendActivity(`You said '${context.activity.text}'`); + let filename = "teams-logo.png"; + let fs = require('fs'); + let path = require('path'); + let stats = fs.statSync(path.join('files', filename)); + let fileSizeInBytes = stats['size']; + await this.sendFileCard(context, filename, fileSizeInBytes); // By calling next() you ensure that the next BotHandler is run. await next(); }); @@ -36,15 +41,6 @@ export class FileUploadBot extends TeamsActivityHandler { }); } - protected async onMessageActivity(context: TurnContext): Promise { - let filename = "teams-logo.png"; - let fs = require('fs'); - let path = require('path'); - let stats = fs.statSync(path.join('files', filename)); - let fileSizeInBytes = stats['size']; - await this.sendFileCard(context, filename, fileSizeInBytes); - } - protected async onTeamsFileConsentAccept(context: TurnContext, fileConsentCardResponse: FileConsentCardResponse): Promise { try { await this.sendFile(fileConsentCardResponse); @@ -88,8 +84,6 @@ export class FileUploadBot extends TeamsActivityHandler { } private async sendFileCard(context: TurnContext, filename: string, filesize: number): Promise { - console.log("FILESIZE " + filesize); - let fileContext = { filename: filename }; diff --git a/libraries/botbuilder/tests/teams/fileUpload/teams-app-manifest/manifest.json b/libraries/botbuilder/tests/teams/fileUpload/teams-app-manifest/manifest.json index e5a022ef9c..0c71ca0035 100644 --- a/libraries/botbuilder/tests/teams/fileUpload/teams-app-manifest/manifest.json +++ b/libraries/botbuilder/tests/teams/fileUpload/teams-app-manifest/manifest.json @@ -3,7 +3,7 @@ "manifestVersion": "1.3", "version": "1.0", "id": "<>", - "packageName": "com.microsoft.teams.samples.v4bot", + "packageName": "com.microsoft.teams.samples.filebot", "developer": { "name": "Microsoft Corp", "websiteUrl": "https://example.azurewebsites.net", diff --git a/libraries/botbuilder/tests/teams/roster/.env b/libraries/botbuilder/tests/teams/roster/.env new file mode 100644 index 0000000000..660828e3e8 --- /dev/null +++ b/libraries/botbuilder/tests/teams/roster/.env @@ -0,0 +1,2 @@ +MicrosoftAppId= +MicrosoftAppPassword= \ No newline at end of file diff --git a/libraries/botbuilder/tests/teams/roster/package.json b/libraries/botbuilder/tests/teams/roster/package.json new file mode 100644 index 0000000000..1179cde90f --- /dev/null +++ b/libraries/botbuilder/tests/teams/roster/package.json @@ -0,0 +1,30 @@ +{ + "name": "messaging-extension-action", + "version": "1.0.0", + "description": "", + "main": "./lib/index.js", + "scripts": { + "start": "tsc --build && node ./lib/index.js", + "build": "tsc --build", + "watch": "nodemon --watch ./src -e ts --exec \"npm run start\"" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "botbuilder": "file:../../../", + "dotenv": "^8.1.0", + "node-fetch": "^2.6.0", + "restify": "^8.4.0", + "uuid": "^3.3.3" + }, + "devDependencies": { + "@types/node": "^12.7.1", + "@types/node-fetch": "^2.5.0", + "@types/request": "^2.48.1", + "@types/restify": "^7.2.7", + "nodemon": "^1.19.1", + "ts-node": "^7.0.1", + "typescript": "^3.2.4" + } +} diff --git a/libraries/botbuilder/tests/teams/roster/src/index.ts b/libraries/botbuilder/tests/teams/roster/src/index.ts new file mode 100644 index 0000000000..fd8aa08817 --- /dev/null +++ b/libraries/botbuilder/tests/teams/roster/src/index.ts @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { config } from 'dotenv'; +import * as path from 'path'; +import * as restify from 'restify'; + +// Import required bot services. +// See https://aka.ms/bot-services to learn more about the different parts of a bot. +import { BotFrameworkAdapter } from 'botbuilder'; + +// This bot's main dialog. +import { RosterBot } from './rosterBot'; + +const ENV_FILE = path.join(__dirname, '..', '.env'); +config({ path: ENV_FILE }); + +// Create HTTP server. +const server = restify.createServer(); +server.listen(process.env.port || process.env.PORT || 3978, () => { + console.log(`\n${server.name} listening to ${server.url}`); + console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`); + console.log(`\nTo test your bot, see: https://aka.ms/debug-with-emulator`); +}); + +// Create adapter. +// See https://aka.ms/about-bot-adapter to learn more about adapters. +const adapter = new BotFrameworkAdapter({ + appId: process.env.MicrosoftAppId, + appPassword: process.env.MicrosoftAppPassword +}); + +// adapter.use(new TranscriptLoggerMiddleware(new FileTranscriptStore('./transcripts'))); + +// Catch-all for errors. +adapter.onTurnError = async (context, error) => { + // This check writes out errors to console log .vs. app insights. + console.error('[onTurnError]:'); + console.error(error); + // Send a message to the user + await context.sendActivity(`Oops. Something went wrong in the bot!\n ${error.message}`); +}; + +// Create the main dialog. +const myBot = new RosterBot(); + +// Listen for incoming requests. +server.post('/api/messages', (req, res) => { + adapter.processActivity(req, res, async (context) => { + // Route to main dialog. + await myBot.run(context); + }); +}); diff --git a/libraries/botbuilder/tests/teams/roster/src/rosterBot.ts b/libraries/botbuilder/tests/teams/roster/src/rosterBot.ts new file mode 100644 index 0000000000..b12869aea2 --- /dev/null +++ b/libraries/botbuilder/tests/teams/roster/src/rosterBot.ts @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { + Activity, + Attachment, + CardFactory, + TeamsActivityHandler, + TurnContext +} from 'botbuilder'; + +export class RosterBot extends TeamsActivityHandler { + constructor() { + super(); + + // See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types. + this.onMessage(async (context, next) => { + await context.sendActivity(`You said '${context.activity.text}'`); + // By calling next() you ensure that the next BotHandler is run. + await next(); + }); + + this.onMembersAdded(async (context, next) => { + const membersAdded = context.activity.membersAdded; + for (const member of membersAdded) { + if (member.id !== context.activity.recipient.id) { + await context.sendActivity('Hello and welcome!'); + } + } + + // By calling next() you ensure that the next BotHandler is run. + await next(); + }); + } + + protected async onMessageActivity(context: TurnContext): Promise { + await context.sendActivity(this.createReply(context.activity, `Echo: ${context.activity.text}this.createReply(context.activity)`)); + TurnContext.removeRecipientMention(context.activity); + + switch (context.activity.text) + { + case "show members": + await this.showMembers(context); + break; + + case "show channels": + await this.showChannels(context); + break; + + case "show details": + await this.showDetails(context); + break; + + default: + await context.sendActivity(this.createReply(context.activity, + 'Invalid command. Type "Show channels" to see a channel list. Type "Show members" to see a list of members in a team. ' + + 'Type "show group chat members" to see members in a group chat.')); + break; + } + } + + private createReply(activity, text = null, locale = null) : Activity { + return { + type: 'message', + from: { id: activity.recipient.id, name: activity.recipient.name }, + recipient: { id: activity.from.id, name: activity.from.name }, + replyToId: activity.id, + serviceUrl: activity.serviceUrl, + channelId: activity.channelId, + conversation: { isGroup: activity.conversation.isGroup, id: activity.conversation.id, name: activity.conversation.name }, + text: text || '', + locale: locale || activity.locale + } as Activity; + } + + private async showMembers(context: TurnContext): Promise { + let teamsChannelAccounts = await this.getMembers(context); + let replyActivity = this.createReply(context.activity, `Total of ${teamsChannelAccounts.length} members are currently in team`); + await context.sendActivity(replyActivity); + + var messages = teamsChannelAccounts.map(function(teamsChannelAccount){ + return `${teamsChannelAccount.AadObjectId} --> ${teamsChannelAccount.Name} --> ${teamsChannelAccount.UserPrincipalName}`; + }); + + await this.sendInBatches(context, messages); + } + + private async showChannels(context: TurnContext): Promise { + let channels = await this.getChannels(context); + await context.sendActivity(this.createReply(context.activity, `Total of ${channels.length} channels are currently in team`)); + + var messages = channels.map(function(channel){ + return `${channel.aadObjectId} --> ${channel.name} --> ${channel.userPrincipalName}`; + }); + + await this.sendInBatches(context, messages); + } + + private async showDetails(context: TurnContext): Promise { + let teamDetails = await this.getTeamDetails(context); + var replyActivity = this.createReply(context.activity, `The team name is ${teamDetails.Name}. The team ID is ${teamDetails.Id}. The AAD GroupID is ${teamDetails.AadGroupId}.`); + await context.sendActivity(replyActivity); + } + + private async getMembers(context: TurnContext): Promise { + return null; + } + + private async getChannels(context: TurnContext): Promise { + return null; + } + + private async getTeamDetails(context: TurnContext): Promise { + return null; + } + + private async sendInBatches(context: TurnContext, messages: string[]): Promise { + let batch: string[] = []; + messages.forEach(async (msg: string) => { + batch.push(msg); + if (batch.length == 10) { + await context.sendActivity(this.createReply(context.activity, batch.join('
'))); + batch = []; + } + }); + + if (batch.length > 0) + { + await context.sendActivity(this.createReply(context.activity, batch.join('
'))); + } + } +} diff --git a/libraries/botbuilder/tests/teams/roster/teams-app-manifest/color.png b/libraries/botbuilder/tests/teams/roster/teams-app-manifest/color.png new file mode 100644 index 0000000000..48a2de1330 Binary files /dev/null and b/libraries/botbuilder/tests/teams/roster/teams-app-manifest/color.png differ diff --git a/libraries/botbuilder/tests/teams/roster/teams-app-manifest/manifest.json b/libraries/botbuilder/tests/teams/roster/teams-app-manifest/manifest.json new file mode 100644 index 0000000000..8430e729e0 --- /dev/null +++ b/libraries/botbuilder/tests/teams/roster/teams-app-manifest/manifest.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.3/MicrosoftTeams.schema.json", + "manifestVersion": "1.3", + "version": "1.0.0", + "id": "", + "packageName": "com.teams.sample.echobot", + "developer": { + "name": "TeamsRosterBot", + "websiteUrl": "https://www.microsoft.com", + "privacyUrl": "https://www.teams.com/privacy", + "termsOfUseUrl": "https://www.teams.com/termsofuser" + }, + "icons": { + "color": "color.png", + "outline": "outline.png" + }, + "name": { + "short": "TeamsRosterBot", + "full": "TeamsRosterBot" + }, + "description": { + "short": "TeamsRosterBot", + "full": "TeamsRosterBot" + }, + "accentColor": "#FFFFFF", + "bots": [ + { + "botId": "", + "scopes": [ + "groupchat", + "team" + ], + "supportsFiles": false, + "isNotificationOnly": false + } + ], + "permissions": [ + "identity", + "messageTeamMembers" + ], + "validDomains": [] +} \ No newline at end of file diff --git a/libraries/botbuilder/tests/teams/roster/teams-app-manifest/outline.png b/libraries/botbuilder/tests/teams/roster/teams-app-manifest/outline.png new file mode 100644 index 0000000000..dbfa927729 Binary files /dev/null and b/libraries/botbuilder/tests/teams/roster/teams-app-manifest/outline.png differ diff --git a/libraries/botbuilder/tests/teams/roster/tsconfig.json b/libraries/botbuilder/tests/teams/roster/tsconfig.json new file mode 100644 index 0000000000..a168d60662 --- /dev/null +++ b/libraries/botbuilder/tests/teams/roster/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "es2016", + "module": "commonjs", + "composite": true, + "declaration": true, + "sourceMap": true, + "outDir": "./lib", + "rootDir": "./src", + } +} \ No newline at end of file