From a8c62f41b95545d99209134ec544e1431f90ff0b Mon Sep 17 00:00:00 2001 From: Alwin Schuster Date: Thu, 19 Jan 2023 15:18:32 +0100 Subject: [PATCH 1/2] Implement UpdateActivityAsync functionality for WebexAdapter --- .../WebexAdapter.cs | 61 +++++++++++++++++- .../WebexClientWrapper.cs | 62 +++++++++++++++++++ 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/libraries/Bot.Builder.Community.Adapters.Webex/WebexAdapter.cs b/libraries/Bot.Builder.Community.Adapters.Webex/WebexAdapter.cs index 9f9452ab..45aee6d1 100644 --- a/libraries/Bot.Builder.Community.Adapters.Webex/WebexAdapter.cs +++ b/libraries/Bot.Builder.Community.Adapters.Webex/WebexAdapter.cs @@ -155,10 +155,67 @@ public override async Task SendActivitiesAsync(ITurnContext /// An activity to be sent back to the messaging API. /// A cancellation token for the task. /// A representing the asynchronous operation. - public override Task UpdateActivityAsync(ITurnContext turnContext, Activity activity, CancellationToken cancellationToken) + public override async Task UpdateActivityAsync(ITurnContext turnContext, Activity activity, + CancellationToken cancellationToken) { - return Task.FromException(new NotSupportedException("Webex adapter does not support updateActivity.")); + if (activity.Id is null) + { + throw new InvalidOperationException($"Activity Id is required for UpdateActivityAsync."); + } + + if (activity.Type != ActivityTypes.Message) + { + throw new InvalidOperationException($"Unsupported Activity Type: '{activity.Type}'. Only Activities of type 'Message' are supported."); + } + + // transform activity into the webex message format + string recipientId; + + // map text format + if (activity.TextFormat == TextFormatTypes.Xml) + { + _logger.LogTrace( + $"Unsupported TextFormat: '{activity.TextFormat}'. Only TextFormat of types 'Plain' or 'Markdown' are supported."); + activity.TextFormat = TextFormatTypes.Plain; + } + + var messageType = activity.TextFormat == TextFormatTypes.Plain + ? MessageTextType.Text + : MessageTextType.Markdown; + + if (activity.Conversation?.Id != null) + { + recipientId = activity.Conversation.Id; + } + else + { + throw new InvalidOperationException("No RoomId to send the message"); + } + + string responseId; + + if (activity.Attachments != null && activity.Attachments.Count > 0) + { + if (activity.Attachments[0].ContentType == "application/vnd.microsoft.card.adaptive") + { + responseId = await _webexClient.CreateUpdateMessageAsync(activity.Id, recipientId, activity.Text, + activity.Attachments, messageType, cancellationToken).ConfigureAwait(false); + } + else + { + throw new NotSupportedException("Webex adapter Update does not support update with attachments other than adaptive cards."); + } + } + else + { + responseId = await _webexClient + .CreateUpdateMessageAsync(activity.Id, recipientId, activity.Text, null, messageType: messageType, cancellationToken) + .ConfigureAwait(false); + } + + return new ResourceResponse(responseId); } + /// /// Standard BotBuilder adapter method to delete a previous message. diff --git a/libraries/Bot.Builder.Community.Adapters.Webex/WebexClientWrapper.cs b/libraries/Bot.Builder.Community.Adapters.Webex/WebexClientWrapper.cs index 94b54ec3..d927d02c 100644 --- a/libraries/Bot.Builder.Community.Adapters.Webex/WebexClientWrapper.cs +++ b/libraries/Bot.Builder.Community.Adapters.Webex/WebexClientWrapper.cs @@ -172,6 +172,68 @@ public virtual async Task CreateMessageWithAttachmentsAsync(string recip return result.Id; } + + public virtual async Task CreateUpdateMessageAsync(string messageId, string roomId, string textOrMarkdown, IList attachments, MessageTextType messageType = MessageTextType.Markdown, CancellationToken cancellationToken = default) + { + Message result; + + var attachmentsContent = new List(); + + if (attachments != null) + { + foreach (var attach in attachments) + { + attachmentsContent.Add(attach.Content); + } + } + + var text = textOrMarkdown ?? string.Empty; + string markdown = null; + + if (!string.IsNullOrEmpty(textOrMarkdown) && messageType == MessageTextType.Markdown) + { + markdown = textOrMarkdown; + text = Shared.MarkdownToPlaintextRenderer.Render(textOrMarkdown); + } + + var request = new WebexMessageRequest + { + RoomId = roomId, + Text = text, + Markdown = markdown, + Attachments = attachmentsContent.Count > 0 ? attachmentsContent : null, + }; + + var http = (HttpWebRequest)WebRequest.Create(new Uri(MessageUrl + "/" + messageId)); + http.PreAuthenticate = true; + http.Headers.Add("Authorization", "Bearer " + Options.WebexAccessToken); + http.Accept = "application/json"; + http.ContentType = "application/json" + + "; charset=utf-8"; + http.Method = "PUT"; + + var parsedContent = JsonConvert.SerializeObject(request); + var encoding = new UTF8Encoding(); + var bytes = encoding.GetBytes(parsedContent); + + var newStream = await http.GetRequestStreamAsync().ConfigureAwait(false); + + await newStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false); + + newStream.Close(); + + var response = await http.GetResponseAsync().ConfigureAwait(false); + + var stream = response.GetResponseStream(); + + using (var sr = new StreamReader(stream)) + { + var content = await sr.ReadToEndAsync().ConfigureAwait(false); + result = JsonConvert.DeserializeObject(content); + } + + return result.Id; + } /// /// Shows details for an attachment action, by ID. From 23d729e002e08990ccb842e379eb62d99c8189a3 Mon Sep 17 00:00:00 2001 From: Alwin Schuster Date: Fri, 20 Jan 2023 08:31:40 +0100 Subject: [PATCH 2/2] UpdateActivityAsyncShouldThrowNotSupportedException should not throw exception anymore --- .../WebexAdapterTests.cs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tests/Bot.Builder.Community.Adapters.Webex.Tests/WebexAdapterTests.cs b/tests/Bot.Builder.Community.Adapters.Webex.Tests/WebexAdapterTests.cs index e182284e..2b185cc0 100644 --- a/tests/Bot.Builder.Community.Adapters.Webex.Tests/WebexAdapterTests.cs +++ b/tests/Bot.Builder.Community.Adapters.Webex.Tests/WebexAdapterTests.cs @@ -229,21 +229,6 @@ await Assert.ThrowsAsync(async () => }); } - [Fact] - public async void UpdateActivityAsyncShouldThrowNotSupportedException() - { - var webexAdapter = new WebexAdapter(new Mock(_testOptions).Object, _adapterOptions); - - var activity = new Activity(); - - var turnContext = new TurnContext(webexAdapter, activity); - - await Assert.ThrowsAsync(async () => - { - await webexAdapter.UpdateActivityAsync(turnContext, activity, default); - }); - } - [Fact] public async void SendActivitiesAsyncNotNullToPersonEmailShouldSucceed() {