diff --git a/libraries/botbuilder/tests/teams/link-unfurling/.env b/libraries/botbuilder/tests/teams/link-unfurling/.env new file mode 100644 index 0000000000..a695b3bf05 --- /dev/null +++ b/libraries/botbuilder/tests/teams/link-unfurling/.env @@ -0,0 +1,2 @@ +MicrosoftAppId= +MicrosoftAppPassword= diff --git a/libraries/botbuilder/tests/teams/link-unfurling/.gitignore b/libraries/botbuilder/tests/teams/link-unfurling/.gitignore new file mode 100644 index 0000000000..a6d1e8839d --- /dev/null +++ b/libraries/botbuilder/tests/teams/link-unfurling/.gitignore @@ -0,0 +1,4 @@ +lib/ +node_modules/ +.vscode/ +**/*.zip \ No newline at end of file diff --git a/libraries/botbuilder/tests/teams/link-unfurling/package.json b/libraries/botbuilder/tests/teams/link-unfurling/package.json new file mode 100644 index 0000000000..8cf8e224ce --- /dev/null +++ b/libraries/botbuilder/tests/teams/link-unfurling/package.json @@ -0,0 +1,30 @@ +{ + "name": "teams-link-unfurling", + "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/link-unfurling/src/index.ts b/libraries/botbuilder/tests/teams/link-unfurling/src/index.ts new file mode 100644 index 0000000000..e5a3ce3b29 --- /dev/null +++ b/libraries/botbuilder/tests/teams/link-unfurling/src/index.ts @@ -0,0 +1,51 @@ +// 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 { LinkUnfurlingBot } from './linkUnfurling'; + +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 +}); + +// 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 LinkUnfurlingBot(); + +// 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/link-unfurling/src/linkUnfurling.ts b/libraries/botbuilder/tests/teams/link-unfurling/src/linkUnfurling.ts new file mode 100644 index 0000000000..add54d07cf --- /dev/null +++ b/libraries/botbuilder/tests/teams/link-unfurling/src/linkUnfurling.ts @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { + AppBasedLinkQuery, + CardFactory, + MessagingExtensionResponse, + MessagingExtensionResult, + TeamsActivityHandler, + TurnContext } +from 'botbuilder'; + +export class LinkUnfurlingBot 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(); + }); + } + + // "Link Unfurling" + // This handler is used for the processing of "composeExtension/queryLink" activities from Teams. + // https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/messaging-extensions/search-extensions#receive-requests-from-links-inserted-into-the-compose-message-box + // By specifying domains under the messageHandlers section in the manifest, the bot can receive + // events when a user enters in a domain in the compose box. + protected async onTeamsAppBasedLinkQuery(context: TurnContext, query: AppBasedLinkQuery): Promise { + const attachment = CardFactory.thumbnailCard('Thumbnail Card', query.url, ["https://raw.githubusercontent.com/microsoft/botframework-sdk/master/icon.png"]); + + const result: MessagingExtensionResult = { + attachmentLayout: 'list', + type: 'result', + attachments: [attachment], + text: 'test unfurl', + } + const response: MessagingExtensionResponse = { + composeExtension: result, + } + + return response; + } +} diff --git a/libraries/botbuilder/tests/teams/link-unfurling/teams-app-manifest/color.png b/libraries/botbuilder/tests/teams/link-unfurling/teams-app-manifest/color.png new file mode 100644 index 0000000000..48a2de1330 Binary files /dev/null and b/libraries/botbuilder/tests/teams/link-unfurling/teams-app-manifest/color.png differ diff --git a/libraries/botbuilder/tests/teams/link-unfurling/teams-app-manifest/manifest.json b/libraries/botbuilder/tests/teams/link-unfurling/teams-app-manifest/manifest.json new file mode 100644 index 0000000000..590276efa2 --- /dev/null +++ b/libraries/botbuilder/tests/teams/link-unfurling/teams-app-manifest/manifest.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://github.com/OfficeDev/microsoft-teams-app-schema/blob/preview/DevPreview/MicrosoftTeams.schema.json", + "manifestVersion": "1.5", + "version": "1.0", + "id": "<>", + "packageName": "com.teams.sample.linkunfurling", + "developer": { + "name": "Link Unfurling1", + "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": "Link Unfurling1", + "full": "Link Unfurling" + }, + "description": { + "short": "Link Unfurling", + "full": "Link Unfurling" + }, + "accentColor": "#FFFFFF", + "bots": [ + { + "botId": "<>", + "scopes": [ "personal", "team" ] + } + ], + "composeExtensions": [ + { + "botId": "<>", + "commands": [ + { + "id": "searchQuery", + "context": [ "compose", "commandBox" ], + "description": "Superfluous Test command to enable link unfurling", + "title": "Search", + "type": "query", + "parameters": [ + { + "name": "searchQuery", + "title": "Search Query", + "description": "Your search query", + "inputType": "text" + } + ] + } + ], + "messageHandlers": [ + { + "type": "link", + "value": { + "domains": [ + "*.com" + ] + } + } + ] + } + ] +} diff --git a/libraries/botbuilder/tests/teams/link-unfurling/teams-app-manifest/outline.png b/libraries/botbuilder/tests/teams/link-unfurling/teams-app-manifest/outline.png new file mode 100644 index 0000000000..dbfa927729 Binary files /dev/null and b/libraries/botbuilder/tests/teams/link-unfurling/teams-app-manifest/outline.png differ diff --git a/libraries/botbuilder/tests/teams/link-unfurling/tsconfig.json b/libraries/botbuilder/tests/teams/link-unfurling/tsconfig.json new file mode 100644 index 0000000000..a168d60662 --- /dev/null +++ b/libraries/botbuilder/tests/teams/link-unfurling/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