diff --git a/samples/51.teams-messaging-extensions-action/README.md b/samples/51.teams-messaging-extensions-action/README.md
index eed334ee..29cf1f85 100644
--- a/samples/51.teams-messaging-extensions-action/README.md
+++ b/samples/51.teams-messaging-extensions-action/README.md
@@ -3,8 +3,8 @@
Bot Framework v4 Conversation Bot sample for Teams.
-This bot has been created using [Bot Framework](https://dev.botframework.com). This sample shows
-how to incorporate basic conversational flow into a Teams application. It also illustrates a few of the Teams specific calls you can make from your bot.
+There are two basic types of Messaging Extension in Teams: [Search-based](https://docs.microsoft.com/en-us/microsoftteams/platform/messaging-extensions/how-to/search-commands/define-search-command) and [Action-based](https://docs.microsoft.com/en-us/microsoftteams/platform/messaging-extensions/how-to/action-commands/define-action-command). This sample illustrates how to
+build an Action-based Messaging Extension.
## Prerequisites
@@ -48,23 +48,13 @@ the Teams service needs to call into the bot.
## Interacting with the bot
-You can interact with this bot by sending it a message, or selecting a command from the command list. The bot will respond to the following strings.
+> Note this `manifest.json` specified that the bot will be called from both the `compose` and `message` areas of Teams. Please refer to Teams documentation for more details.
-1. **Show Welcome**
- - **Result:** The bot will send the welcome card for you to interact with
- - **Valid Scopes:** personal, group chat, team chat
-2. **MentionMe**
- - **Result:** The bot will respond to the message and mention the user
- - **Valid Scopes:** personal, group chat, team chat
-3. **MessageAllMembers**
- - **Result:** The bot will send a 1-on-1 message to each member in the current conversation (aka on the conversation's roster).
- - **Valid Scopes:** personal, group chat, team chat
+1) Selecting the **Create Card** command from the Compose Box command list. The parameters dialog will be displayed and can be submitted to initiate the card creation within the Messaging Extension code.
-You can select an option from the command list by typing ```@TeamsConversationBot``` into the compose message area and ```What can I do?``` text above the compose area.
+or
-### Avoiding Permission-Related Errors
-
-You may encounter permission-related errors when sending a proactive message. This can often be mitigated by using `MicrosoftAppCredentials.TrustServiceUrl()`. See [the documentation](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-proactive-message?view=azure-bot-service-4.0&tabs=csharp#avoiding-401-unauthorized-errors) for more information.
+2) Selecting the **Share Message** command from the Message command list.
## Deploy the bot to Azure
diff --git a/samples/51.teams-messaging-extensions-action/src/main/java/com/microsoft/bot/sample/teamsaction/Application.java b/samples/51.teams-messaging-extensions-action/src/main/java/com/microsoft/bot/sample/teamsaction/Application.java
index d7e43318..c4931047 100644
--- a/samples/51.teams-messaging-extensions-action/src/main/java/com/microsoft/bot/sample/teamsaction/Application.java
+++ b/samples/51.teams-messaging-extensions-action/src/main/java/com/microsoft/bot/sample/teamsaction/Application.java
@@ -14,11 +14,11 @@ import org.springframework.context.annotation.Import;
/**
* This is the starting point of the Sprint Boot Bot application.
+ *
+ * This class also provides overrides for dependency injections. A class that extends the {@link
+ * com.microsoft.bot.builder.Bot} interface should be annotated with @Component.
*
- * This class also provides overrides for dependency injections. A class that extends the
- * {@link com.microsoft.bot.builder.Bot} interface should be annotated with @Component.
- *
- * @see TeamsConversationBot
+ * @see TeamsMessagingExtensionsActionBot
*/
@SpringBootApplication
@@ -29,6 +29,7 @@ import org.springframework.context.annotation.Import;
@Import({BotController.class})
public class Application extends BotDependencyConfiguration {
+
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
diff --git a/samples/51.teams-messaging-extensions-action/src/main/java/com/microsoft/bot/sample/teamsaction/TeamsMessagingExtensionsActionBot.java b/samples/51.teams-messaging-extensions-action/src/main/java/com/microsoft/bot/sample/teamsaction/TeamsMessagingExtensionsActionBot.java
index ed13ac0e..867fb466 100644
--- a/samples/51.teams-messaging-extensions-action/src/main/java/com/microsoft/bot/sample/teamsaction/TeamsMessagingExtensionsActionBot.java
+++ b/samples/51.teams-messaging-extensions-action/src/main/java/com/microsoft/bot/sample/teamsaction/TeamsMessagingExtensionsActionBot.java
@@ -3,210 +3,109 @@
package com.microsoft.bot.sample.teamsaction;
-import com.codepoetics.protonpack.collectors.CompletableFutures;
-import com.microsoft.bot.builder.BotFrameworkAdapter;
-import com.microsoft.bot.builder.MessageFactory;
import com.microsoft.bot.builder.TurnContext;
import com.microsoft.bot.builder.teams.TeamsActivityHandler;
-import com.microsoft.bot.builder.teams.TeamsInfo;
-import com.microsoft.bot.connector.authentication.MicrosoftAppCredentials;
-import com.microsoft.bot.integration.Configuration;
-import com.microsoft.bot.schema.ActionTypes;
-import com.microsoft.bot.schema.Activity;
-import com.microsoft.bot.schema.CardAction;
-import com.microsoft.bot.schema.ConversationParameters;
-import com.microsoft.bot.schema.ConversationReference;
+import com.microsoft.bot.schema.CardImage;
import com.microsoft.bot.schema.HeroCard;
-import com.microsoft.bot.schema.Mention;
-import com.microsoft.bot.schema.teams.TeamInfo;
-import com.microsoft.bot.schema.teams.TeamsChannelAccount;
-import org.apache.commons.lang3.StringUtils;
+import com.microsoft.bot.schema.teams.*;
import org.springframework.stereotype.Component;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.concurrent.CompletableFuture;
/**
* This class implements the functionality of the Bot.
*
*
This is where application specific logic for interacting with the users would be
- * added. For this sample, the {@link #onMessageActivity(TurnContext)} echos the text
- * back to the user. The {@link #onMembersAdded(List, TurnContext)} will send a greeting
- * to new conversation participants.
+ * added. There are two basic types of Messaging Extension in Teams: Search-based and Action-based.
+ * This sample illustrates how to build an Action-based Messaging Extension.
*/
@Component
public class TeamsMessagingExtensionsActionBot extends TeamsActivityHandler {
- private String appId;
- private String appPassword;
-
- public TeamsMessagingExtensionsActionBot(Configuration configuration) {
- appId = configuration.getProperty("MicrosoftAppId");
- appPassword = configuration.getProperty("MicrosoftAppPassword");
- }
-
@Override
- protected CompletableFuture onMessageActivity(TurnContext turnContext) {
- turnContext.getActivity().removeRecipientMention();
-
- switch (turnContext.getActivity().getText().trim()) {
- case "MentionMe":
- return mentionActivity(turnContext);
-
- case "UpdateCardAction":
- return updateCardActivity(turnContext);
-
- case "Delete":
- return deleteCardActivity(turnContext);
-
- case "MessageAllMembers":
- return messageAllMembers(turnContext);
+ protected CompletableFuture onTeamsMessagingExtensionSubmitAction(
+ TurnContext turnContext,
+ MessagingExtensionAction action
+ ) {
+ switch (action.getCommandId()) {
+ // These commandIds are defined in the Teams App Manifest.
+ case "createCard":
+ return createCardCommand(turnContext, action);
+ case "shareMessage":
+ return shareMessageCommand(turnContext, action);
default:
- // This will come back deserialized as a Map.
- Object value = new Object() {
- int count = 0;
- };
-
- HeroCard card = new HeroCard() {{
- setTitle("Welcome Card");
- setText("Click the buttons below to update this card");
- setButtons(Arrays.asList(
- new CardAction() {{
- setType(ActionTypes.MESSAGE_BACK);
- setTitle("Update Card");
- setText("UpdateCardAction");
- setValue(value);
- }},
- new CardAction() {{
- setType(ActionTypes.MESSAGE_BACK);
- setTitle("Message All Members");
- setText("MessageAllMembers");
- }}
- ));
- }};
-
- return turnContext.sendActivity(MessageFactory.attachment(card.toAttachment()))
- .thenApply(resourceResponse -> null);
+ return notImplemented(
+ String.format("Invalid CommandId: %s", action.getCommandId()));
}
}
- @Override
- protected CompletableFuture onTeamsMembersAdded(
- List membersAdded,
- TeamInfo teamInfo,
- TurnContext turnContext
+ private CompletableFuture createCardCommand(
+ TurnContext turnContext,
+ MessagingExtensionAction action
) {
- return membersAdded.stream()
- .filter(member -> !StringUtils.equals(member.getId(), turnContext.getActivity().getRecipient().getId()))
- .map(channel -> turnContext.sendActivity(
- MessageFactory.text("Welcome to the team " + channel.getGivenName() + " " + channel.getSurname() + ".")))
- .collect(CompletableFutures.toFutureList())
- .thenApply(resourceResponses -> null);
- }
-
- private CompletableFuture deleteCardActivity(TurnContext turnContext) {
- return turnContext.deleteActivity(turnContext.getActivity().getReplyToId());
- }
-
- // If you encounter permission-related errors when sending this message, see
- // https://aka.ms/BotTrustServiceUrl
- private CompletableFuture messageAllMembers(TurnContext turnContext) {
- String teamsChannelId = turnContext.getActivity().teamsGetChannelId();
- String serviceUrl = turnContext.getActivity().getServiceUrl();
- MicrosoftAppCredentials credentials = new MicrosoftAppCredentials(appId, appPassword);
-
- return TeamsInfo.getMembers(turnContext)
- .thenCompose(members -> {
- List> conversations = new ArrayList<>();
-
- // Send a message to each member. These will all go out
- // at the same time.
- for (TeamsChannelAccount member : members) {
- Activity proactiveMessage = MessageFactory.text(
- "Hello " + member.getGivenName() + " " + member.getSurname()
- + ". I'm a Teams conversation bot.");
-
- ConversationParameters conversationParameters = new ConversationParameters() {{
- setIsGroup(false);
- setBot(turnContext.getActivity().getRecipient());
- setMembers(Collections.singletonList(member));
- setTenantId(turnContext.getActivity().getConversation().getTenantId());
- }};
-
- conversations.add(
- ((BotFrameworkAdapter) turnContext.getAdapter()).createConversation(
- teamsChannelId,
- serviceUrl,
- credentials,
- conversationParameters,
- (context) -> {
- ConversationReference reference = context.getActivity().getConversationReference();
- return context.getAdapter().continueConversation(
- appId,
- reference,
- (inner_context) -> inner_context.sendActivity(proactiveMessage)
- .thenApply(resourceResponse -> null)
- );
- }
- )
- );
- }
-
- return CompletableFuture.allOf(conversations.toArray(new CompletableFuture[0]));
- })
- // After all member messages are sent, send confirmation to the user.
- .thenApply(conversations -> turnContext.sendActivity(MessageFactory.text("All messages have been sent.")))
- .thenApply(allSent -> null);
- }
-
- private CompletableFuture updateCardActivity(TurnContext turnContext) {
- Map data = (Map) turnContext.getActivity().getValue();
- data.put("count", (int) data.get("count") + 1);
+ Map actionData = (Map) action.getData();
HeroCard card = new HeroCard() {{
- setTitle("Welcome Card");
- setText("Update count - " + data.get("count"));
- setButtons(Arrays.asList(
- new CardAction() {{
- setType(ActionTypes.MESSAGE_BACK);
- setTitle("Update Card");
- setText("UpdateCardAction");
- setValue(data);
- }},
- new CardAction() {{
- setType(ActionTypes.MESSAGE_BACK);
- setTitle("Message All Members");
- setText("MessageAllMembers");
- }},
- new CardAction() {{
- setType(ActionTypes.MESSAGE_BACK);
- setTitle("Delete card");
- setText("Delete");
- }}
- ));
+ setTitle(actionData.get("title"));
+ setSubtitle(actionData.get("subTitle"));
+ setText(actionData.get("text"));
}};
- Activity updatedActivity = MessageFactory.attachment(card.toAttachment());
- updatedActivity.setId(turnContext.getActivity().getReplyToId());
+ List attachments = Arrays
+ .asList(new MessagingExtensionAttachment() {{
+ setContent(card);
+ setContentType(HeroCard.CONTENTTYPE);
+ setPreview(card.toAttachment());
+ }});
- return turnContext.updateActivity(updatedActivity)
- .thenApply(resourceResponse -> null);
+ return CompletableFuture.completedFuture(new MessagingExtensionActionResponse() {{
+ setComposeExtension(new MessagingExtensionResult() {{
+ setAttachments(attachments);
+ setAttachmentLayout("list");
+ setType("result");
+ }});
+ }});
}
- private CompletableFuture mentionActivity(TurnContext turnContext) {
- Mention mention = new Mention();
- mention.setMentioned(turnContext.getActivity().getFrom());
- mention.setText("" + URLEncoder.encode(turnContext.getActivity().getFrom().getName()) + "");
+ private CompletableFuture shareMessageCommand(
+ TurnContext turnContext,
+ MessagingExtensionAction action
+ ) {
+ Map actionData = (Map) action.getData();
- Activity replyActivity = MessageFactory.text("Hello " + mention.getText() + ".'");
- replyActivity.setMentions(Collections.singletonList(mention));
+ HeroCard card = new HeroCard() {{
+ setTitle(
+ action.getMessagePayload().getFrom().getUser() != null ? action.getMessagePayload()
+ .getFrom().getUser().getDisplayName() : "");
+ setText(action.getMessagePayload().getBody().getContent());
+ }};
- return turnContext.sendActivity(replyActivity)
- .thenApply(resourceResponse -> null);
+ if (action.getMessagePayload().getAttachments() != null && !action.getMessagePayload()
+ .getAttachments().isEmpty()) {
+ card.setSubtitle("Attachments not included)");
+ }
+
+ boolean includeImage = actionData.get("includeImage") != null ? (
+ Boolean.valueOf(actionData.get("includeImage"))
+ ) : false;
+ if (includeImage) {
+ card.setImages(Arrays.asList(new CardImage() {{
+ setUrl(
+ "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQtB3AwMUeNoq4gUBGe6Ocj8kyh3bXa9ZbV7u1fVKQoyKFHdkqU");
+ }}));
+ }
+
+ return CompletableFuture.completedFuture(new MessagingExtensionActionResponse() {{
+ setComposeExtension(new MessagingExtensionResult() {{
+ setAttachmentLayout("list");
+ setType("result");
+ setAttachments(Arrays.asList(new MessagingExtensionAttachment() {{
+ setContent(card);
+ setContentType(HeroCard.CONTENTTYPE);
+ setPreview(card.toAttachment());
+ }}));
+ }});
+ }});
}
}
diff --git a/samples/51.teams-messaging-extensions-action/teamsAppManifest/manifest.json b/samples/51.teams-messaging-extensions-action/teamsAppManifest/manifest.json
index 0dcba156..6faf2f43 100644
--- a/samples/51.teams-messaging-extensions-action/teamsAppManifest/manifest.json
+++ b/samples/51.teams-messaging-extensions-action/teamsAppManifest/manifest.json
@@ -1,78 +1,78 @@
{
- "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json",
- "manifestVersion": "1.5",
- "version": "1.0",
- "id": "<>",
- "packageName": "com.microsoft.teams.samples",
- "developer": {
- "name": "Microsoft",
- "websiteUrl": "https://dev.botframework.com",
- "privacyUrl": "https://privacy.microsoft.com",
- "termsOfUseUrl": "https://www.microsoft.com/en-us/legal/intellectualproperty/copyright/default.aspx"
- },
- "name": {
- "short": "Action Messaging Extension",
- "full": "Microsoft Teams Action Based Messaging Extension"
- },
- "description": {
- "short": "Sample demonstrating an Action Based Messaging Extension",
- "full": "Sample Action Messaging Extension built with the Bot Builder SDK"
- },
- "icons": {
- "outline": "icon-outline.png",
- "color": "icon-color.png"
- },
- "accentColor": "#FFFFFF",
- "composeExtensions": [
- {
- "botId": "<>",
- "commands": [
+ "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json",
+ "manifestVersion": "1.5",
+ "version": "1.0",
+ "id": "<>",
+ "packageName": "com.microsoft.teams.samples",
+ "developer": {
+ "name": "Microsoft",
+ "websiteUrl": "https://dev.botframework.com",
+ "privacyUrl": "https://privacy.microsoft.com",
+ "termsOfUseUrl": "https://www.microsoft.com/en-us/legal/intellectualproperty/copyright/default.aspx"
+ },
+ "name": {
+ "short": "Action Messaging Extension",
+ "full": "Microsoft Teams Action Based Messaging Extension"
+ },
+ "description": {
+ "short": "Sample demonstrating an Action Based Messaging Extension",
+ "full": "Sample Action Messaging Extension built with the Bot Builder SDK"
+ },
+ "icons": {
+ "outline": "icon-outline.png",
+ "color": "icon-color.png"
+ },
+ "accentColor": "#FFFFFF",
+ "composeExtensions": [
{
- "id": "createCard",
- "type": "action",
- "context": [ "compose" ],
- "description": "Command to run action to create a Card from Compose Box",
- "title": "Create Card",
- "parameters": [
- {
- "name": "title",
- "title": "Card title",
- "description": "Title for the card",
- "inputType": "text"
- },
- {
- "name": "subTitle",
- "title": "Subtitle",
- "description": "Subtitle for the card",
- "inputType": "text"
- },
- {
- "name": "text",
- "title": "Text",
- "description": "Text for the card",
- "inputType": "textarea"
- }
- ]
- },
- {
- "id": "shareMessage",
- "type": "action",
- "context": [ "message" ],
- "description": "Test command to run action on message context (message sharing)",
- "title": "Share Message",
- "parameters": [
- {
- "name": "includeImage",
- "title": "Include Image",
- "description": "Include image in Hero Card",
- "inputType": "toggle"
- }
- ]
+ "botId": "<>",
+ "commands": [
+ {
+ "id": "createCard",
+ "type": "action",
+ "context": [ "compose" ],
+ "description": "Command to run action to create a Card from Compose Box",
+ "title": "Create Card",
+ "parameters": [
+ {
+ "name": "title",
+ "title": "Card title",
+ "description": "Title for the card",
+ "inputType": "text"
+ },
+ {
+ "name": "subTitle",
+ "title": "Subtitle",
+ "description": "Subtitle for the card",
+ "inputType": "text"
+ },
+ {
+ "name": "text",
+ "title": "Text",
+ "description": "Text for the card",
+ "inputType": "textarea"
+ }
+ ]
+ },
+ {
+ "id": "shareMessage",
+ "type": "action",
+ "context": [ "message" ],
+ "description": "Test command to run action on message context (message sharing)",
+ "title": "Share Message",
+ "parameters": [
+ {
+ "name": "includeImage",
+ "title": "Include Image",
+ "description": "Include image in Hero Card",
+ "inputType": "toggle"
+ }
+ ]
+ }
+ ]
}
- ]
- }
- ],
- "permissions": [
- "identity"
- ]
+ ],
+ "permissions": [
+ "identity"
+ ]
}