/// <summary> /// Called when the dialog is started and pushed onto the dialog stack. /// </summary> /// <param name="dc">The <see cref="DialogContext"/> for the current turn of conversation.</param> /// <param name="options">Optional, initial information to pass to the dialog.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) { if (options is CancellationToken) { throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); } if (Disabled != null && Disabled.GetValue(dc.State) == true) { return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false)); } string message = Message.GetValueOrNull(dc.State); if (string.IsNullOrEmpty(message)) { throw new ArgumentException($"A {nameof(Message)} is required for {Kind}."); } var response = new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = MessagingExtensionResultResponseType.message.ToString(), Text = message, }, CacheInfo = GetCacheInfo(dc) }; var invokeResponse = CreateInvokeResponseActivity(response); ResourceResponse sendResponse = await dc.Context.SendActivityAsync(invokeResponse, cancellationToken : cancellationToken).ConfigureAwait(false); return(await dc.EndDialogAsync(sendResponse, cancellationToken : cancellationToken).ConfigureAwait(false)); }
protected override Task <MessagingExtensionResponse> OnTeamsMessagingExtensionQueryAsync(ITurnContext <IInvokeActivity> turnContext, MessagingExtensionQuery query, CancellationToken cancellationToken) { var title = ""; var titleParam = query.Parameters?.FirstOrDefault(p => p.Name == "cardTitle"); if (titleParam != null) { title = titleParam.Value.ToString(); } if (query == null || query.CommandId != "getRandomText") { // We only process the 'getRandomText' queries with this message extension throw new NotImplementedException($"Invalid CommandId: {query.CommandId}"); } var attachments = new MessagingExtensionAttachment[5]; for (int i = 0; i < 5; i++) { attachments[i] = GetAttachment(title); } var result = new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { AttachmentLayout = "list", Type = "result", Attachments = attachments.ToList() }, }; return(Task.FromResult(result)); }
protected override async Task <MessagingExtensionResponse> OnTeamsMessagingExtensionSelectItemAsync(ITurnContext <IInvokeActivity> turnContext, JObject query, CancellationToken cancellationToken) { var searchQuery = query.ToObject <SearchQuery>(); var bfLogo = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQtB3AwMUeNoq4gUBGe6Ocj8kyh3bXa9ZbV7u1fVKQoyKFHdkqU"; var card = new HeroCard { Title = $"You selected a search result!", Text = $"You searched for \"{searchQuery.Query}\"", Images = new List <CardImage> { new CardImage { Url = bfLogo } } }; var attachment = new MessagingExtensionAttachment { ContentType = HeroCard.ContentType, Content = card }; var messagingExtensionResponse = new MessagingExtensionResponse(); messagingExtensionResponse.ComposeExtension = CreateMessagingExtensionResult(new List <MessagingExtensionAttachment> { attachment }); return(messagingExtensionResponse); }
/// <inheritdoc/> protected override Task <MessagingExtensionResponse> OnTeamsMessagingExtensionConfigurationQuerySettingUrlAsync( ITurnContext <IInvokeActivity> turnContext, MessagingExtensionQuery query, CancellationToken cancellationToken) { var openSettingAction = new CardAction { Type = ActionTypes.OpenUrl, Value = $"{this.appSettings.BaseUrl}/mesettings", }; // ME Result. var result = new MessagingExtensionResult { Type = "config", SuggestedActions = new MessagingExtensionSuggestedAction { Actions = new List <CardAction> { openSettingAction }, }, }; // ME response. var response = new MessagingExtensionResponse() { ComposeExtension = result, }; return(Task.FromResult(response)); }
/// <summary> /// Open the Messaging Extension Configuration Page /// </summary> /// <param name="turnContext">The turn context.</param> /// <param name="query">The matched url.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>A Task resolving to the settings / logout page </returns> /// <remarks> /// For more information on Link Unfurling see the documentation /// https://docs.microsoft.com/en-us/microsoftteams/platform/messaging-extensions/how-to/link-unfurling?tabs=dotnet /// </remarks> protected override Task <MessagingExtensionResponse> OnTeamsMessagingExtensionConfigurationQuerySettingUrlAsync( ITurnContext <IInvokeActivity> turnContext, MessagingExtensionQuery query, CancellationToken cancellationToken) { var messagingExtensionReponse = new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "config", SuggestedActions = new MessagingExtensionSuggestedAction { Actions = new List <CardAction> { new CardAction { Type = ActionTypes.OpenUrl, Value = this.options.Value.SettingsPageUrl, }, }, }, }, }; return(Task.FromResult(messagingExtensionReponse)); }
public void MessagingExtensionResponseInitsWithNoArgs() { var msgExtResponse = new MessagingExtensionResponse(); Assert.NotNull(msgExtResponse); Assert.IsType <MessagingExtensionResponse>(msgExtResponse); }
/// <summary> /// Prepares a message extension response with sign-in action as compose extension. /// </summary> /// <param name="signInUrl">Sign-in url.</param> /// <returns>Messaging extension response.</returns> private MessagingExtensionResponse GetSignInResponse(string signInUrl) { // Sign-in action. var signInAction = new CardAction { Type = ActionTypes.OpenUrl, Value = signInUrl, Title = "Sign in", }; // ME Result. var result = new MessagingExtensionResult { Type = "auth", SuggestedActions = new MessagingExtensionSuggestedAction { Actions = new List <CardAction> { signInAction }, }, }; // ME response. var response = new MessagingExtensionResponse() { ComposeExtension = result, }; return(response); }
public MessagingExtensionResponse GetComposeExtensionQueryResult(List <MessagingExtensionAttachment> composeExtensionAttachments) { MessagingExtensionResponse composeExtensionResponse = new MessagingExtensionResponse(); MessagingExtensionResult composeExtensionResult = new MessagingExtensionResult(); composeExtensionResult.Type = "result"; composeExtensionResult.Attachments = composeExtensionAttachments; composeExtensionResult.AttachmentLayout = "list"; composeExtensionResponse.ComposeExtension = composeExtensionResult; return(composeExtensionResponse); }
protected override async Task <MessagingExtensionResponse> OnTeamsMessagingExtensionQueryAsync(ITurnContext <IInvokeActivity> turnContext, MessagingExtensionQuery query, CancellationToken cancellationToken) { var searchQuery = query.Parameters[0].Value as string; var messagingExtensionResponse = new MessagingExtensionResponse(); messagingExtensionResponse.ComposeExtension = CreateMessagingExtensionResult(new List <MessagingExtensionAttachment> { CreateSearchResultAttachment(searchQuery), CreateDummySearchResultAttachment(), CreateSelectItemsResultAttachment(searchQuery) }); return(messagingExtensionResponse); }
public void MessagingExtensionResponseInits() { var composeExtension = new MessagingExtensionResult("list", "message", null, null, "happy dance"); var cacheInfo = new CacheInfo(); var msgExtResponse = new MessagingExtensionResponse(composeExtension) { CacheInfo = cacheInfo }; Assert.NotNull(msgExtResponse); Assert.IsType <MessagingExtensionResponse>(msgExtResponse); Assert.Equal(composeExtension, msgExtResponse.ComposeExtension); Assert.Equal(cacheInfo, msgExtResponse.CacheInfo); }
/// <summary> /// Handle when the user is searching in the messaging extension query. /// Apps should handle user queries and return appropriate results. /// </summary> /// <param name="turnContext">The turn context.</param> /// <param name="query">The messaging extension query.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>A Task that resolves to the list of cards that matched the query.</returns> protected override Task <MessagingExtensionResponse> OnTeamsMessagingExtensionQueryAsync( ITurnContext <IInvokeActivity> turnContext, MessagingExtensionQuery query, CancellationToken cancellationToken) { var attachment = new HeroCard("Query not implemented", "App should handle query approperiately."); var attachments = new MessagingExtensionAttachment(HeroCard.ContentType, null /*url*/, attachment); var response = new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult( AttachmentLayoutTypes.List, "result" /*type*/, new[] { attachments }), }; return(Task.FromResult(response)); }
/// <inheritdoc/> public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) { if (options is CancellationToken) { throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); } if (Disabled != null && Disabled.GetValue(dc.State)) { return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false)); } if (Card == null) { throw new ArgumentException($"A valid card is required for {Kind}."); } var activity = await Card.BindAsync(dc, dc.State).ConfigureAwait(false); if (activity?.Attachments?.Any() != true) { throw new InvalidOperationException($"Invalid activity. An attachment is required for {Kind}."); } var attachment = activity.Attachments[0]; var extensionAttachment = new MessagingExtensionAttachment(attachment.ContentType, null, attachment.Content); var response = new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = MEResultResponseType.result.ToString(), AttachmentLayout = MEAttachmentLayoutResponseType.list.ToString(), // TODO: enum this Attachments = new List <MessagingExtensionAttachment> { extensionAttachment } }, CacheInfo = GetCacheInfo(dc), }; var invokeResponse = CreateInvokeResponseActivity(response); ResourceResponse sendResponse = await dc.Context.SendActivityAsync(invokeResponse, cancellationToken : cancellationToken).ConfigureAwait(false); return(await dc.EndDialogAsync(sendResponse, cancellationToken : cancellationToken).ConfigureAwait(false)); }
/// <inheritdoc/> public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) { if (options is CancellationToken) { throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); } if (Disabled != null && Disabled.GetValue(dc.State)) { return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false)); } string configUrl = ConfigUrl.GetValueOrNull(dc.State); if (string.IsNullOrEmpty(configUrl)) { throw new InvalidOperationException($"{nameof(ConfigUrl)} is required for {Kind}."); } var response = new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = MEResultResponseType.config.ToString(), SuggestedActions = new MessagingExtensionSuggestedAction { Actions = new List <CardAction> { new CardAction { Type = ActionTypes.OpenUrl, Value = configUrl, }, }, }, }, CacheInfo = GetCacheInfo(dc) }; var invokeResponse = CreateInvokeResponseActivity(response); ResourceResponse sendResponse = await dc.Context.SendActivityAsync(invokeResponse, cancellationToken : cancellationToken).ConfigureAwait(false); return(await dc.EndDialogAsync(sendResponse, cancellationToken : cancellationToken).ConfigureAwait(false)); }
public MessagingExtensionResponse GetConfig() { string configUrl = ConfigurationManager.AppSettings["BaseUri"].ToString() + "/composeExtensionSettings.html"; CardAction configExp = new CardAction(ActionTypes.OpenUrl, "Config", null, null, null, configUrl); List <CardAction> cardActions = new List <CardAction>(); cardActions.Add(configExp); MessagingExtensionResponse composeExtensionResponse = new MessagingExtensionResponse(); MessagingExtensionResult composeExtensionResult = new MessagingExtensionResult(); MessagingExtensionSuggestedAction objSuggestedAction = new MessagingExtensionSuggestedAction(); objSuggestedAction.Actions = cardActions; composeExtensionResult.SuggestedActions = objSuggestedAction; composeExtensionResult.Type = "config"; composeExtensionResponse.ComposeExtension = composeExtensionResult; return(composeExtensionResponse); }
protected override async Task <MessagingExtensionResponse> OnTeamsMessagingExtensionConfigurationQuerySettingUrlAsync(ITurnContext <IInvokeActivity> turnContext, MessagingExtensionQuery query, CancellationToken cancellationToken) { var messageExtensionResponse = new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "config", SuggestedActions = new MessagingExtensionSuggestedAction { Actions = new List <CardAction> { new CardAction { Type = ActionTypes.OpenUrl, Value = "https://teamssettingspagescenario.azurewebsites.net", }, }, }, }, }; return(messageExtensionResponse); }
public async Task <MessagingExtensionResponse> GetComposeExtensionResponseAsync(ITurnContext <IInvokeActivity> turnContext, MessagingExtensionQuery query) { MessagingExtensionResponse composeExtensionResponse = null; ImageResult imageResult = null; List <MessagingExtensionAttachment> composeExtensionAttachments = new List <MessagingExtensionAttachment>(); var userData = await TemplateUtility.GetBotUserDataObject(_userState, turnContext, query); var userPreferredCardType = userData.ComposeExtensionCardType; var activity = turnContext.Activity; bool isSettingUrl = false; if (string.Equals(activity.Name.ToLower(), Strings.ComposeExtensionQuerySettingUrl)) { isSettingUrl = true; } if (query.CommandId == null || query.Parameters == null) { return(null); } var initialRunParameter = GetQueryParameterByName(query, Strings.manifestInitialRun); var queryParameter = GetQueryParameterByName(query, Strings.manifestParameterName); if (userData == null) { composeExtensionResponse = new MessagingExtensionResponse(); string message = Strings.ComposeExtensionNoUserData; composeExtensionResponse.ComposeExtension = GetMessageResponseResult(message); return(composeExtensionResponse); } /** * Below are the checks for various states that may occur * Note that the order of many of these blocks of code do matter */ // situation where the incoming payload was received from the config popup if (!string.IsNullOrEmpty(query.State)) { /** * // need to keep going to return a response so do not return here * // these variables are changed so if the word 'setting' kicked off the compose extension, * // then the word setting will not retrigger the config experience **/ queryParameter = ""; initialRunParameter = "true"; } // this is a sitaution where the user's preferences have not been set up yet if (userData.ComposeExtensionCardType == null) { composeExtensionResponse = GetConfig(); return(composeExtensionResponse); } /** * // this is the situation where the user has entered the word 'reset' and wants * // to clear his/her settings * // resetKeyword for English is "reset" **/ if (string.Equals(queryParameter.ToLower(), Strings.ComposeExtensionResetKeyword)) { composeExtensionResponse = new MessagingExtensionResponse(); composeExtensionResponse.ComposeExtension = GetMessageResponseResult(Strings.ComposeExtensionResetText); return(composeExtensionResponse); } /** * // this is the situation where the user has entered "setting" or "settings" in order * // to repromt the config experience * // keywords for English are "setting" and "settings" **/ if (string.Equals(queryParameter.ToLower(), Strings.ComposeExtensionSettingKeyword) || string.Equals(queryParameter.ToLower(), Strings.ComposeExtensionSettingsKeyword) || (isSettingUrl)) { composeExtensionResponse = GetConfig(); return(composeExtensionResponse); } /** * // this is the situation where the user in on the initial run of the compose extension * // e.g. when the user first goes to the compose extension and the search bar is still blank * // in order to get the compose extension to run the initial run, the setting "initialRun": true * // must be set in the manifest for the compose extension **/ if (initialRunParameter == "true") { // Signin Experience, please uncomment below code for Signin Experience // ComposeExtensionResponse = GetSignin(composeExtensionResponse); // Return composeExtensionResponse; composeExtensionResponse = new MessagingExtensionResponse(); var historySearchWikiResult = userData.ComposeExtensionSelectedResults; if (historySearchWikiResult != null) { foreach (var searchResult in historySearchWikiResult) { WikiHelperSearchResult wikiSearchResult = new WikiHelperSearchResult(searchResult.imageUrl, searchResult.highlightedTitle, searchResult.text); // Create the card itself and the preview card based upon the information var createdCardAttachment = TemplateUtility.CreateComposeExtensionCardsAttachments(wikiSearchResult, userPreferredCardType); composeExtensionAttachments.Add(createdCardAttachment); } composeExtensionResponse = GetComposeExtensionQueryResult(composeExtensionAttachments); } else { composeExtensionResponse.ComposeExtension = GetMessageResponseResult(Strings.ComposeExtensionInitialRunText); } return(composeExtensionResponse); } /** * Below here is simply the logic to call the Wikipedia API and create the response for * a query; the general flow is to call the Wikipedia API for the query and then call the * Wikipedia API for each entry for the query to see if that entry has an image; in order * to get the asynchronous sections handled, an array of Promises for cards is used; each * Promise is resolved when it is discovered if an image exists for that entry; once all * of the Promises are resolved, the response is sent back to Teams */ WikiResult wikiResult = await SearchWiki(queryParameter, query); // enumerate search results and build Promises for cards for response foreach (var searchResult in wikiResult.query.search) { //Get the Image result on the basis of Image Title one by one imageResult = await SearchWikiImage(searchResult); //Get the Image Url from imageResult string imageUrl = GetImageURL(imageResult); string cardText = searchResult.snippet + " ..."; WikiHelperSearchResult wikiSearchResult = new WikiHelperSearchResult(imageUrl, searchResult.title, cardText); // Create the card itself and the preview card based upon the information var createdCardAttachment = TemplateUtility.CreateComposeExtensionCardsAttachments(wikiSearchResult, userPreferredCardType); composeExtensionAttachments.Add(createdCardAttachment); } composeExtensionResponse = GetComposeExtensionQueryResult(composeExtensionAttachments); return(composeExtensionResponse); }
protected override async Task <MessagingExtensionResponse> OnTeamsMessagingExtensionQueryAsync(ITurnContext <IInvokeActivity> turnContext, MessagingExtensionQuery query, CancellationToken cancellationToken) { var text = query?.Parameters?[0]?.Value as string ?? string.Empty; switch (text) { case "adaptive card": MessagingExtensionResponse response = GetAdaptiveCard(); return(response); case "connector card": MessagingExtensionResponse connectorCard = GetConnectorCard(); return(connectorCard); case "result grid": MessagingExtensionResponse resultGrid = GetResultGrid(); return(resultGrid); } var packages = await FindPackages(text); // We take every row of the results and wrap them in cards wrapped in MessagingExtensionAttachment objects. // The Preview is optional, if it includes a Tap, that will trigger the OnTeamsMessagingExtensionSelectItemAsync event back on this bot. var attachments = packages.Select(package => { var previewCard = new ThumbnailCard { Title = package.Item1, Tap = new CardAction { Type = "invoke", Value = package } }; if (!string.IsNullOrEmpty(package.Item5)) { previewCard.Images = new List <CardImage>() { new CardImage(package.Item5, "Icon") }; } var attachment = new MessagingExtensionAttachment { ContentType = HeroCard.ContentType, Content = new HeroCard { Title = package.Item1 }, Preview = previewCard.ToAttachment() }; return(attachment); }).ToList(); // The list of MessagingExtensionAttachments must we wrapped in a MessagingExtensionResult wrapped in a MessagingExtensionResponse. return(new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "result", AttachmentLayout = "list", Attachments = attachments } }); }
/// <summary> /// Handle the callback received when the user selects an item from the results list /// </summary> /// <param name="activity"></param> /// <returns></returns> public async Task <MessagingExtensionResponse> HandleComposeExtensionSelectedItem(ITurnContext <IInvokeActivity> turnContext, MessagingExtensionQuery query) { // Keep a history of recently-selected items in bot user data. The history will be returned in response to the initialRun query var userData = await TemplateUtility.GetBotUserDataObject(_userState, turnContext, query); //Get the Max number of History items from config file int maxComposeExtensionHistoryCount = Convert.ToInt32(ConfigurationManager.AppSettings[MaxComposeExtensionHistoryCountKey]); WikiHelperSearchResult selectedItem = JsonConvert.DeserializeObject <WikiHelperSearchResult>(turnContext.Activity.Value.ToString()); var historySearchWikiResult = userData.ComposeExtensionSelectedResults; //Removing other occurrences of the current selectedItem so there are not duplicates in the most recently used list if (historySearchWikiResult != null && historySearchWikiResult.Count > 0) { int index = 0; while (index < historySearchWikiResult.Count) { if (string.Equals(historySearchWikiResult[index].highlightedTitle.ToLower(), selectedItem.highlightedTitle.ToLower())) { historySearchWikiResult.RemoveAt(index); } else { index++; } } } else { historySearchWikiResult = new List <WikiHelperSearchResult>(); } //Add new item in list historySearchWikiResult.Insert(0, selectedItem); //Restrict the transaction History with Max Items. if (historySearchWikiResult.Count > maxComposeExtensionHistoryCount) { historySearchWikiResult = historySearchWikiResult.GetRange(0, maxComposeExtensionHistoryCount); } //Save the history Items in user Data await TemplateUtility.SaveBotUserDataObject(_userState, turnContext, historySearchWikiResult); MessagingExtensionResponse composeExtensionResponse = new MessagingExtensionResponse(); List <MessagingExtensionAttachment> composeExtensionAttachment = new List <MessagingExtensionAttachment>(); if (selectedItem != null) { // create the card itself and the preview card based upon the information // check user preference for which type of card to create var userPreferredCardType = userData.ComposeExtensionCardType; var createdCardAttachment = TemplateUtility.CreateComposeExtensionCardsAttachmentsSelectedItem(selectedItem, userPreferredCardType); composeExtensionAttachment.Add(createdCardAttachment); composeExtensionResponse = GetComposeExtensionQueryResult(composeExtensionAttachment); } else { composeExtensionResponse.ComposeExtension = GetMessageResponseResult(Strings.ComposeExtensionInitialRunText); } return(composeExtensionResponse); }