diff --git a/src/Libraries/Kenc.Cloudflare.Core.IntegrationTests/IntegrationTests.cs b/src/Libraries/Kenc.Cloudflare.Core.IntegrationTests/IntegrationTests.cs index 9186a68..57cd8ff 100644 --- a/src/Libraries/Kenc.Cloudflare.Core.IntegrationTests/IntegrationTests.cs +++ b/src/Libraries/Kenc.Cloudflare.Core.IntegrationTests/IntegrationTests.cs @@ -1,6 +1,10 @@ namespace Kenc.Cloudflare.Core.IntegrationTests { + using System.Collections.Generic; + using System.Net.Http; using System.Threading.Tasks; + using Kenc.Cloudflare.Core.Clients; + using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] @@ -15,8 +19,8 @@ public async Task GetDomain() var domainId = TestContextSetting("domainId"); var domainName = TestContextSetting("domainName"); - var client = CreateClient(); - var domain = await client.Zones.ListAsync(domainName, Clients.Enums.ZoneStatus.Active); + CloudflareClient client = CreateClient(); + IList domain = await client.Zones.ListAsync(domainName, Clients.Enums.ZoneStatus.Active); Assert.IsNotNull(domain); Assert.AreEqual(domainId, domain[0].Id); } @@ -26,8 +30,8 @@ public async Task ListTxtRecords() { var domainId = TestContextSetting("domainId"); - var client = CreateClient(); - var dnsRecords = await client.Zones.DNSSettings.ListAsync(domainId, Clients.Enums.DNSRecordType.TXT); + CloudflareClient client = CreateClient(); + Entities.EntityList dnsRecords = await client.Zones.DNSSettings.ListAsync(domainId, Clients.Enums.DNSRecordType.TXT); Assert.IsNotNull(dnsRecords); Assert.AreNotEqual(0, dnsRecords.Count); } @@ -35,22 +39,27 @@ public async Task ListTxtRecords() [TestMethod] public async Task CreateTextRecord() { - var recordIdentifier = $"_intTest{System.DateTime.UtcNow.ToString("yyyymmddhhMM")}"; + var recordIdentifier = $"_intTest{System.DateTime.UtcNow:yyyymmddhhMM}"; var domainId = TestContextSetting("domainId"); - var client = CreateClient(); - var record = await client.Zones.DNSSettings.CreateRecordAsync(domainId, recordIdentifier, Clients.Enums.DNSRecordType.TXT, recordIdentifier); + CloudflareClient client = CreateClient(); + Entities.DNSRecord record = await client.Zones.DNSSettings.CreateRecordAsync(domainId, recordIdentifier, Clients.Enums.DNSRecordType.TXT, recordIdentifier); Assert.IsNotNull(record); Assert.AreEqual(recordIdentifier, record.Content); } - private Clients.CloudflareClient CreateClient() + private CloudflareClient CreateClient() { var apiKey = TestContextSetting("cloudflareapikey"); var username = TestContextSetting("cloudflareusername"); - var restFactory = new Clients.CloudflareRestClientFactory(Clients.CloudflareClient.V4Endpoint); - return new Clients.CloudflareClient(restFactory, username, apiKey, Clients.CloudflareClient.V4Endpoint); + var serviceCollection = new ServiceCollection(); + serviceCollection.AddHttpClient(); + var services = serviceCollection.BuildServiceProvider(); + var httpClientFactory = services.GetRequiredService(); + + var restClientFactory = new CloudflareRestClientFactory(httpClientFactory); + return new CloudflareClient(restClientFactory, username, apiKey, CloudflareAPIEndpoint.V4Endpoint); } private string TestContextSetting(string name) diff --git a/src/Libraries/Kenc.Cloudflare.Core.Tests/CloudflareRestClientTests.cs b/src/Libraries/Kenc.Cloudflare.Core.Tests/CloudflareRestClientTests.cs index 6f1242a..b86acb4 100644 --- a/src/Libraries/Kenc.Cloudflare.Core.Tests/CloudflareRestClientTests.cs +++ b/src/Libraries/Kenc.Cloudflare.Core.Tests/CloudflareRestClientTests.cs @@ -32,7 +32,7 @@ public async Task CloudflareRestClient_ShouldUseHttpClientFactoryToCreateClientF .Returns(httpClient); var cloudflareRestClient = new CloudflareRestClient(httpClientFactory.Object, "username", "apikey"); - var user = await cloudflareRestClient.GetAsync(new System.Uri(CloudflareClient.V4Endpoint, "user")); + var user = await cloudflareRestClient.GetAsync(new System.Uri(CloudflareAPIEndpoint.V4Endpoint, "user")); // assert httpClientFactory.Verify(x => x.CreateClient(It.IsAny()), Times.Once, $"{nameof(CloudflareRestClient)} should have called httpClientFactory.CreateClient())"); @@ -58,7 +58,7 @@ public async Task CloudflareRestClient_ShouldThrowCloudflareException() .Returns(httpClient); var cloudflareRestClient = new CloudflareRestClient(httpClientFactory.Object, "username", "apikey"); - var user = await cloudflareRestClient.GetAsync(new System.Uri(CloudflareClient.V4Endpoint, "user")); + var user = await cloudflareRestClient.GetAsync(new System.Uri(CloudflareAPIEndpoint.V4Endpoint, "user")); } [DataTestMethod] @@ -84,10 +84,10 @@ public async Task CloudflareRestClient_ShouldThrowCloudflareExceptionRegardlessO .Returns(httpClient); var cloudflareRestClient = new CloudflareRestClient(httpClientFactory.Object, "username", "apikey"); - var user = await cloudflareRestClient.GetAsync(new System.Uri(CloudflareClient.V4Endpoint, "user")); + var user = await cloudflareRestClient.GetAsync(new System.Uri(CloudflareAPIEndpoint.V4Endpoint, "user")); } - private HttpResponseMessage CreateResponseMessage(HttpStatusCode statuscode, CloudflareResult response) + private HttpResponseMessage CreateResponseMessage(HttpStatusCode statuscode, CloudflareResult response) where TResponse : class, ICloudflareEntity { return new HttpResponseMessage() { diff --git a/src/Libraries/Kenc.Cloudflare.Core.Tests/HttpClientFactory.cs b/src/Libraries/Kenc.Cloudflare.Core.Tests/HttpClientFactory.cs deleted file mode 100644 index 252cd35..0000000 --- a/src/Libraries/Kenc.Cloudflare.Core.Tests/HttpClientFactory.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Kenc.Cloudflare.Core.Tests -{ - using System.Net.Http; - - class MyHttpClientFactory : IHttpClientFactory - { - public HttpClient CreateClient(string name) - { - return HttpClientFactory.Create(); - } - } -} diff --git a/src/Libraries/Kenc.Cloudflare.Core.Tests/ZoneClientTests.cs b/src/Libraries/Kenc.Cloudflare.Core.Tests/ZoneClientTests.cs index 5fae29c..57cb338 100644 --- a/src/Libraries/Kenc.Cloudflare.Core.Tests/ZoneClientTests.cs +++ b/src/Libraries/Kenc.Cloudflare.Core.Tests/ZoneClientTests.cs @@ -28,7 +28,7 @@ public async Task ZoneClient_GetCallsRestClient() restClient.Setup(x => x.GetAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(zone); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var result = await zoneClient.GetAsync(zoneIdentifier); // assert @@ -46,7 +46,7 @@ public async Task ZoneClient_GetDoesntSwallowExceptions() new CloudflareAPIError("1049", " is not a registered domain") })); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); _ = await zoneClient.GetAsync(zoneIdentifier); } @@ -57,7 +57,7 @@ public async Task ZoneClient_GetDoesntSwallowExceptions() public async Task ZoneClient_GetThrowsArgumentExceptionForInvalidIdentifierInputs(string identifier) { var restClient = new Mock(); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); _ = await zoneClient.GetAsync(identifier); } @@ -69,7 +69,7 @@ public async Task ZoneClient_ListCallsRestClient() restClient.Setup(x => x.GetAsync>(It.IsAny(), It.IsAny())) .ReturnsAsync(zone); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var result = await zoneClient.ListAsync(); // assert @@ -86,7 +86,7 @@ public async Task ZoneClient_ListPassesAppropriateParameters(string name, ZoneSt restClient.Setup(x => x.GetAsync>(It.IsAny(), It.IsAny())) .ReturnsAsync(zone); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var result = await zoneClient.ListAsync(name, status, page, perPage, order, direction, match); // assert @@ -112,7 +112,7 @@ public async Task ZoneClient_ListDoesntSwallowExceptions() new CloudflareAPIError("1049", " is not a registered domain") })); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); _ = await zoneClient.ListAsync(); } @@ -124,7 +124,7 @@ public async Task ZoneClient_CreateCallsRestClient() restClient.Setup(x => x.PostAsync(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(zone); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var account = new Account { @@ -148,7 +148,7 @@ public async Task ZoneClient_CreateDoesntSwallowExceptions() new CloudflareAPIError("1049", " is not a registered domain") })); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var account = new Account { @@ -169,7 +169,7 @@ public async Task ZoneClient_CreateDoesntSwallowExceptions() public async Task ZoneClient_CreateThrowsArgumentExceptionForInvalidIdentifierInputs(string name, string accountId, string accountName) { var restClient = new Mock(); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var account = new Account { @@ -187,7 +187,7 @@ public async Task ZoneClient_DeleteCallsRestClient() restClient.Setup(x => x.DeleteAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(idResult); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var identifier = "1235678"; var result = await zoneClient.DeleteAsync(identifier); @@ -207,7 +207,7 @@ public async Task ZoneClient_DeleteDoesntSwallowExceptions() new CloudflareAPIError("1001", "Invalid zone identifier") })); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var identifier = "1235678"; _ = await zoneClient.DeleteAsync(identifier); @@ -220,7 +220,7 @@ public async Task ZoneClient_DeleteDoesntSwallowExceptions() public async Task ZoneClient_DeleteThrowsArgumentExceptionForInvalidIdentifierInputs(string identifier) { var restClient = new Mock(); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); _ = await zoneClient.DeleteAsync(identifier); } @@ -229,18 +229,17 @@ public async Task ZoneClient_InitiateZoneActivationCheckCallsRestClient() { var idResult = new IdResult(); var restClient = new Mock(); - restClient.Setup(x => x.PutAsync(It.IsAny(), null, It.IsAny())) + restClient.Setup(x => x.PutAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(idResult); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var result = await zoneClient.InitiateZoneActivationCheckAsync(zoneIdentifier); // assert Assert.AreSame(idResult, result, "The returned zone object should have been passed through"); restClient.Verify(x => - x.PutAsync( + x.PutAsync( It.Is(y => y.PathAndQuery == $"/client/v4/zones/{zoneIdentifier}/activation_check"), - null, It.IsAny()), Times.Once, "Put should have been called on the REST client."); @@ -251,12 +250,12 @@ public async Task ZoneClient_InitiateZoneActivationCheckCallsRestClient() public async Task ZoneClient_InitiateZoneActivationCheckDoesntSwallowExceptions() { var restClient = new Mock(); - restClient.Setup(x => x.PutAsync(It.IsAny(), null, It.IsAny())) + restClient.Setup(x => x.PutAsync(It.IsAny(), It.IsAny())) .ThrowsAsync(new CloudflareException(new List { new CloudflareAPIError("1049", " is not a registered domain") })); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); _ = await zoneClient.InitiateZoneActivationCheckAsync(zoneIdentifier); } @@ -267,7 +266,7 @@ public async Task ZoneClient_InitiateZoneActivationCheckDoesntSwallowExceptions( public async Task ZoneClient_InitiateZoneActivationCheckThrowsArgumentExceptionForInvalidIdentifierInputs(string identifier) { var restClient = new Mock(); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); _ = await zoneClient.InitiateZoneActivationCheckAsync(identifier); } @@ -283,7 +282,7 @@ public async Task ZoneClient_PurgeAllFilesCallsRestClient(bool purgeAll) It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(idResult); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var result = await zoneClient.PurgeAllFiles(zoneIdentifier, purgeAll); // assert @@ -309,7 +308,7 @@ public async Task ZoneClient_PurgeAllFilesDoesntSwallowExceptions() new CloudflareAPIError("1049", " is not a registered domain") })); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); _ = await zoneClient.PurgeAllFiles(zoneIdentifier, true); } @@ -320,7 +319,7 @@ public async Task ZoneClient_PurgeAllFilesDoesntSwallowExceptions() public async Task ZoneClient_PurgeAllFilesThrowsArgumentExceptionForInvalidIdentifierInputs(string identifier) { var restClient = new Mock(); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); _ = await zoneClient.PurgeAllFiles(identifier, true); } @@ -335,7 +334,7 @@ public async Task ZoneClient_PurgeFilesByTagsOrHostsCallsRestClient(string[] tag It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(idResult); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var result = await zoneClient.PurgeFilesByTagsOrHosts(zoneIdentifier, tags, hosts); // assert @@ -368,7 +367,7 @@ public async Task ZoneClient_PurgeFilesByTagsOrHostsDoesntSwallowExceptions() new CloudflareAPIError("1049", " is not a registered domain") })); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); _ = await zoneClient.PurgeFilesByTagsOrHosts(zoneIdentifier, new string[] { "some-tag" }, new string[] { "example.invalid" }); } @@ -377,7 +376,7 @@ public async Task ZoneClient_PurgeFilesByTagsOrHostsDoesntSwallowExceptions() public async Task ZoneClient_PurgeFilesByTagsOrHostsThrowsArgumentExceptionForInvalidIdentifierInputs() { var restClient = new Mock(); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); _ = await zoneClient.PurgeFilesByTagsOrHosts(string.Empty, new string[] { "tags" }, new string[] { "hosts" }); } @@ -387,7 +386,7 @@ public async Task ZoneClient_PurgeFilesByTagsOrHostsThrowsArgumentExceptionForIn public async Task ZoneClient_PurgeFilesByTagsOrHostsThrowsArgumentExceptionForInvalidInputs(string[] tags, string[] hosts) { var restClient = new Mock(); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); _ = await zoneClient.PurgeFilesByTagsOrHosts(zoneIdentifier, tags, hosts); } diff --git a/src/Libraries/Kenc.Cloudflare.Core.Tests/ZoneDNSSettingsClientTests.cs b/src/Libraries/Kenc.Cloudflare.Core.Tests/ZoneDNSSettingsClientTests.cs index 77afd7b..c1d3e38 100644 --- a/src/Libraries/Kenc.Cloudflare.Core.Tests/ZoneDNSSettingsClientTests.cs +++ b/src/Libraries/Kenc.Cloudflare.Core.Tests/ZoneDNSSettingsClientTests.cs @@ -25,7 +25,7 @@ public async Task ZoneDNSSettingsClient_GetCallsRestClient() restClient.Setup(x => x.GetAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(zone); - var client = new ZoneDNSSettingsClient(restClient.Object, CloudflareClient.V4Endpoint); + var client = new ZoneDNSSettingsClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var result = await client.GetAsync(zoneIdentifier, "domain.invalid"); // assert @@ -46,7 +46,7 @@ public async Task ZoneDNSSettingsClient_GetDoesntSwallowExceptions() new CloudflareAPIError("1049", " is not a registered domain") })); - var client = new ZoneDNSSettingsClient(restClient.Object, CloudflareClient.V4Endpoint); + var client = new ZoneDNSSettingsClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); _ = await client.GetAsync(zoneIdentifier, "domain.invalid"); } @@ -59,7 +59,7 @@ public async Task ZoneDNSSettingsClient_GetDoesntSwallowExceptions() public async Task ZoneDNSSettingsClient_GetThrowsArgumentExceptionForInvalidInputs(string identifier, string name) { var restClient = new Mock(); - var client = new ZoneDNSSettingsClient(restClient.Object, CloudflareClient.V4Endpoint); + var client = new ZoneDNSSettingsClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); _ = await client.GetAsync(identifier, name); } @@ -71,7 +71,7 @@ public async Task ZoneDNSSettingsClient_ListCallsRestClient() restClient.Setup(x => x.GetAsync>(It.IsAny(), It.IsAny())) .ReturnsAsync(zone); - var client = new ZoneDNSSettingsClient(restClient.Object, CloudflareClient.V4Endpoint); + var client = new ZoneDNSSettingsClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var result = await client.ListAsync(zoneIdentifier); // assert @@ -91,7 +91,7 @@ public async Task ZoneDNSSettingsClient_ListPassesAppropriateParameters(string z restClient.Setup(x => x.GetAsync>(It.IsAny(), It.IsAny())) .ReturnsAsync(records); - var zoneClient = new ZoneDNSSettingsClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneDNSSettingsClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var result = await zoneClient.ListAsync(zoneIdentifier, type, name, content, page, perPage, order, direction, match); // assert @@ -124,7 +124,7 @@ public async Task ZoneDNSSettingsClient_ListDoesntSwallowExceptions() new CloudflareAPIError("1049", " is not a registered domain") })); - var zoneClient = new ZoneClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); _ = await zoneClient.ListAsync(); } } diff --git a/src/Libraries/Kenc.Cloudflare.Core.Tests/ZoneSettingsClientTests.cs b/src/Libraries/Kenc.Cloudflare.Core.Tests/ZoneSettingsClientTests.cs index 3918f31..3c75ff2 100644 --- a/src/Libraries/Kenc.Cloudflare.Core.Tests/ZoneSettingsClientTests.cs +++ b/src/Libraries/Kenc.Cloudflare.Core.Tests/ZoneSettingsClientTests.cs @@ -24,7 +24,7 @@ public async Task ZoneClient_GetCallsRestClient() restClient.Setup(x => x.GetAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(zone); - var zoneClient = new ZoneSettingsClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneSettingsClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var result = await zoneClient.GetAsync(zoneIdentifier, "setting"); // assert @@ -45,7 +45,7 @@ public async Task ZoneClient_GetDoesntSwallowExceptions() new CloudflareAPIError("1049", " is not a registered domain") })); - var zoneClient = new ZoneSettingsClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneSettingsClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var result = await zoneClient.GetAsync(zoneIdentifier, "setting"); } @@ -58,8 +58,8 @@ public async Task ZoneClient_GetDoesntSwallowExceptions() public async Task ZoneClient_GetThrowsArgumentExceptionForInvalidInputs(string identifier, string name) { var restClient = new Mock(); - var zoneClient = new ZoneSettingsClient(restClient.Object, CloudflareClient.V4Endpoint); - var result = await zoneClient.GetAsync(identifier, name); + var zoneClient = new ZoneSettingsClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); + _ = await zoneClient.GetAsync(identifier, name); } [TestMethod] @@ -70,7 +70,7 @@ public async Task ZoneClient_ListCallsRestClient() restClient.Setup(x => x.GetAsync>(It.IsAny(), It.IsAny())) .ReturnsAsync(zone); - var zoneClient = new ZoneSettingsClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneSettingsClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var result = await zoneClient.ListAsync(zoneIdentifier); // assert @@ -88,8 +88,8 @@ public async Task ZoneClient_ListCallsRestClient() public async Task ZoneClient_ListThrowsArgumentExceptionForInvalidIdentifierInputs(string identifier) { var restClient = new Mock(); - var zoneClient = new ZoneSettingsClient(restClient.Object, CloudflareClient.V4Endpoint); - var result = await zoneClient.ListAsync(identifier); + var zoneClient = new ZoneSettingsClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); + _ = await zoneClient.ListAsync(identifier); } [TestMethod] @@ -102,7 +102,7 @@ public async Task ZoneClient_ListDoesntSwallowExceptions() new CloudflareAPIError("1049", " is not a registered domain") })); - var zoneClient = new ZoneSettingsClient(restClient.Object, CloudflareClient.V4Endpoint); + var zoneClient = new ZoneSettingsClient(restClient.Object, CloudflareAPIEndpoint.V4Endpoint); var result = await zoneClient.ListAsync(zoneIdentifier); } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareAPIEndpoint.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareAPIEndpoint.cs new file mode 100644 index 0000000..c8addf6 --- /dev/null +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareAPIEndpoint.cs @@ -0,0 +1,15 @@ +namespace Kenc.Cloudflare.Core.Clients +{ + using System; + + /// + /// Static class listing Cloudflare API endpoints. + /// + public static class CloudflareAPIEndpoint + { + /// + /// Cloudflare API v4 endpoint. + /// + public readonly static Uri V4Endpoint = new Uri("https://api.cloudflare.com/client/v4/"); + } +} diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareClient.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareClient.cs index 3ec18a7..620da98 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareClient.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareClient.cs @@ -3,25 +3,40 @@ using System; using Kenc.Cloudflare.Core.Clients.EntityClients; + /// + /// Implementation of for interacting with the Cloudflare API. + /// + /// public class CloudflareClient : ICloudflareClient { - public readonly static Uri V4Endpoint = new Uri("https://api.cloudflare.com/client/v4/"); - private readonly IRestClient restClient; + public IZoneClient Zones { get; private set; } + + public IUserClient UserClient { get; private set; } + + public IZoneDNSSettingsClient ZoneDNSSettingsClient { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// RestClient factory to use. + /// Cloudflare Username + /// Cloudflare APIKey + /// Cloudflare Endpoint. + /// Throws when any of the parameters are null or public CloudflareClient(ICloudflareRestClientFactory restClientFactory, string username, string apiKey, Uri endpoint) { + _ = string.IsNullOrEmpty(apiKey) ? throw new ArgumentNullException(nameof(apiKey)) : apiKey; + _ = string.IsNullOrEmpty(username) ? throw new ArgumentNullException(nameof(username)) : username; + _ = endpoint ?? throw new ArgumentNullException(nameof(endpoint)); + _ = restClientFactory ?? throw new ArgumentNullException(nameof(restClientFactory)); + restClient = restClientFactory.CreateRestClient(username, apiKey); Zones = new ZoneClient(restClient, endpoint); UserClient = new UserClient(restClient, endpoint); ZoneDNSSettingsClient = new ZoneDNSSettingsClient(restClient, endpoint); } - - public IZoneClient Zones { get; private set; } - - public IUserClient UserClient { get; private set; } - - public IZoneDNSSettingsClient ZoneDNSSettingsClient { get; private set; } } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareClientFactory.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareClientFactory.cs index 831d2ae..7a4b8c3 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareClientFactory.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareClientFactory.cs @@ -2,44 +2,35 @@ { using System; + /// + /// Implementation of . + /// + /// public class CloudflareClientFactory : ICloudflareClientFactory { - private string username; - private string apiKey; - private ICloudflareRestClientFactory restClientFactory; - private Uri endpoint; + private readonly string apiKey; + private readonly string username; + private readonly Uri endpoint; + private readonly ICloudflareRestClientFactory restClientFactory; - public CloudflareClientFactory() + /// + /// Initializes a new instance of . + /// + /// Cloudflare username. + /// Cloudflare API key. + /// Rest factory. + /// Cloudflare API endpoint. + public CloudflareClientFactory(string username, string apiKey, ICloudflareRestClientFactory cloudflareRestClientFactory, Uri endpoint) { + this.apiKey = string.IsNullOrEmpty(apiKey) ? throw new ArgumentNullException(nameof(apiKey)) : apiKey; + this.username = string.IsNullOrEmpty(username) ? throw new ArgumentNullException(nameof(username)) : username; + this.endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint)); + this.restClientFactory = cloudflareRestClientFactory ?? throw new ArgumentNullException(nameof(cloudflareRestClientFactory)); } public ICloudflareClient Create() { return new CloudflareClient(restClientFactory, username, apiKey, endpoint); } - - public ICloudflareClientFactory WithUsername(string username) - { - this.username = username; - return this; - } - - public ICloudflareClientFactory WithAPIKey(string apiKey) - { - this.apiKey = apiKey; - return this; - } - - public ICloudflareClientFactory WithEndpoint(Uri endpoint) - { - this.endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint)); - return this; - } - - public ICloudflareClientFactory WithRestClientFactory(ICloudflareRestClientFactory cloudflareRestClientFactory) - { - this.restClientFactory = cloudflareRestClientFactory; - return this; - } } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareRestClient.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareRestClient.cs index d51b373..3ead3f8 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareRestClient.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareRestClient.cs @@ -13,14 +13,14 @@ using Kenc.Cloudflare.Core.Exceptions; using Newtonsoft.Json; - public class CloudflareRestClient : IRestClient + public class CloudflareRestClient : IRestClient, IDisposable { + private bool disposed = false; + private const string AuthHeaderKey = "X-Auth-Key"; private const string AuthHeaderUsername = "X-Auth-Email"; private const string ApplicationJsonMime = "application/json"; - private readonly string apiKey; - private readonly string username; private readonly string UserAgent; private static readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings @@ -29,9 +29,9 @@ public class CloudflareRestClient : IRestClient NullValueHandling = NullValueHandling.Ignore }; - private readonly JsonMediaTypeFormatter jsonMediaTypeFormatter; + private readonly JsonMediaTypeFormatter jsonMediaTypeFormatter = new JsonMediaTypeFormatter { SerializerSettings = JsonSettings }; - private readonly IHttpClientFactory httpClientFactory; + private readonly HttpClient httpClient; /// /// Initializes a new instance of the class. @@ -41,28 +41,19 @@ public class CloudflareRestClient : IRestClient /// Cloudflare API key. public CloudflareRestClient(IHttpClientFactory httpClientFactory, string username, string apiKey) { - if (string.IsNullOrEmpty(username)) - { - throw new ArgumentNullException(nameof(username)); - } - - if (string.IsNullOrEmpty(apiKey)) - { - throw new ArgumentNullException(nameof(apiKey)); - } - - this.apiKey = apiKey; - this.username = username; - this.httpClientFactory = httpClientFactory; - - jsonMediaTypeFormatter = new JsonMediaTypeFormatter() - { - SerializerSettings = JsonSettings - }; + _ = string.IsNullOrEmpty(apiKey) ? throw new ArgumentNullException(nameof(apiKey)) : apiKey; + _ = string.IsNullOrEmpty(username) ? throw new ArgumentNullException(nameof(username)) : username; + _ = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); Type client = typeof(CloudflareRestClient); - var runtimeVersion = client.Assembly.GetCustomAttribute(); + AssemblyFileVersionAttribute runtimeVersion = client.Assembly.GetCustomAttribute(); UserAgent = $"{client.FullName}/{runtimeVersion.Version} ({RuntimeInformation.OSDescription} {RuntimeInformation.ProcessArchitecture})"; + + httpClient = httpClientFactory.CreateClient("Cloudflare"); + httpClient.DefaultRequestHeaders.Add(AuthHeaderKey, apiKey); + httpClient.DefaultRequestHeaders.Add(AuthHeaderUsername, username); + httpClient.DefaultRequestHeaders.Add(HttpRequestHeader.UserAgent.ToString(), UserAgent); + httpClient.DefaultRequestHeaders.Add(HttpRequestHeader.ContentType.ToString(), ApplicationJsonMime); } /// @@ -73,10 +64,9 @@ public CloudflareRestClient(IHttpClientFactory httpClientFactory, string usernam /// Cancellation token. /// Data returned from the server as /// - public async Task GetAsync(Uri uri, CancellationToken cancellationToken = default) where TResult : ICloudflareEntity + public async Task GetAsync(Uri uri, CancellationToken cancellationToken = default) where TResult : class, ICloudflareEntity { - using var client = GetClient(); - var response = await client.GetAsync(uri, cancellationToken) + HttpResponseMessage response = await httpClient.GetAsync(uri, cancellationToken) .ConfigureAwait(false); return (await HandleResponse(response).ConfigureAwait(false)).Result; @@ -92,11 +82,10 @@ public async Task GetAsync(Uri uri, CancellationToken cancella /// Cancellation token. /// Data returned from the server as /// - public async Task PatchAsync(Uri uri, TMessage message, CancellationToken cancellationToken = default) where TResult : ICloudflareEntity + public async Task PatchAsync(Uri uri, TMessage message, CancellationToken cancellationToken = default) where TResult : class, ICloudflareEntity { - using var client = GetClient(); var objectContent = new ObjectContent(message, jsonMediaTypeFormatter); - var response = await client.PatchAsync(uri, objectContent, cancellationToken) + HttpResponseMessage response = await httpClient.PatchAsync(uri, objectContent, cancellationToken) .ConfigureAwait(false); return (await HandleResponse(response).ConfigureAwait(false)).Result; @@ -112,10 +101,9 @@ public async Task PatchAsync(Uri uri, TMessage messa /// Cancellation token. /// Data returned from the server as /// - public async Task PostAsync(Uri uri, TMessage message, CancellationToken cancellationToken = default) where TResult : ICloudflareEntity + public async Task PostAsync(Uri uri, TMessage message, CancellationToken cancellationToken = default) where TResult : class, ICloudflareEntity { - using var client = GetClient(); - var response = await client.PostAsync(uri, message, jsonMediaTypeFormatter, cancellationToken) + HttpResponseMessage response = await httpClient.PostAsync(uri, message, jsonMediaTypeFormatter, cancellationToken) .ConfigureAwait(false); return (await HandleResponse(response).ConfigureAwait(false)).Result; @@ -130,15 +118,13 @@ public async Task PostAsync(Uri uri, TMessage messag /// public async Task DeleteAsync(Uri uri, CancellationToken cancellationToken = default) { - using var client = this.GetClient(); - await client.DeleteAsync(uri, cancellationToken) + await httpClient.DeleteAsync(uri, cancellationToken) .ConfigureAwait(false); } - public async Task DeleteAsync(Uri uri, CancellationToken cancellationToken = default) where TResult : ICloudflareEntity + public async Task DeleteAsync(Uri uri, CancellationToken cancellationToken = default) where TResult : class, ICloudflareEntity { - using var client = GetClient(); - var response = await client.DeleteAsync(uri, cancellationToken) + HttpResponseMessage response = await httpClient.DeleteAsync(uri, cancellationToken) .ConfigureAwait(false); return (await HandleResponse(response) @@ -146,10 +132,9 @@ public async Task DeleteAsync(Uri uri, CancellationToken cance .Result; } - public async Task PutAsync(Uri uri, TMessage payload, CancellationToken cancellationToken = default) where TResult : ICloudflareEntity + public async Task PutAsync(Uri uri, CancellationToken cancellationToken = default) where TResult : class, ICloudflareEntity { - using var client = GetClient(); - var response = await client.PutAsync(uri, payload, jsonMediaTypeFormatter, cancellationToken) + HttpResponseMessage response = await httpClient.PutAsync(uri, null, cancellationToken) .ConfigureAwait(false); return (await HandleResponse(response) @@ -157,14 +142,24 @@ public async Task PutAsync(Uri uri, TMessage payload .Result; } - private async Task> HandleResponse(HttpResponseMessage httpResponseMessage) where TResult : ICloudflareEntity + public async Task PutAsync(Uri uri, TMessage payload, CancellationToken cancellationToken = default) where TResult : class, ICloudflareEntity where TMessage : class, ICloudflareEntity + { + HttpResponseMessage response = await httpClient.PutAsync(uri, payload, jsonMediaTypeFormatter, cancellationToken) + .ConfigureAwait(false); + + return (await HandleResponse(response) + .ConfigureAwait(false)) + .Result; + } + + private async Task> HandleResponse(HttpResponseMessage httpResponseMessage) where TResult : class, ICloudflareEntity { if (!httpResponseMessage.IsSuccessStatusCode) { Debug.WriteLine("Encountered a non-positive http status code {0}", httpResponseMessage.StatusCode); } - var result = await httpResponseMessage.Content.ReadAsAsync>(); + CloudflareResult result = await httpResponseMessage.Content.ReadAsAsync>(); if (result.Errors != null && result.Errors.Count > 0) { // we got a negative response back. @@ -174,15 +169,26 @@ private async Task> HandleResponse(HttpRespon return result; } - private HttpClient GetClient() + protected virtual void Dispose(bool disposing) { - HttpClient client = httpClientFactory.CreateClient("Cloudflare"); - client.DefaultRequestHeaders.Add(AuthHeaderKey, apiKey); - client.DefaultRequestHeaders.Add(AuthHeaderUsername, username); - client.DefaultRequestHeaders.Add(HttpRequestHeader.UserAgent.ToString(), UserAgent); - client.DefaultRequestHeaders.Add(HttpRequestHeader.ContentType.ToString(), ApplicationJsonMime); + if (!disposed) + { + if (disposing) + { + httpClient.Dispose(); + } - return client; + disposed = true; + } + } + + /// + /// Implementation of the disposable pattern. + /// + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); } } } \ No newline at end of file diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareRestClientFactory.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareRestClientFactory.cs index a6d50e3..daa5ec0 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareRestClientFactory.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/CloudflareRestClientFactory.cs @@ -2,26 +2,26 @@ { using System; using System.Net.Http; - using Microsoft.Extensions.DependencyInjection; + /// + /// Implementation of + /// + /// public class CloudflareRestClientFactory : ICloudflareRestClientFactory { - private readonly ServiceProvider services; + private readonly IHttpClientFactory httpClientFactory; - public CloudflareRestClientFactory(Uri baseUri) + /// + /// Initializes a new instance of the + /// + /// Http client factory. + public CloudflareRestClientFactory(IHttpClientFactory httpClientFactory) { - var serviceCollection = new ServiceCollection(); - serviceCollection.AddHttpClient("cloudflare", c => - { - c.BaseAddress = baseUri; - }); - - services = serviceCollection.BuildServiceProvider(); + this.httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); } public IRestClient CreateRestClient(string username, string password) { - var httpClientFactory = services.GetService(); return new CloudflareRestClient(httpClientFactory, username, password); } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IEntityClient.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IEntityClient.cs index c35cc68..ce9b27e 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IEntityClient.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IEntityClient.cs @@ -2,6 +2,5 @@ { public interface IEntityClient { - } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IUserClient.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IUserClient.cs index 5e59747..b13d2a7 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IUserClient.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IUserClient.cs @@ -11,8 +11,8 @@ public interface IUserClient : IEntityClient /// /// Cancellation token. /// object. - /// - Task GetUserAsync(CancellationToken cancellationToken = default(CancellationToken)); + /// Thrown when an error is returned from the Cloudflare API. + Task GetUserAsync(CancellationToken cancellationToken = default); /// /// Edit part of your user details @@ -24,7 +24,7 @@ public interface IUserClient : IEntityClient /// Zipcode /// Cancellation token. /// object. - /// - Task PatchUserAsync(string firstName = null, string lastName = null, string telephone = null, string country = null, string zipcode = null, CancellationToken cancellationToken = default(CancellationToken)); + /// Thrown when an error is returned from the Cloudflare API. + Task PatchUserAsync(string? firstName = null, string? lastName = null, string? telephone = null, string? country = null, string? zipcode = null, CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IZoneClient.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IZoneClient.cs index 9a3cc02..d914149 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IZoneClient.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IZoneClient.cs @@ -6,6 +6,10 @@ using Kenc.Cloudflare.Core.Clients.Enums; using Kenc.Cloudflare.Core.Entities; + /// + /// Interface for clients interacting with the Cloudflare API Zone entity. + /// https://api.cloudflare.com/#zone-properties + /// public interface IZoneClient : IEntityClient { IZoneSettingsClient Settings { get; } @@ -21,9 +25,9 @@ public interface IZoneClient : IEntityClient /// Sorting order. /// Sorting direction. /// Match settings. - /// - /// - Task> ListAsync(string domain = null, ZoneStatus? status = null, int? page = null, int? perPage = null, string order = null, Direction? direction = null, Match? match = null, CancellationToken cancellationToken = default); + /// of all zones matching the filters. + /// Thrown when an error is returned from the Cloudflare API. + Task> ListAsync(string? domain = null, ZoneStatus? status = null, int? page = null, int? perPage = null, string? order = null, Direction? direction = null, Match? match = null, CancellationToken cancellationToken = default); /// /// Retrieves a single zone based on . @@ -31,37 +35,39 @@ public interface IZoneClient : IEntityClient /// Zone identifier. /// Cancellation token. /// - /// + /// Thrown when an error is returned from the Cloudflare API. Task GetAsync(string identifier, CancellationToken cancellationToken = default); /// - /// Create a new zone + /// Creates a new zone /// /// Name of the zone. /// Account object with name and id. /// Cancellation token. - /// . - /// + /// The created object. + /// Thrown when an error is returned from the Cloudflare API. Task CreateAsync(string name, Account account, CancellationToken cancellationToken = default); /// - /// + /// Patches a zone. + /// Only non-null values will be updated. + /// https://api.cloudflare.com/#zone-edit-zone /// - /// - /// - /// - /// - /// - /// - Task PatchZoneAsync(string identifier, bool? paused = null, IList vanityNameServers = null, string planId = null, CancellationToken cancellationToken = default); + /// Target zone identifier. + /// Indicates if the zone is only using Cloudflare DNS services. A true value means the zone will not receive security or performance benefits. + /// An array of domains used for custom name servers. This is only available for Business and Enterprise plans. + /// The desired plan for the zone. Changing this value will create/cancel associated subscriptions. To view available plans for this zone, see Zone Plans + /// The resulting object. + /// Thrown when an error is returned from the Cloudflare API. + Task PatchZoneAsync(string identifier, bool? paused = null, IList? vanityNameServers = null, string? planId = null, CancellationToken cancellationToken = default); /// /// Initiate another zone activation check for the target zone. /// /// Target zone identifier. /// Cancellation token. - /// Identifier of the new zone check. - /// + /// Identifier of the new zone check as an . + /// Thrown when an error is returned from the Cloudflare API. Task InitiateZoneActivationCheckAsync(string identifier, CancellationToken cancellationToken = default); /// @@ -70,8 +76,8 @@ public interface IZoneClient : IEntityClient /// Target zone identifier. /// Purge everything? /// Cancellation token. - /// Identifier of the new zone check. - /// + /// Identifier of the new zone check as an + /// Thrown when an error is returned from the Cloudflare API. Task PurgeAllFiles(string identifier, bool purgeEverything, CancellationToken cancellationToken = default); /// @@ -81,9 +87,9 @@ public interface IZoneClient : IEntityClient /// Array of tags to clean/ /// Array of hosts to clean. /// Cancellation token. - /// Identifier of the operation. + /// Identifier of the operation as an . /// Enterprise only feature. - /// + /// Thrown when an error is returned from the Cloudflare API. Task PurgeFilesByTagsOrHosts(string identifier, string[] tags, string[] hosts, CancellationToken cancellationToken = default); /// @@ -91,8 +97,8 @@ public interface IZoneClient : IEntityClient /// /// Identifier of the zone to delete. /// Cancellation token. - /// - /// + /// + /// Thrown when an error is returned from the Cloudflare API. Task DeleteAsync(string identifier, CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IZoneDNSSettingsClient.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IZoneDNSSettingsClient.cs index b7f2b9f..55969c9 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IZoneDNSSettingsClient.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IZoneDNSSettingsClient.cs @@ -21,8 +21,8 @@ public interface IZoneDNSSettingsClient : IEntityClient /// Whether to match all search requirements or at least one (any). /// Cancellation token. /// - /// - Task> ListAsync(string zoneIdentifier, DNSRecordType? type = null, string name = null, string content = null, int? page = null, int? perPage = null, string order = null, Direction? direction = null, Match? match = null, CancellationToken cancellationToken = default); + /// Thrown when an error is returned from the Cloudflare API. + Task> ListAsync(string zoneIdentifier, DNSRecordType? type = null, string? name = null, string? content = null, int? page = null, int? perPage = null, string? order = null, Direction? direction = null, Match? match = null, CancellationToken cancellationToken = default); /// /// Retrieves a single DNS record. @@ -31,6 +31,7 @@ public interface IZoneDNSSettingsClient : IEntityClient /// Target dns setting name. /// Cancellation token. /// + /// Thrown when an error is returned from the Cloudflare API. Task GetAsync(string zoneIdentifier, string name, CancellationToken cancellationToken = default); /// Creates a new DNS record @@ -44,6 +45,7 @@ public interface IZoneDNSSettingsClient : IEntityClient /// Wether traffic is proxied. /// Cancellation token. /// + /// Thrown when an error is returned from the Cloudflare API. Task CreateRecordAsync(string zoneIdentififer, string name, DNSRecordType type, string content, int? ttl = null, int? priority = null, bool? proxied = null, CancellationToken cancellationToken = default); /// @@ -52,6 +54,7 @@ public interface IZoneDNSSettingsClient : IEntityClient /// DNS Record to delete. /// Cancellation token. /// + /// Thrown when an error is returned from the Cloudflare API. Task DeleteRecordAsync(DNSRecord record, CancellationToken cancellationToken = default); /// @@ -67,6 +70,7 @@ public interface IZoneDNSSettingsClient : IEntityClient /// Wether the connection should be proxied, optional. Will update the record if specified. /// Optional cancellation token. /// + /// Thrown when an error is returned from the Cloudflare API. Task PatchDNSRecordAsync(string recordId, string zoneIdentififer, string name, DNSRecordType? type, string? content, int? ttl, bool? proxied, CancellationToken cancellationToken = default); /// @@ -81,6 +85,7 @@ public interface IZoneDNSSettingsClient : IEntityClient /// Wether the connection should be proxied. /// Cancellation token. /// + /// Thrown when an error is returned from the Cloudflare API. Task UpdateRecordAsync(string recordId, string zoneIdentififer, string name, DNSRecordType type, string content, int ttl, bool proxied, CancellationToken cancellationToken = default); } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IZoneSettingsClient.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IZoneSettingsClient.cs index c2abbd3..14136ef 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IZoneSettingsClient.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/IZoneSettingsClient.cs @@ -12,8 +12,8 @@ public interface IZoneSettingsClient : IEntityClient /// Target zone identifier. /// Cancellation token. /// An - /// - Task> ListAsync(string zoneIdentifier, CancellationToken cancellationToken = default(CancellationToken)); + /// Thrown when an error is returned from the Cloudflare API. + Task> ListAsync(string zoneIdentifier, CancellationToken cancellationToken = default); /// /// Retrieves a single setting. @@ -21,8 +21,8 @@ public interface IZoneSettingsClient : IEntityClient /// Target zone identifier. /// Target setting name. /// Cancellation token. - /// - Task GetAsync(string zoneIdentifier, string name, CancellationToken cancellationToken = default(CancellationToken)); - + /// The setting as a object. + /// Thrown when an error is returned from the Cloudflare API. + Task GetAsync(string zoneIdentifier, string name, CancellationToken cancellationToken = default); } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/UserClient.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/UserClient.cs index 9e63464..b7b8f54 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/UserClient.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/UserClient.cs @@ -4,11 +4,18 @@ using System.Threading; using System.Threading.Tasks; using Kenc.Cloudflare.Core.Entities; + using Kenc.Cloudflare.Core.Payloads; + /// + /// Implementation of a + /// + /// public class UserClient : IUserClient { - private readonly IRestClient restClient; + public static readonly string EntityNameSingular = "user"; + private readonly Uri baseUri; + private readonly IRestClient restClient; /// /// Initializes a new instance of the class. @@ -20,15 +27,25 @@ public UserClient(IRestClient restClient, Uri baseUri) this.restClient = restClient; } - public async Task GetUserAsync(CancellationToken cancellationToken = default(CancellationToken)) + public async Task GetUserAsync(CancellationToken cancellationToken = default) { - var targetUri = new Uri(baseUri, "user"); + var targetUri = new Uri(baseUri, EntityNameSingular); return await restClient.GetAsync(targetUri, cancellationToken); } - public Task PatchUserAsync(string firstName = null, string lastName = null, string telephone = null, string country = null, string zipcode = null, CancellationToken cancellationToken = default(CancellationToken)) + public async Task PatchUserAsync(string? firstName = null, string? lastName = null, string? telephone = null, string? country = null, string? zipcode = null, CancellationToken cancellationToken = default) { - throw new NotImplementedException(); + var targetUri = new Uri(baseUri, EntityNameSingular); + var payload = new UpdateUserPayload + { + FirstName = firstName, + LastName = lastName, + Telephone = telephone, + Country = country, + Zipcode = zipcode + }; + + return await restClient.PatchAsync(targetUri, payload, cancellationToken); } } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/ZoneClient.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/ZoneClient.cs index a0b1d4e..8528a98 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/ZoneClient.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/ZoneClient.cs @@ -28,8 +28,8 @@ public class ZoneClient : IZoneClient /// Client to use to send requests. public ZoneClient(IRestClient restClient, Uri baseUri) { - this.baseUri = baseUri; - this.restClient = restClient; + this.baseUri = baseUri ?? throw new ArgumentNullException(nameof(baseUri)); + this.restClient = restClient ?? throw new ArgumentNullException(nameof(restClient)); Settings = new ZoneSettingsClient(restClient, baseUri); DNSSettings = new ZoneDNSSettingsClient(restClient, baseUri); @@ -42,8 +42,8 @@ public ZoneClient(IRestClient restClient, Uri baseUri) /// Account object with name and id. /// Cancellation token. /// . - /// - public async Task CreateAsync(string name, Account account, CancellationToken cancellationToken = default(CancellationToken)) + /// Thrown when an error is returned from the Cloudflare API. + public async Task CreateAsync(string name, Account account, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(name)) { @@ -69,8 +69,8 @@ public ZoneClient(IRestClient restClient, Uri baseUri) /// /// Zone identifier. /// - /// - public async Task GetAsync(string identifier, CancellationToken cancellationToken = default(CancellationToken)) + /// Thrown when an error is returned from the Cloudflare API. + public async Task GetAsync(string identifier, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(identifier)) { @@ -80,7 +80,7 @@ public ZoneClient(IRestClient restClient, Uri baseUri) return await restClient.GetAsync(new Uri(baseUri, $"{EntityNamePlural}/{identifier}"), cancellationToken); } - public async Task> ListAsync(string domain = null, ZoneStatus? status = null, int? page = null, int? perPage = null, string order = null, Direction? direction = null, Match? match = null, CancellationToken cancellationToken = default(CancellationToken)) + public async Task> ListAsync(string? domain = null, ZoneStatus? status = null, int? page = null, int? perPage = null, string? order = null, Direction? direction = null, Match? match = null, CancellationToken cancellationToken = default) { var parameters = new List(); if (!string.IsNullOrEmpty(domain)) @@ -128,7 +128,7 @@ public ZoneClient(IRestClient restClient, Uri baseUri) return await restClient.GetAsync>(uri, cancellationToken); } - public Task PatchZoneAsync(string identifier, bool? paused = null, IList vanityNameServers = null, string planId = null, CancellationToken cancellationToken = default(CancellationToken)) + public Task PatchZoneAsync(string identifier, bool? paused = null, IList? vanityNameServers = null, string? planId = null, CancellationToken cancellationToken = default) { throw new NotImplementedException(); } @@ -139,7 +139,7 @@ public ZoneClient(IRestClient restClient, Uri baseUri) /// Target zone identifier. /// Cancellation token. /// Identifier of the new zone check. - /// + /// Thrown when an error is returned from the Cloudflare API. public async Task InitiateZoneActivationCheckAsync(string identifier, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(identifier)) @@ -148,7 +148,7 @@ public async Task InitiateZoneActivationCheckAsync(string identifier, } var uri = new Uri(baseUri, $"{EntityNamePlural}/{identifier}/activation_check"); - return await restClient.PutAsync(uri, null, cancellationToken); + return await restClient.PutAsync(uri, cancellationToken); } /// @@ -158,8 +158,8 @@ public async Task InitiateZoneActivationCheckAsync(string identifier, /// Purge everything? /// Cancellation token. /// Identifier of the new zone check. - /// - public async Task PurgeAllFiles(string identifier, bool purgeEverything, CancellationToken cancellationToken = default(CancellationToken)) + /// Thrown when an error is returned from the Cloudflare API. + public async Task PurgeAllFiles(string identifier, bool purgeEverything, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(identifier)) { @@ -171,7 +171,7 @@ public async Task InitiateZoneActivationCheckAsync(string identifier, return await restClient.PostAsync(uri, payload, cancellationToken); } - public async Task PurgeFilesByTagsOrHosts(string identifier, string[] tags, string[] hosts, CancellationToken cancellationToken = default(CancellationToken)) + public async Task PurgeFilesByTagsOrHosts(string identifier, string[] tags, string[] hosts, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(identifier)) { @@ -184,11 +184,11 @@ public async Task InitiateZoneActivationCheckAsync(string identifier, } var uri = new Uri(baseUri, $"{EntityNamePlural}/{identifier}/purge_cache"); - var payload = new PurgeFilesByTagsOrHostsPayload(tags, hosts); + var payload = new PurgeFilesByTagsOrHostsPayload(tags ?? new string[0], hosts ?? new string[0]); return await restClient.PostAsync(uri, payload, cancellationToken); } - public async Task DeleteAsync(string identifier, CancellationToken cancellationToken = default(CancellationToken)) + public async Task DeleteAsync(string identifier, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(identifier)) { diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/ZoneDNSSettingsClient.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/ZoneDNSSettingsClient.cs index 7217c86..37f3a5a 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/ZoneDNSSettingsClient.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/ZoneDNSSettingsClient.cs @@ -11,8 +11,9 @@ using Kenc.Cloudflare.Core.Payloads; /// - /// + /// Implementation of . /// + /// public class ZoneDNSSettingsClient : IZoneDNSSettingsClient { public static readonly string EntityNamePlural = "dns_records"; @@ -67,7 +68,7 @@ public async Task GetAsync(string zoneIdentifier, string name, Cancel return await restClient.GetAsync(uri, cancellationToken); } - public async Task> ListAsync(string zoneIdentifier, DNSRecordType? type = null, string name = null, string content = null, int? page = null, int? perPage = null, string order = null, Direction? direction = null, Match? match = null, CancellationToken cancellationToken = default) + public async Task> ListAsync(string zoneIdentifier, DNSRecordType? type = null, string? name = null, string? content = null, int? page = null, int? perPage = null, string? order = null, Direction? direction = null, Match? match = null, CancellationToken cancellationToken = default) { var parameters = new List(); if (type.HasValue) @@ -149,15 +150,9 @@ public Task UpdateRecordAsync(DNSRecord dnsRecord, CancellationToken public async Task PatchDNSRecordAsync(string recordId, string zoneIdentififer, string name, DNSRecordType? type, string? content, int? ttl, bool? proxied, CancellationToken cancellationToken = default) { - if (string.IsNullOrEmpty(zoneIdentififer)) - { - throw new ArgumentNullException(nameof(zoneIdentififer)); - } - - if (string.IsNullOrEmpty(name)) - { - throw new ArgumentNullException(nameof(name)); - } + _ = string.IsNullOrEmpty(name) ? throw new ArgumentNullException(nameof(name)) : name; + _ = string.IsNullOrEmpty(recordId) ? throw new ArgumentNullException(nameof(recordId)) : recordId; + _ = string.IsNullOrEmpty(zoneIdentififer) ? throw new ArgumentNullException(nameof(zoneIdentififer)) : zoneIdentififer; var payload = new UpdateDNSRecord(name, type, content, ttl, proxied); var uri = new Uri(baseUri, $"zones/{zoneIdentififer}/{EntityNamePlural}/{recordId}"); diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/ZoneSettingsClient.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/ZoneSettingsClient.cs index 3287953..e5f1d2a 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/ZoneSettingsClient.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/EntityClients/ZoneSettingsClient.cs @@ -24,8 +24,8 @@ public ZoneSettingsClient(IRestClient restClient, Uri baseUri) /// Target zone identifier. /// Cancellation token. /// An - /// - public async Task> ListAsync(string zoneIdentifier, CancellationToken cancellationToken = default(CancellationToken)) + /// Thrown when an error is returned from the Cloudflare API. + public async Task> ListAsync(string zoneIdentifier, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(zoneIdentifier)) { @@ -43,7 +43,7 @@ public ZoneSettingsClient(IRestClient restClient, Uri baseUri) /// Target setting name. /// Cancellation token. /// - public async Task GetAsync(string zoneIdentifier, string name, CancellationToken cancellationToken = default(CancellationToken)) + public async Task GetAsync(string zoneIdentifier, string name, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(zoneIdentifier)) { diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/Enums/Match.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/Enums/Match.cs index dc7975f..f4b91d1 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/Enums/Match.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/Enums/Match.cs @@ -1,7 +1,7 @@ -using System.Runtime.Serialization; - -namespace Kenc.Cloudflare.Core.Clients.Enums +namespace Kenc.Cloudflare.Core.Clients.Enums { + using System.Runtime.Serialization; + /// /// Whether to match all search requirements or at least one(any) /// diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/HttpClientFactory.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/HttpClientFactory.cs deleted file mode 100644 index f444b81..0000000 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/HttpClientFactory.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Kenc.Cloudflare.Core.Clients -{ - using System; - using System.Net.Http; - - public class HttpClientFactory : IHttpClientFactory - { - private readonly string apiKey; - private readonly string username; - private readonly IServiceProvider serviceProvider; - - public HttpClientFactory(IServiceProvider serviceProvider, string username, string apiKey) - { - this.apiKey = apiKey; - this.username = username; - this.serviceProvider = serviceProvider; - } - - public HttpClient CreateClient(string name) - { - var httpClient = (HttpClient)this.serviceProvider.GetService(typeof(HttpClient)); - httpClient.DefaultRequestHeaders.Add("X-Auth-Key", this.apiKey); - httpClient.DefaultRequestHeaders.Add("X-Auth-Email", this.username); - - return httpClient; - } - } -} diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/ICloudflareClient.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/ICloudflareClient.cs index 22264bc..8ed7cd1 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/ICloudflareClient.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/ICloudflareClient.cs @@ -2,12 +2,27 @@ { using Kenc.Cloudflare.Core.Clients.EntityClients; + /// + /// Interface for a client interacting with the Cloudflare API. + /// public interface ICloudflareClient { + /// + /// Gets a client for interacting with Zones. + /// https://api.cloudflare.com/#zone-properties + /// IZoneClient Zones { get; } + /// + /// Gets a client for interacting with the currently signed in user. + /// https://api.cloudflare.com/#user-properties + /// IUserClient UserClient { get; } + /// + /// Gets a client for interacting with a Zones DNS settings. + /// https://api.cloudflare.com/#zone-settings-get-all-zone-settings + /// IZoneDNSSettingsClient ZoneDNSSettingsClient { get; } } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/ICloudflareClientBuilder.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/ICloudflareClientBuilder.cs new file mode 100644 index 0000000..d7ad7fe --- /dev/null +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/ICloudflareClientBuilder.cs @@ -0,0 +1,14 @@ +namespace Kenc.Cloudflare.Core.Clients +{ + /// + /// Interface for a factory creating a . + /// + public interface ICloudflareClientFactory + { + /// + /// Create an instance of . + /// + /// + ICloudflareClient Create(); + } +} \ No newline at end of file diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/ICloudflareClientFactory.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/ICloudflareClientFactory.cs deleted file mode 100644 index 068911c..0000000 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/ICloudflareClientFactory.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Kenc.Cloudflare.Core.Clients -{ - public interface ICloudflareClientFactory - { - ICloudflareClient Create(); - ICloudflareClientFactory WithAPIKey(string apiKey); - ICloudflareClientFactory WithEndpoint(System.Uri endpoint); - ICloudflareClientFactory WithRestClientFactory(ICloudflareRestClientFactory cloudflareRestClientFactory); - ICloudflareClientFactory WithUsername(string username); - } -} \ No newline at end of file diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/ICloudflareRestClientFactory.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/ICloudflareRestClientFactory.cs index 19c3f77..df4b76d 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/ICloudflareRestClientFactory.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/ICloudflareRestClientFactory.cs @@ -1,7 +1,16 @@ namespace Kenc.Cloudflare.Core.Clients { + /// + /// Interface for creating restful clients. + /// public interface ICloudflareRestClientFactory { + /// + /// Creates a new with the and for authentication. + /// + /// Username. + /// API Key + /// IRestClient CreateRestClient(string username, string apiKey); } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/IRestClient.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/IRestClient.cs index f2a75ad..1686d69 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/IRestClient.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Clients/IRestClient.cs @@ -17,8 +17,8 @@ public interface IRestClient /// Endpoint to target. /// Cancellation token. /// Data returned from the server as - /// - Task GetAsync(Uri uri, CancellationToken cancellationToken = default) where TResult : ICloudflareEntity; + /// Thrown when an error is returned from the Cloudflare API. + Task GetAsync(Uri uri, CancellationToken cancellationToken = default) where TResult : class, ICloudflareEntity; /// /// Sends a PATCH request to the . @@ -29,8 +29,8 @@ public interface IRestClient /// Object to send of type /// Cancellation token. /// Data returned from the server as - /// - Task PatchAsync(Uri uri, TMessage message, CancellationToken cancellationToken = default) where TResult : ICloudflareEntity; + /// Thrown when an error is returned from the Cloudflare API. + Task PatchAsync(Uri uri, TMessage message, CancellationToken cancellationToken = default) where TResult : class, ICloudflareEntity; /// /// Sends a POST request to the . @@ -41,17 +41,29 @@ public interface IRestClient /// Object to send of type /// Cancellation token. /// Data returned from the server as - /// - Task PostAsync(Uri uri, TMessage message, CancellationToken cancellationToken = default) where TResult : ICloudflareEntity; + /// Thrown when an error is returned from the Cloudflare API. + Task PostAsync(Uri uri, TMessage message, CancellationToken cancellationToken = default) where TResult : class, ICloudflareEntity; /// /// Sends a DELETE request to the /// /// Endpoint to target. /// Cancellation token. - /// An async Task. - /// - Task DeleteAsync(Uri uri, CancellationToken cancellationToken = default) where TResult : ICloudflareEntity; + /// Data returned from the server as + /// Thrown when an error is returned from the Cloudflare API. + Task DeleteAsync(Uri uri, CancellationToken cancellationToken = default) where TResult : class, ICloudflareEntity; + + /// + /// Sends a PUT request to the + /// + /// Type of data to send. + /// Type of message to receive. + /// Endpoint to target. + /// Cancellation token. + /// + /// Thrown when an error is returned from the Cloudflare API. + Task PutAsync(Uri uri, CancellationToken cancellationToken = default) where TResult : class, ICloudflareEntity; + /// /// Sends a PUT request to the @@ -62,6 +74,7 @@ public interface IRestClient /// Payload to the request. /// Cancellation token. /// - Task PutAsync(Uri uri, TMessage message, CancellationToken cancellationToken = default) where TResult : ICloudflareEntity; + /// Thrown when an error is returned from the Cloudflare API. + Task PutAsync(Uri uri, TMessage message, CancellationToken cancellationToken = default) where TResult : class, ICloudflareEntity where TMessage : class, ICloudflareEntity; } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Clients/RestClientFactory.cs b/src/Libraries/Kenc.Cloudflare.Core/Clients/RestClientFactory.cs deleted file mode 100644 index 5e3c1d4..0000000 --- a/src/Libraries/Kenc.Cloudflare.Core/Clients/RestClientFactory.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Kenc.Cloudflare.Core.Clients -{ - using System.Net.Http; - - public class RestClientFactory : ICloudflareRestClientFactory - { - private readonly IHttpClientFactory httpClientFactory; - - public RestClientFactory(IHttpClientFactory httpClientFactory) - { - this.httpClientFactory = httpClientFactory; - } - - public IRestClient CreateRestClient(string username, string apiKey) - { - return new CloudflareRestClient(httpClientFactory, username, apiKey); - } - } -} diff --git a/src/Libraries/Kenc.Cloudflare.Core/CloudflareResult.cs b/src/Libraries/Kenc.Cloudflare.Core/CloudflareResult.cs index 4a92c5e..64f8dec 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/CloudflareResult.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/CloudflareResult.cs @@ -1,10 +1,11 @@ namespace Kenc.Cloudflare.Core { using System.Collections.Generic; + using Kenc.Cloudflare.Core.Entities; using Kenc.Cloudflare.Core.Exceptions; using Newtonsoft.Json; - public class CloudflareResult + public class CloudflareResult where T : class, ICloudflareEntity { [JsonProperty(propertyName: "result")] public T Result { get; set; } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Entities/Account.cs b/src/Libraries/Kenc.Cloudflare.Core/Entities/Account.cs index 00487d3..40bce69 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Entities/Account.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Entities/Account.cs @@ -9,12 +9,12 @@ public class Account : ICloudflareEntity { [JsonProperty(propertyName: "id")] - public string Id { get; set; } + public string Id { get; set; } = string.Empty; [JsonProperty(propertyName: "name")] - public string Name { get; set; } + public string Name { get; set; } = string.Empty; [JsonProperty(propertyName: "settings")] - public AccountSettings Settings { get; set; } + public AccountSettings Settings { get; set; } = new AccountSettings(); } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Entities/AccountSettings.cs b/src/Libraries/Kenc.Cloudflare.Core/Entities/AccountSettings.cs index b731855..7929330 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Entities/AccountSettings.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Entities/AccountSettings.cs @@ -12,6 +12,6 @@ public class AccountSettings /// Boolean value indicating whether or not membership in this account requires that Two-Factor Authentication is enabled /// [JsonProperty(propertyName: "enforce_twofactor")] - bool EnforceTwofactor { get; set; } + public bool EnforceTwofactor { get; set; } } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Entities/DNSRecord.cs b/src/Libraries/Kenc.Cloudflare.Core/Entities/DNSRecord.cs index ad20b61..3208e0d 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Entities/DNSRecord.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Entities/DNSRecord.cs @@ -7,16 +7,16 @@ public class DNSRecord : ICloudflareEntity { [JsonProperty(propertyName: "id")] - public string Id { get; set; } + public string Id { get; set; } = string.Empty; [JsonProperty(propertyName: "type")] public DNSRecordType Type { get; set; } [JsonProperty(propertyName: "name")] - public string Name { get; set; } + public string Name { get; set; } = string.Empty; [JsonProperty(propertyName: "content")] - public string Content { get; set; } + public string Content { get; set; } = string.Empty; [JsonProperty(propertyName: "proxiable")] public bool Proxiable { get; set; } @@ -31,10 +31,10 @@ public class DNSRecord : ICloudflareEntity public bool Locked { get; set; } [JsonProperty(propertyName: "zone_id")] - public string ZoneId { get; set; } + public string ZoneId { get; set; } = string.Empty; [JsonProperty(propertyName: "zone_name")] - public string ZoneName { get; set; } + public string ZoneName { get; set; } = string.Empty; [JsonProperty(propertyName: "created_on")] public DateTime CreatedOn { get; set; } @@ -43,6 +43,6 @@ public class DNSRecord : ICloudflareEntity public DateTime? ModifiedOn { get; set; } [JsonProperty(propertyName: "data")] - public string Data { get; set; } + public string Data { get; set; } = string.Empty; } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Entities/EntityList.cs b/src/Libraries/Kenc.Cloudflare.Core/Entities/EntityList.cs index 1888028..33a8b63 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Entities/EntityList.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Entities/EntityList.cs @@ -8,6 +8,6 @@ /// The type of items. public class EntityList : List, ICloudflareEntity where T : ICloudflareEntity { - // todo KENCHR: consider changing to IReadOnlyList. + // todo Kencdk: consider changing to IReadOnlyList. } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Entities/IdResult.cs b/src/Libraries/Kenc.Cloudflare.Core/Entities/IdResult.cs index 14db98d..caa4d0b 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Entities/IdResult.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Entities/IdResult.cs @@ -5,6 +5,6 @@ public class IdResult : ICloudflareEntity { [JsonProperty(propertyName: "id")] - string Id { get; set; } + public string Id { get; set; } = string.Empty; } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Entities/Plan.cs b/src/Libraries/Kenc.Cloudflare.Core/Entities/Plan.cs index 4ac05d4..c1a8afb 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Entities/Plan.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Entities/Plan.cs @@ -8,27 +8,27 @@ public class Plan { [JsonProperty(propertyName: "id")] - string Id { get; set; } + public string? Id { get; set; } [JsonProperty(propertyName: "name")] - string Name { get; set; } + public string? Name { get; set; } [JsonProperty(propertyName: "price")] - int Price { get; set; } + public int Price { get; set; } [JsonProperty(propertyName: "currency")] - string Currency { get; set; } + public string? Currency { get; set; } [JsonProperty(propertyName: "frequency")] - string Fequency { get; set; } + public string? Fequency { get; set; } [JsonProperty(propertyName: "legacy_id")] - string LegacyId { get; set; } + public string? LegacyId { get; set; } [JsonProperty(propertyName: "is_subscribed")] - bool IsSubscribed { get; set; } + public bool IsSubscribed { get; set; } [JsonProperty(propertyName: "can_subscribe")] - bool CanSubscribe { get; set; } + public bool CanSubscribe { get; set; } } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Entities/User.cs b/src/Libraries/Kenc.Cloudflare.Core/Entities/User.cs index 140888f..ce8b7f0 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Entities/User.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Entities/User.cs @@ -10,39 +10,39 @@ public class User : ICloudflareEntity { [JsonProperty(propertyName: "id")] - string Id { get; set; } + public string Id { get; set; } = string.Empty; [JsonProperty(propertyName: "email")] - string Email { get; set; } + public string Email { get; set; } = string.Empty; [JsonProperty(propertyName: "first_name")] - string FirstName { get; set; } + public string FirstName { get; set; } = string.Empty; [JsonProperty(propertyName: "last_name")] - string LastName { get; set; } + public string LastName { get; set; } = string.Empty; [JsonProperty(propertyName: "username")] - string Username { get; set; } + public string Username { get; set; } = string.Empty; [JsonProperty(propertyName: "telephone")] - string Telephone { get; set; } + public string? Telephone { get; set; } [JsonProperty(propertyName: "country")] - string Country { get; set; } + public string? Country { get; set; } [JsonProperty(propertyName: "zipcode")] - string Zipcode { get; set; } + public string? Zipcode { get; set; } [JsonProperty(propertyName: "created_on")] - DateTime CreatedOn { get; set; } + public DateTime CreatedOn { get; set; } [JsonProperty(propertyName: "modified_on")] - DateTime ModifiedOn { get; set; } + public DateTime ModifiedOn { get; set; } [JsonProperty(propertyName: "two_factor_authentication_enabled")] - bool TwoFactorAuthenticationEnabled { get; set; } + public bool TwoFactorAuthenticationEnabled { get; set; } [JsonProperty(propertyName: "suspended")] - bool Suspended { get; set; } + public bool Suspended { get; set; } } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Entities/Zone.cs b/src/Libraries/Kenc.Cloudflare.Core/Entities/Zone.cs index ff930fe..7c90418 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Entities/Zone.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Entities/Zone.cs @@ -11,26 +11,26 @@ public class Zone : ICloudflareEntity { [JsonProperty(propertyName: "id")] - public string Id { get; set; } + public string Id { get; set; } = string.Empty; /// /// max length: 253 /// pattern: ^([a - zA - Z0 - 9][\-a - zA - Z0 - 9]*\.)+[\-a-zA-Z0-9]{2,20}$ /// [JsonProperty(propertyName: "name")] - public string Name { get; set; } + public string Name { get; set; } = string.Empty; [JsonProperty(propertyName: "development_mode")] public int DevelopmentMode { get; set; } [JsonProperty(propertyName: "original_name_servers")] - public IList OriginalNameServers { get; set; } + public IList? OriginalNameServers { get; set; } [JsonProperty(propertyName: "original_registrar")] - public string OriginalRegistrar { get; set; } + public string? OriginalRegistrar { get; set; } [JsonProperty(propertyName: "original_dnshost")] - public string OriginalDnsHost { get; set; } + public string? OriginalDnsHost { get; set; } [JsonProperty(propertyName: "created_on")] public DateTime? CreatedOn { get; set; } @@ -42,30 +42,30 @@ public class Zone : ICloudflareEntity public DateTime? ActivatedOn { get; set; } [JsonProperty(propertyName: "owner")] - public ZoneOwner Owner { get; set; } + public ZoneOwner? Owner { get; set; } [JsonProperty(propertyName: "Account")] - public Account Account { get; set; } + public Account? Account { get; set; } [JsonProperty(propertyName: "permissions")] - public IList Permissions { get; set; } + public IList? Permissions { get; set; } [JsonProperty(propertyName: "plan")] - public Plan Plan { get; set; } + public Plan? Plan { get; set; } [JsonProperty(propertyName: "plan_pending")] - public Plan PlanPending { get; set; } + public Plan? PlanPending { get; set; } [JsonProperty(propertyName: "status")] - public string Status { get; set; } + public string Status { get; set; } = string.Empty; [JsonProperty(propertyName: "paused")] public bool Paused { get; set; } [JsonProperty(propertyName: "type")] - public string Type { get; set; } + public string Type { get; set; } = string.Empty; [JsonProperty(propertyName: "name_servers")] - public IList NameServers { get; set; } + public IList NameServers { get; set; } = new List(); } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Entities/ZoneOwner.cs b/src/Libraries/Kenc.Cloudflare.Core/Entities/ZoneOwner.cs index b2d0008..89e9e7b 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Entities/ZoneOwner.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Entities/ZoneOwner.cs @@ -5,12 +5,12 @@ public class ZoneOwner { [JsonProperty(propertyName: "id")] - string Id { get; set; } + public string? Id { get; set; } [JsonProperty(propertyName: "name")] - string Name { get; set; } + public string? Name { get; set; } [JsonProperty(propertyName: "type")] - string Type { get; set; } + public string? Type { get; set; } } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Entities/ZoneSetting.cs b/src/Libraries/Kenc.Cloudflare.Core/Entities/ZoneSetting.cs index e289045..30991de 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Entities/ZoneSetting.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Entities/ZoneSetting.cs @@ -6,10 +6,10 @@ public class ZoneSetting : ICloudflareEntity { [JsonProperty(propertyName: "id")] - public string Id { get; set; } + public string? Id { get; set; } [JsonProperty(propertyName: "value")] - public string Value { get; set; } + public string? Value { get; set; } [JsonProperty(propertyName: "editable")] public bool Editable { get; set; } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Exceptions/CloudflareAPIError.cs b/src/Libraries/Kenc.Cloudflare.Core/Exceptions/CloudflareAPIError.cs index 4e22677..1114555 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Exceptions/CloudflareAPIError.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Exceptions/CloudflareAPIError.cs @@ -2,14 +2,23 @@ { using Newtonsoft.Json; + /// + /// Wrapper for errors from the Cloudflare REST API. + /// https://api.cloudflare.com/#getting-started-responses + /// public class CloudflareAPIError { [JsonProperty(propertyName: "code")] - public string Code { get; set; } + public string Code { get; private set; } [JsonProperty(propertyName: "message")] - public string Message { get; set; } + public string Message { get; private set; } + /// + /// Initializes a new instace of the class. + /// + /// Cloudflare API error code. + /// Cloudflare API error message. public CloudflareAPIError(string code, string message) { Code = code; diff --git a/src/Libraries/Kenc.Cloudflare.Core/Exceptions/CloudflareException.cs b/src/Libraries/Kenc.Cloudflare.Core/Exceptions/CloudflareException.cs index 10db203..14fb985 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Exceptions/CloudflareException.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Exceptions/CloudflareException.cs @@ -4,10 +4,20 @@ using System.Collections.Generic; using System.Text; + /// + /// Exception wrapping errors from the Cloudflare API. + /// public class CloudflareException : Exception { + /// + /// Gets a list of returned from the API. + /// public IList Errors { get; private set; } + /// + /// Initializes a new instance of the class. + /// + /// List of errors returned by the Cloudflare API. public CloudflareException(IList errors) : base() { Errors = errors; @@ -16,7 +26,7 @@ public CloudflareException(IList errors) : base() public override string ToString() { var stringBuilder = new StringBuilder(); - foreach (var error in Errors) + foreach (CloudflareAPIError error in Errors) { stringBuilder.AppendLine($"{error.Code}: {error.Message}"); } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Helpers/EnumValueMemberHelper.cs b/src/Libraries/Kenc.Cloudflare.Core/Helpers/EnumValueMemberHelper.cs index 47ca114..f9d0b00 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Helpers/EnumValueMemberHelper.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Helpers/EnumValueMemberHelper.cs @@ -1,13 +1,13 @@ -using System; -using System.Reflection; -using System.Runtime.Serialization; - -namespace Kenc.Cloudflare.Core.Helpers +namespace Kenc.Cloudflare.Core.Helpers { + using System; + using System.Reflection; + using System.Runtime.Serialization; + public static class EnumValueMemberHelper { /// - /// Converts an enum value to it's enum member .value. + /// Converts an enum value to it's enum member value. /// Modified version of: http://www.wackylabs.net/2006/06/getting-the-xmlenumattribute-value-for-an-enum-field/ /// /// @@ -15,7 +15,7 @@ public static class EnumValueMemberHelper public static string ConvertToString(this Enum enumValue) { // Get the Type of the enum - var type = enumValue.GetType(); + Type type = enumValue.GetType(); // Get the FieldInfo for the member field with the enums name FieldInfo info = type.GetField(enumValue.ToString("G")); @@ -26,8 +26,8 @@ public static string ConvertToString(this Enum enumValue) return enumValue.ToString("G"); } - object[] o = info.GetCustomAttributes(typeof(EnumMemberAttribute), false); - EnumMemberAttribute att = (EnumMemberAttribute)o[0]; + var o = info.GetCustomAttributes(typeof(EnumMemberAttribute), false); + var att = (EnumMemberAttribute)o[0]; return att.Value; } } diff --git a/src/Libraries/Kenc.Cloudflare.Core/Payloads/UpdateDNSRecord.cs b/src/Libraries/Kenc.Cloudflare.Core/Payloads/UpdateDNSRecord.cs index 936c8e5..5852832 100644 --- a/src/Libraries/Kenc.Cloudflare.Core/Payloads/UpdateDNSRecord.cs +++ b/src/Libraries/Kenc.Cloudflare.Core/Payloads/UpdateDNSRecord.cs @@ -13,7 +13,7 @@ public class UpdateDNSRecord : ICloudflarePayload public DNSRecordType? Type { get; } [JsonProperty(propertyName: "content")] - public string Content { get; } + public string? Content { get; } [JsonProperty(propertyName: "ttl")] public int? TimeToLive { get; } @@ -21,7 +21,7 @@ public class UpdateDNSRecord : ICloudflarePayload [JsonProperty(propertyName: "proxied")] public bool? Proxied { get; } - public UpdateDNSRecord(string name, DNSRecordType? type, string content, int? ttl, bool? proxied) + public UpdateDNSRecord(string name, DNSRecordType? type, string? content, int? ttl, bool? proxied) { Name = name; Type = type; diff --git a/src/Libraries/Kenc.Cloudflare.Core/Payloads/UpdateUserPayload.cs b/src/Libraries/Kenc.Cloudflare.Core/Payloads/UpdateUserPayload.cs new file mode 100644 index 0000000..8dd2323 --- /dev/null +++ b/src/Libraries/Kenc.Cloudflare.Core/Payloads/UpdateUserPayload.cs @@ -0,0 +1,38 @@ +namespace Kenc.Cloudflare.Core.Payloads +{ + using Kenc.Cloudflare.Core.PayloadEntities; + using Newtonsoft.Json; + + public class UpdateUserPayload : ICloudflarePayload + { + /// + /// Gets or sets the User's first name + /// + [JsonProperty(propertyName: "first_name")] + public string? FirstName { get; set; } + + /// + /// Gets or sets the User's last name + /// + [JsonProperty(propertyName: "last_name")] + public string? LastName { get; set; } + + /// + /// Gets or sets the User's telephone number + /// + [JsonProperty(propertyName: "telephone")] + public string? Telephone { get; set; } + + /// + /// Gets or sets the country in which the user lives. + /// + [JsonProperty(propertyName: "country")] + public string? Country { get; set; } + + /// + /// Gets or sets the zipcode or postal code where the user lives. + /// + [JsonProperty(propertyName: "zipcode")] + public string? Zipcode { get; set; } + } +}