diff --git a/Vonage.Test.Unit/Conversations/CreateConversation/RequestBuilderTest.cs b/Vonage.Test.Unit/Conversations/CreateConversation/RequestBuilderTest.cs index 69e1eb27b..96285240f 100644 --- a/Vonage.Test.Unit/Conversations/CreateConversation/RequestBuilderTest.cs +++ b/Vonage.Test.Unit/Conversations/CreateConversation/RequestBuilderTest.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Net.Http; using Vonage.Common.Test.Extensions; using Vonage.Conversations.CreateConversation; using Xunit; @@ -35,6 +36,23 @@ public void Build_ShouldReturnFailure_GivenDisplayNameLengthIsAbove50Characters( .Should() .BeParsingFailure("DisplayName length cannot be higher than 50."); + [Theory] + [InlineData("PUT")] + [InlineData("DELETE")] + [InlineData("HEAD")] + [InlineData("OPTIONS")] + [InlineData("TRACE")] + [InlineData("PATCH")] + [InlineData("CONNECT")] + public void Build_ShouldReturnFailure_GivenHttpMethodIsNotGetOrPost(string method) => + CreateConversationRequest.Build() + .WithCallback(new Callback(new Uri("https://example.com"), "mask", + new CallbackParameters("appId", new Uri("https://example.com")), new HttpMethod(method))) + .Create() + .Map(request => request.Callback) + .Should() + .BeParsingFailure("Callback HttpMethod must be GET or POST."); + [Theory] [InlineData("")] [InlineData(" ")] @@ -55,6 +73,17 @@ public void Build_ShouldReturnFailure_GivenNameLengthIsAbove100Characters() => .Should() .BeParsingFailure("Name length cannot be higher than 100."); + [Fact] + public void Build_ShouldSetCallback() => + CreateConversationRequest.Build() + .WithCallback(new Callback(new Uri("https://example.com"), "mask", + new CallbackParameters("appId", new Uri("https://example.com")), HttpMethod.Get)) + .Create() + .Map(request => request.Callback) + .Should() + .BeSuccess(new Callback(new Uri("https://example.com"), "mask", + new CallbackParameters("appId", new Uri("https://example.com")), HttpMethod.Get)); + [Fact] public void Build_ShouldSetDisplayName() => CreateConversationRequest.Build() diff --git a/Vonage/Conversations/CreateConversation/Callback.cs b/Vonage/Conversations/CreateConversation/Callback.cs new file mode 100644 index 000000000..4aba5f88d --- /dev/null +++ b/Vonage/Conversations/CreateConversation/Callback.cs @@ -0,0 +1,10 @@ +using System; +using System.Net.Http; + +namespace Vonage.Conversations.CreateConversation; + +public record Callback( + Uri Url, + string EventMask, + CallbackParameters Parameters, + HttpMethod Method); \ No newline at end of file diff --git a/Vonage/Conversations/CreateConversation/CallbackParameters.cs b/Vonage/Conversations/CreateConversation/CallbackParameters.cs new file mode 100644 index 000000000..927057860 --- /dev/null +++ b/Vonage/Conversations/CreateConversation/CallbackParameters.cs @@ -0,0 +1,5 @@ +using System; + +namespace Vonage.Conversations.CreateConversation; + +public record CallbackParameters(string ApplicationId, Uri NccoUrl); \ No newline at end of file diff --git a/Vonage/Conversations/CreateConversation/CreateConversationRequest.cs b/Vonage/Conversations/CreateConversation/CreateConversationRequest.cs index a10c6ef63..b90769aec 100644 --- a/Vonage/Conversations/CreateConversation/CreateConversationRequest.cs +++ b/Vonage/Conversations/CreateConversation/CreateConversationRequest.cs @@ -8,6 +8,10 @@ namespace Vonage.Conversations.CreateConversation; /// public readonly struct CreateConversationRequest : IVonageRequest { + /// + /// + public Maybe Callback { get; internal init; } + /// /// public Maybe DisplayName { get; internal init; } diff --git a/Vonage/Conversations/CreateConversation/CreateConversationRequestBuilder.cs b/Vonage/Conversations/CreateConversation/CreateConversationRequestBuilder.cs index b1469e8d9..a7aea2d96 100644 --- a/Vonage/Conversations/CreateConversation/CreateConversationRequestBuilder.cs +++ b/Vonage/Conversations/CreateConversation/CreateConversationRequestBuilder.cs @@ -1,5 +1,9 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; using Vonage.Common.Client; +using Vonage.Common.Failures; using Vonage.Common.Monads; using Vonage.Common.Validation; @@ -9,6 +13,9 @@ internal class CreateConversationRequestBuilder : IBuilderForOptional { private const int DisplayNameMaxLength = 50; private const int NameMaxLength = 100; + + private readonly IEnumerable allowedMethods = new[] {HttpMethod.Get, HttpMethod.Post}; + private Maybe callback; private Maybe properties; private Maybe name; private Maybe displayName; @@ -21,13 +28,20 @@ public Result Create() => Result.Evaluate) .Bind(evaluation => evaluation.WithRules( VerifyName, VerifyNameLength, VerifyDisplayName, - VerifyDisplayNameLength)); + VerifyDisplayNameLength, this.VerifyCallbackHttpMethod)); + + public IBuilderForOptional WithCallback(Callback value) + { + this.callback = value; + return this; + } public IBuilderForOptional WithDisplayName(string value) { @@ -53,6 +67,14 @@ public IBuilderForOptional WithProperties(Properties value) return this; } + private Result VerifyCallbackHttpMethod(CreateConversationRequest request) => + request.Callback.Match( + some => this.allowedMethods.Contains(some.Method) + ? Result.FromSuccess(request) + : ResultFailure.FromErrorMessage("Callback HttpMethod must be GET or POST.") + .ToResult(), + () => request); + private static Result VerifyDisplayName(CreateConversationRequest request) => request.DisplayName.Match( some => InputValidation.VerifyNotEmpty(request, some, nameof(request.DisplayName)), @@ -80,6 +102,13 @@ private static Result VerifyNameLength(CreateConversa /// public interface IBuilderForOptional : IVonageRequestBuilder { + /// + /// Sets the Callback. + /// + /// The callback. + /// The builder. + IBuilderForOptional WithCallback(Callback value); + /// /// Sets the Display Name. /// diff --git a/Vonage/Conversations/CreateConversation/CreateConversationResponse.cs b/Vonage/Conversations/CreateConversation/CreateConversationResponse.cs index 57f156afd..8f12ae5d1 100644 --- a/Vonage/Conversations/CreateConversation/CreateConversationResponse.cs +++ b/Vonage/Conversations/CreateConversation/CreateConversationResponse.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Text.Json.Serialization; using Vonage.Common; using Vonage.Common.Monads; @@ -27,11 +26,4 @@ public record Timestamp(DateTimeOffset Created, [property: JsonConverter(typeof(MaybeJsonConverter))] Maybe Destroyed); -public record Properties( - [property: JsonPropertyName("ttl")] int TimeToLive, string Type, - [property: JsonPropertyName("custom_sort_key")] - string CustomSortKey, - [property: JsonPropertyName("custom_data")] - Dictionary CustomData); - public record Links(HalLink Self); \ No newline at end of file diff --git a/Vonage/Conversations/CreateConversation/Properties.cs b/Vonage/Conversations/CreateConversation/Properties.cs new file mode 100644 index 000000000..ce34fc64d --- /dev/null +++ b/Vonage/Conversations/CreateConversation/Properties.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Vonage.Conversations.CreateConversation; + +public record Properties( + [property: JsonPropertyName("ttl")] int TimeToLive, string Type, + [property: JsonPropertyName("custom_sort_key")] + string CustomSortKey, + [property: JsonPropertyName("custom_data")] + Dictionary CustomData); \ No newline at end of file