Added 'DnsRecords' extensions
This commit is contained in:
19
README.md
19
README.md
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
This project aims to implement the [Cloudflare API] in an extensible way.
|
This project aims to implement the [Cloudflare API] in an extensible way.
|
||||||
|
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
There should be a package for each API section as defined by Cloudflare.
|
There should be a package for each API section as defined by Cloudflare.
|
||||||
@@ -9,12 +10,18 @@ There should be a package for each API section as defined by Cloudflare.
|
|||||||
|
|
||||||
### [Cloudflare]
|
### [Cloudflare]
|
||||||
|
|
||||||
This is the base client, that will perform the request itself. It has the base url and holds the credentials.
|
This is the core. It contains the base client, that will perform the request itself. It contains the base url and holds the credentials.
|
||||||
|
|
||||||
|
|
||||||
|
### [Cloudflare.Dns]
|
||||||
|
|
||||||
|
This package contains the feature set of the _DNS_ section of the Cloudflare API.
|
||||||
|
|
||||||
|
|
||||||
### [Cloudflare.Zones]
|
### [Cloudflare.Zones]
|
||||||
|
|
||||||
If you install this package, you will get all methods to handle a DNS zone.
|
This package contains the feature set of the _Domain/Zone Management_ section of the Cloudflare API.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -22,12 +29,14 @@ If you install this package, you will get all methods to handle a DNS zone.
|
|||||||
Published under [MIT License] (see [choose a license])
|
Published under [MIT License] (see [choose a license])
|
||||||
|
|
||||||
[](https://link.am-wd.de/donate)
|
[](https://link.am-wd.de/donate)
|
||||||
[](https://link.am-wd.de/codeium)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Cloudflare]: Cloudflare/README.md
|
[Cloudflare]: src/Cloudflare/README.md
|
||||||
[Cloudflare.Zones]: Extensions/Cloudflare.Zones/README.md
|
[Cloudflare.Dns]: src/Extensions/Cloudflare.Dns/README.md
|
||||||
|
[Cloudflare.Zones]: src/Extensions/Cloudflare.Zones/README.md
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Cloudflare API]: https://developers.cloudflare.com/api/
|
[Cloudflare API]: https://developers.cloudflare.com/api/
|
||||||
[MIT License]: LICENSE.txt
|
[MIT License]: LICENSE.txt
|
||||||
|
|||||||
@@ -29,5 +29,11 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty("total_count")]
|
[JsonProperty("total_count")]
|
||||||
public int? TotalCount { get; set; }
|
public int? TotalCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total number of pages of results.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("total_pages")]
|
||||||
|
public int? TotalPages { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- Only build package for tagged releases or Debug on CI (only dev NuGet feed) -->
|
<!-- Only build package for tagged releases or Debug on CI (only dev NuGet feed) -->
|
||||||
<PropertyGroup Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('$(CI_COMMIT_TAG)', '^dns\/v[0-9.]+')) or ('$(Configuration)' == 'Debug' and '$(GITLAB_CI)' == 'true')">
|
<!--<PropertyGroup Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('$(CI_COMMIT_TAG)', '^dns\/v[0-9.]+')) or ('$(Configuration)' == 'Debug' and '$(GITLAB_CI)' == 'true')">-->
|
||||||
|
<PropertyGroup Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('$(CI_COMMIT_TAG)', '^dns\/v[0-9.]+')) or '$(Configuration)' == 'Debug'">
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
638
src/Extensions/Cloudflare.Dns/DnsRecordsExtensions.cs
Normal file
638
src/Extensions/Cloudflare.Dns/DnsRecordsExtensions.cs
Normal file
@@ -0,0 +1,638 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns.Internals;
|
||||||
|
|
||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extensions for <see href="https://developers.cloudflare.com/api/resources/dns/subresources/records/">DNS Records</see>.
|
||||||
|
/// </summary>
|
||||||
|
public static class DnsRecordsExtensions
|
||||||
|
{
|
||||||
|
private static readonly IReadOnlyCollection<DnsRecordType> _dataComponentTypes = [
|
||||||
|
DnsRecordType.CAA,
|
||||||
|
DnsRecordType.CERT,
|
||||||
|
DnsRecordType.DNSKEY,
|
||||||
|
DnsRecordType.DS,
|
||||||
|
DnsRecordType.HTTPS,
|
||||||
|
DnsRecordType.LOC,
|
||||||
|
DnsRecordType.NAPTR,
|
||||||
|
DnsRecordType.SMIMEA,
|
||||||
|
DnsRecordType.SRV,
|
||||||
|
DnsRecordType.SSHFP,
|
||||||
|
DnsRecordType.SVCB,
|
||||||
|
DnsRecordType.TLSA,
|
||||||
|
DnsRecordType.URI,
|
||||||
|
];
|
||||||
|
|
||||||
|
private static readonly IReadOnlyCollection<DnsRecordType> _priorityTypes = [
|
||||||
|
DnsRecordType.MX,
|
||||||
|
DnsRecordType.SRV,
|
||||||
|
DnsRecordType.URI,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Send a Batch of DNS Record API calls to be executed together.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Notes:
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item>
|
||||||
|
/// Although Cloudflare will execute the batched operations in a single database
|
||||||
|
/// transaction, Cloudflare's distributed KV store must treat each record change
|
||||||
|
/// as a single key-value pair. This means that the propagation of changes is not
|
||||||
|
/// atomic. See
|
||||||
|
/// <see href="https://developers.cloudflare.com/dns/manage-dns-records/how-to/batch-record-changes/">the documentation</see>
|
||||||
|
/// for more information.
|
||||||
|
/// </item>
|
||||||
|
/// <item>
|
||||||
|
/// The operations you specify within the /batch request body are always executed
|
||||||
|
/// in the following order:
|
||||||
|
/// <list type="number">
|
||||||
|
/// <item>Deletes (DELETE)</item>
|
||||||
|
/// <item>Updates (PATCH)</item>
|
||||||
|
/// <item>Overwrites (PUT)</item>
|
||||||
|
/// <item>Creates (POST)</item>
|
||||||
|
/// </list>
|
||||||
|
/// </item>
|
||||||
|
/// </list>
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<BatchDnsRecordsResponse>> BatchDnsRecords(this ICloudflareClient client, BatchDnsRecordsRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.ZoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
// Deletes (DELETE)
|
||||||
|
var deletes = new List<Identifier>();
|
||||||
|
foreach (string delete in request.Deletes ?? [])
|
||||||
|
{
|
||||||
|
delete.ValidateCloudflareId();
|
||||||
|
deletes.Add(new Identifier { Id = delete });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates (PATCH)
|
||||||
|
var patches = new List<InternalBatchUpdateRequest>();
|
||||||
|
foreach (var patch in request.Updates ?? [])
|
||||||
|
{
|
||||||
|
patch.Id.ValidateCloudflareId();
|
||||||
|
|
||||||
|
var req = ValidateRequest(patch);
|
||||||
|
req.Id = patch.Id;
|
||||||
|
|
||||||
|
patches.Add(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates (POST)
|
||||||
|
var posts = new List<InternalDnsRecordRequest>();
|
||||||
|
foreach (var post in request.Creates ?? [])
|
||||||
|
{
|
||||||
|
var req = (InternalDnsRecordRequest)ValidateRequest(post);
|
||||||
|
posts.Add(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrites (PUT)
|
||||||
|
var puts = new List<InternalBatchUpdateRequest>();
|
||||||
|
foreach (var put in request.Overwrites ?? [])
|
||||||
|
{
|
||||||
|
put.Id.ValidateCloudflareId();
|
||||||
|
|
||||||
|
var req = ValidateRequest(put);
|
||||||
|
req.Id = put.Id;
|
||||||
|
|
||||||
|
puts.Add(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
var batchReq = new InternalBatchRequest();
|
||||||
|
|
||||||
|
if (deletes.Count > 0)
|
||||||
|
batchReq.Deletes = deletes;
|
||||||
|
|
||||||
|
if (patches.Count > 0)
|
||||||
|
batchReq.Patches = patches;
|
||||||
|
|
||||||
|
if (posts.Count > 0)
|
||||||
|
batchReq.Posts = posts;
|
||||||
|
|
||||||
|
if (puts.Count > 0)
|
||||||
|
batchReq.Puts = puts;
|
||||||
|
|
||||||
|
return client.PostAsync<BatchDnsRecordsResponse, InternalBatchRequest>($"/zones/{request.ZoneId}/dns_records/batch", batchReq, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new DNS record for a zone.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Notes:
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item>A/AAAA records cannot exist on the same name as CNAME records.</item>
|
||||||
|
/// <item>NS records cannot exist on the same name as any other record type.</item>
|
||||||
|
/// <item>Domain names are always represented in Punycode, even if Unicode characters were used when creating the record.</item>
|
||||||
|
/// </list>
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<DnsRecord>> CreateDnsRecord(this ICloudflareClient client, CreateDnsRecordRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.ZoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
var req = ValidateRequest(request);
|
||||||
|
|
||||||
|
return client.PostAsync<DnsRecord, InternalDnsRecordRequest>($"/zones/{request.ZoneId}/dns_records", req, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete DNS Record.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="recordId">The record identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<Identifier>> DeleteDnsRecord(this ICloudflareClient client, string zoneId, string recordId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
zoneId.ValidateCloudflareId();
|
||||||
|
recordId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.DeleteAsync<Identifier>($"/zones/{zoneId}/dns_records/{recordId}", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update an existing DNS record.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Notes:
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item>A/AAAA records cannot exist on the same name as CNAME records.</item>
|
||||||
|
/// <item>NS records cannot exist on the same name as any other record type.</item>
|
||||||
|
/// <item>Domain names are always represented in Punycode, even if Unicode characters were used when creating the record.</item>
|
||||||
|
/// </list>
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<DnsRecord>> UpdateDnsRecord(this ICloudflareClient client, UpdateDnsRecordRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.ZoneId.ValidateCloudflareId();
|
||||||
|
request.RecordId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
var req = ValidateRequest(request);
|
||||||
|
|
||||||
|
return client.PatchAsync<DnsRecord, InternalDnsRecordRequest>($"/zones/{request.ZoneId}/dns_records/{request.RecordId}", req, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// You can export your <see href="https://en.wikipedia.org/wiki/Zone_file">BIND config</see> through this endpoint.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<string>> ExportDnsRecords(this ICloudflareClient client, string zoneId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
zoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.GetAsync<string>($"/zones/{zoneId}/dns_records/export", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DNS Record Details.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="recordId">The record identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<DnsRecord>> DnsRecordDetails(this ICloudflareClient client, string zoneId, string recordId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
zoneId.ValidateCloudflareId();
|
||||||
|
recordId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.GetAsync<DnsRecord>($"/zones/{zoneId}/dns_records/{recordId}", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// You can upload your <see href="https://en.wikipedia.org/wiki/Zone_file">BIND config</see> through this endpoint.
|
||||||
|
/// It assumes that cURL is called from a location with bind_config.txt (valid BIND config) present.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// See <see href="https://developers.cloudflare.com/dns/manage-dns-records/how-to/import-and-export/">the documentation</see> for more information.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<RecordImportResponse>> ImportDnsRecords(this ICloudflareClient client, ImportDnsRecordsRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.ZoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(request.File))
|
||||||
|
throw new ArgumentNullException(nameof(request.File));
|
||||||
|
|
||||||
|
var req = new MultipartFormDataContent();
|
||||||
|
|
||||||
|
if (request.Proxied.HasValue)
|
||||||
|
req.Add(new StringContent(request.Proxied.Value.ToString().ToLowerInvariant()), "proxied");
|
||||||
|
|
||||||
|
byte[] fileBytes = File.Exists(request.File)
|
||||||
|
? File.ReadAllBytes(request.File)
|
||||||
|
: Encoding.UTF8.GetBytes(request.File);
|
||||||
|
|
||||||
|
req.Add(new ByteArrayContent(fileBytes), "file");
|
||||||
|
|
||||||
|
return client.PostAsync<RecordImportResponse, MultipartFormDataContent>($"/zones/{request.ZoneId}/dns_records/import", req, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List, search, sort, and filter a zones' DNS records.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="options">Filter options (optional).</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<IReadOnlyCollection<DnsRecord>>> ListDnsRecords(this ICloudflareClient client, string zoneId, ListDnsRecordsFilter? options = null, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
zoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.GetAsync<IReadOnlyCollection<DnsRecord>>($"/zones/{zoneId}/dns_records", options, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Scan for common DNS records on your domain and automatically add them to your zone.
|
||||||
|
/// Useful if you haven't updated your nameservers yet.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<RecordScanResponse>> ScanDnsRecords(this ICloudflareClient client, string zoneId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
zoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.PostAsync<RecordScanResponse, object>($"/zones/{zoneId}/dns_records/scan", null, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overwrite an existing DNS record.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Notes:
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item>A/AAAA records cannot exist on the same name as CNAME records.</item>
|
||||||
|
/// <item>NS records cannot exist on the same name as any other record type.</item>
|
||||||
|
/// <item>Domain names are always represented in Punycode, even if Unicode characters were used when creating the record.</item>
|
||||||
|
/// </list>
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<DnsRecord>> OverwriteDnsRecord(this ICloudflareClient client, OverwriteDnsRecordRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.ZoneId.ValidateCloudflareId();
|
||||||
|
request.RecordId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
var req = ValidateRequest(request);
|
||||||
|
|
||||||
|
return client.PutAsync<DnsRecord, InternalDnsRecordRequest>($"/zones/{request.ZoneId}/dns_records/{request.RecordId}", req, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InternalDnsRecordRequest ValidateRequest(CreateDnsRecordRequest request)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(request.Name))
|
||||||
|
throw new ArgumentNullException(nameof(request.Name));
|
||||||
|
|
||||||
|
if (!Enum.IsDefined(typeof(DnsRecordType), request.Type))
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.Type), request.Type, $"The value '{request.Type}' is not valid. Valid value are in {nameof(DnsRecordType)}.");
|
||||||
|
|
||||||
|
var req = new InternalDnsRecordRequest
|
||||||
|
{
|
||||||
|
Name = request.Name.Trim(),
|
||||||
|
Type = request.Type,
|
||||||
|
Comment = request.Comment?.Trim(),
|
||||||
|
Proxied = request.Proxied,
|
||||||
|
Tags = request.Tags?
|
||||||
|
.Where(t => !string.IsNullOrWhiteSpace(t))
|
||||||
|
.Select(t => t.Trim())
|
||||||
|
.ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!_dataComponentTypes.Contains(request.Type) && string.IsNullOrWhiteSpace(request.Content))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(request.Content));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
req.Content = request.Content?.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.Type == DnsRecordType.CNAME && request.Settings != null && request.Settings is CNAMERecordSettings cnameSettings)
|
||||||
|
req.Settings = cnameSettings;
|
||||||
|
|
||||||
|
if (_dataComponentTypes.Contains(request.Type) && request.Data == null)
|
||||||
|
throw new ArgumentNullException(nameof(request.Data));
|
||||||
|
|
||||||
|
if (_priorityTypes.Contains(request.Type))
|
||||||
|
{
|
||||||
|
if (!request.Priority.HasValue)
|
||||||
|
throw new ArgumentNullException(nameof(request.Priority));
|
||||||
|
|
||||||
|
req.Priority = request.Priority.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.TimeToLive.HasValue)
|
||||||
|
{
|
||||||
|
if (request.TimeToLive == 1)
|
||||||
|
{
|
||||||
|
req.Ttl = 1;
|
||||||
|
}
|
||||||
|
else if (request.TimeToLive < 30 || 86400 < request.TimeToLive)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.TimeToLive), request.TimeToLive, $"The value '{request.TimeToLive}' is not valid. Valid value are between 60 (30 for Enterprise) and 86400.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
req.Ttl = request.TimeToLive.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (request.Type)
|
||||||
|
{
|
||||||
|
case DnsRecordType.CAA:
|
||||||
|
if (request.Data is CAARecordData caaData)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(caaData.Tag))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(caaData.Tag)}");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(caaData.Value))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(caaData.Value)}");
|
||||||
|
|
||||||
|
req.Data = caaData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The type of the value '{nameof(request.Data)}' has to be '{nameof(CAARecordData)}'", nameof(request.Data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DnsRecordType.CERT:
|
||||||
|
if (request.Data is CERTRecordData certData)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(certData.Certificate))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(certData.Certificate)}");
|
||||||
|
|
||||||
|
req.Data = certData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The type of the value '{nameof(request.Data)}' has to be '{nameof(CAARecordData)}'", nameof(request.Data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DnsRecordType.DNSKEY:
|
||||||
|
if (request.Data is DNSKEYRecordData dnskeyData)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(dnskeyData.PublicKey))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(dnskeyData.PublicKey)}");
|
||||||
|
|
||||||
|
req.Data = dnskeyData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The type of the value '{nameof(request.Data)}' has to be '{nameof(DNSKEYRecordData)}'", nameof(request.Data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DnsRecordType.DS:
|
||||||
|
if (request.Data is DSRecordData dsData)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(dsData.Digest))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(dsData.Digest)}");
|
||||||
|
|
||||||
|
req.Data = dsData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The type of the value '{nameof(request.Data)}' has to be '{nameof(DSRecordData)}'", nameof(request.Data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DnsRecordType.HTTPS:
|
||||||
|
if (request.Data is HTTPSRecordData httpsData)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(httpsData.Target))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(httpsData.Target)}");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(httpsData.Value))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(httpsData.Value)}");
|
||||||
|
|
||||||
|
req.Data = httpsData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The type of the value '{nameof(request.Data)}' has to be '{nameof(HTTPSRecordData)}'", nameof(request.Data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DnsRecordType.LOC:
|
||||||
|
if (request.Data is LOCRecordData locData)
|
||||||
|
{
|
||||||
|
if (locData.LatitudeDegrees.HasValue && (locData.LatitudeDegrees < 0 || 90 < locData.LatitudeDegrees))
|
||||||
|
throw new ArgumentOutOfRangeException($"{nameof(request.Data)}.{nameof(locData.LatitudeDegrees)}", locData.LatitudeDegrees, $"The value '{locData.LatitudeDegrees}' is not valid. Valid value are between {0} and {90}.");
|
||||||
|
|
||||||
|
if (locData.LatitudeMinutes.HasValue && (locData.LatitudeMinutes < 0 || 59 < locData.LatitudeMinutes))
|
||||||
|
throw new ArgumentOutOfRangeException($"{nameof(request.Data)}.{nameof(locData.LatitudeMinutes)}", locData.LatitudeMinutes, $"The value '{locData.LatitudeMinutes}' is not valid. Valid value are between {0} and {59}.");
|
||||||
|
|
||||||
|
if (locData.LatitudeSeconds.HasValue && (locData.LatitudeSeconds < 0 || 59.999 < locData.LatitudeSeconds))
|
||||||
|
throw new ArgumentOutOfRangeException($"{nameof(request.Data)}.{nameof(locData.LatitudeSeconds)}", locData.LatitudeSeconds, $"The value '{locData.LatitudeSeconds}' is not valid. Valid value are between {0} and {59.999}.");
|
||||||
|
|
||||||
|
if (locData.LatitudeDirection.HasValue && !Enum.IsDefined(typeof(LOCRecordLatitudeDirection), locData.LatitudeDirection))
|
||||||
|
throw new ArgumentOutOfRangeException($"{nameof(request.Data)}.{nameof(locData.LatitudeDirection)}", locData.LatitudeDirection, $"The value '{locData.LatitudeDirection}' is not valid.");
|
||||||
|
|
||||||
|
if (locData.LongitudeDegrees.HasValue && (locData.LongitudeDegrees < 0 || 180 < locData.LongitudeDegrees))
|
||||||
|
throw new ArgumentOutOfRangeException($"{nameof(request.Data)}.{nameof(locData.LongitudeDegrees)}", locData.LongitudeDegrees, $"The value '{locData.LongitudeDegrees}' is not valid. Valid value are between {0} and {180}.");
|
||||||
|
|
||||||
|
if (locData.LongitudeMinutes.HasValue && (locData.LongitudeMinutes < 0 || 59 < locData.LongitudeMinutes))
|
||||||
|
throw new ArgumentOutOfRangeException($"{nameof(request.Data)}.{nameof(locData.LongitudeMinutes)}", locData.LongitudeMinutes, $"The value '{locData.LongitudeMinutes}' is not valid. Valid value are between {0} and {59}.");
|
||||||
|
|
||||||
|
if (locData.LongitudeSeconds.HasValue && (locData.LongitudeSeconds < 0 || 59.999 < locData.LongitudeSeconds))
|
||||||
|
throw new ArgumentOutOfRangeException($"{nameof(request.Data)}.{nameof(locData.LongitudeSeconds)}", locData.LongitudeSeconds, $"The value '{locData.LongitudeSeconds}' is not valid. Valid value are between {0} and {59.999}.");
|
||||||
|
|
||||||
|
if (locData.LongitudeDirection.HasValue && (!Enum.IsDefined(typeof(LOCRecordLongitudeDirection), locData.LongitudeDirection)))
|
||||||
|
throw new ArgumentOutOfRangeException($"{nameof(request.Data)}.{nameof(locData.LongitudeDirection)}", locData.LongitudeDirection, $"The value '{locData.LongitudeDirection}' is not valid.");
|
||||||
|
|
||||||
|
if (locData.Altitude.HasValue && (locData.Altitude < -100_000 || 42_849_672.95 < locData.Altitude))
|
||||||
|
throw new ArgumentOutOfRangeException($"{nameof(request.Data)}.{nameof(locData.Altitude)}", locData.Size, $"The value '{locData.Altitude}' is not valid. Valid value are between {-100_000} and {42_849_672.95}.");
|
||||||
|
|
||||||
|
if (locData.Size.HasValue && (locData.Size < 0 || 90_000_000 < locData.Size))
|
||||||
|
throw new ArgumentOutOfRangeException($"{nameof(request.Data)}.{nameof(locData.Size)}", locData.Size, $"The value '{locData.Size}' is not valid. Valid value are between {0} and {90_000_000}.");
|
||||||
|
|
||||||
|
if (locData.PrecisionHorizontal.HasValue && (locData.PrecisionHorizontal < 0 || 90_000_000 < locData.PrecisionHorizontal))
|
||||||
|
throw new ArgumentOutOfRangeException($"{nameof(request.Data)}.{nameof(locData.PrecisionHorizontal)}", locData.Size, $"The value '{locData.PrecisionHorizontal}' is not valid. Valid value are between {0} and {90_000_000}.");
|
||||||
|
|
||||||
|
if (locData.PrecisionVertical.HasValue && (locData.PrecisionVertical < 0 || 90_000_000 < locData.PrecisionVertical))
|
||||||
|
throw new ArgumentOutOfRangeException($"{nameof(request.Data)}.{nameof(locData.PrecisionVertical)}", locData.PrecisionVertical, $"The value '{locData.PrecisionVertical}' is not valid. Valid value are between {0} and {90_000_000}.");
|
||||||
|
|
||||||
|
if (locData.LatitudeSeconds.HasValue)
|
||||||
|
locData.LatitudeSeconds = Math.Floor(locData.LatitudeSeconds.Value * 1000) / 1000; // Truncate to 3 decimal places
|
||||||
|
|
||||||
|
if (locData.LongitudeSeconds.HasValue)
|
||||||
|
locData.LongitudeSeconds = Math.Floor(locData.LongitudeSeconds.Value * 1000) / 1000; // Truncate to 3 decimal places
|
||||||
|
|
||||||
|
if (locData.Altitude.HasValue)
|
||||||
|
locData.Altitude = Math.Floor(locData.Altitude.Value * 100) / 100; // Truncate to 2 decimal places
|
||||||
|
|
||||||
|
req.Data = locData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The type of the value '{nameof(request.Data)}' has to be '{nameof(LOCRecordData)}'", nameof(request.Data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DnsRecordType.NAPTR:
|
||||||
|
if (request.Data is NAPTRRecordData naptrData)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(naptrData.Flags))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(naptrData.Flags)}");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(naptrData.Regex))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(naptrData.Regex)}");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(naptrData.Replacement))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(naptrData.Replacement)}");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(naptrData.Service))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(naptrData.Service)}");
|
||||||
|
|
||||||
|
req.Data = naptrData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The type of the value '{nameof(request.Data)}' has to be '{nameof(NAPTRRecordData)}'", nameof(request.Data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DnsRecordType.SMIMEA:
|
||||||
|
if (request.Data is SMIMEARecordData smimeaData)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(smimeaData.Certificate))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(smimeaData.Certificate)}");
|
||||||
|
|
||||||
|
req.Data = smimeaData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The type of the value '{nameof(request.Data)}' has to be '{nameof(SMIMEARecordData)}'", nameof(request.Data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DnsRecordType.SRV:
|
||||||
|
if (request.Data is SRVRecordData srvData)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(srvData.Target))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(srvData.Target)}");
|
||||||
|
|
||||||
|
req.Data = srvData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The type of the value '{nameof(request.Data)}' has to be '{nameof(SRVRecordData)}'", nameof(request.Data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DnsRecordType.SSHFP:
|
||||||
|
if (request.Data is SSHFPRecordData sshfpData)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(sshfpData.Fingerprint))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(sshfpData.Fingerprint)}");
|
||||||
|
|
||||||
|
req.Data = sshfpData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The type of the value '{nameof(request.Data)}' has to be '{nameof(SSHFPRecordData)}'", nameof(request.Data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DnsRecordType.SVCB:
|
||||||
|
if (request.Data is SVCBRecordData svcbData)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(svcbData.Target))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(svcbData.Target)}");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(svcbData.Value))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(svcbData.Value)}");
|
||||||
|
|
||||||
|
req.Data = svcbData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The type of the value '{nameof(request.Data)}' has to be '{nameof(SVCBRecordData)}'", nameof(request.Data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DnsRecordType.TLSA:
|
||||||
|
if (request.Data is TLSARecordData tlsaData)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(tlsaData.Certificate))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(tlsaData.Certificate)}");
|
||||||
|
|
||||||
|
req.Data = tlsaData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The type of the value '{nameof(request.Data)}' has to be '{nameof(TLSARecordData)}'", nameof(request.Data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DnsRecordType.URI:
|
||||||
|
if (request.Data is URIRecordData uriData)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(uriData.Target))
|
||||||
|
throw new ArgumentNullException($"{nameof(request.Data)}.{nameof(uriData.Target)}");
|
||||||
|
|
||||||
|
req.Data = uriData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The type of the value '{nameof(request.Data)}' has to be '{nameof(URIRecordData)}'", nameof(request.Data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InternalBatchUpdateRequest ValidateRequest(BatchDnsRecordsRequest.Post request)
|
||||||
|
{
|
||||||
|
var req = ValidateRequest(new CreateDnsRecordRequest("", request.Name)
|
||||||
|
{
|
||||||
|
Comment = request.Comment,
|
||||||
|
Content = request.Content,
|
||||||
|
Data = request.Data,
|
||||||
|
Priority = request.Priority,
|
||||||
|
Proxied = request.Proxied,
|
||||||
|
Settings = request.Settings,
|
||||||
|
Tags = request.Tags,
|
||||||
|
TimeToLive = request.TimeToLive,
|
||||||
|
Type = request.Type
|
||||||
|
});
|
||||||
|
|
||||||
|
return new InternalBatchUpdateRequest
|
||||||
|
{
|
||||||
|
Comment = req.Comment,
|
||||||
|
Content = req.Content,
|
||||||
|
Data = req.Data,
|
||||||
|
Name = req.Name,
|
||||||
|
Priority = req.Priority,
|
||||||
|
Proxied = req.Proxied,
|
||||||
|
Settings = req.Settings,
|
||||||
|
Tags = req.Tags,
|
||||||
|
Ttl = req.Ttl,
|
||||||
|
Type = req.Type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
277
src/Extensions/Cloudflare.Dns/Enums/DnsRecordType.cs
Normal file
277
src/Extensions/Cloudflare.Dns/Enums/DnsRecordType.cs
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// DNS record types.
|
||||||
|
/// <see href="https://github.com/cloudflare/cloudflare-typescript/blob/v4.4.1/src/resources/dns/records.ts">Source</see>
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// A list with short description can be found <see href="https://en.wikipedia.org/wiki/List_of_DNS_record_types">@wikipedia</see>.
|
||||||
|
/// </remarks>
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public enum DnsRecordType : int
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Address record.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Returns a 32-bit IPv4 address, most commonly used to map hostnames to an IP address of the host, but it is also used for DNSBLs, storing subnet masks in RFC 1101, etc.
|
||||||
|
/// <code>
|
||||||
|
/// example.com. 3600 IN A 96.7.128.175
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "A")]
|
||||||
|
A = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IPv6 address record.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Returns a 128-bit IPv6 address, most commonly used to map hostnames to an IP address of the host.
|
||||||
|
/// <code>
|
||||||
|
/// example.com. 3600 IN AAAA 2600:1408:ec00:36::1736:7f31
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "AAAA")]
|
||||||
|
AAAA = 28,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Certification Authority Authorization.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// DNS Certification Authority Authorization, constraining acceptable CAs for a host/domain.
|
||||||
|
/// <code>
|
||||||
|
/// example.com. 604800 IN CAA 0 issue "letsencrypt.org"
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "CAA")]
|
||||||
|
CAA = 257,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Certificate record.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Stores PKIX, SPKI, PGP, etc.
|
||||||
|
/// <code>
|
||||||
|
/// example.com. 86400 IN CERT 2 77 2 TUlJQ1l6Q0NBY3lnQXdJQkFnSUJBREFOQmdrcWh
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "CERT")]
|
||||||
|
CERT = 37,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Canonical name record.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Alias of one name to another: the DNS lookup will continue by retrying the lookup with the new name.
|
||||||
|
/// <code>
|
||||||
|
/// autodiscover.example.com. 86400 IN CNAME mail.example.com.
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "CNAME")]
|
||||||
|
CNAME = 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DNS Key record.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The key record used in DNSSEC. Uses the same format as the KEY record.
|
||||||
|
/// <code>
|
||||||
|
/// example.com. 3600 IN DNSKEY 256 3 13 OtuN/SL9sE+SDQ0tOLeezr1KzUNi77FflTjxQylUhm3V7m13Vz9tYQuc SGK0pyxISo9CQsszubAwJSypq3li3g==
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "DNSKEY")]
|
||||||
|
DNSKEY = 48,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delegation signer.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The record used to identify the DNSSEC signing key of a delegated zone.
|
||||||
|
/// <code>
|
||||||
|
/// example.com. 86400 IN DS 370 13 2 BE74359954660069D5C63D200C39F5603827D7DD02B56F120EE9F3A8 6764247C
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "DS")]
|
||||||
|
DS = 43,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HTTPS Binding.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// RR that improves performance for clients that need to resolve many resources to access a domain.
|
||||||
|
/// <code>
|
||||||
|
/// example.com. 3600 IN HTTPS 1 svc.example.com. alpn=h2
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "HTTPS")]
|
||||||
|
HTTPS = 65,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Location record.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Specifies a geographical location associated with a domain name.
|
||||||
|
/// <code>
|
||||||
|
/// SW1A2AA.find.me.uk. 2592000 IN LOC 51 30 12.748 N 0 7 39.611 W 0.00m 0.00m 0.00m 0.00m
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "LOC")]
|
||||||
|
LOC = 29,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mail exchange record.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// List of mail exchange servers that accept email for a domain.
|
||||||
|
/// <code>
|
||||||
|
/// example.com. 43200 IN MX 0 mail.example.com.
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "MX")]
|
||||||
|
MX = 15,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Naming Authority Pointer.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Allows regular-expression-based rewriting of domain names which can then be used as URIs, further domain names to lookups, etc.
|
||||||
|
/// <code>
|
||||||
|
/// example.com. 86400 IN NAPTR 100 10 "S" "SIP+D2T" "" _sip._tcp.example.com.
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "NAPTR")]
|
||||||
|
NAPTR = 35,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name server record.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Delegates a DNS zone to use the given authoritative name servers.
|
||||||
|
/// <code>
|
||||||
|
/// example.com. 86400 IN NS a.iana-servers.net.
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "NS")]
|
||||||
|
NS = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// OpenPGP public key record.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// A DNS-based Authentication of Named Entities (DANE) method for publishing and locating OpenPGP
|
||||||
|
/// public keys in DNS for a specific email address using an OPENPGPKEY DNS resource record.
|
||||||
|
/// <code>
|
||||||
|
/// 00d8d3f11739d2f3537099982b4674c29fc59a8fda350fca1379613a._openpgpkey.example.com. 3600 IN OPENPGPKEY a2V5S0VZMTIzNGtleUtFWQ==
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "OPENPGPKEY")]
|
||||||
|
OPENPGPKEY = 61,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// PTR Resource Record.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Pointer to a canonical name.
|
||||||
|
/// Unlike a CNAME, DNS processing stops and just the name is returned.
|
||||||
|
/// The most common use is for implementing reverse DNS lookups, but other uses include such things as DNS-SD.
|
||||||
|
/// <code>
|
||||||
|
/// 14.215.184.93.in-addr.arpa. 86400 IN PTR example.com.
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "PTR")]
|
||||||
|
PTR = 12,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// S/MIME cert association.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Associates an S/MIME certificate with a domain name for sender authentication.
|
||||||
|
/// <code>
|
||||||
|
/// example.com. 3600 IN SMIMEA 0 0 0 keyKEY1234keyKEY
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "SMIMEA")]
|
||||||
|
SMIMEA = 53,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Service locator.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Generalized service location record, used for newer protocols instead of creating protocol-specific records such as MX.
|
||||||
|
/// <code>
|
||||||
|
/// _autodiscover._tcp.example.com. 604800 IN SRV 1 0 443 mail.example.com.
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "SRV")]
|
||||||
|
SRV = 33,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SSH Public Key Fingerprint.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Resource record for publishing SSH public host key fingerprints in the DNS, in order to aid in verifying the authenticity of the host.
|
||||||
|
/// RFC 6594 defines ECC SSH keys and SHA-256 hashes. See the IANA SSHFP RR parameters registry for details.
|
||||||
|
/// <code>
|
||||||
|
/// example.com. 600 IN SSHFP 2 1 123456789abcdef67890123456789abcdef67890
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "SSHFP")]
|
||||||
|
SSHFP = 44,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Service Binding.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// RR that improves performance for clients that need to resolve many resources to access a domain.
|
||||||
|
/// <code>
|
||||||
|
/// example.com. 3600 IN SVCB 1 . alpn="h2,http/1.1"
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "SVCB")]
|
||||||
|
SVCB = 64,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TLSA certificate association.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// A record for DANE. RFC 6698 defines "The TLSA DNS resource record is used to associate a TLS server certificate
|
||||||
|
/// or public key with the domain name where the record is found, thus forming a 'TLSA certificate association'".
|
||||||
|
/// <code>
|
||||||
|
/// _443._tcp.example.com. 3600 IN TLSA 3 0 18cb0fc6c527506a053f4f14c8464bebbd6dede2738d11468dd953d7d6a3021f1
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "TLSA")]
|
||||||
|
TLSA = 52,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Text record.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Originally for arbitrary human-readable text in a DNS record.
|
||||||
|
/// Since the early 1990s, however, this record more often carries machine-readable data, such as specified by RFC 1464,
|
||||||
|
/// opportunistic encryption, Sender Policy Framework, DKIM, DMARC, DNS-SD, etc.
|
||||||
|
/// <br/>
|
||||||
|
/// More information about TXT records on <see href="https://www.cloudflare.com/learning/dns/dns-records/dns-txt-record/">Cloudflare</see>.
|
||||||
|
/// <code>
|
||||||
|
/// example.com. 86400 IN TXT "v=spf1 -all"
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "TXT")]
|
||||||
|
TXT = 16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Uniform Resource Identifier.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Can be used for publishing mappings from hostnames to URIs.
|
||||||
|
/// <code>
|
||||||
|
/// _ftp._tcp.example.com. 3600 IN URI 10 1 "ftp://ftp.example.com/public"
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "URI")]
|
||||||
|
URI = 256,
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/Extensions/Cloudflare.Dns/Enums/FilterMatchType.cs
Normal file
24
src/Extensions/Cloudflare.Dns/Enums/FilterMatchType.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Options how to match the query filter.
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public enum FilterMatchType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Match any rule.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "any")]
|
||||||
|
Any = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Match all rules.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "all")]
|
||||||
|
All = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
439
src/Extensions/Cloudflare.Dns/Filters/ListDnsRecordsFilter.cs
Normal file
439
src/Extensions/Cloudflare.Dns/Filters/ListDnsRecordsFilter.cs
Normal file
@@ -0,0 +1,439 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Filter for listing DNS records.
|
||||||
|
/// </summary>
|
||||||
|
public class ListDnsRecordsFilter : IQueryParameterFilter
|
||||||
|
{
|
||||||
|
#region Comment
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exact value of the DNS record comment.
|
||||||
|
/// This is a convenience alias for <see cref="CommentExact"/>.
|
||||||
|
/// </summary>
|
||||||
|
public string? Comment { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If this parameter is present, only records <em>without</em> a comment are returned.
|
||||||
|
/// </summary>
|
||||||
|
public bool? CommentAbsent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Substring of the DNS record comment.
|
||||||
|
/// Comment filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
public string? CommentContains { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Suffix of the DNS record comment.
|
||||||
|
/// Comment filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
public string? CommentEndsWith { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exact value of the DNS record comment.
|
||||||
|
/// Comment filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
public string? CommentExact { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If this parameter is present, only records <em>with</em> a comment are returned.
|
||||||
|
/// </summary>
|
||||||
|
public bool? CommentPresent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prefix of the DNS record comment.
|
||||||
|
/// Comment filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
public string? CommentStartsWith { get; set; }
|
||||||
|
|
||||||
|
#endregion Comment
|
||||||
|
|
||||||
|
#region Content
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exact value of the DNS record Content.
|
||||||
|
/// This is a convenience alias for <see cref="ContentExact"/>.
|
||||||
|
/// </summary>
|
||||||
|
public string? Content { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Substring of the DNS record Content.
|
||||||
|
/// Content filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
public string? ContentContains { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Suffix of the DNS record Content.
|
||||||
|
/// Content filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
public string? ContentEndsWith { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exact value of the DNS record Content.
|
||||||
|
/// Content filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
public string? ContentExact { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prefix of the DNS record Content.
|
||||||
|
/// Content filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
public string? ContentStartsWith { get; set; }
|
||||||
|
|
||||||
|
#endregion Content
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Direction to order DNS records in.
|
||||||
|
/// </summary>
|
||||||
|
public SortDirection? Direction { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to match all search requirements or at least one (any).
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// If set to <see cref="FilterMatchType.All"/>, acts like a logical AND between filters.
|
||||||
|
/// <br/>
|
||||||
|
/// If set to <see cref="FilterMatchType.Any"/>, acts like a logical OR instead.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Note that the interaction between tag filters is controlled by the <see cref="TagMatch"/> parameter instead.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public FilterMatchType? Match { get; set; }
|
||||||
|
|
||||||
|
#region Name
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exact value of the DNS record Name.
|
||||||
|
/// This is a convenience alias for <see cref="NameExact"/>.
|
||||||
|
/// </summary>
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Substring of the DNS record Name.
|
||||||
|
/// Name filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
public string? NameContains { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Suffix of the DNS record Name.
|
||||||
|
/// Name filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
public string? NameEndsWith { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exact value of the DNS record Name.
|
||||||
|
/// Name filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
public string? NameExact { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prefix of the DNS record Name.
|
||||||
|
/// Name filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
public string? NameStartsWith { get; set; }
|
||||||
|
|
||||||
|
#endregion Name
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Field to order DNS records by.
|
||||||
|
/// </summary>
|
||||||
|
public DnsRecordsOrderBy? OrderBy { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Page number of paginated results.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>1 <= X</value>
|
||||||
|
public int? Page { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of DNS records per page.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>1 <= X <= 5,000,000</value>
|
||||||
|
public int? PerPage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the record is receiving the performance and security benefits of Cloudflare.
|
||||||
|
/// </summary>
|
||||||
|
public bool? Proxied { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allows searching in multiple properties of a DNS record simultaneously.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This parameter is intended for human users, not automation.
|
||||||
|
/// Its exact behavior is intentionally left unspecified and is subject to change in the future.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// <em>
|
||||||
|
/// This parameter works independently of the <see cref="Match"/> setting.
|
||||||
|
/// <br/>
|
||||||
|
/// For automated searches, please use the other available parameters.
|
||||||
|
/// </em>
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public string? Search { get; set; }
|
||||||
|
|
||||||
|
#region Tag
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Condition on the DNS record tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// Parameter values can be of the form <c><tag-name>:<tag-value></c> to search for an exact name:value pair,
|
||||||
|
/// or just <c><tag-name></c> to search for records with a specific tag name regardless of its value.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// This is a convenience shorthand for the more powerful <c>tag.<predicate></c> parameters.
|
||||||
|
/// <br/>
|
||||||
|
/// Examples:
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item><c>tag=important</c> is equivalent to <c>tag.present=important</c></item>
|
||||||
|
/// <item><c>tag=team:DNS</c> is equivalent to <c>tag.exact=team:DNS</c></item>
|
||||||
|
/// </list>
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public string? Tag { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name of a tag which must <em>not</em> be present on the DNS record.
|
||||||
|
/// Tag filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
public string? TagAbsent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A tag and value, of the form <c><tag-name>:<tag-value></c>.
|
||||||
|
/// Tag filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The API will only return DNS records that have a tag named <c><tag-name></c> whose value contains <c><tag-value></c>.
|
||||||
|
/// </remarks>
|
||||||
|
public string? TagContains { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A tag and value, of the form <c><tag-name>:<tag-value></c>.
|
||||||
|
/// Tag filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The API will only return DNS records that have a tag named <c><tag-name></c> whose value ends with <c><tag-value></c>.
|
||||||
|
/// </remarks>
|
||||||
|
public string? TagEndsWith { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A tag and value, of the form <c><tag-name>:<tag-value></c>.
|
||||||
|
/// Tag filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The API will only return DNS records that have a tag named <c><tag-name></c> whose value is <c><tag-value></c>.
|
||||||
|
/// </remarks>
|
||||||
|
public string? TagExact { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name of a tag which must be present on the DNS record.
|
||||||
|
/// Tag filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
public string? TagPresent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A tag and value, of the form <c><tag-name>:<tag-value></c>.
|
||||||
|
/// Tag filters are case-insensitive.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The API will only return DNS records that have a tag named <c><tag-name></c> whose value starts with <c><tag-value></c>.
|
||||||
|
/// </remarks>
|
||||||
|
public string? TagStartsWith { get; set; }
|
||||||
|
|
||||||
|
#endregion Tag
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to match all tag search requirements or at least one (any).
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// If set to <see cref="FilterMatchType.All"/>, acts like a logical AND between filters.
|
||||||
|
/// <br/>
|
||||||
|
/// If set to <see cref="FilterMatchType.Any"/>, acts like a logical OR instead.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Note that the regular <see cref="Match"/> parameter is still used to combine the resulting condition with other filters that aren't related to tags.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public FilterMatchType? TagMatch { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Record type.
|
||||||
|
/// </summary>
|
||||||
|
public DnsRecordType? Type { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IDictionary<string, string> GetQueryParameters()
|
||||||
|
{
|
||||||
|
var dict = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
#pragma warning disable CS8602, CS8604 // There will be no null value below.
|
||||||
|
|
||||||
|
#region Comment
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(Comment))
|
||||||
|
dict.Add("comment", Comment.Trim());
|
||||||
|
|
||||||
|
if (CommentAbsent.HasValue && CommentAbsent.Value)
|
||||||
|
dict.Add("comment.absent", "true");
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(CommentContains))
|
||||||
|
dict.Add("comment.contains", CommentContains.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(CommentEndsWith))
|
||||||
|
dict.Add("comment.endswith", CommentEndsWith.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(CommentExact))
|
||||||
|
dict.Add("comment.exact", CommentExact.Trim());
|
||||||
|
|
||||||
|
if (CommentPresent.HasValue && CommentPresent.Value)
|
||||||
|
dict.Add("comment.present", "true");
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(CommentStartsWith))
|
||||||
|
dict.Add("comment.startswith", CommentStartsWith.Trim());
|
||||||
|
|
||||||
|
#endregion Comment
|
||||||
|
|
||||||
|
#region Content
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(Content))
|
||||||
|
dict.Add("content", Content.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(ContentContains))
|
||||||
|
dict.Add("content.contains", ContentContains.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(ContentEndsWith))
|
||||||
|
dict.Add("content.endswith", ContentEndsWith.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(ContentExact))
|
||||||
|
dict.Add("content.exact", ContentExact.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(ContentStartsWith))
|
||||||
|
dict.Add("content.startswith", ContentStartsWith.Trim());
|
||||||
|
|
||||||
|
#endregion Content
|
||||||
|
|
||||||
|
if (Direction.HasValue && Enum.IsDefined(typeof(SortDirection), Direction.Value))
|
||||||
|
dict.Add("direction", Direction.Value.GetEnumMemberValue());
|
||||||
|
|
||||||
|
if (Match.HasValue && Enum.IsDefined(typeof(FilterMatchType), Match.Value))
|
||||||
|
dict.Add("match", Match.Value.GetEnumMemberValue());
|
||||||
|
|
||||||
|
#region Name
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(Name))
|
||||||
|
dict.Add("name", Name.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(NameContains))
|
||||||
|
dict.Add("name.contains", NameContains.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(NameEndsWith))
|
||||||
|
dict.Add("name.endswith", NameEndsWith.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(NameExact))
|
||||||
|
dict.Add("name.exact", NameExact.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(NameStartsWith))
|
||||||
|
dict.Add("name.startswith", NameStartsWith.Trim());
|
||||||
|
|
||||||
|
#endregion Name
|
||||||
|
|
||||||
|
if (OrderBy.HasValue && Enum.IsDefined(typeof(DnsRecordsOrderBy), OrderBy.Value))
|
||||||
|
dict.Add("order", OrderBy.Value.GetEnumMemberValue());
|
||||||
|
|
||||||
|
if (Page.HasValue && Page.Value >= 1)
|
||||||
|
dict.Add("page", Page.Value.ToString());
|
||||||
|
|
||||||
|
if (PerPage.HasValue && PerPage.Value >= 1 && PerPage.Value <= 5_000_000)
|
||||||
|
dict.Add("per_page", PerPage.Value.ToString());
|
||||||
|
|
||||||
|
if (Proxied.HasValue)
|
||||||
|
dict.Add("proxied", Proxied.Value.ToString().ToLowerInvariant());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(Search))
|
||||||
|
dict.Add("search", Search.Trim());
|
||||||
|
|
||||||
|
#region Tag
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(Tag))
|
||||||
|
dict.Add("tag", Tag.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(TagAbsent))
|
||||||
|
dict.Add("tag.absent", TagAbsent.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(TagContains))
|
||||||
|
dict.Add("tag.contains", TagContains.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(TagEndsWith))
|
||||||
|
dict.Add("tag.endswith", TagEndsWith.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(TagExact))
|
||||||
|
dict.Add("tag.exact", TagExact.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(TagPresent))
|
||||||
|
dict.Add("tag.present", TagPresent.Trim());
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(TagStartsWith))
|
||||||
|
dict.Add("tag.startswith", TagStartsWith.Trim());
|
||||||
|
|
||||||
|
#endregion Tag
|
||||||
|
|
||||||
|
if (TagMatch.HasValue && Enum.IsDefined(typeof(FilterMatchType), TagMatch.Value))
|
||||||
|
dict.Add("tag_match", TagMatch.Value.GetEnumMemberValue());
|
||||||
|
|
||||||
|
if (Type.HasValue && Enum.IsDefined(typeof(DnsRecordType), Type.Value))
|
||||||
|
dict.Add("type", Type.Value.GetEnumMemberValue());
|
||||||
|
|
||||||
|
#pragma warning restore CS8602, CS8604
|
||||||
|
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Possible fields to order DNS records by.
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public enum DnsRecordsOrderBy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Order by record type.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "type")]
|
||||||
|
Type = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Order by record name.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "name")]
|
||||||
|
Name = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Order by record content.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "content")]
|
||||||
|
Content = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Order by record TTL.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "ttl")]
|
||||||
|
Ttl = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Order by record proxied.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "proxied")]
|
||||||
|
Proxied = 5
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns.Internals
|
||||||
|
{
|
||||||
|
internal class InternalBatchRequest
|
||||||
|
{
|
||||||
|
[JsonProperty("deletes")]
|
||||||
|
public IReadOnlyCollection<Identifier>? Deletes { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("patches")]
|
||||||
|
public IReadOnlyCollection<InternalBatchUpdateRequest>? Patches { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("posts")]
|
||||||
|
public IReadOnlyCollection<InternalDnsRecordRequest>? Posts { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("puts")]
|
||||||
|
public IReadOnlyCollection<InternalBatchUpdateRequest>? Puts { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class InternalBatchUpdateRequest : InternalDnsRecordRequest
|
||||||
|
{
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public string? Id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns.Internals
|
||||||
|
{
|
||||||
|
internal class InternalDnsRecordRequest
|
||||||
|
{
|
||||||
|
[JsonProperty("comment")]
|
||||||
|
public string? Comment { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("proxied")]
|
||||||
|
public bool? Proxied { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("settings")]
|
||||||
|
public object? Settings { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("tags")]
|
||||||
|
public IReadOnlyCollection<string>? Tags { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("ttl")]
|
||||||
|
public int? Ttl { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("content")]
|
||||||
|
public string? Content { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("type")]
|
||||||
|
public DnsRecordType Type { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("priority")]
|
||||||
|
public int? Priority { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public object? Data { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
122
src/Extensions/Cloudflare.Dns/Models/DNSAnalyticsQuery.cs
Normal file
122
src/Extensions/Cloudflare.Dns/Models/DNSAnalyticsQuery.cs
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
internal class DNSAnalyticsQuery
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Array of dimension names.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("dimensions")]
|
||||||
|
public IReadOnlyCollection<string>? Dimensions { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Limit number of returned metrics.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("limit")]
|
||||||
|
public int? Limit { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Array of metric names.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("metrics")]
|
||||||
|
public IReadOnlyCollection<string>? Metrics { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start date and time of requesting data period.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("since")]
|
||||||
|
public DateTime? Since { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unit of time to group data by.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("time_delta")]
|
||||||
|
public TimeDeltaUnit? TimeDelta { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("until")]
|
||||||
|
public DateTime? Until { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Segmentation filter in 'attribute operator value' format.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("filters")]
|
||||||
|
public string? Filters { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Array of dimensions to sort by, where each dimension may be prefixed
|
||||||
|
/// by <c>-</c> (descending) or <c>+</c> (ascending).
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("sort")]
|
||||||
|
public IReadOnlyCollection<string>? Sort { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time delta units.
|
||||||
|
/// <see href="https://github.com/cloudflare/cloudflare-typescript/blob/v4.4.1/src/resources/dns/dns.ts#L103">Source</see>
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public enum TimeDeltaUnit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// All time.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "all")]
|
||||||
|
All = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Auto.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "auto")]
|
||||||
|
Auto = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Year.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "year")]
|
||||||
|
Year = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Quarter.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "quarter")]
|
||||||
|
Quarter = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Month.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "month")]
|
||||||
|
Month = 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Week.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "week")]
|
||||||
|
Week = 6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Day.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "day")]
|
||||||
|
Day = 7,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hour.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "hour")]
|
||||||
|
Hour = 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dekaminute.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "dekaminute")]
|
||||||
|
DekaMinute = 9,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minute.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "minute")]
|
||||||
|
Minute = 10
|
||||||
|
}
|
||||||
|
}
|
||||||
120
src/Extensions/Cloudflare.Dns/Models/DnsRecord.cs
Normal file
120
src/Extensions/Cloudflare.Dns/Models/DnsRecord.cs
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A DNS record.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DnsRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
protected DnsRecord(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DNS record name (or @ for the zone apex) in Punycode.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Record type.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("type")]
|
||||||
|
public DnsRecordType Type { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Comments or notes about the DNS record.
|
||||||
|
/// This field has no effect on DNS responses.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("comment")]
|
||||||
|
public string? Comment { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DNS record content.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("content")]
|
||||||
|
public string? Content { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the record is receiving the performance and security benefits of
|
||||||
|
/// Cloudflare.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("proxied")]
|
||||||
|
public bool? Proxied { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Settings for the DNS record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("settings")]
|
||||||
|
public DnsRecordSettings? Settings { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Custom tags for the DNS record.
|
||||||
|
/// This field has no effect on DNS responses.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("tags")]
|
||||||
|
public IReadOnlyCollection<string>? Tags { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time To Live (TTL) of the DNS record in seconds.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Setting to <c>1</c> means 'automatic'. Value must be between <c>60</c> and <c>86400</c>, with the
|
||||||
|
/// minimum reduced to <c>30</c> for Enterprise zones.
|
||||||
|
/// </remarks>
|
||||||
|
[JsonProperty("ttl")]
|
||||||
|
public int? TimeToLive { get; set; }
|
||||||
|
|
||||||
|
#region Response
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifier.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public string? Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When the record was created.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("created_on")]
|
||||||
|
public DateTime CreatedOn { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extra Cloudflare-specific information about the record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("meta")]
|
||||||
|
public JToken? Meta { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When the record was last modified.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("modified_on")]
|
||||||
|
public DateTime ModifiedOn { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the record can be proxied by Cloudflare or not.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("proxiable")]
|
||||||
|
public bool Proxiable { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When the record comment was last modified. Omitted if there is no comment.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("comment_modified_on")]
|
||||||
|
public DateTime? CommentModifiedOn { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When the record tags were last modified. Omitted if there are no tags.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("tags_modified_on")]
|
||||||
|
public DateTime? TagsModifiedOn { get; set; }
|
||||||
|
|
||||||
|
#endregion Response
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/Extensions/Cloudflare.Dns/Models/DnsRecordSettings.cs
Normal file
26
src/Extensions/Cloudflare.Dns/Models/DnsRecordSettings.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// IP Settings for the DNS record.
|
||||||
|
/// </summary>
|
||||||
|
public class DnsRecordSettings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// When enabled, only A records will be generated, and AAAA records will not be
|
||||||
|
/// created. This setting is intended for exceptional cases. Note that this option
|
||||||
|
/// only applies to proxied records and it has no effect on whether Cloudflare
|
||||||
|
/// communicates with the origin using IPv4 or IPv6.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("ipv4_only")]
|
||||||
|
public bool? IPv4Only { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When enabled, only AAAA records will be generated, and A records will not be
|
||||||
|
/// created. This setting is intended for exceptional cases. Note that this option
|
||||||
|
/// only applies to proxied records and it has no effect on whether Cloudflare
|
||||||
|
/// communicates with the origin using IPv4 or IPv6.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("ipv6_only")]
|
||||||
|
public bool? IPv6Only { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/Extensions/Cloudflare.Dns/Models/Records/AAAARecord.cs
Normal file
18
src/Extensions/Cloudflare.Dns/Models/Records/AAAARecord.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// IPv6 address record.
|
||||||
|
/// </summary>
|
||||||
|
public class AAAARecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ARecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public AAAARecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.AAAA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/Extensions/Cloudflare.Dns/Models/Records/ARecord.cs
Normal file
18
src/Extensions/Cloudflare.Dns/Models/Records/ARecord.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Address record.
|
||||||
|
/// </summary>
|
||||||
|
public class ARecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ARecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public ARecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.A;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/Extensions/Cloudflare.Dns/Models/Records/CAARecord.cs
Normal file
48
src/Extensions/Cloudflare.Dns/Models/Records/CAARecord.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Certification Authority Authorization record.
|
||||||
|
/// </summary>
|
||||||
|
public class CAARecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CAARecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public CAARecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.CAA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a CAA record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public CAARecordData? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a CAA record.
|
||||||
|
/// </summary>
|
||||||
|
public class CAARecordData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Flags for the CAA record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("flags")]
|
||||||
|
public int? Flags { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the property controlled by this record (e.g.: issue, issuewild, iodef).
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("tag")]
|
||||||
|
public string? Tag { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Value of the record. This field's semantics depend on the chosen tag.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("value")]
|
||||||
|
public string? Value { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/Extensions/Cloudflare.Dns/Models/Records/CERTRecord.cs
Normal file
54
src/Extensions/Cloudflare.Dns/Models/Records/CERTRecord.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Certificate record.
|
||||||
|
/// </summary>
|
||||||
|
public class CERTRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CERTRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public CERTRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.CERT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a CERT record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public CERTRecordData? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a CERT record.
|
||||||
|
/// </summary>
|
||||||
|
public class CERTRecordData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Algorithm.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("algorithm")]
|
||||||
|
public int? Algorithm { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Certificate.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("certificate")]
|
||||||
|
public string? Certificate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Key tag.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("key_tag")]
|
||||||
|
public int? KeyTag { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("type")]
|
||||||
|
public int? Type { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/Extensions/Cloudflare.Dns/Models/Records/CNAMERecord.cs
Normal file
41
src/Extensions/Cloudflare.Dns/Models/Records/CNAMERecord.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Canonical Name record.
|
||||||
|
/// </summary>
|
||||||
|
public class CNAMERecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CNAMERecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public CNAMERecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.CNAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Settings for the DNS record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("settings")]
|
||||||
|
public new CNAMERecordSettings? Settings { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Settings for the DNS record.
|
||||||
|
/// </summary>
|
||||||
|
public class CNAMERecordSettings : DnsRecordSettings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// If enabled, causes the CNAME record to be resolved externally and the resulting
|
||||||
|
/// address records (e.g., A and AAAA) to be returned instead of the CNAME record
|
||||||
|
/// itself.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This setting is unavailable for proxied records, since they are always flattened.
|
||||||
|
/// </remarks>
|
||||||
|
[JsonProperty("flatten_cname")]
|
||||||
|
public bool? FlattenCname { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/Extensions/Cloudflare.Dns/Models/Records/DNSKEYRecord.cs
Normal file
54
src/Extensions/Cloudflare.Dns/Models/Records/DNSKEYRecord.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// DNS Key record.
|
||||||
|
/// </summary>
|
||||||
|
public class DNSKEYRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DNSKEYRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public DNSKEYRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.DNSKEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a DNSKEY record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public DNSKEYRecordData? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a DNSKEY record.
|
||||||
|
/// </summary>
|
||||||
|
public class DNSKEYRecordData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Algorithm.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("algorithm")]
|
||||||
|
public int? Algorithm { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flags.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("flags")]
|
||||||
|
public int? Flags { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Protocol.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("protocol")]
|
||||||
|
public int? Protocol { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Public key.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("public_key")]
|
||||||
|
public string? PublicKey { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/Extensions/Cloudflare.Dns/Models/Records/DSRecord.cs
Normal file
54
src/Extensions/Cloudflare.Dns/Models/Records/DSRecord.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Delegate Signer record.
|
||||||
|
/// </summary>
|
||||||
|
public class DSRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DSRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public DSRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.DS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a DS record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public DSRecordData? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a DS record.
|
||||||
|
/// </summary>
|
||||||
|
public class DSRecordData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Algorithm.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("algorithm")]
|
||||||
|
public int? Algorithm { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Digest.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("digest")]
|
||||||
|
public string? Digest { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Digest type.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("digest_type")]
|
||||||
|
public int? DigestType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Key tag.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("key_tag")]
|
||||||
|
public int? KeyTag { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/Extensions/Cloudflare.Dns/Models/Records/HTTPSRecord.cs
Normal file
48
src/Extensions/Cloudflare.Dns/Models/Records/HTTPSRecord.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// HTTPS binding record.
|
||||||
|
/// </summary>
|
||||||
|
public class HTTPSRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HTTPSRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public HTTPSRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.HTTPS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a HTTPS record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public HTTPSRecordData? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a HTTPS record.
|
||||||
|
/// </summary>
|
||||||
|
public class HTTPSRecordData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Priority.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("priority")]
|
||||||
|
public int? Priority { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Target.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("target")]
|
||||||
|
public string? Target { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Value.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("value")]
|
||||||
|
public string? Value { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
143
src/Extensions/Cloudflare.Dns/Models/Records/LOCRecord.cs
Normal file
143
src/Extensions/Cloudflare.Dns/Models/Records/LOCRecord.cs
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Location record.
|
||||||
|
/// </summary>
|
||||||
|
public class LOCRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="LOCRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public LOCRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.LOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a LOC record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public LOCRecordData? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a LOC record.
|
||||||
|
/// </summary>
|
||||||
|
public class LOCRecordData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Altitude of location in meters.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("altitude")]
|
||||||
|
public double? Altitude { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Degrees of latitude.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("lat_degrees")]
|
||||||
|
public double? LatitudeDegrees { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Latitude direction.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("lat_direction")]
|
||||||
|
public LOCRecordLatitudeDirection? LatitudeDirection { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minutes of latitude.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("lat_minutes")]
|
||||||
|
public double? LatitudeMinutes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Seconds of latitude.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("lat_seconds")]
|
||||||
|
public double? LatitudeSeconds { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Degrees of longitude.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("long_degrees")]
|
||||||
|
public double? LongitudeDegrees { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Longitude direction.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("long_direction")]
|
||||||
|
public LOCRecordLongitudeDirection? LongitudeDirection { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minutes of longitude.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("long_minutes")]
|
||||||
|
public double? LongitudeMinutes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Seconds of longitude.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("long_seconds")]
|
||||||
|
public double? LongitudeSeconds { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Horizontal precision of location.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("precision_horz")]
|
||||||
|
public double? PrecisionHorizontal { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Vertical precision of location.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("precision_vert")]
|
||||||
|
public double? PrecisionVertical { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Size of location in meters.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("size")]
|
||||||
|
public double? Size { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Location record latitude direction.
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public enum LOCRecordLatitudeDirection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// North.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "N")]
|
||||||
|
North = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// South.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "S")]
|
||||||
|
South = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Location record longitude direction.
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public enum LOCRecordLongitudeDirection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// East.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "E")]
|
||||||
|
East = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// West.
|
||||||
|
/// </summary>
|
||||||
|
[EnumMember(Value = "W")]
|
||||||
|
West = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/Extensions/Cloudflare.Dns/Models/Records/MXRecord.cs
Normal file
25
src/Extensions/Cloudflare.Dns/Models/Records/MXRecord.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Mail Exchange record.
|
||||||
|
/// </summary>
|
||||||
|
public class MXRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MXRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public MXRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.MX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required for MX, SRV and URI records; unused by other record types.
|
||||||
|
/// Records with lower priorities are preferred.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("priority")]
|
||||||
|
public int? Priority { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
66
src/Extensions/Cloudflare.Dns/Models/Records/NAPTRRecord.cs
Normal file
66
src/Extensions/Cloudflare.Dns/Models/Records/NAPTRRecord.cs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Naming authority pointer record.
|
||||||
|
/// </summary>
|
||||||
|
public class NAPTRRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="NAPTRRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public NAPTRRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.NAPTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a NAPTR record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public NAPTRRecordData? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a NAPTR record.
|
||||||
|
/// </summary>
|
||||||
|
public class NAPTRRecordData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Flags.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("flags")]
|
||||||
|
public string? Flags { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Order.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("order")]
|
||||||
|
public int? Order { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preference.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("preference")]
|
||||||
|
public int? Preference { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Regular expression.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("regex")]
|
||||||
|
public string? Regex { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replacement.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("replacement")]
|
||||||
|
public string? Replacement { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Service.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("service")]
|
||||||
|
public string? Service { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/Extensions/Cloudflare.Dns/Models/Records/NSRecord.cs
Normal file
18
src/Extensions/Cloudflare.Dns/Models/Records/NSRecord.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Name Server record.
|
||||||
|
/// </summary>
|
||||||
|
public class NSRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="NSRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public NSRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.NS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// OpenPGP Publi Key record.
|
||||||
|
/// </summary>
|
||||||
|
public class OPENPGPKEYRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="OPENPGPKEYRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public OPENPGPKEYRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.OPENPGPKEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A single Base64-encoded OpenPGP Transferable Public Key (RFC 4880 Section 11.1).
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("content")]
|
||||||
|
public new string? Content { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/Extensions/Cloudflare.Dns/Models/Records/PTRRecord.cs
Normal file
18
src/Extensions/Cloudflare.Dns/Models/Records/PTRRecord.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// PTR resource record.
|
||||||
|
/// </summary>
|
||||||
|
public class PTRRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="PTRRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public PTRRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.PTR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/Extensions/Cloudflare.Dns/Models/Records/SMIMEARecord.cs
Normal file
54
src/Extensions/Cloudflare.Dns/Models/Records/SMIMEARecord.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// S/MIME cert association record.
|
||||||
|
/// </summary>
|
||||||
|
public class SMIMEARecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SMIMEARecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public SMIMEARecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.SMIMEA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a SMIMEA record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public SMIMEARecordData? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a SMIMEA record.
|
||||||
|
/// </summary>
|
||||||
|
public class SMIMEARecordData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Certificate.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("certificate")]
|
||||||
|
public string? Certificate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Matching type.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("matching_type")]
|
||||||
|
public int? MatchingType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Selector.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("selector")]
|
||||||
|
public int? Selector { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Usage.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("usage")]
|
||||||
|
public int? Usage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/Extensions/Cloudflare.Dns/Models/Records/SRVRecord.cs
Normal file
55
src/Extensions/Cloudflare.Dns/Models/Records/SRVRecord.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Service locator record.
|
||||||
|
/// </summary>
|
||||||
|
public class SRVRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SRVRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public SRVRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.SRV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a SRV record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public SRVRecordData? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a SRV record.
|
||||||
|
/// </summary>
|
||||||
|
public class SRVRecordData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The port of the service.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("port")]
|
||||||
|
public int? Port { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required for MX, SRV and URI records; unused by other record types.
|
||||||
|
/// Records with lower priorities are preferred.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("priority")]
|
||||||
|
public int? Priority { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A valid hostname.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("target")]
|
||||||
|
public string? Target { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The record weight.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("weight")]
|
||||||
|
public int? Weight { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/Extensions/Cloudflare.Dns/Models/Records/SSHFPRecord.cs
Normal file
48
src/Extensions/Cloudflare.Dns/Models/Records/SSHFPRecord.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// SSH Public Key Fingerprint record.
|
||||||
|
/// </summary>
|
||||||
|
public class SSHFPRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SSHFPRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public SSHFPRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.SSHFP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a SSHFP record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public SSHFPRecordData? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a SSHFP record.
|
||||||
|
/// </summary>
|
||||||
|
public class SSHFPRecordData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Algorithm.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("algorithm")]
|
||||||
|
public int? Algorithm { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fingerprint.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("fingerprint")]
|
||||||
|
public string? Fingerprint { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("type")]
|
||||||
|
public int? Type { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/Extensions/Cloudflare.Dns/Models/Records/SVCBRecord.cs
Normal file
48
src/Extensions/Cloudflare.Dns/Models/Records/SVCBRecord.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Service Binding record.
|
||||||
|
/// </summary>
|
||||||
|
public class SVCBRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SVCBRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public SVCBRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.SVCB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a SVCB record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public SVCBRecordData? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a SVCB record.
|
||||||
|
/// </summary>
|
||||||
|
public class SVCBRecordData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Priority.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("priority")]
|
||||||
|
public int? Priority { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Target.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("target")]
|
||||||
|
public string? Target { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Value.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("value")]
|
||||||
|
public string? Value { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/Extensions/Cloudflare.Dns/Models/Records/TLSARecord.cs
Normal file
54
src/Extensions/Cloudflare.Dns/Models/Records/TLSARecord.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// TLSA certificate association record.
|
||||||
|
/// </summary>
|
||||||
|
public class TLSARecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="TLSARecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public TLSARecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.TLSA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a TLSA record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public TLSARecordData? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a TLSA record.
|
||||||
|
/// </summary>
|
||||||
|
public class TLSARecordData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Certificate.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("certificate")]
|
||||||
|
public string? Certificate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Matching type.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("matching_type")]
|
||||||
|
public int? MatchingType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Selector.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("selector")]
|
||||||
|
public int? Selector { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Usage.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("usage")]
|
||||||
|
public int? Usage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/Extensions/Cloudflare.Dns/Models/Records/TXTRecord.cs
Normal file
29
src/Extensions/Cloudflare.Dns/Models/Records/TXTRecord.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Text record.
|
||||||
|
/// </summary>
|
||||||
|
public class TXTRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="TXTRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public TXTRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.TXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Text content for the record. The content must consist of quoted "character
|
||||||
|
/// strings" (RFC 1035), each with a length of up to 255 bytes. Strings exceeding
|
||||||
|
/// this allowed maximum length are automatically split.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Learn more at <see href="https://www.cloudflare.com/learning/dns/dns-records/dns-txt-record/"/>.
|
||||||
|
/// </remarks>
|
||||||
|
[JsonProperty("content")]
|
||||||
|
public new string? Content { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/Extensions/Cloudflare.Dns/Models/Records/URIRecord.cs
Normal file
49
src/Extensions/Cloudflare.Dns/Models/Records/URIRecord.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Uniform Resource Identifier record.
|
||||||
|
/// </summary>
|
||||||
|
public class URIRecord : DnsRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="URIRecord"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public URIRecord(string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.URI;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required for MX, SRV and URI records; unused by other record types.
|
||||||
|
/// Records with lower priorities are preferred.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("priority")]
|
||||||
|
public int? Priority { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a URI record.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public URIRecordData? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a URI record.
|
||||||
|
/// </summary>
|
||||||
|
public class URIRecordData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The record content.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("target")]
|
||||||
|
public string? Target { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The record weight.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("weight")]
|
||||||
|
public int? Weight { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,21 @@ This package contains the feature set of the _DNS_ section of the Cloudflare API
|
|||||||
- [List Account Custom Nameservers](https://developers.cloudflare.com/api/resources/custom_nameservers/methods/get/)
|
- [List Account Custom Nameservers](https://developers.cloudflare.com/api/resources/custom_nameservers/methods/get/)
|
||||||
|
|
||||||
|
|
||||||
|
### [DNS]
|
||||||
|
|
||||||
|
#### [Records]
|
||||||
|
|
||||||
|
- [Batch DNS Records](https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/batch/)
|
||||||
|
- [Create DNS Record](https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/create/)
|
||||||
|
- [Delete DNS Record](https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/delete/)
|
||||||
|
- [Update DNS Record](https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/edit/)
|
||||||
|
- [Export DNS Records](https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/export/)
|
||||||
|
- [DNS Record Details](https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/get/)
|
||||||
|
- [Import DNS Records](https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/import/)
|
||||||
|
- [List DNS Records](https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/list/)
|
||||||
|
- [Scan DNS Records](https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/scan/)
|
||||||
|
- [Overwrite DNS Record](https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/update/)
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -21,3 +36,6 @@ Published under MIT License (see [choose a license])
|
|||||||
[choose a license]: https://choosealicense.com/licenses/mit/
|
[choose a license]: https://choosealicense.com/licenses/mit/
|
||||||
|
|
||||||
[Account Custom Nameservers]: https://developers.cloudflare.com/api/resources/custom_nameservers/
|
[Account Custom Nameservers]: https://developers.cloudflare.com/api/resources/custom_nameservers/
|
||||||
|
|
||||||
|
[DNS]: https://developers.cloudflare.com/api/resources/dns/
|
||||||
|
[Records]: https://developers.cloudflare.com/api/resources/dns/subresources/records/
|
||||||
|
|||||||
159
src/Extensions/Cloudflare.Dns/Requests/BatchDnsRecordsRequest.cs
Normal file
159
src/Extensions/Cloudflare.Dns/Requests/BatchDnsRecordsRequest.cs
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to manipulate DNS records.
|
||||||
|
/// </summary>
|
||||||
|
public class BatchDnsRecordsRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BatchDnsRecordsRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
public BatchDnsRecordsRequest(string zoneId)
|
||||||
|
{
|
||||||
|
ZoneId = zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The zone identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string ZoneId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The DNS records to delete.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyCollection<string>? Deletes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The DNS records to update.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyCollection<Patch>? Updates { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The DNS records to create.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyCollection<Post>? Creates { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The DNS records to overwrite.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyCollection<Put>? Overwrites { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to update a DNS record.
|
||||||
|
/// </summary>
|
||||||
|
public class Patch : Post
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Patch"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The DNS record identifier.</param>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public Patch(string id, string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The DNS record identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string Id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to create a DNS record.
|
||||||
|
/// </summary>
|
||||||
|
public class Post
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Post"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public Post(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DNS record name (or @ for the zone apex) in Punycode.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time To Live (TTL) of the DNS record in seconds.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Setting to <c>1</c> means 'automatic'. Value must be between <c>60</c> and <c>86400</c>, with the
|
||||||
|
/// minimum reduced to <c>30</c> for Enterprise zones.
|
||||||
|
/// </remarks>
|
||||||
|
public int? TimeToLive { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DNS record type.
|
||||||
|
/// </summary>
|
||||||
|
public DnsRecordType Type { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Comments or notes about the DNS record.
|
||||||
|
/// This field has no effect on DNS responses.
|
||||||
|
/// </summary>
|
||||||
|
public string? Comment { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The content of the DNS record.
|
||||||
|
/// </summary>
|
||||||
|
public string? Content { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a record.
|
||||||
|
/// </summary>
|
||||||
|
public object? Data { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required for MX, SRV and URI records; unused by other record types.
|
||||||
|
/// Records with lower priorities are preferred.
|
||||||
|
/// </summary>
|
||||||
|
public int? Priority { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the record is receiving the performance and security benefits of
|
||||||
|
/// Cloudflare.
|
||||||
|
/// </summary>
|
||||||
|
public bool? Proxied { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Settings for the DNS record.
|
||||||
|
/// </summary>
|
||||||
|
public DnsRecordSettings? Settings { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Custom tags for the DNS record.
|
||||||
|
/// This field has no effect on DNS responses.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyCollection<string>? Tags { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to overwrite a DNS record.
|
||||||
|
/// </summary>
|
||||||
|
public class Put : Post
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Put"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The DNS record identifier.</param>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public Put(string id, string name)
|
||||||
|
: base(name)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The DNS record identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string Id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to create a DNS record.
|
||||||
|
/// </summary>
|
||||||
|
public class CreateDnsRecordRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CreateDnsRecordRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public CreateDnsRecordRequest(string zoneId, string name)
|
||||||
|
{
|
||||||
|
ZoneId = zoneId;
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The zone identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string ZoneId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DNS record name (or @ for the zone apex) in Punycode.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time To Live (TTL) of the DNS record in seconds.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Setting to <c>1</c> means 'automatic'. Value must be between <c>60</c> and <c>86400</c>, with the
|
||||||
|
/// minimum reduced to <c>30</c> for Enterprise zones.
|
||||||
|
/// </remarks>
|
||||||
|
public int? TimeToLive { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DNS record type.
|
||||||
|
/// </summary>
|
||||||
|
public DnsRecordType Type { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Comments or notes about the DNS record.
|
||||||
|
/// This field has no effect on DNS responses.
|
||||||
|
/// </summary>
|
||||||
|
public string? Comment { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The content of the DNS record.
|
||||||
|
/// </summary>
|
||||||
|
public string? Content { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Components of a record.
|
||||||
|
/// </summary>
|
||||||
|
public object? Data { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required for MX, SRV and URI records; unused by other record types.
|
||||||
|
/// Records with lower priorities are preferred.
|
||||||
|
/// </summary>
|
||||||
|
public int? Priority { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the record is receiving the performance and security benefits of
|
||||||
|
/// Cloudflare.
|
||||||
|
/// </summary>
|
||||||
|
public bool? Proxied { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Settings for the DNS record.
|
||||||
|
/// </summary>
|
||||||
|
public DnsRecordSettings? Settings { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Custom tags for the DNS record.
|
||||||
|
/// This field has no effect on DNS responses.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyCollection<string>? Tags { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to delete a DNS record.
|
||||||
|
/// </summary>
|
||||||
|
public class DeleteDnsRecordRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DeleteDnsRecordRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="recordId">The DNS record identifier.</param>
|
||||||
|
public DeleteDnsRecordRequest(string zoneId, string recordId)
|
||||||
|
{
|
||||||
|
ZoneId = zoneId;
|
||||||
|
RecordId = recordId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The zone identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string ZoneId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The DNS record identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string RecordId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to import DNS records.
|
||||||
|
/// </summary>
|
||||||
|
public class ImportDnsRecordsRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ImportDnsRecordsRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
public ImportDnsRecordsRequest(string zoneId)
|
||||||
|
{
|
||||||
|
ZoneId = zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The zone identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string ZoneId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// BIND config to import.
|
||||||
|
/// </summary>
|
||||||
|
public string? File { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not proxiable records should receive the performance and
|
||||||
|
/// security benefits of Cloudflare.
|
||||||
|
/// </summary>
|
||||||
|
public bool? Proxied { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to overwrite a DNS record.
|
||||||
|
/// </summary>
|
||||||
|
public class OverwriteDnsRecordRequest : CreateDnsRecordRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="OverwriteDnsRecordRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="recordId">The DNS record identifier.</param>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public OverwriteDnsRecordRequest(string zoneId, string recordId, string name)
|
||||||
|
: base(zoneId, name)
|
||||||
|
{
|
||||||
|
RecordId = recordId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The DNS record identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string RecordId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to update a DNS record.
|
||||||
|
/// </summary>
|
||||||
|
public class UpdateDnsRecordRequest : CreateDnsRecordRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UpdateDnsRecordRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="recordId">The DNS record identifier.</param>
|
||||||
|
/// <param name="name">DNS record name (or @ for the zone apex) in Punycode.</param>
|
||||||
|
public UpdateDnsRecordRequest(string zoneId, string recordId, string name)
|
||||||
|
: base(zoneId, name)
|
||||||
|
{
|
||||||
|
RecordId = recordId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The DNS record identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string RecordId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The response for a batch update request.
|
||||||
|
/// </summary>
|
||||||
|
public class BatchDnsRecordsResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The records that were deleted (DELETE).
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("deletes")]
|
||||||
|
public IReadOnlyCollection<DnsRecord>? Deletes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The records that were updated (PATCH).
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("patches")]
|
||||||
|
public IReadOnlyCollection<DnsRecord>? Updates { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The records that were created (POST).
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("posts")]
|
||||||
|
public IReadOnlyCollection<DnsRecord>? Creates { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The records that were overwritten (PUT).
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("puts")]
|
||||||
|
public IReadOnlyCollection<DnsRecord>? Overwrites { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The response for a DNS record import.
|
||||||
|
/// </summary>
|
||||||
|
public class RecordImportResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Number of DNS records added.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("recs_added")]
|
||||||
|
public int? RecordsAdded { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total number of DNS records parsed.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("total_records_parsed")]
|
||||||
|
public int? TotalRecordsParsed { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The response for a DNS record scan.
|
||||||
|
/// </summary>
|
||||||
|
public class RecordScanResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Number of DNS records added.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("recs_added")]
|
||||||
|
public int? RecordsAdded { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total number of DNS records parsed.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("total_records_parsed")]
|
||||||
|
public int? TotalRecordsParsed { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,12 +20,12 @@ This package contains the feature set of the _Domain/Zone Management_ section of
|
|||||||
- [List Zones](https://developers.cloudflare.com/api/resources/zones/methods/list/)
|
- [List Zones](https://developers.cloudflare.com/api/resources/zones/methods/list/)
|
||||||
|
|
||||||
|
|
||||||
##### [Activation Check]
|
#### [Activation Check]
|
||||||
|
|
||||||
- [Rerun The Activation Check](https://developers.cloudflare.com/api/resources/zones/subresources/activation_check/methods/trigger/)
|
- [Rerun The Activation Check](https://developers.cloudflare.com/api/resources/zones/subresources/activation_check/methods/trigger/)
|
||||||
|
|
||||||
|
|
||||||
##### [Holds]
|
#### [Holds]
|
||||||
|
|
||||||
- [Create Zone Hold](https://developers.cloudflare.com/api/resources/zones/subresources/holds/methods/create/)
|
- [Create Zone Hold](https://developers.cloudflare.com/api/resources/zones/subresources/holds/methods/create/)
|
||||||
- [Remove Zone Hold](https://developers.cloudflare.com/api/resources/zones/subresources/holds/methods/delete/)
|
- [Remove Zone Hold](https://developers.cloudflare.com/api/resources/zones/subresources/holds/methods/delete/)
|
||||||
@@ -33,18 +33,18 @@ This package contains the feature set of the _Domain/Zone Management_ section of
|
|||||||
- [Get Zone Hold](https://developers.cloudflare.com/api/resources/zones/subresources/holds/methods/get/)
|
- [Get Zone Hold](https://developers.cloudflare.com/api/resources/zones/subresources/holds/methods/get/)
|
||||||
|
|
||||||
|
|
||||||
##### [Plans]
|
#### [Plans]
|
||||||
|
|
||||||
- [Available Plan Details](https://developers.cloudflare.com/api/resources/zones/subresources/plans/methods/get/)
|
- [Available Plan Details](https://developers.cloudflare.com/api/resources/zones/subresources/plans/methods/get/)
|
||||||
- [List Available Plans](https://developers.cloudflare.com/api/resources/zones/subresources/plans/methods/list/)
|
- [List Available Plans](https://developers.cloudflare.com/api/resources/zones/subresources/plans/methods/list/)
|
||||||
|
|
||||||
|
|
||||||
##### [Rate Plans]
|
#### [Rate Plans]
|
||||||
|
|
||||||
- [List Available Rate Plans](https://developers.cloudflare.com/api/resources/zones/subresources/rate_plans/methods/get/)
|
- [List Available Rate Plans](https://developers.cloudflare.com/api/resources/zones/subresources/rate_plans/methods/get/)
|
||||||
|
|
||||||
|
|
||||||
##### [Settings]
|
#### [Settings]
|
||||||
|
|
||||||
- **DEPRECATED** [Edit Multiple Zone Settings](https://developers.cloudflare.com/api/resources/zones/subresources/settings/methods/bulk_edit/)
|
- **DEPRECATED** [Edit Multiple Zone Settings](https://developers.cloudflare.com/api/resources/zones/subresources/settings/methods/bulk_edit/)
|
||||||
- [Edit Zone Setting](https://developers.cloudflare.com/api/resources/zones/subresources/settings/methods/edit/)
|
- [Edit Zone Setting](https://developers.cloudflare.com/api/resources/zones/subresources/settings/methods/edit/)
|
||||||
@@ -52,7 +52,7 @@ This package contains the feature set of the _Domain/Zone Management_ section of
|
|||||||
- **DEPRECATED** [Get All Zone Settings](https://developers.cloudflare.com/api/resources/zones/subresources/settings/methods/list/)
|
- **DEPRECATED** [Get All Zone Settings](https://developers.cloudflare.com/api/resources/zones/subresources/settings/methods/list/)
|
||||||
|
|
||||||
|
|
||||||
##### [Subscriptions]
|
#### [Subscriptions]
|
||||||
|
|
||||||
- [Create Zone Subscription](https://developers.cloudflare.com/api/resources/zones/subresources/subscriptions/methods/create/)
|
- [Create Zone Subscription](https://developers.cloudflare.com/api/resources/zones/subresources/subscriptions/methods/create/)
|
||||||
- [Zone Subscription Details](https://developers.cloudflare.com/api/resources/zones/subresources/subscriptions/methods/get/)
|
- [Zone Subscription Details](https://developers.cloudflare.com/api/resources/zones/subresources/subscriptions/methods/get/)
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns.Internals;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsRecordsExtensions
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class BatchDnsRecordsTest
|
||||||
|
{
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string RecordId = "023e105f4ecef8ad9ca31a8372d0c355";
|
||||||
|
|
||||||
|
private const string DomainName = "example.com";
|
||||||
|
private const string IpContent = "96.7.128.175";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
|
||||||
|
private List<(string RequestPath, InternalBatchRequest Request, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
private CloudflareResponse<BatchDnsRecordsResponse> _response;
|
||||||
|
private BatchDnsRecordsRequest _request;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<BatchDnsRecordsResponse>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors = [
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
Result = new BatchDnsRecordsResponse()
|
||||||
|
};
|
||||||
|
|
||||||
|
_request = new BatchDnsRecordsRequest(ZoneId)
|
||||||
|
{
|
||||||
|
Deletes = [RecordId],
|
||||||
|
Updates = [new BatchDnsRecordsRequest.Patch(RecordId, DomainName) { Type = DnsRecordType.A, Content = IpContent }],
|
||||||
|
Overwrites = [new BatchDnsRecordsRequest.Put(RecordId, DomainName) { Type = DnsRecordType.A, Content = IpContent }],
|
||||||
|
Creates = [new BatchDnsRecordsRequest.Post(DomainName) { Type = DnsRecordType.A, Content = IpContent }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldExecuteBatchDnsRecords()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.BatchDnsRecords(_request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, _callbacks.Count);
|
||||||
|
|
||||||
|
var callback = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/dns_records/batch", callback.RequestPath);
|
||||||
|
Assert.IsNull(callback.QueryFilter);
|
||||||
|
Assert.IsNotNull(callback.Request);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, callback.Request.Deletes.Count);
|
||||||
|
Assert.AreEqual(RecordId, callback.Request.Deletes.First().Id);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, callback.Request.Patches.Count);
|
||||||
|
var patch = callback.Request.Patches.First();
|
||||||
|
Assert.AreEqual(RecordId, patch.Id);
|
||||||
|
Assert.AreEqual(DomainName, patch.Name);
|
||||||
|
Assert.AreEqual(DnsRecordType.A, patch.Type);
|
||||||
|
Assert.AreEqual(IpContent, patch.Content);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, callback.Request.Puts.Count);
|
||||||
|
var put = callback.Request.Puts.First();
|
||||||
|
Assert.AreEqual(RecordId, put.Id);
|
||||||
|
Assert.AreEqual(DomainName, put.Name);
|
||||||
|
Assert.AreEqual(DnsRecordType.A, put.Type);
|
||||||
|
Assert.AreEqual(IpContent, put.Content);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, callback.Request.Posts.Count);
|
||||||
|
var post = callback.Request.Posts.First();
|
||||||
|
Assert.AreEqual(DomainName, post.Name);
|
||||||
|
Assert.AreEqual(DnsRecordType.A, post.Type);
|
||||||
|
Assert.AreEqual(IpContent, post.Content);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<BatchDnsRecordsResponse, InternalBatchRequest>($"/zones/{ZoneId}/dns_records/batch", It.IsAny<InternalBatchRequest>(), null, It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PostAsync<BatchDnsRecordsResponse, InternalBatchRequest>(It.IsAny<string>(), It.IsAny<InternalBatchRequest>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, InternalBatchRequest, IQueryParameterFilter, CancellationToken>((requestPath, request, queryFilter, _) => _callbacks.Add((requestPath, request, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,76 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsRecordsExtensions
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class DeleteDnsRecordTest
|
||||||
|
{
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string RecordId = "023e105f4ecef8ad9ca31a8372d0c355";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<Identifier> _response;
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<Identifier>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors = [
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
Result = new Identifier
|
||||||
|
{
|
||||||
|
Id = RecordId,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldDeleteDnsRecord()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.DeleteDnsRecord(ZoneId, RecordId);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, _callbacks.Count);
|
||||||
|
|
||||||
|
var callback = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/dns_records/{RecordId}", callback.RequestPath);
|
||||||
|
Assert.IsNull(callback.QueryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.DeleteAsync<Identifier>($"/zones/{ZoneId}/dns_records/{RecordId}", null, It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.DeleteAsync<Identifier>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsRecordsExtensions
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class DnsRecordDetailsTest
|
||||||
|
{
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string RecordId = "023e105f4ecef8ad9ca31a8372d0c355";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<DnsRecord> _response;
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<DnsRecord>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors = [
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
Result = new ARecord("example.com")
|
||||||
|
{
|
||||||
|
Id = RecordId,
|
||||||
|
Content = "96.7.128.175",
|
||||||
|
Proxiable = true,
|
||||||
|
Proxied = true,
|
||||||
|
TimeToLive = 1,
|
||||||
|
Settings = new(),
|
||||||
|
Comment = "Domain verification record",
|
||||||
|
Tags = [],
|
||||||
|
CreatedOn = DateTime.Parse("2014-01-01T05:20:00.12345Z"),
|
||||||
|
ModifiedOn = DateTime.Parse("2014-01-01T05:20:00.12345Z"),
|
||||||
|
CommentModifiedOn = DateTime.Parse("2024-01-01T05:20:00.12345Z"),
|
||||||
|
TagsModifiedOn = DateTime.Parse("2025-01-01T05:20:00.12345Z"),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldDeleteDnsRecord()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.DnsRecordDetails(ZoneId, RecordId);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, _callbacks.Count);
|
||||||
|
|
||||||
|
var callback = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/dns_records/{RecordId}", callback.RequestPath);
|
||||||
|
Assert.IsNull(callback.QueryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.GetAsync<DnsRecord>($"/zones/{ZoneId}/dns_records/{RecordId}", null, It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.GetAsync<DnsRecord>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsRecordsExtensions
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ExportDnsRecordsTest
|
||||||
|
{
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<string> _response;
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<string>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Result = "This is my BIND export file."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldExportZoneDnsRecords()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.ExportDnsRecords(ZoneId);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, _callbacks.Count);
|
||||||
|
|
||||||
|
var callback = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/dns_records/export", callback.RequestPath);
|
||||||
|
Assert.IsNull(callback.QueryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.GetAsync<string>($"/zones/{ZoneId}/dns_records/export", null, It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.GetAsync<string>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsRecordsExtensions
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ImportDnsRecordsTest
|
||||||
|
{
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string BindConfigContent = "www.example.com. 300 IN A 127.0.0.1";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
|
||||||
|
private List<(string RequestPath, MultipartFormDataContent Request, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
private CloudflareResponse<RecordImportResponse> _response;
|
||||||
|
private ImportDnsRecordsRequest _request;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<RecordImportResponse>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors = [
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
Result = new RecordImportResponse
|
||||||
|
{
|
||||||
|
RecordsAdded = 5,
|
||||||
|
TotalRecordsParsed = 6,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_request = new ImportDnsRecordsRequest(ZoneId)
|
||||||
|
{
|
||||||
|
File = BindConfigContent
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldImportDnsRecordsFromString()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.ImportDnsRecords(_request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, _callbacks.Count);
|
||||||
|
|
||||||
|
var callback = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/dns_records/import", callback.RequestPath);
|
||||||
|
Assert.IsNotNull(callback.Request);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, callback.Request.Count());
|
||||||
|
|
||||||
|
var part = callback.Request.First();
|
||||||
|
Assert.AreEqual("file", part.Headers.ContentDisposition.Name);
|
||||||
|
Assert.IsInstanceOfType<ByteArrayContent>(part);
|
||||||
|
Assert.AreEqual(BindConfigContent, await part.ReadAsStringAsync());
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<RecordImportResponse, MultipartFormDataContent>($"/zones/{ZoneId}/dns_records/import", It.IsAny<MultipartFormDataContent>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldImportDnsRecordsFromFile()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
string file = Path.GetTempFileName();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.WriteAllText(file, BindConfigContent);
|
||||||
|
_request.File = file;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.ImportDnsRecords(_request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, _callbacks.Count);
|
||||||
|
|
||||||
|
var callback = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/dns_records/import", callback.RequestPath);
|
||||||
|
Assert.IsNotNull(callback.Request);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, callback.Request.Count());
|
||||||
|
|
||||||
|
var part = callback.Request.First();
|
||||||
|
Assert.AreEqual("file", part.Headers.ContentDisposition.Name);
|
||||||
|
Assert.IsInstanceOfType<ByteArrayContent>(part);
|
||||||
|
Assert.AreEqual(BindConfigContent, await part.ReadAsStringAsync());
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<RecordImportResponse, MultipartFormDataContent>($"/zones/{ZoneId}/dns_records/import", It.IsAny<MultipartFormDataContent>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
File.Delete(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(true)]
|
||||||
|
[DataRow(false)]
|
||||||
|
public async Task ShouldImportDnsRecordsFromStringWithProxied(bool proxied)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Proxied = proxied;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.ImportDnsRecords(_request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, _callbacks.Count);
|
||||||
|
|
||||||
|
var callback = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/dns_records/import", callback.RequestPath);
|
||||||
|
Assert.IsNotNull(callback.Request);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, callback.Request.Count());
|
||||||
|
|
||||||
|
var part = callback.Request.First();
|
||||||
|
Assert.AreEqual("proxied", part.Headers.ContentDisposition.Name);
|
||||||
|
Assert.IsInstanceOfType<StringContent>(part);
|
||||||
|
Assert.AreEqual(proxied.ToString().ToLower(), await part.ReadAsStringAsync());
|
||||||
|
|
||||||
|
part = callback.Request.Last();
|
||||||
|
Assert.AreEqual("file", part.Headers.ContentDisposition.Name);
|
||||||
|
Assert.IsInstanceOfType<ByteArrayContent>(part);
|
||||||
|
Assert.AreEqual(BindConfigContent, await part.ReadAsStringAsync());
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<RecordImportResponse, MultipartFormDataContent>($"/zones/{ZoneId}/dns_records/import", It.IsAny<MultipartFormDataContent>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(true)]
|
||||||
|
[DataRow(false)]
|
||||||
|
public async Task ShouldImportDnsRecordsFromFileWithProxied(bool proxied)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
string file = Path.GetTempFileName();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.WriteAllText(file, BindConfigContent);
|
||||||
|
_request.File = file;
|
||||||
|
_request.Proxied = proxied;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.ImportDnsRecords(_request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, _callbacks.Count);
|
||||||
|
|
||||||
|
var callback = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/dns_records/import", callback.RequestPath);
|
||||||
|
Assert.IsNotNull(callback.Request);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, callback.Request.Count());
|
||||||
|
|
||||||
|
var part = callback.Request.First();
|
||||||
|
Assert.AreEqual("proxied", part.Headers.ContentDisposition.Name);
|
||||||
|
Assert.IsInstanceOfType<StringContent>(part);
|
||||||
|
Assert.AreEqual(proxied.ToString().ToLower(), await part.ReadAsStringAsync());
|
||||||
|
|
||||||
|
part = callback.Request.Last();
|
||||||
|
Assert.AreEqual("file", part.Headers.ContentDisposition.Name);
|
||||||
|
Assert.IsInstanceOfType<ByteArrayContent>(part);
|
||||||
|
Assert.AreEqual(BindConfigContent, await part.ReadAsStringAsync());
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<RecordImportResponse, MultipartFormDataContent>($"/zones/{ZoneId}/dns_records/import", It.IsAny<MultipartFormDataContent>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
File.Delete(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
[ExpectedException(typeof(ArgumentNullException))]
|
||||||
|
public async Task ShouldThrowArgumentNullExceptionForFile(string file)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.File = file;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await client.ImportDnsRecords(_request);
|
||||||
|
|
||||||
|
// Assert - ArgumentNullException
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PostAsync<RecordImportResponse, MultipartFormDataContent>(It.IsAny<string>(), It.IsAny<MultipartFormDataContent>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, MultipartFormDataContent, IQueryParameterFilter, CancellationToken>((requestPath, request, queryFilter, _) => _callbacks.Add((requestPath, request, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,813 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsRecordsExtensions
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ListDnsRecordsTest
|
||||||
|
{
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
|
||||||
|
private CloudflareResponse<IReadOnlyCollection<DnsRecord>> _response;
|
||||||
|
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<IReadOnlyCollection<DnsRecord>>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors = [
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
ResultInfo = new PaginationInfo
|
||||||
|
{
|
||||||
|
Count = 1,
|
||||||
|
Page = 1,
|
||||||
|
PerPage = 20,
|
||||||
|
TotalCount = 2000,
|
||||||
|
TotalPages = 100,
|
||||||
|
},
|
||||||
|
Result = [
|
||||||
|
new ARecord("example.com")
|
||||||
|
{
|
||||||
|
Id = "023e105f4ecef8ad9ca31a8372d0c353",
|
||||||
|
Content = "96.7.128.175",
|
||||||
|
Proxiable = true,
|
||||||
|
Proxied = true,
|
||||||
|
TimeToLive = 1,
|
||||||
|
Settings = new(),
|
||||||
|
Comment = "Domain verification record",
|
||||||
|
Tags = [],
|
||||||
|
CreatedOn = DateTime.Parse("2014-01-01T05:20:00.12345Z"),
|
||||||
|
ModifiedOn = DateTime.Parse("2014-01-01T05:20:00.12345Z"),
|
||||||
|
CommentModifiedOn = DateTime.Parse("2024-01-01T05:20:00.12345Z"),
|
||||||
|
TagsModifiedOn = DateTime.Parse("2025-01-01T05:20:00.12345Z"),
|
||||||
|
},
|
||||||
|
new AAAARecord("example.com")
|
||||||
|
{
|
||||||
|
Id = "023e105f4ecef8ad9ca31a8372d0c355",
|
||||||
|
Content = "2600:1408:ec00:36::1736:7f31",
|
||||||
|
Proxiable = true,
|
||||||
|
Proxied = true,
|
||||||
|
TimeToLive = 1,
|
||||||
|
Settings = new(),
|
||||||
|
Comment = "Domain verification record",
|
||||||
|
Tags = [],
|
||||||
|
CreatedOn = DateTime.Parse("2014-01-01T05:20:00.12345Z"),
|
||||||
|
ModifiedOn = DateTime.Parse("2014-01-01T05:20:00.12345Z"),
|
||||||
|
CommentModifiedOn = DateTime.Parse("2024-01-01T05:20:00.12345Z"),
|
||||||
|
TagsModifiedOn = DateTime.Parse("2025-01-01T05:20:00.12345Z"),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldListDnsRecords()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.ListDnsRecords(ZoneId);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, _callbacks.Count);
|
||||||
|
|
||||||
|
var callback = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/dns_records", callback.RequestPath);
|
||||||
|
Assert.IsNull(callback.QueryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.GetAsync<IReadOnlyCollection<DnsRecord>>($"/zones/{ZoneId}/dns_records", null, It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldListDnsRecordsWithFilter()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter
|
||||||
|
{
|
||||||
|
Name = "example.com"
|
||||||
|
};
|
||||||
|
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.ListDnsRecords(ZoneId, filter);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, _callbacks.Count);
|
||||||
|
|
||||||
|
var callback = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/dns_records", callback.RequestPath);
|
||||||
|
Assert.IsNotNull(callback.QueryFilter);
|
||||||
|
|
||||||
|
Assert.IsInstanceOfType<ListDnsRecordsFilter>(callback.QueryFilter);
|
||||||
|
Assert.AreEqual("example.com", ((ListDnsRecordsFilter)callback.QueryFilter).Name);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.GetAsync<IReadOnlyCollection<DnsRecord>>($"/zones/{ZoneId}/dns_records", filter, It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ShouldReturnEmptyParameterList()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ShouldReturnFullParameterList()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter
|
||||||
|
{
|
||||||
|
Comment = "Hello World",
|
||||||
|
CommentAbsent = true,
|
||||||
|
CommentContains = "lo Wor",
|
||||||
|
CommentEndsWith = "ld",
|
||||||
|
CommentExact = "Hello World",
|
||||||
|
CommentPresent = true,
|
||||||
|
CommentStartsWith = "He",
|
||||||
|
|
||||||
|
Content = "127.0.0.1",
|
||||||
|
ContentContains = "7.0.0",
|
||||||
|
ContentEndsWith = "0.1",
|
||||||
|
ContentExact = "127.0.0.1",
|
||||||
|
ContentStartsWith = "127",
|
||||||
|
|
||||||
|
Direction = SortDirection.Descending,
|
||||||
|
Match = FilterMatchType.All,
|
||||||
|
|
||||||
|
Name = "example.com",
|
||||||
|
NameContains = "ample",
|
||||||
|
NameEndsWith = ".com",
|
||||||
|
NameExact = "example.com",
|
||||||
|
NameStartsWith = "ex",
|
||||||
|
|
||||||
|
OrderBy = DnsRecordsOrderBy.Name,
|
||||||
|
Page = 2,
|
||||||
|
PerPage = 5,
|
||||||
|
Proxied = true,
|
||||||
|
Search = "Some Search",
|
||||||
|
|
||||||
|
Tag = "team:DNS",
|
||||||
|
TagAbsent = "important",
|
||||||
|
TagContains = "greeting:ello",
|
||||||
|
TagEndsWith = "greeting:rld",
|
||||||
|
TagExact = "greeting:Hello World",
|
||||||
|
TagPresent = "important",
|
||||||
|
TagStartsWith = "greeting:Hel",
|
||||||
|
|
||||||
|
TagMatch = FilterMatchType.Any,
|
||||||
|
Type = DnsRecordType.A,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(33, dict.Count);
|
||||||
|
|
||||||
|
Assert.IsTrue(dict.ContainsKey("comment"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("comment.absent"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("comment.contains"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("comment.endswith"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("comment.exact"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("comment.present"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("comment.startswith"));
|
||||||
|
|
||||||
|
Assert.IsTrue(dict.ContainsKey("content"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("content.contains"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("content.endswith"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("content.exact"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("content.startswith"));
|
||||||
|
|
||||||
|
Assert.IsTrue(dict.ContainsKey("direction"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("match"));
|
||||||
|
|
||||||
|
Assert.IsTrue(dict.ContainsKey("name"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("name.contains"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("name.endswith"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("name.exact"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("name.startswith"));
|
||||||
|
|
||||||
|
Assert.IsTrue(dict.ContainsKey("order"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("page"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("per_page"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("proxied"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("search"));
|
||||||
|
|
||||||
|
Assert.IsTrue(dict.ContainsKey("tag"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("tag.absent"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("tag.contains"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("tag.endswith"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("tag.exact"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("tag.present"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("tag.startswith"));
|
||||||
|
|
||||||
|
Assert.IsTrue(dict.ContainsKey("tag_match"));
|
||||||
|
Assert.IsTrue(dict.ContainsKey("type"));
|
||||||
|
|
||||||
|
Assert.AreEqual("Hello World", dict["comment"]);
|
||||||
|
Assert.AreEqual("true", dict["comment.absent"]);
|
||||||
|
Assert.AreEqual("lo Wor", dict["comment.contains"]);
|
||||||
|
Assert.AreEqual("ld", dict["comment.endswith"]);
|
||||||
|
Assert.AreEqual("Hello World", dict["comment.exact"]);
|
||||||
|
Assert.AreEqual("true", dict["comment.present"]);
|
||||||
|
Assert.AreEqual("He", dict["comment.startswith"]);
|
||||||
|
|
||||||
|
Assert.AreEqual("127.0.0.1", dict["content"]);
|
||||||
|
Assert.AreEqual("7.0.0", dict["content.contains"]);
|
||||||
|
Assert.AreEqual("0.1", dict["content.endswith"]);
|
||||||
|
Assert.AreEqual("127.0.0.1", dict["content.exact"]);
|
||||||
|
Assert.AreEqual("127", dict["content.startswith"]);
|
||||||
|
|
||||||
|
Assert.AreEqual("desc", dict["direction"]);
|
||||||
|
Assert.AreEqual("all", dict["match"]);
|
||||||
|
|
||||||
|
Assert.AreEqual("example.com", dict["name"]);
|
||||||
|
Assert.AreEqual("ample", dict["name.contains"]);
|
||||||
|
Assert.AreEqual(".com", dict["name.endswith"]);
|
||||||
|
Assert.AreEqual("example.com", dict["name.exact"]);
|
||||||
|
Assert.AreEqual("ex", dict["name.startswith"]);
|
||||||
|
|
||||||
|
Assert.AreEqual("name", dict["order"]);
|
||||||
|
Assert.AreEqual("2", dict["page"]);
|
||||||
|
Assert.AreEqual("5", dict["per_page"]);
|
||||||
|
Assert.AreEqual("true", dict["proxied"]);
|
||||||
|
Assert.AreEqual("Some Search", dict["search"]);
|
||||||
|
|
||||||
|
Assert.AreEqual("team:DNS", dict["tag"]);
|
||||||
|
Assert.AreEqual("important", dict["tag.absent"]);
|
||||||
|
Assert.AreEqual("greeting:ello", dict["tag.contains"]);
|
||||||
|
Assert.AreEqual("greeting:rld", dict["tag.endswith"]);
|
||||||
|
Assert.AreEqual("greeting:Hello World", dict["tag.exact"]);
|
||||||
|
Assert.AreEqual("important", dict["tag.present"]);
|
||||||
|
Assert.AreEqual("greeting:Hel", dict["tag.startswith"]);
|
||||||
|
|
||||||
|
Assert.AreEqual("any", dict["tag_match"]);
|
||||||
|
Assert.AreEqual("A", dict["type"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddComment(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { Comment = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow(false)]
|
||||||
|
public void ShouldNotAddCommentAbsent(bool? b)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { CommentAbsent = b };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddCommentContains(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { CommentContains = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddCommentEndsWith(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { CommentEndsWith = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddCommentExact(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { CommentExact = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow(false)]
|
||||||
|
public void ShouldNotAddCommentPresent(bool? b)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { CommentPresent = b };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddCommentStartsWith(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { CommentStartsWith = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddContent(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { Content = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddContentContains(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { ContentContains = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddContentEndsWith(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { ContentEndsWith = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddContentExact(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { ContentExact = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddContentStartsWith(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { ContentStartsWith = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow((SortDirection)0)]
|
||||||
|
public void ShouldNotAddDirection(SortDirection? direction)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { Direction = direction };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow((FilterMatchType)0)]
|
||||||
|
public void ShouldNotAddMatch(FilterMatchType? match)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { Match = match };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddName(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { Name = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddNameContains(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { NameContains = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddNameEndsWith(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { NameEndsWith = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddNameExact(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { NameExact = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddNameStartsWith(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { NameStartsWith = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow((DnsRecordsOrderBy)0)]
|
||||||
|
public void ShouldNotAddOrder(DnsRecordsOrderBy? order)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { OrderBy = order };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow(0)]
|
||||||
|
public void ShouldNotAddPage(int? page)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { Page = page };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow(0)]
|
||||||
|
[DataRow(5_000_001)]
|
||||||
|
public void ShouldNotAddPerPage(int? perPage)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { PerPage = perPage };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddTag(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { Tag = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddTagAbsent(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { TagAbsent = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddTagContains(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { TagContains = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddTagEndsWith(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { TagEndsWith = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddTagExact(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { TagExact = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddTagPresent(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { TagPresent = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldNotAddTagStartsWith(string str)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { TagStartsWith = str };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow((FilterMatchType)0)]
|
||||||
|
public void ShouldNotAddTagMatch(FilterMatchType? tagMatch)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { TagMatch = tagMatch };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow((DnsRecordType)0)]
|
||||||
|
public void ShouldNotAddType(DnsRecordType? type)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter = new ListDnsRecordsFilter { Type = type };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var dict = filter.GetQueryParameters();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.GetAsync<IReadOnlyCollection<DnsRecord>>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns.Internals;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsRecordsExtensions
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class OverwriteDnsRecordTest
|
||||||
|
{
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string RecordId = "023e105f4ecef8ad9ca31a8372d0c355";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<DnsRecord> _response;
|
||||||
|
private List<(string RequestPath, InternalDnsRecordRequest Request)> _callbacks;
|
||||||
|
private OverwriteDnsRecordRequest _request;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<DnsRecord>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors = [
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
Result = new ARecord("*.example.com")
|
||||||
|
{
|
||||||
|
Id = RecordId,
|
||||||
|
Content = "96.7.128.175",
|
||||||
|
Proxiable = true,
|
||||||
|
Proxied = true,
|
||||||
|
TimeToLive = 1,
|
||||||
|
Settings = new(),
|
||||||
|
Comment = "Domain verification record",
|
||||||
|
Tags = [],
|
||||||
|
CreatedOn = DateTime.Parse("2014-01-01T05:20:00.12345Z"),
|
||||||
|
ModifiedOn = DateTime.Parse("2014-01-01T05:20:00.12345Z"),
|
||||||
|
CommentModifiedOn = DateTime.Parse("2024-01-01T05:20:00.12345Z"),
|
||||||
|
TagsModifiedOn = DateTime.Parse("2025-01-01T05:20:00.12345Z"),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_request = new OverwriteDnsRecordRequest(ZoneId, RecordId, "example.com")
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.A,
|
||||||
|
Content = "127.0.1.22"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldOverwriteDnsRecord()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.OverwriteDnsRecord(_request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, _callbacks.Count);
|
||||||
|
|
||||||
|
var callback = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/dns_records/{RecordId}", callback.RequestPath);
|
||||||
|
Assert.IsNotNull(callback.Request);
|
||||||
|
|
||||||
|
Assert.AreEqual("example.com", callback.Request.Name);
|
||||||
|
Assert.AreEqual(DnsRecordType.A, callback.Request.Type);
|
||||||
|
Assert.AreEqual("127.0.1.22", callback.Request.Content);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PutAsync<DnsRecord, InternalDnsRecordRequest>($"/zones/{ZoneId}/dns_records/{RecordId}", It.IsAny<InternalDnsRecordRequest>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PutAsync<DnsRecord, InternalDnsRecordRequest>(It.IsAny<string>(), It.IsAny<InternalDnsRecordRequest>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, InternalDnsRecordRequest, CancellationToken>((requestPath, request, _) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsRecordsExtensions
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ScanDnsRecordsTest
|
||||||
|
{
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<RecordScanResponse> _response;
|
||||||
|
private List<string> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<RecordScanResponse>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors = [
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
Result = new RecordScanResponse
|
||||||
|
{
|
||||||
|
RecordsAdded = 5,
|
||||||
|
TotalRecordsParsed = 6,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldScanDnsRecords()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.ScanDnsRecords(ZoneId);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, _callbacks.Count);
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/dns_records/scan", _callbacks.First());
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<RecordScanResponse, object>($"/zones/{ZoneId}/dns_records/scan", null, null, It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PostAsync<RecordScanResponse, object>(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, object, IQueryParameterFilter, CancellationToken>((requestPath, _, _, _) => _callbacks.Add(requestPath))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns.Internals;
|
||||||
|
using Moq;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsRecordsExtensions
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class UpdateDnsRecordTest
|
||||||
|
{
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string RecordId = "023e105f4ecef8ad9ca31a8372d0c355";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<DnsRecord> _response;
|
||||||
|
private List<(string RequestPath, InternalDnsRecordRequest Request)> _callbacks;
|
||||||
|
private UpdateDnsRecordRequest _request;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<DnsRecord>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors = [
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
Result = new ARecord("example.com")
|
||||||
|
{
|
||||||
|
Id = RecordId,
|
||||||
|
Name = "*.example.com",
|
||||||
|
Content = "96.7.128.175",
|
||||||
|
Proxiable = true,
|
||||||
|
Proxied = true,
|
||||||
|
TimeToLive = 1,
|
||||||
|
Settings = new(),
|
||||||
|
Meta = new JObject(),
|
||||||
|
Comment = "Domain verification record",
|
||||||
|
Tags = [],
|
||||||
|
CreatedOn = DateTime.Parse("2014-01-01T05:20:00.12345Z"),
|
||||||
|
ModifiedOn = DateTime.Parse("2014-01-01T05:20:00.12345Z"),
|
||||||
|
CommentModifiedOn = DateTime.Parse("2024-01-01T05:20:00.12345Z"),
|
||||||
|
TagsModifiedOn = DateTime.Parse("2025-01-01T05:20:00.12345Z"),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_request = new UpdateDnsRecordRequest(ZoneId, RecordId, "example.com")
|
||||||
|
{
|
||||||
|
Type = DnsRecordType.A,
|
||||||
|
Content = "127.0.1.22"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldUpdateDnsRecord()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.UpdateDnsRecord(_request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, _callbacks.Count);
|
||||||
|
|
||||||
|
var callback = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/dns_records/{RecordId}", callback.RequestPath);
|
||||||
|
Assert.IsNotNull(callback.Request);
|
||||||
|
|
||||||
|
Assert.AreEqual("example.com", callback.Request.Name);
|
||||||
|
Assert.AreEqual(DnsRecordType.A, callback.Request.Type);
|
||||||
|
Assert.AreEqual("127.0.1.22", callback.Request.Content);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PatchAsync<DnsRecord, InternalDnsRecordRequest>($"/zones/{ZoneId}/dns_records/{RecordId}", It.IsAny<InternalDnsRecordRequest>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PatchAsync<DnsRecord, InternalDnsRecordRequest>(It.IsAny<string>(), It.IsAny<InternalDnsRecordRequest>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, InternalDnsRecordRequest, CancellationToken>((requestPath, request, _) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user