Merge pull request #2953 from microsoft/gary/adapters-ga-work
Adapter updates ahead of GA
This commit is contained in:
Коммит
93129b16c9
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
@ -13,6 +14,8 @@ using Microsoft.Bot.Builder.Adapters.Facebook.FacebookEvents;
|
|||
using Microsoft.Bot.Builder.Integration.AspNet.Core;
|
||||
using Microsoft.Bot.Schema;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Microsoft.Bot.Builder.Adapters.Facebook
|
||||
|
@ -22,6 +25,7 @@ namespace Microsoft.Bot.Builder.Adapters.Facebook
|
|||
private const string HubModeSubscribe = "subscribe";
|
||||
|
||||
private readonly FacebookClientWrapper _facebookClient;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FacebookAdapter"/> class using configuration settings.
|
||||
|
@ -33,8 +37,9 @@ namespace Microsoft.Bot.Builder.Adapters.Facebook
|
|||
/// AppSecret: The secret used to validate incoming webhooks.
|
||||
/// AccessToken: An access token for the bot.
|
||||
/// </remarks>
|
||||
public FacebookAdapter(IConfiguration configuration)
|
||||
: this(new FacebookClientWrapper(new FacebookAdapterOptions(configuration["FacebookVerifyToken"], configuration["FacebookAppSecret"], configuration["FacebookAccessToken"])))
|
||||
/// <param name="logger">The ILogger implementation this adapter should use.</param>
|
||||
public FacebookAdapter(IConfiguration configuration, ILogger logger = null)
|
||||
: this(new FacebookClientWrapper(new FacebookAdapterOptions(configuration["FacebookVerifyToken"], configuration["FacebookAppSecret"], configuration["FacebookAccessToken"])), logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -43,9 +48,11 @@ namespace Microsoft.Bot.Builder.Adapters.Facebook
|
|||
/// Creates a Facebook adapter.
|
||||
/// </summary>
|
||||
/// <param name="facebookClient">A Facebook API interface.</param>
|
||||
public FacebookAdapter(FacebookClientWrapper facebookClient)
|
||||
/// <param name="logger">The ILogger implementation this adapter should use.</param>
|
||||
public FacebookAdapter(FacebookClientWrapper facebookClient, ILogger logger = null)
|
||||
{
|
||||
_facebookClient = facebookClient ?? throw new ArgumentNullException(nameof(facebookClient));
|
||||
_logger = logger ?? NullLogger.Instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -63,25 +70,24 @@ namespace Microsoft.Bot.Builder.Adapters.Facebook
|
|||
{
|
||||
if (activity.Type != ActivityTypes.Message)
|
||||
{
|
||||
throw new Exception("Only Activities of type Message are supported for sending.");
|
||||
_logger.LogTrace($"Unsupported Activity Type: '{activity.Type}'. Only Activities of type 'Message' are supported.");
|
||||
}
|
||||
|
||||
var message = FacebookHelper.ActivityToFacebook(activity);
|
||||
|
||||
if (message.Message.Attachment != null)
|
||||
else
|
||||
{
|
||||
message.Message.Attachments = null;
|
||||
message.Message.Text = null;
|
||||
var message = FacebookHelper.ActivityToFacebook(activity);
|
||||
|
||||
if (message.Message.Attachment != null)
|
||||
{
|
||||
message.Message.Text = null;
|
||||
}
|
||||
|
||||
var res = await _facebookClient.SendMessageAsync("/me/messages", message, null, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var response = new ResourceResponse() { Id = res, };
|
||||
|
||||
responses.Add(response);
|
||||
}
|
||||
|
||||
var res = await _facebookClient.SendMessageAsync("/me/messages", message, null, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var response = new ResourceResponse()
|
||||
{
|
||||
Id = res,
|
||||
};
|
||||
|
||||
responses.Add(response);
|
||||
}
|
||||
|
||||
return responses.ToArray();
|
||||
|
@ -145,7 +151,7 @@ namespace Microsoft.Bot.Builder.Adapters.Facebook
|
|||
/// <param name="bot">A bot logic function.</param>
|
||||
/// <param name="cancellationToken">A cancellation token for the task.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
public async Task ProcessAsync(HttpRequest request, HttpResponse response, IBot bot, CancellationToken cancellationToken)
|
||||
public async Task ProcessAsync(HttpRequest request, HttpResponse response, IBot bot, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (request.Query["hub.mode"] == HubModeSubscribe)
|
||||
{
|
||||
|
@ -174,7 +180,7 @@ namespace Microsoft.Bot.Builder.Adapters.Facebook
|
|||
{
|
||||
var payload = new List<FacebookMessage>();
|
||||
|
||||
payload = entry.Changes ?? entry.Messaging;
|
||||
payload = entry.Changes.Any() ? entry.Changes : entry.Messaging;
|
||||
|
||||
foreach (var message in payload)
|
||||
{
|
||||
|
@ -187,7 +193,7 @@ namespace Microsoft.Bot.Builder.Adapters.Facebook
|
|||
}
|
||||
|
||||
// Handle standby messages (this bot is not the active receiver)
|
||||
if (entry.Standby != null)
|
||||
if (!entry.Standby.Any())
|
||||
{
|
||||
payload = entry.Standby;
|
||||
|
||||
|
|
|
@ -20,21 +20,36 @@ namespace Microsoft.Bot.Builder.Adapters.Facebook.FacebookEvents
|
|||
public long Time { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the messaging list.
|
||||
/// Gets the messaging list.
|
||||
/// </summary>
|
||||
/// <value>List containing one messaging object. Note that even though this is an enumerable, it will only contain one object.</value>
|
||||
public List<FacebookMessage> Messaging { get; set; }
|
||||
public List<FacebookMessage> Messaging { get; } = new List<FacebookMessage>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the changes list.
|
||||
/// Gets the changes list.
|
||||
/// </summary>
|
||||
/// <value>List containing the list of changes.</value>
|
||||
public List<FacebookMessage> Changes { get; set; }
|
||||
public List<FacebookMessage> Changes { get; } = new List<FacebookMessage>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the standby messages list.
|
||||
/// Gets the standby messages list.
|
||||
/// </summary>
|
||||
/// <value>List containing the messages sent while in standby mode.</value>
|
||||
public List<FacebookMessage> Standby { get; set; }
|
||||
public List<FacebookMessage> Standby { get; } = new List<FacebookMessage>();
|
||||
|
||||
public bool ShouldSerializeMessaging()
|
||||
{
|
||||
return Messaging.Count > 0;
|
||||
}
|
||||
|
||||
public bool ShouldSerializeStandby()
|
||||
{
|
||||
return Messaging.Count > 0;
|
||||
}
|
||||
|
||||
public bool ShouldSerializeChanges()
|
||||
{
|
||||
return Messaging.Count > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,11 @@ namespace Microsoft.Bot.Builder.Adapters.Facebook.FacebookEvents
|
|||
[JsonProperty(PropertyName = "object")]
|
||||
public string ResponseObject { get; set; }
|
||||
|
||||
public List<FacebookEntry> Entry { get; set; }
|
||||
public List<FacebookEntry> Entry { get; } = new List<FacebookEntry>();
|
||||
|
||||
public bool ShouldSerializeEntry()
|
||||
{
|
||||
return Entry.Count > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
@ -38,7 +39,7 @@ namespace Microsoft.Bot.Builder.Adapters.Facebook
|
|||
facebookMessage = activity.GetChannelData<FacebookMessage>();
|
||||
|
||||
// make sure the quick reply has a type
|
||||
if (activity.GetChannelData<FacebookMessage>().Message.QuickReplies != null)
|
||||
if (activity.GetChannelData<FacebookMessage>().Message.QuickReplies.Any())
|
||||
{
|
||||
foreach (var reply in facebookMessage.Message.QuickReplies)
|
||||
{
|
||||
|
|
|
@ -24,11 +24,11 @@ namespace Microsoft.Bot.Builder.Adapters.Facebook
|
|||
public string StickerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of attachments.
|
||||
/// Gets a list of attachments.
|
||||
/// </summary>
|
||||
/// <value>Attachments.</value>
|
||||
[JsonProperty(PropertyName = "attachments")]
|
||||
public List<FacebookAttachment> Attachments { get; set; }
|
||||
public List<FacebookAttachment> Attachments { get; } = new List<FacebookAttachment>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the attachment.
|
||||
|
@ -45,12 +45,11 @@ namespace Microsoft.Bot.Builder.Adapters.Facebook
|
|||
public string Metadata { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the quick replies.
|
||||
/// Gets the quick replies.
|
||||
/// </summary>
|
||||
/// <value>The quick replies array.</value>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "it needs to be set in ActivityToFacebook method")]
|
||||
[JsonProperty(PropertyName = "quick_replies")]
|
||||
public List<FacebookQuickReply> QuickReplies { get; set; } = new List<FacebookQuickReply>();
|
||||
public List<FacebookQuickReply> QuickReplies { get; } = new List<FacebookQuickReply>();
|
||||
|
||||
[JsonProperty(PropertyName = "is_echo")]
|
||||
public bool IsEcho { get; set; }
|
||||
|
@ -64,5 +63,10 @@ namespace Microsoft.Bot.Builder.Adapters.Facebook
|
|||
{
|
||||
return IsEcho;
|
||||
}
|
||||
|
||||
public bool ShouldSerializeAttachments()
|
||||
{
|
||||
return Attachments.Count > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU' ">
|
||||
<DocumentationFile>bin\$(Configuration)\netstandard2.0\Microsoft.Bot.Builder.Adapters.Facebook.xml</DocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -13,10 +13,14 @@
|
|||
<PackageId>Microsoft.Bot.Builder.Adapters.Slack</PackageId>
|
||||
<Description>Library for connecting bots with Slack.</Description>
|
||||
<Summary>This library implements C# classes for the Slack adapter.</Summary>
|
||||
<!-- The SlackAPI package isn't signed, so supress the warning. There seems to not be a way to supress this for ONLY SlackAPI. -->
|
||||
<NoWarn>$(NoWarn),CS8002</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DocumentationFile>bin\$(Configuration)\netstandard2.0\Microsoft.Bot.Builder.Adapters.Slack.xml</DocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -12,12 +12,15 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.Bot.Builder.Integration.AspNet.Core;
|
||||
using Microsoft.Bot.Schema;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
namespace Microsoft.Bot.Builder.Adapters.Slack
|
||||
{
|
||||
public class SlackAdapter : BotAdapter, IBotFrameworkHttpAdapter
|
||||
{
|
||||
private readonly SlackClientWrapper _slackClient;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SlackAdapter"/> class using configuration settings.
|
||||
|
@ -29,8 +32,9 @@ namespace Microsoft.Bot.Builder.Adapters.Slack
|
|||
/// SlackBotToken: A token for a bot to work on a single workspace.
|
||||
/// SlackClientSigningSecret: The token used to validate that incoming webhooks are originated from Slack.
|
||||
/// </remarks>
|
||||
public SlackAdapter(IConfiguration configuration)
|
||||
: this(new SlackClientWrapper(new SlackAdapterOptions(configuration["SlackVerificationToken"], configuration["SlackBotToken"], configuration["SlackClientSigningSecret"])))
|
||||
/// <param name="logger">The ILogger implementation this adapter should use.</param>
|
||||
public SlackAdapter(IConfiguration configuration, ILogger logger = null)
|
||||
: this(new SlackClientWrapper(new SlackAdapterOptions(configuration["SlackVerificationToken"], configuration["SlackBotToken"], configuration["SlackClientSigningSecret"])), logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -39,9 +43,11 @@ namespace Microsoft.Bot.Builder.Adapters.Slack
|
|||
/// Creates a Slack adapter.
|
||||
/// </summary>
|
||||
/// <param name="slackClient">An initialized instance of the SlackClientWrapper class to connect to.</param>
|
||||
public SlackAdapter(SlackClientWrapper slackClient)
|
||||
/// <param name="logger">The ILogger implementation this adapter should use.</param>
|
||||
public SlackAdapter(SlackClientWrapper slackClient, ILogger logger = null)
|
||||
{
|
||||
_slackClient = slackClient ?? throw new ArgumentNullException(nameof(slackClient));
|
||||
_logger = logger ?? NullLogger.Instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -69,25 +75,25 @@ namespace Microsoft.Bot.Builder.Adapters.Slack
|
|||
{
|
||||
if (activity.Type != ActivityTypes.Message)
|
||||
{
|
||||
throw new ArgumentException("Unsupported Activity Type. Only Activities of type ‘Message’ are supported.", nameof(activities));
|
||||
_logger.LogTrace($"Unsupported Activity Type: '{activity.Type}'. Only Activities of type 'Message' are supported.");
|
||||
}
|
||||
|
||||
var message = SlackHelper.ActivityToSlack(activity);
|
||||
|
||||
var slackResponse = await _slackClient.PostMessageAsync(message, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (slackResponse != null && slackResponse.Ok)
|
||||
else
|
||||
{
|
||||
var resourceResponse = new ActivityResourceResponse()
|
||||
var message = SlackHelper.ActivityToSlack(activity);
|
||||
|
||||
var slackResponse = await _slackClient.PostMessageAsync(message, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (slackResponse != null && slackResponse.Ok)
|
||||
{
|
||||
Id = slackResponse.Ts,
|
||||
ActivityId = slackResponse.Ts,
|
||||
Conversation = new ConversationAccount()
|
||||
var resourceResponse = new ActivityResourceResponse()
|
||||
{
|
||||
Id = slackResponse.Channel,
|
||||
},
|
||||
};
|
||||
responses.Add(resourceResponse);
|
||||
Id = slackResponse.Ts,
|
||||
ActivityId = slackResponse.Ts,
|
||||
Conversation = new ConversationAccount() { Id = slackResponse.Channel, },
|
||||
};
|
||||
responses.Add(resourceResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU' ">
|
||||
<DocumentationFile>bin\$(Configuration)\netstandard2.0\Microsoft.Bot.Builder.Adapters.Twilio.xml</DocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -13,6 +13,8 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.Bot.Builder.Integration.AspNet.Core;
|
||||
using Microsoft.Bot.Schema;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
namespace Microsoft.Bot.Builder.Adapters.Twilio
|
||||
{
|
||||
|
@ -22,6 +24,7 @@ namespace Microsoft.Bot.Builder.Adapters.Twilio
|
|||
public class TwilioAdapter : BotAdapter, IBotFrameworkHttpAdapter
|
||||
{
|
||||
private readonly TwilioClientWrapper _twilioClient;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TwilioAdapter"/> class using configuration settings.
|
||||
|
@ -34,8 +37,9 @@ namespace Microsoft.Bot.Builder.Adapters.Twilio
|
|||
/// TwilioAuthToken: The authentication token for the account.
|
||||
/// TwilioValidationUrl: The validation URL for incoming requests.
|
||||
/// </remarks>
|
||||
public TwilioAdapter(IConfiguration configuration)
|
||||
: this(new TwilioClientWrapper(new TwilioAdapterOptions(configuration["TwilioNumber"], configuration["TwilioAccountSid"], configuration["TwilioAuthToken"], new Uri(configuration["TwilioValidationUrl"]))))
|
||||
/// <param name="logger">The ILogger implementation this adapter should use.</param>
|
||||
public TwilioAdapter(IConfiguration configuration, ILogger logger)
|
||||
: this(new TwilioClientWrapper(new TwilioAdapterOptions(configuration["TwilioNumber"], configuration["TwilioAccountSid"], configuration["TwilioAuthToken"], new Uri(configuration["TwilioValidationUrl"]))), logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -43,9 +47,11 @@ namespace Microsoft.Bot.Builder.Adapters.Twilio
|
|||
/// Initializes a new instance of the <see cref="TwilioAdapter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="twilioClient">The Twilio client to connect to.</param>
|
||||
public TwilioAdapter(TwilioClientWrapper twilioClient)
|
||||
/// <param name="logger">The ILogger implementation this adapter should use.</param>
|
||||
public TwilioAdapter(TwilioClientWrapper twilioClient, ILogger logger = null)
|
||||
{
|
||||
_twilioClient = twilioClient ?? throw new ArgumentNullException(nameof(twilioClient));
|
||||
_logger = logger ?? NullLogger.Instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -67,19 +73,18 @@ namespace Microsoft.Bot.Builder.Adapters.Twilio
|
|||
{
|
||||
if (activity.Type != ActivityTypes.Message)
|
||||
{
|
||||
throw new ArgumentException("Unsupported Activity Type. Only Activities of type ‘Message’ are supported.", nameof(activities));
|
||||
_logger.LogTrace($"Unsupported Activity Type: '{activity.Type}'. Only Activities of type 'Message' are supported.");
|
||||
}
|
||||
|
||||
var messageOptions = TwilioHelper.ActivityToTwilio(activity, _twilioClient.Options.TwilioNumber);
|
||||
|
||||
var res = await _twilioClient.SendMessage(messageOptions).ConfigureAwait(false);
|
||||
|
||||
var response = new ResourceResponse()
|
||||
else
|
||||
{
|
||||
Id = res,
|
||||
};
|
||||
var messageOptions = TwilioHelper.ActivityToTwilio(activity, _twilioClient.Options.TwilioNumber);
|
||||
|
||||
responses.Add(response);
|
||||
var res = await _twilioClient.SendMessage(messageOptions).ConfigureAwait(false);
|
||||
|
||||
var response = new ResourceResponse() { Id = res, };
|
||||
|
||||
responses.Add(response);
|
||||
}
|
||||
}
|
||||
|
||||
return responses.ToArray();
|
||||
|
@ -96,7 +101,7 @@ namespace Microsoft.Bot.Builder.Adapters.Twilio
|
|||
/// <returns>A task that represents the work queued to execute.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="httpRequest"/>,
|
||||
/// <paramref name="httpResponse"/>, or <paramref name="bot"/> is <c>null</c>.</exception>
|
||||
public async Task ProcessAsync(HttpRequest httpRequest, HttpResponse httpResponse, IBot bot, CancellationToken cancellationToken = default)
|
||||
public async Task ProcessAsync(HttpRequest httpRequest, HttpResponse httpResponse, IBot bot, CancellationToken cancellationToken)
|
||||
{
|
||||
if (httpRequest == null)
|
||||
{
|
||||
|
|
|
@ -13,10 +13,14 @@
|
|||
<PackageId>Microsoft.Bot.Builder.Adapters.Webex</PackageId>
|
||||
<Description>Library for connecting bots with Webex Teams API.</Description>
|
||||
<Summary>This library implements C# classes for the Webex Adapter</Summary>
|
||||
<!-- The Thrzn41.WebexTeams package isn't signed, so supress the warning. There seems to not be a way to supress this for ONLY Thrzn41.WebexTeams. -->
|
||||
<NoWarn>$(NoWarn),CS8002</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU' ">
|
||||
<DocumentationFile>bin\$(Configuration)\netstandard2.0\Microsoft.Bot.Builder.Adapters.Webex.xml</DocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -10,6 +10,8 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.Bot.Builder.Integration.AspNet.Core;
|
||||
using Microsoft.Bot.Schema;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Newtonsoft.Json;
|
||||
using Thrzn41.WebexTeams.Version1;
|
||||
|
||||
|
@ -18,6 +20,7 @@ namespace Microsoft.Bot.Builder.Adapters.Webex
|
|||
public class WebexAdapter : BotAdapter, IBotFrameworkHttpAdapter
|
||||
{
|
||||
private readonly WebexClientWrapper _webexClient;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WebexAdapter"/> class using configuration settings.
|
||||
|
@ -30,8 +33,9 @@ namespace Microsoft.Bot.Builder.Adapters.Webex
|
|||
/// WebexSecret: The secret used to validate incoming webhooks.
|
||||
/// WebexWebhookName: A name for the webhook subscription.
|
||||
/// </remarks>
|
||||
public WebexAdapter(IConfiguration configuration)
|
||||
: this(new WebexClientWrapper(new WebexAdapterOptions(configuration["WebexAccessToken"], new Uri(configuration["WebexPublicAddress"]), configuration["WebexSecret"], configuration["WebexWebhookName"])))
|
||||
/// <param name="logger">The ILogger implementation this adapter should use.</param>
|
||||
public WebexAdapter(IConfiguration configuration, ILogger logger)
|
||||
: this(new WebexClientWrapper(new WebexAdapterOptions(configuration["WebexAccessToken"], new Uri(configuration["WebexPublicAddress"]), configuration["WebexSecret"], configuration["WebexWebhookName"])), logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -40,9 +44,11 @@ namespace Microsoft.Bot.Builder.Adapters.Webex
|
|||
/// Creates a Webex adapter.
|
||||
/// </summary>
|
||||
/// <param name="webexClient">A Webex API interface.</param>
|
||||
public WebexAdapter(WebexClientWrapper webexClient)
|
||||
/// <param name="logger">The ILogger implementation this adapter should use.</param>
|
||||
public WebexAdapter(WebexClientWrapper webexClient, ILogger logger = null)
|
||||
{
|
||||
_webexClient = webexClient ?? throw new ArgumentNullException(nameof(webexClient));
|
||||
_logger = logger ?? NullLogger.Instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -59,55 +65,59 @@ namespace Microsoft.Bot.Builder.Adapters.Webex
|
|||
{
|
||||
if (activity.Type != ActivityTypes.Message)
|
||||
{
|
||||
throw new ArgumentException("Unsupported Activity Type. Only Activities of type ‘Message’ are supported.", nameof(activities));
|
||||
}
|
||||
|
||||
// transform activity into the webex message format
|
||||
string personIdOrEmail;
|
||||
|
||||
if (activity.GetChannelData<WebhookEventData>()?.MessageData.PersonEmail != null)
|
||||
{
|
||||
personIdOrEmail = activity.GetChannelData<WebhookEventData>()?.MessageData.PersonEmail;
|
||||
_logger.LogTrace($"Unsupported Activity Type: '{activity.Type}'. Only Activities of type 'Message' are supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (activity.Recipient?.Id != null)
|
||||
// transform activity into the webex message format
|
||||
string personIdOrEmail;
|
||||
|
||||
if (activity.GetChannelData<WebhookEventData>()?.MessageData.PersonEmail != null)
|
||||
{
|
||||
personIdOrEmail = activity.Recipient.Id;
|
||||
personIdOrEmail = activity.GetChannelData<WebhookEventData>()?.MessageData.PersonEmail;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("No Person or Email 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.CreateMessageWithAttachmentsAsync(personIdOrEmail, activity.Text, activity.Attachments, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var files = new List<Uri>();
|
||||
|
||||
foreach (var attachment in activity.Attachments)
|
||||
if (activity.Recipient?.Id != null)
|
||||
{
|
||||
var file = new Uri(attachment.ContentUrl);
|
||||
files.Add(file);
|
||||
personIdOrEmail = activity.Recipient.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("No Person or Email to send the message");
|
||||
}
|
||||
|
||||
responseId = await _webexClient.CreateMessageAsync(personIdOrEmail, activity.Text, files.Count > 0 ? files : null, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
responseId = await _webexClient.CreateMessageAsync(personIdOrEmail, activity.Text, cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
responses.Add(new ResourceResponse(responseId));
|
||||
string responseId;
|
||||
|
||||
if (activity.Attachments != null && activity.Attachments.Count > 0)
|
||||
{
|
||||
if (activity.Attachments[0].ContentType == "application/vnd.microsoft.card.adaptive")
|
||||
{
|
||||
responseId = await _webexClient.CreateMessageWithAttachmentsAsync(personIdOrEmail, activity.Text, activity.Attachments, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var files = new List<Uri>();
|
||||
|
||||
foreach (var attachment in activity.Attachments)
|
||||
{
|
||||
var file = new Uri(attachment.ContentUrl);
|
||||
files.Add(file);
|
||||
}
|
||||
|
||||
responseId = await _webexClient.CreateMessageAsync(personIdOrEmail, activity.Text, files.Count > 0 ? files : null, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
responseId = await _webexClient
|
||||
.CreateMessageAsync(personIdOrEmail, activity.Text, cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
responses.Add(new ResourceResponse(responseId));
|
||||
}
|
||||
}
|
||||
|
||||
return responses.ToArray();
|
||||
|
|
|
@ -226,22 +226,35 @@ namespace Microsoft.Bot.Builder.Adapters.Facebook.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async void SendActivitiesAsyncShouldFailWithActivityTypeNotMessage()
|
||||
public async void SendActivitiesAsyncShouldSucceedAndNoActivityReturnedWithActivityTypeNotMessage()
|
||||
{
|
||||
var facebookAdapter = new FacebookAdapter(new Mock<FacebookClientWrapper>(_testOptions).Object);
|
||||
const string testResponse = "Test Response";
|
||||
var facebookClientWrapper = new Mock<FacebookClientWrapper>(_testOptions);
|
||||
var facebookAdapter = new FacebookAdapter(facebookClientWrapper.Object);
|
||||
var attachments = new List<Attachment>();
|
||||
var activity = new Activity
|
||||
{
|
||||
Type = ActivityTypes.Event,
|
||||
Type = ActivityTypes.Trace,
|
||||
Text = "Test text",
|
||||
Conversation = new ConversationAccount()
|
||||
{
|
||||
Id = "Test id",
|
||||
},
|
||||
ChannelData = new FacebookMessage("recipientId", new Message(), "messagingtype"),
|
||||
Attachments = attachments,
|
||||
};
|
||||
Activity[] activities = { activity };
|
||||
ResourceResponse[] responses = null;
|
||||
|
||||
attachments.Add(new Attachment("text/html", "http://contoso.com"));
|
||||
facebookClientWrapper.Setup(api => api.SendMessageAsync(It.IsAny<string>(), It.IsAny<FacebookMessage>(), It.IsAny<HttpMethod>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult(testResponse));
|
||||
|
||||
using (var turnContext = new TurnContext(facebookAdapter, activity))
|
||||
{
|
||||
await Assert.ThrowsAsync<Exception>(async () =>
|
||||
{
|
||||
await facebookAdapter.SendActivitiesAsync(turnContext, activities, default);
|
||||
});
|
||||
responses = await facebookAdapter.SendActivitiesAsync(turnContext, activities, default);
|
||||
}
|
||||
|
||||
Assert.True(responses.Length == 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<!-- The SlackAPI package isn't signed, so supress the warning. There seems to not be a way to supress this for ONLY SlackAPI. -->
|
||||
<NoWarn>$(NoWarn),CS8002</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
<DelaySign>true</DelaySign>
|
||||
<AssemblyOriginatorKeyFile>..\..\..\build\35MSSharedLib1024.snk</AssemblyOriginatorKeyFile>
|
||||
<DefineConstants>SIGNASSEMBLY</DefineConstants>
|
||||
<!-- The SlackAPI package isn't signed, so supress the warning. There seems to not be a way to supress this for ONLY SlackAPI. -->
|
||||
<NoWarn>$(NoWarn),CS8002</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -51,21 +51,22 @@ namespace Microsoft.Bot.Builder.Adapters.Twilio.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async void SendActivitiesAsyncShouldFailWithActivityTypeNotMessage()
|
||||
public async void SendActivitiesAsyncShouldSucceedAndNoActivityReturnedWithActivityTypeNotMessage()
|
||||
{
|
||||
var twilioAdapter = new TwilioAdapter(new Mock<TwilioClientWrapper>(_testOptions).Object);
|
||||
var activity = new Mock<Activity>().SetupAllProperties();
|
||||
activity.Object.Type = ActivityTypes.Trace;
|
||||
activity.Object.Attachments = new List<Attachment> { new Attachment(contentUrl: "http://example.com") };
|
||||
activity.Object.Conversation = new ConversationAccount(id: "MockId");
|
||||
activity.Object.Text = "Trace content";
|
||||
|
||||
var activity = new Activity()
|
||||
{
|
||||
Type = ActivityTypes.Event,
|
||||
};
|
||||
const string resourceIdentifier = "Mocked Resource Identifier";
|
||||
var twilioApi = new Mock<TwilioClientWrapper>(_testOptions);
|
||||
twilioApi.Setup(x => x.SendMessage(It.IsAny<CreateMessageOptions>())).Returns(Task.FromResult(resourceIdentifier));
|
||||
|
||||
Activity[] activities = { activity };
|
||||
var twilioAdapter = new TwilioAdapter(twilioApi.Object);
|
||||
var resourceResponses = await twilioAdapter.SendActivitiesAsync(null, new Activity[] { activity.Object }, default).ConfigureAwait(false);
|
||||
|
||||
await Assert.ThrowsAsync<ArgumentException>(async () =>
|
||||
{
|
||||
await twilioAdapter.SendActivitiesAsync(new TurnContext(twilioAdapter, activity), activities, default);
|
||||
});
|
||||
Assert.True(resourceResponses.Length == 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<!-- The Thrzn41.WebexTeams package isn't signed, so supress the warning. There seems to not be a way to supress this for ONLY Thrzn41.WebexTeams. -->
|
||||
<NoWarn>$(NoWarn),CS8002</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -322,22 +323,24 @@ namespace Microsoft.Bot.Builder.Adapters.Webex.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async void SendActivitiesAsyncShouldFailWithActivityTypeNotMessage()
|
||||
public async void SendActivitiesAsyncShouldSucceedAndNoActivityReturnedWithActivityTypeNotMessage()
|
||||
{
|
||||
var webexAdapter = new WebexAdapter(new Mock<WebexClientWrapper>(_testOptions).Object);
|
||||
var activity = new Activity
|
||||
{
|
||||
Type = ActivityTypes.Event,
|
||||
};
|
||||
const string expectedResponseId = "Mocked Response Id";
|
||||
var webexApi = new Mock<WebexClientWrapper>(_testOptions);
|
||||
webexApi.Setup(x => x.CreateMessageWithAttachmentsAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IList<Attachment>>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult(expectedResponseId));
|
||||
|
||||
Activity[] activities = { activity };
|
||||
var webexAdapter = new WebexAdapter(webexApi.Object);
|
||||
|
||||
var turnContext = new TurnContext(webexAdapter, activity);
|
||||
var activity = new Mock<Activity>().SetupAllProperties();
|
||||
activity.Object.Type = ActivityTypes.Trace;
|
||||
activity.Object.Recipient = new ChannelAccount(id: "MockId");
|
||||
activity.Object.Text = "Trace content";
|
||||
|
||||
await Assert.ThrowsAsync<ArgumentException>(async () =>
|
||||
{
|
||||
await webexAdapter.SendActivitiesAsync(turnContext, activities, default);
|
||||
});
|
||||
var turnContext = new TurnContext(webexAdapter, activity.Object);
|
||||
|
||||
var resourceResponse = await webexAdapter.SendActivitiesAsync(turnContext, new Activity[] { activity.Object }, default).ConfigureAwait(false);
|
||||
|
||||
Assert.True(resourceResponse.Length == 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
Загрузка…
Ссылка в новой задаче