diff --git a/CHANGELOG.md b/CHANGELOG.md index c65e5392..f1ecaf52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Change Log +## [v5.39.0](https://github.com/plivo/plivo-dotnet/tree/v5.39.0) (2023-11-10) +**Feature - Verify Caller Id API support** +- API support for verifying, updating, getting and deleting caller IDs. ## [5.38.0](https://github.com/plivo/plivo-dotnet/tree/v5.38.0) (2023-11-08) **Verify Service** diff --git a/README.md b/README.md index 8b5900a6..64f1024f 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ You can install this SDK either by referencing the .dll file or using NuGet. Use the following line to install the latest SDK using the NuGet CLI. ``` -PM> Install-Package Plivo -Version 5.38.0 +PM> Install-Package Plivo -Version 5.39.0 ``` You can also use the .NET CLI to install this package as follows ``` -> dotnet add package Plivo --version 5.38.0 +> dotnet add package Plivo --version 5.39.0 ``` ## Getting started diff --git a/src/Plivo/Plivo.csproj b/src/Plivo/Plivo.csproj index bd9e6d2a..b47e0faa 100644 --- a/src/Plivo/Plivo.csproj +++ b/src/Plivo/Plivo.csproj @@ -1,7 +1,7 @@ netstandard2.0;netstandard1.3 - 5.38.0 + 5.39.0 Plivo SDKs Team Plivo Inc. diff --git a/src/Plivo/Plivo.nuspec b/src/Plivo/Plivo.nuspec index 24a09b30..63aac5ae 100644 --- a/src/Plivo/Plivo.nuspec +++ b/src/Plivo/Plivo.nuspec @@ -4,7 +4,7 @@ A .NET SDK to make voice calls and send SMS using Plivo and to generate Plivo XML A .NET SDK to make voice calls and send SMS using Plivo and to generate Plivo XML Plivo - 5.38.0 + 5.39.0 Plivo Plivo SDKs Team Plivo, Inc. @@ -12,6 +12,7 @@ http://github.com/plivo/plivo-dotnet false + * 5.39.0 API support for verifying, updating, getting and deleting caller IDs. * 5.38.0 Adding verify service APIs. * 5.37.0 API support for Create, Update, Get, Delete and List Tollfree Verification. * 5.36.0 Added New Params `campaign_source`. diff --git a/src/Plivo/PlivoApi.cs b/src/Plivo/PlivoApi.cs index 6b7f22d8..85f3ac36 100755 --- a/src/Plivo/PlivoApi.cs +++ b/src/Plivo/PlivoApi.cs @@ -30,6 +30,7 @@ using Plivo.Resource.Profile; using Plivo.Resource.Token; using Plivo.Resource.TollfreeVerification; +using Plivo.Resource.VerifyCallerId; namespace Plivo { @@ -80,6 +81,7 @@ public class PlivoApi private readonly Lazy _multiPartyCall; private readonly Lazy _tollfreeVerification; + private readonly Lazy _verifyCallerId; /// /// Gets the account. @@ -202,6 +204,8 @@ public class PlivoApi public MultiPartyCallInterface MultiPartyCall => _multiPartyCall.Value; public TollfreeVerificationInterface TollfreeVerification => _tollfreeVerification.Value; + + public VerifyCallerIdInterface VerifyCallerId => _verifyCallerId.Value; /// @@ -255,6 +259,7 @@ public PlivoApi( new Lazy(() => new ComplianceApplicationInterface(Client)); _multiPartyCall = new Lazy(() => new MultiPartyCallInterface(Client)); _tollfreeVerification = new Lazy(() => new TollfreeVerificationInterface(Client)); + _verifyCallerId = new Lazy(() => new VerifyCallerIdInterface(Client)); } } } \ No newline at end of file diff --git a/src/Plivo/Resource/VerifyCallerId/AsyncResponse.cs b/src/Plivo/Resource/VerifyCallerId/AsyncResponse.cs new file mode 100644 index 00000000..e58264c4 --- /dev/null +++ b/src/Plivo/Resource/VerifyCallerId/AsyncResponse.cs @@ -0,0 +1,7 @@ +namespace Plivo.Resource.VerifyCallerId +{ + public class AsyncResponse : BaseResponse + { + + } +} \ No newline at end of file diff --git a/src/Plivo/Resource/VerifyCallerId/GetVerifiedCallerIdResponse.cs b/src/Plivo/Resource/VerifyCallerId/GetVerifiedCallerIdResponse.cs new file mode 100644 index 00000000..ee64f7f8 --- /dev/null +++ b/src/Plivo/Resource/VerifyCallerId/GetVerifiedCallerIdResponse.cs @@ -0,0 +1,37 @@ +using Newtonsoft.Json; + +namespace Plivo.Resource.VerifyCallerId +{ + [JsonObject(MemberSerialization.OptIn)] + public class GetVerifiedCallerIdResponse : Resource + { + [JsonProperty("api_id")] + public string ApiID { get; set; } + + [JsonProperty("alias")] + public string Alias { get; set; } + + [JsonProperty("country")] + public string Country { get; set; } + + [JsonProperty("created_at")] + public string CreatedAt { get; set; } + + [JsonProperty("modified_at")] + public string ModifiedAt { get; set; } + + [JsonProperty("phone_number")] + public string PhoneNumber { get; set; } + + [JsonProperty("subaccount")] + public string Subaccount { get; set; } + + [JsonProperty("verification_uuid")] + public string VerificationUuid { get; set; } + + public override string ToString() + { + return JsonConvert.SerializeObject(this, Formatting.Indented); + } + } +} \ No newline at end of file diff --git a/src/Plivo/Resource/VerifyCallerId/InitiateVerifyResponse.cs b/src/Plivo/Resource/VerifyCallerId/InitiateVerifyResponse.cs new file mode 100644 index 00000000..8573b9ca --- /dev/null +++ b/src/Plivo/Resource/VerifyCallerId/InitiateVerifyResponse.cs @@ -0,0 +1,31 @@ +using Newtonsoft.Json; + +namespace Plivo.Resource.VerifyCallerId +{ + [JsonObject(MemberSerialization.OptIn)] + public class InitiateVerifyResponse : Resource + { + [JsonProperty("api_id")] + public new string ApiId { get; set; } + + [JsonProperty("verification_uuid")] + public new string VerificationUuid { get; set; } + + [JsonProperty("message")] + public new string Message { get; set; } + + [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)] // Ignore null values for "error" + public string Error { get; set; } + + public override string ToString() + { + var settings = new JsonSerializerSettings + { + Formatting = Formatting.Indented, + NullValueHandling = NullValueHandling.Ignore // Ignore null values globally + }; + + return JsonConvert.SerializeObject(this, settings); + } + } +} \ No newline at end of file diff --git a/src/Plivo/Resource/VerifyCallerId/ListVerifiedCallerIdResponse.cs b/src/Plivo/Resource/VerifyCallerId/ListVerifiedCallerIdResponse.cs new file mode 100644 index 00000000..4074820e --- /dev/null +++ b/src/Plivo/Resource/VerifyCallerId/ListVerifiedCallerIdResponse.cs @@ -0,0 +1,37 @@ +using Newtonsoft.Json; + +namespace Plivo.Resource.VerifyCallerId +{ + [JsonObject(MemberSerialization.OptIn)] + public class ListVerifiedCallerIdResponse : Resource + { + [JsonProperty("alias")] + public string Alias { get; set; } + + [JsonProperty("country")] + public string Country { get; set; } + + [JsonProperty("created_at")] + public string CreatedAt { get; set; } + + [JsonProperty("modified_at")] + public string ModifiedAt { get; set; } + + [JsonProperty("phone_number")] + public string PhoneNumber { get; set; } + + [JsonProperty("resource_uri")] + public string ResourceUri { get; set; } + + [JsonProperty("subaccount")] + public string Subaccount { get; set; } + + [JsonProperty("verification_uuid")] + public string VerificationUuid { get; set; } + + public override string ToString() + { + return JsonConvert.SerializeObject(this, Formatting.Indented); + } + } +} \ No newline at end of file diff --git a/src/Plivo/Resource/VerifyCallerId/VerifyCallerId.cs b/src/Plivo/Resource/VerifyCallerId/VerifyCallerId.cs new file mode 100644 index 00000000..95a53fcd --- /dev/null +++ b/src/Plivo/Resource/VerifyCallerId/VerifyCallerId.cs @@ -0,0 +1,38 @@ +using Newtonsoft.Json; + +namespace Plivo.Resource.VerifyCallerId +{ + + [JsonObject(MemberSerialization.OptIn)] + public class VerifyCallerId : Resource + { + [JsonProperty("api_id")] + public string ApiID { get; set; } + + [JsonProperty("alias")] + public string Alias { get; set; } + + [JsonProperty("channel")] + public string Channel { get; set; } + + [JsonProperty("country")] + public string Country { get; set; } + + [JsonProperty("created_at")] + public string CreatedAt { get; set; } + + [JsonProperty("phone_number")] + public string PhoneNumber { get; set; } + + [JsonProperty("subaccount")] + public string Subaccount { get; set; } + + [JsonProperty("verification_uuid")] + public string VerificationUuid { get; set; } + + public override string ToString() + { + return JsonConvert.SerializeObject(this, Formatting.Indented); + } + } +} \ No newline at end of file diff --git a/src/Plivo/Resource/VerifyCallerId/VerifyCallerIdInterface.cs b/src/Plivo/Resource/VerifyCallerId/VerifyCallerIdInterface.cs new file mode 100644 index 00000000..fd7bcba0 --- /dev/null +++ b/src/Plivo/Resource/VerifyCallerId/VerifyCallerIdInterface.cs @@ -0,0 +1,277 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Plivo.Client; +using Plivo.Exception; +using Plivo.Resource.Application; + +namespace Plivo.Resource.VerifyCallerId +{ + public class VerifyCallerIdInterface : ResourceInterface + { + public VerifyCallerIdInterface(HttpClient client) : base(client) + { + Uri = "Account/" + Client.GetAuthId() + "/VerifiedCallerId/"; + } + + #region Initiate + + public InitiateVerifyResponse Initiate(string phoneNumber, string channel = null, string alias = null, string subaccount = null) + { + Dictionary data = null; + var mandatoryParams = new List { "phoneNumber" }; + data = CreateData( + mandatoryParams, + new + { + phoneNumber, + channel, + alias, + subaccount + }); + + return ExecuteWithExceptionUnwrap(() => + { + var result = Task.Run(async () => await Client.Update(Uri, data).ConfigureAwait(false)).Result; + result.Object.StatusCode = result.StatusCode; + return result.Object; + }); + } + + public async Task InitiateAsync(string phoneNumber, string channel = null, string alias = null, string subaccount = null) + { + Dictionary data = null; + var mandatoryParams = new List { "phoneNumber" }; + data = CreateData( + mandatoryParams, + new + { + phoneNumber, + channel, + alias, + subaccount + }); + + var result = await Client.Update(Uri, data); + result.Object.StatusCode = result.StatusCode; + return result.Object; + } + + #endregion + + #region Verify + + public VerifyCallerId Verify(string otp, string verificationUuid) + { + if (string.IsNullOrEmpty(verificationUuid)) + { + throw new PlivoValidationException("verification Uuid is a required parameter"); + } + Dictionary data = null; + var mandatoryParams = new List { "otp" }; + data = CreateData( + mandatoryParams, + new + { + otp + }); + + return ExecuteWithExceptionUnwrap(() => + { + var result = Task.Run(async () => await Client.Update(Uri + "Verification/" + verificationUuid, data).ConfigureAwait(false)).Result; + result.Object.StatusCode = result.StatusCode; + return result.Object; + }); + } + + public async Task VerifyAsync(string otp, string verificationUuid) + { + if (string.IsNullOrEmpty(verificationUuid)) + { + throw new PlivoValidationException("verification Uuid is a required parameter"); + } + Dictionary data = null; + var mandatoryParams = new List { "otp" }; + data = CreateData( + mandatoryParams, + new + { + otp + }); + + var result = await Client.Update(Uri + "Verification/" + verificationUuid, data); + result.Object.StatusCode = result.StatusCode; + return result.Object; + } + + #endregion + + #region Update + + public GetVerifiedCallerIdResponse Update(string phoneNumber, string alias = null, string subaccount = null) + { + if (string.IsNullOrEmpty(phoneNumber)) + { + throw new PlivoValidationException("phoneNumber is a required parameter"); + } + Dictionary data = null; + var mandatoryParams = new List {""}; + data = CreateData( + mandatoryParams, + new + { + alias, + subaccount + }); + + return ExecuteWithExceptionUnwrap(() => + { + var result = Task.Run(async () => await Client.Update(Uri + phoneNumber, data).ConfigureAwait(false)).Result; + result.Object.StatusCode = result.StatusCode; + return result.Object; + }); + } + + public async Task UpdateAsync(string phoneNumber, string alias = null, string subaccount = null) + { + if (string.IsNullOrEmpty(phoneNumber)) + { + throw new PlivoValidationException("phoneNumber is a required parameter"); + } + Dictionary data = null; + var mandatoryParams = new List {""}; + data = CreateData( + mandatoryParams, + new + { + alias, + subaccount + }); + + var result = await Client.Update(Uri + phoneNumber, data); + result.Object.StatusCode = result.StatusCode; + return result.Object; + } + + #endregion + + #region Get + + public GetVerifiedCallerIdResponse Get(string phoneNumber) + { + if (string.IsNullOrEmpty(phoneNumber)) + { + throw new PlivoValidationException("phoneNumber is a required parameter"); + } + return ExecuteWithExceptionUnwrap(() => + { + var verifiedCallerId = Task.Run(async () => await GetResource(phoneNumber).ConfigureAwait(false)).Result; + verifiedCallerId.Interface = this; + return verifiedCallerId; + }); + } + + public async Task GetAsync(string phoneNumber) + { + if (string.IsNullOrEmpty(phoneNumber)) + { + throw new PlivoValidationException("phoneNumber is a required parameter"); + } + var verifiedCallerId = await GetResource(phoneNumber); + verifiedCallerId.Interface = this; + return verifiedCallerId; + } + + #endregion + + #region List + + public ListResponse List(uint? limit = null, uint? offset = null, + string country = null, string alias = null, string subaccount = null) + { + var mandatoryParams = new List { "" }; + var data = CreateData( + mandatoryParams, + new + { + limit, + offset, + country, + alias, + subaccount, + }); + return ExecuteWithExceptionUnwrap(() => + { + var resources = Task.Run(async () => await ListResources>(data).ConfigureAwait(false)).Result; + resources.Objects.ForEach( + (obj) => obj.Interface = this + ); + return resources; + }); + } + + public async Task> ListAsync(uint? limit = null, uint? offset = null, + string country = null, string alias = null, string subaccount = null) + { + var mandatoryParams = new List { "" }; + var data = CreateData( + mandatoryParams, new + { + limit, + offset, + country, + alias, + subaccount, + }); + + var resources = await ListResources>(data); + resources.Objects.ForEach( + (obj) => obj.Interface = this + ); + return resources; + } + #endregion + + #region Delete + + public DeleteResponse Delete(string phoneNumber) + { + if (string.IsNullOrEmpty(phoneNumber)) + { + throw new PlivoValidationException("phoneNumber is a required parameter"); + } + var mandatoryParams = new List { "" }; + var data = CreateData ( + mandatoryParams, new {}); + + return ExecuteWithExceptionUnwrap (() => { + var result = Task.Run (async () => + await Client.Delete> (Uri + phoneNumber, data). + ConfigureAwait (false)).Result; + try { + result.Object.StatusCode = result.StatusCode; + } catch (System.NullReferenceException) { + + } + return result.Object; + }); + } + + public async Task DeleteAsync(string phoneNumber) { + if (string.IsNullOrEmpty(phoneNumber)) + { + throw new PlivoValidationException("phoneNumber is a required parameter"); + } + var mandatoryParams = new List { "" }; + var data = CreateData ( + mandatoryParams, new {}); + + var result = Task.Run (async () => + await Client.Delete (Uri + phoneNumber, data).ConfigureAwait (false)).Result; + await Task.WhenAll(); + result.Object.StatusCode = result.StatusCode; + return result.Object; + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Plivo/Version.cs b/src/Plivo/Version.cs index 9bf5159b..c2dfbfb8 100644 --- a/src/Plivo/Version.cs +++ b/src/Plivo/Version.cs @@ -10,7 +10,7 @@ public class Version /// /// DotNet SDK version /// - public const string SdkVersion = "5.38.0"; + public const string SdkVersion = "5.39.0"; /// /// Plivo API version /// diff --git a/tests/Plivo.Test/Mocks/getVerifiedCallerIdResponse.json b/tests/Plivo.Test/Mocks/getVerifiedCallerIdResponse.json new file mode 100644 index 00000000..fdaddb47 --- /dev/null +++ b/tests/Plivo.Test/Mocks/getVerifiedCallerIdResponse.json @@ -0,0 +1,10 @@ +{ + "alias": "test", + "api_id": "35c999a4-f1ad-4af7-9cc6-c8ccac7fd283", + "country": "US", + "created_at": "2023-10-13T11:46:58.334899Z", + "modified_at": "2023-10-13T11:46:58.334899Z", + "phone_number": "+919999999999", + "subaccount": "", + "verification_uuid": "605c75f2-02b6-4cb8-883d-69cf37b21e5a" +} \ No newline at end of file diff --git a/tests/Plivo.Test/Mocks/initiateVerifyResponse.json b/tests/Plivo.Test/Mocks/initiateVerifyResponse.json new file mode 100644 index 00000000..2b85e95b --- /dev/null +++ b/tests/Plivo.Test/Mocks/initiateVerifyResponse.json @@ -0,0 +1,5 @@ +{ + "api_id": "b1e04bbb-9cb3-435e-946a-aea5e4f4709e", + "message": "Verification code is sent to number +919999999999 which is valid for 15 minutes", + "verification_uuid": "74df1f8f-056d-4c9c-8fc5-11615fbb23a0" +} \ No newline at end of file diff --git a/tests/Plivo.Test/Mocks/listVerifiedCallerIdResponse.json b/tests/Plivo.Test/Mocks/listVerifiedCallerIdResponse.json new file mode 100644 index 00000000..b68ae0ba --- /dev/null +++ b/tests/Plivo.Test/Mocks/listVerifiedCallerIdResponse.json @@ -0,0 +1,22 @@ +{ + "api_id": "5449144c-ff78-4da3-b6a2-9b22abdb7bd4", + "meta": { + "limit": 20, + "next": null, + "offset": 0, + "previous": null, + "total_count": 1 + }, + "objects": [ + { + "alias": "test", + "country": "IN", + "created_at": "2023-09-26T07:58:10.345732Z", + "modified_at": "2023-09-26T07:58:10.345732Z", + "phone_number": "+919999999999", + "resource_uri": "/v1/Account/authID/VerifiedCallerId/919999999999", + "subaccount": "subaccount", + "verification_uuid": "30fe8cc9-be93-4315-afa8-7fe26d05bb01" + } + ] +} \ No newline at end of file diff --git a/tests/Plivo.Test/Mocks/verifyCallerIdResponse.json b/tests/Plivo.Test/Mocks/verifyCallerIdResponse.json new file mode 100644 index 00000000..2db982e5 --- /dev/null +++ b/tests/Plivo.Test/Mocks/verifyCallerIdResponse.json @@ -0,0 +1,9 @@ +{ + "alias": "QA Test", + "api_id": "910cc1e1-c5fc-4f58-b9de-aa30e1cfd241", + "channel": "call", + "country": "US", + "created_at": "2023-10-13T11:46:58.334898885Z", + "phone_number": "+919999999999", + "verification_uuid": "605c75f2-02b6-4cb8-883d-69cf37b21e5a" +} \ No newline at end of file diff --git a/tests/Plivo.Test/Resources/TestVerifyCallerId.cs b/tests/Plivo.Test/Resources/TestVerifyCallerId.cs new file mode 100644 index 00000000..39af9869 --- /dev/null +++ b/tests/Plivo.Test/Resources/TestVerifyCallerId.cs @@ -0,0 +1,131 @@ +using System.Collections.Generic; +using NUnit.Framework; +using Plivo.Http; +using Plivo.Resource; +using Plivo.Resource.VerifyCallerId; +using Plivo.Utilities; +using System; +using Plivo.Test; + +namespace Plivo.Test.Resources +{ + [TestFixture] + public class TestVerifyCallerId : BaseTestCase + { + [Test] + public void TestVerifyCallerIdInitiate() + { + var data = new Dictionary() + { + {"phone_number", "+919999999999"} + }; + + var request = + new PlivoRequest( + "POST", + "Account/MAXXXXXXXXXXXXXXXXXX/VerifiedCallerId/", + "", + data); + + var response = + System.IO.File.ReadAllText( + SOURCE_DIR + @"../Mocks/initiateVerifyResponse.json" + ); + Setup( + 202, + response + ); + Assert.Empty( + ComparisonUtilities.Compare( + response, + Api.VerifyCallerId.Initiate(phoneNumber:"+919999999999"))); + + AssertRequest(request); + + } + + [Test] + public void TestVerifyCallerIdVerify() + { + var data = new Dictionary() + { + {"otp", "123456"} + }; + var verification_uuid = "4124e518-a8c9-4feb-8cff-d86636ba9234"; + var request = + new PlivoRequest( + "POST", + "Account/MAXXXXXXXXXXXXXXXXXX/VerifiedCallerId/Verification/" + verification_uuid , + "", + data); + + var response = + System.IO.File.ReadAllText( + SOURCE_DIR + @"../Mocks/verifyCallerIdResponse.json" + ); + Setup( + 202, + response + ); + Assert.Empty( + ComparisonUtilities.Compare( + response, + Api.VerifyCallerId.Verify(otp:"123456",verification_uuid))); + + AssertRequest(request); + } + + [Test] + public void TestVerifyCallerIdGet() + { + var phoneNumber = "+919999999999"; + var request = + new PlivoRequest( + "GET", + "Account/MAXXXXXXXXXXXXXXXXXX/VerifiedCallerId/" + phoneNumber, + ""); + var response = + System.IO.File.ReadAllText( + SOURCE_DIR + @"Mocks/getVerifiedCallerIdResponse.json" + ); + Setup( + 200, + response + ); + + Assert.Empty(ComparisonUtilities.Compare(response, Api.VerifyCallerId.Verify(phoneNumber: "+919999999999"))); + AssertRequest(request); + } + + [Test] + public void TestVerifyCallerIdList() + { + var data = new Dictionary() + { + {"limit", 10} + }; + var request = + new PlivoRequest( + "GET", + "Account/MAXXXXXXXXXXXXXXXXXX/VerifiedCallerId/", + ""); + var response = + System.IO.File.ReadAllText( + SOURCE_DIR + @"Mocks/listVerifiedCallerIdResponse.json" + ); + Setup>( + 200, + response + ); + Assert.Empty( + ComparisonUtilities.Compare( + response, + Api.VerifyCallerId.List(limit: 10))); + + AssertRequest(request); + } + + + } + +} diff --git a/version.json b/version.json index f5d9619e..0a87a7f1 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "version": "5.38.0", + "version": "5.39.0", "publicReleaseRefSpec": [ "^refs/heads/master$", "^refs/heads/v\\d+(?:\\.\\d+)?$"