public void AppBasedLinkQueryInitsWithNoArgs() { var appBasedLinkQuery = new AppBasedLinkQuery(); Assert.NotNull(appBasedLinkQuery); Assert.IsType <AppBasedLinkQuery>(appBasedLinkQuery); }
protected virtual Task <InvokeResponse> OnAppBasedLinkQueryAsync( ITurnContext <IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken) { return(Task.FromResult <InvokeResponse>(null)); }
/// <summary> /// Unfurl / Get a preview for the a link pasted inside the Teams' compose box. /// </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 either a login card or the adaptive card of the Reddit post.</returns> /// <remarks> /// For more information on link unfurling in Teams, see the documentation /// https://docs.microsoft.com/en-us/microsoftteams/platform/messaging-extensions/how-to/link-unfurling?tabs=dotnet . /// </remarks> protected override Task <MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync( ITurnContext <IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken) { turnContext = turnContext ?? throw new ArgumentNullException(nameof(turnContext)); query = query ?? throw new ArgumentNullException(nameof(query)); this.RecordEvent(nameof(this.OnTeamsAppBasedLinkQueryAsync), turnContext); return(this.GetRedditPostAsync(query.Url)); }
public void AppBasedLinkQueryInits() { var url = "http://example.com"; var state = "magicCode"; var appBasedLinkQuery = new AppBasedLinkQuery(url) { State = state }; Assert.NotNull(appBasedLinkQuery); Assert.IsType <AppBasedLinkQuery>(appBasedLinkQuery); Assert.Equal(url, appBasedLinkQuery.Url); Assert.Equal(state, appBasedLinkQuery.State); }
public async Task <InvokeResponse> HandleAppBasedLinkQueryAsync( ITurnContext <IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken) { var url = query?.Url?.Trim() ?? string.Empty; var result = new InvokeResponse { Status = (int)HttpStatusCode.OK }; if (url.Contains("OpenPositionsPersonalTab")) { var positionIdParam = HttpUtility.ParseQueryString(new Uri(url).Query).Get("positionId"); if (int.TryParse(positionIdParam, out var positionId)) { result = await PositionMessagingExtensionResponse(turnContext, positionId); } } return(result); }
protected async override Task <MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync(ITurnContext <IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken) { var state = query.State; // Check the state value var tokenResponse = await GetTokenResponse(turnContext, state, cancellationToken); if (tokenResponse == null || string.IsNullOrEmpty(tokenResponse.Token)) { // There is no token, so the user has not signed in yet. // Retrieve the OAuth Sign in Link to use in the MessagingExtensionResult Suggested Actions var signInLink = await GetSignInLinkAsync(turnContext, cancellationToken).ConfigureAwait(false); return(new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "auth", SuggestedActions = new MessagingExtensionSuggestedAction { Actions = new List <CardAction> { new CardAction { Type = ActionTypes.OpenUrl, Value = signInLink, Title = "Bot Service OAuth", }, }, }, }, }); } var client = new SimpleGraphClient(tokenResponse.Token); var profile = await client.GetMyProfile(); var heroCard = new ThumbnailCard { Title = "Thumbnail Card", Text = $"Hello, {profile.DisplayName}", Images = new List <CardImage> { new CardImage("https://raw.githubusercontent.com/microsoft/botframework-sdk/master/icon.png") }, }; var attachments = new MessagingExtensionAttachment(HeroCard.ContentType, null, heroCard); var result = new MessagingExtensionResult("list", "result", new[] { attachments }); return(new MessagingExtensionResponse(result)); }
protected override async Task <MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync(ITurnContext <IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken) { var projectLinkQuery = new TestLinkQuery(); return(await projectLinkQuery.HandleInvokeActivityAsync(turnContext, query).ConfigureAwait(false)); }
/// <summary> /// Invoked when an app based link query activity is received from the connector. /// </summary> /// <param name="turnContext">A strongly-typed context object for this turn.</param> /// <param name="query">The invoke request body type for app-based link query.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>The Messaging Extension Response for the query.</returns> protected virtual Task <MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync(ITurnContext <IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken) { throw new InvokeResponseException(HttpStatusCode.NotImplemented); }
/// <summary> /// Handles app-based link query asynchronously. /// </summary> /// <param name="turnContext">The turn context.</param> /// <param name="query">The app-based link query.</param> /// <returns>Task tracking operation.</returns> public virtual Task <InvokeResponse> HandleAppBasedLinkQueryAsync(ITurnContext turnContext, AppBasedLinkQuery query) { return(Task.FromResult <InvokeResponse>(null)); }
protected override async Task <MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync(ITurnContext <IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken) { var heroCard = new ThumbnailCard { Title = "Thumbnail Card", Text = query.Url, Images = new List <CardImage> { new CardImage("https://raw.githubusercontent.com/microsoft/botframework-sdk/master/icon.png") }, }; var attachments = new MessagingExtensionAttachment(HeroCard.ContentType, null, heroCard); var result = new MessagingExtensionResult(AttachmentLayoutTypes.List, "result", new[] { attachments }, null, "test unfurl"); return(new MessagingExtensionResponse(result)); }
/// <summary> /// Invoked when an app based link query activity is received from the connector. /// </summary> /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param> /// <param name="query">The invoke request body type for app-based link query</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param> /// <returns>The Messaging Extension Response for the query.</returns> protected async override Task <MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync(ITurnContext <IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken) { var state = query.State; bool isSignedIn; _isSignedIn.TryGetValue("isSignedIn", out isSignedIn); var previewCard = new ThumbnailCard(); var attachment = new MessagingExtensionAttachment(); if (string.IsNullOrEmpty(state)) { return(new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "config", SuggestedActions = new MessagingExtensionSuggestedAction { Actions = new List <CardAction> { new CardAction { Type = ActionTypes.OpenUrl, Value = $"{_applicationBaseUrl}/config", Title = "Select login option", }, }, }, }, }); } else if (state == "sso" || isSignedIn) { var tokenResponse = await GetTokenResponse(turnContext, _botConnectionName, state, cancellationToken); if (tokenResponse == null || string.IsNullOrEmpty(tokenResponse.Token)) { isSignedIn = true; _isSignedIn.AddOrUpdate("isSignedIn", true, (key, newValue) => true); var signInLink = await GetSignInLinkAsync(turnContext, _botConnectionName, cancellationToken).ConfigureAwait(false); return(new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "auth", SuggestedActions = new MessagingExtensionSuggestedAction { Actions = new List <CardAction> { new CardAction { Type = ActionTypes.OpenUrl, Value = signInLink, Title = "Bot Service OAuth", }, }, }, }, }); } var client = new SimpleGraphClient(tokenResponse.Token); var profile = await client.GetMeAsync(); var photo = await client.GetPhotoAsync(); var title = !string.IsNullOrEmpty(profile.JobTitle) ? profile.JobTitle : "Unknown"; previewCard = new ThumbnailCard { Title = $"Hello! {profile.DisplayName}", Text = $"Job title: {title}", Subtitle = $"Email: {profile.UserPrincipalName}", Images = new List <CardImage> { new CardImage { Url = photo } } }; attachment = new MessagingExtensionAttachment { ContentType = ThumbnailCard.ContentType, Content = previewCard, Preview = previewCard.ToAttachment() }; return(new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "result", AttachmentLayout = "list", Attachments = new List <MessagingExtensionAttachment> { attachment } }, }); } else if (state == "usercredentials" || state.Contains("userName") || isSignedIn) { if (state.Contains("userName")) { JObject asJobject = JObject.Parse(state); var userName = (string)asJobject.ToObject <CardTaskFetchValue <string> >()?.UserName; var password = (string)asJobject.ToObject <CardTaskFetchValue <string> >()?.Password; if (userName == Constant.UserName && password == Constant.Password) { previewCard = new ThumbnailCard { Title = $"Hello! Test user", Text = "Job title: Data Scientist", Subtitle = "Email: [email protected]", Images = new List <CardImage> { new CardImage { Url = "https://media.istockphoto.com/vectors/profile-placeholder-image-gray-silhouette-no-photo-vector-id1016744034?k=20&m=1016744034&s=612x612&w=0&h=kjCAwH5GOC3n3YRTHBaLDsLIuF8P3kkAJc9RvfiYWBY=" } } }; attachment = new MessagingExtensionAttachment { ContentType = ThumbnailCard.ContentType, Content = previewCard, Preview = previewCard.ToAttachment() }; return(new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "result", AttachmentLayout = "list", Attachments = new List <MessagingExtensionAttachment> { attachment } }, }); } else { previewCard = new ThumbnailCard { Title = "Invalid credentials", }; attachment = new MessagingExtensionAttachment { ContentType = ThumbnailCard.ContentType, Content = previewCard, Preview = previewCard.ToAttachment() }; return(new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "result", AttachmentLayout = "list", Attachments = new List <MessagingExtensionAttachment> { attachment } }, }); } } else { return(new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "auth", SuggestedActions = new MessagingExtensionSuggestedAction { Actions = new List <CardAction> { new CardAction { Type = ActionTypes.OpenUrl, Value = $"{_applicationBaseUrl}/popUpSignin?from=msgext", Title = "Using username/password", }, }, }, }, }); } } else { var facebooktokenResponse = await GetTokenResponse(turnContext, _facebookConnectionName, state, cancellationToken); if (facebooktokenResponse == null || string.IsNullOrEmpty(facebooktokenResponse.Token)) { _isSignedIn.AddOrUpdate("isSignedIn", false, (key, newValue) => false); var fbsignInLink = await GetSignInLinkAsync(turnContext, _facebookConnectionName, cancellationToken).ConfigureAwait(false); return(new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "auth", SuggestedActions = new MessagingExtensionSuggestedAction { Actions = new List <CardAction> { new CardAction { Type = ActionTypes.OpenUrl, Value = fbsignInLink, Title = "Facebook auth", }, }, }, }, }); } FacebookProfile fbProfile = await FacebookHelper.GetFacebookProfileName(facebooktokenResponse.Token); previewCard = new ThumbnailCard { Title = $"Hello! {fbProfile.Name}", Images = new List <CardImage> { new CardImage { Url = fbProfile.ProfilePicture.data.url } } }; attachment = new MessagingExtensionAttachment { ContentType = ThumbnailCard.ContentType, Content = previewCard, Preview = previewCard.ToAttachment() }; return(new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "result", AttachmentLayout = "list", Attachments = new List <MessagingExtensionAttachment> { attachment } }, }); } }
//protected override Task<MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync(ITurnContext<IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken) //{ // var heroCard = new ThumbnailCard // { // Title = "Thumbnail Card", // Text = query.Url, // Images = new List<CardImage> { new CardImage("https://raw.githubusercontent.com/microsoft/botframework-sdk/master/icon.png") }, // }; // var attachments = new MessagingExtensionAttachment(HeroCard.ContentType, null, heroCard); // var result = new MessagingExtensionResult("list", "result", new[] { attachments }); // return Task.FromResult(new MessagingExtensionResponse(result)); //} protected override Task <MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync(ITurnContext <IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken) { var heroCard = new ThumbnailCard { Title = "Thumbnail Card", Text = query.Url, Images = new List <CardImage> { new CardImage("https://www.leaders-in-law.com/wp-content/uploads/2020/03/COVID-19.png") }, }; var attachments = new MessagingExtensionAttachment(HeroCard.ContentType, null, heroCard); var result = new MessagingExtensionResult("list", "result", new[] { attachments }); return(Task.FromResult(new MessagingExtensionResponse(result))); }
protected override Task <InvokeResponse> OnAppBasedLinkQueryAsync(ITurnContext <IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken) => _invokeActivityHandler.HandleAppBasedLinkQueryAsync(turnContext, query, cancellationToken);
/// <summary> /// Handles app-based link query asynchronously. /// </summary> /// <param name="turnContext">The turn context.</param> /// <param name="query">The app-based link query.</param> /// <returns>Task tracking operation.</returns> public override async Task <InvokeResponse> HandleAppBasedLinkQueryAsync(ITurnContext turnContext, AppBasedLinkQuery query) { var previewImg = new List <CardImage> { new CardImage("https://assets.pokemon.com/assets/cms2/img/pokedex/full/025.png", "Pokemon"), }; var preview = new ThumbnailCard("Preview Card", null, $"Your query URL: {query.Url}", previewImg).ToAttachment(); var heroCard = new HeroCard("Preview Card", null, $"Your query URL: <pre>{query.Url}</pre>", previewImg).ToAttachment(); var resultCards = new List <MessagingExtensionAttachment> { heroCard.ToMessagingExtensionAttachment(preview) }; return(new InvokeResponse { Status = 200, Body = new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult("list", "result", resultCards), }, }); }
/// <summary> /// Get the login or preview response for the given link. /// </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 either a login card or </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 /// /// This method also implements messaging extension authentication to get the reddit API token for the user. /// https://docs.microsoft.com/en-us/microsoftteams/platform/messaging-extensions/how-to/add-authentication /// </remarks> protected override async Task <MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync( ITurnContext <IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken = default) { turnContext = turnContext ?? throw new ArgumentNullException(nameof(turnContext)); query = query ?? throw new ArgumentNullException(nameof(query)); IUserTokenProvider tokenProvider = turnContext.Adapter as IUserTokenProvider; // Get the magic code out of the request for when the login flow is completed. // https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-authentication?view=azure-bot-service-4.0#securing-the-sign-in-url string magicCode = (turnContext.Activity?.Value as JObject)?.Value <string>("state"); // Get the token from the Azure Bot Framework Token Service to handle token storage // https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-authentication?view=azure-bot-service-4.0#about-the-bot-framework-token-service var tokenResponse = await tokenProvider ?.GetUserTokenAsync( turnContext : turnContext, connectionName : this.options.Value.BotFrameworkConnectionName, magicCode : magicCode, cancellationToken : cancellationToken); try { // Execute the domain logic to get the reddit link RedditLinkModel redditLink = await this.redditHttpClient.GetLinkAsync(tokenResponse?.Token, query.Url); var preview = new MessagingExtensionAttachment( contentType: HeroCard.ContentType, contentUrl: null, content: this.RenderLinkHeroCard(redditLink)); return(new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "result", AttachmentLayout = AttachmentLayoutTypes.List, Attachments = new List <MessagingExtensionAttachment>() { new MessagingExtensionAttachment { ContentType = AdaptiveCard.ContentType, Content = this.RenderLinkAdaptiveCard(redditLink), Preview = preview, }, }, }, }); } catch (RedditUnauthorizedException) { this.logger.LogInformation("Attempt to fetch post resulted in unauthorized, triggering log-in flow"); // "log out" the user, so log-in gets a new token. await tokenProvider.SignOutUserAsync( turnContext : turnContext, connectionName : this.options.Value.BotFrameworkConnectionName, cancellationToken : cancellationToken); return(await this .GetAuthenticationMessagingExtensionResponseAsync(turnContext, cancellationToken) .ConfigureAwait(false)); } #pragma warning disable CA1031 catch (Exception ex) #pragma warning restore CA1031 { this.logger.LogError(ex, "Failed to get reddit post"); return(null); } }
protected override Task <MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync(ITurnContext <IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken) { Record.Add(MethodBase.GetCurrentMethod().Name); return(Task.FromResult(new MessagingExtensionResponse())); }
/// <summary> /// This method is called when user enters a url in compose box from a domain that this app unfurls. /// /// Application authenticates the user to read resource and insert a card with resource information and option to review it in a meeting. /// </summary> /// <param name="turnContext">Turn context.</param> /// <param name="query">Query - this contains the url that user entered.</param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>ME response.</returns> protected async override Task <MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync(ITurnContext <IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken) { this.logger.LogInformation($"OnTeamsAppBasedLinkQueryAsync: {query.Url}"); // Make sure its a valid url. if (!this.urlParser.IsValidResourceUrl(query.Url)) { return(null); } // Make sure the user is signed-in. var isUserSignedIn = await turnContext.IsUserSignedInAsync(this.appSettings.GraphConnectionName, query.State, cancellationToken); if (!isUserSignedIn) { this.logger.LogInformation("User is not signed-in."); var signInUrl = await turnContext.GetOAuthSignInUrlAsync(this.appSettings.GraphConnectionName, cancellationToken); var signInResponse = this.GetSignInResponse(signInUrl); return(signInResponse); } // If the user is signed-in: // 1. Check if user is authorized to access the resource. (Skipped in this sample). // 2. Create a card with resource information/preview image and option to review it in a meeting. var resourceId = this.urlParser.GetResourceId(query.Url); var resource = await this.resourceProvider.GetResourceAsync(resourceId); return(this.GetContentCardResponse(resource)); }
protected async override Task <MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync(ITurnContext <IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken) { var tokenResponse = await GetTokenResponse(turnContext, query.State, cancellationToken); if (tokenResponse == null || string.IsNullOrEmpty(tokenResponse.Token)) { // There is no token, so the user has not signed in yet. // Retrieve the OAuth Sign in Link to use in the MessagingExtensionResult Suggested Actions var signInLink = await(turnContext.Adapter as IUserTokenProvider).GetOauthSignInLinkAsync(turnContext, _connectionName, cancellationToken); return(new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "auth", SuggestedActions = new MessagingExtensionSuggestedAction { Actions = new List <CardAction> { new CardAction { Type = ActionTypes.OpenUrl, Value = signInLink, Title = "Bot Service OAuth", }, }, }, }, }); } var client = new SimpleGraphClient(tokenResponse.Token); var profile = await client.GetMyProfile(); var imagelink = await client.GetPhotoAsync(); var heroCard = new ThumbnailCard { Title = "Thumbnail Card", Text = $"Hello {profile.DisplayName}", Images = new List <CardImage> { new CardImage(imagelink) } }; var attachments = new MessagingExtensionAttachment(HeroCard.ContentType, null, heroCard); var result = new MessagingExtensionResult("list", "result", new[] { attachments }); return(new MessagingExtensionResponse(result)); }