diff --git a/src/Enclave.Sdk/Clients/AuthorityClient.cs b/src/Enclave.Sdk/Clients/AuthorityClient.cs
deleted file mode 100644
index c413012..0000000
--- a/src/Enclave.Sdk/Clients/AuthorityClient.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Enclave.Sdk.Api.Clients.Interfaces;
-
-namespace Enclave.Sdk.Api.Clients;
-
-public class AuthorityClient : ClientBase, IAuthorityClient
-{
- private string _orgRoute;
-
- public AuthorityClient(HttpClient httpClient, string orgRoute)
- : base(httpClient)
- {
- _orgRoute = orgRoute;
- }
-}
diff --git a/src/Enclave.Sdk/Clients/ClientBase.cs b/src/Enclave.Sdk/Clients/ClientBase.cs
index 3afbd75..3fafe03 100644
--- a/src/Enclave.Sdk/Clients/ClientBase.cs
+++ b/src/Enclave.Sdk/Clients/ClientBase.cs
@@ -1,5 +1,4 @@
using System.Diagnostics.CodeAnalysis;
-using System.Net;
using System.Net.Http.Json;
using System.Net.Mime;
using System.Text;
@@ -10,7 +9,7 @@ namespace Enclave.Sdk.Api.Clients;
///
/// Base class used for commonly accessed methods and properties for all clients.
///
-public abstract class ClientBase
+internal abstract class ClientBase
{
///
/// HttpClient used for all clients API calls.
@@ -33,7 +32,7 @@ protected ClientBase(HttpClient httpClient)
/// the object to encode.
/// String content of object.
/// throws if data provided is null.
- protected StringContent CreateJsonContent(TModel data)
+ protected static StringContent CreateJsonContent(TModel data)
{
if (data is null)
{
@@ -52,7 +51,7 @@ protected StringContent CreateJsonContent(TModel data)
/// the object type to deserialise to.
/// httpContent from the API call.
/// the object of type specified.
- protected async Task DeserialiseAsync(HttpContent httpContent)
+ protected static async Task DeserialiseAsync(HttpContent httpContent)
{
if (httpContent is null)
{
diff --git a/src/Enclave.Sdk/Clients/DNSClient.cs b/src/Enclave.Sdk/Clients/DNSClient.cs
index 73c8e42..2c0508d 100644
--- a/src/Enclave.Sdk/Clients/DNSClient.cs
+++ b/src/Enclave.Sdk/Clients/DNSClient.cs
@@ -1,14 +1,249 @@
+using System.Net.Http.Json;
+using System.Web;
using Enclave.Sdk.Api.Clients.Interfaces;
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.Dns;
+using Enclave.Sdk.Api.Data.Pagination;
+using Enclave.Sdk.Api.Data.PatchModel;
namespace Enclave.Sdk.Api.Clients;
-public class DnsClient : ClientBase, IDnsClient
+///
+internal class DnsClient : ClientBase, IDnsClient
{
- private string _orgRoute;
+ private readonly string _orgRoute;
+ ///
+ /// Constructor which will be called by when it's created.
+ ///
+ /// an instance of httpClient with a baseURL referencing the API.
+ /// The organisation API route.
public DnsClient(HttpClient httpClient, string orgRoute)
: base(httpClient)
{
_orgRoute = orgRoute;
}
+
+ ///
+ public async Task GetPropertiesSummaryAsync()
+ {
+ var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/dns", Constants.JsonSerializerOptions);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task> GetZonesAsync(int? pageNumber = null, int? perPage = null)
+ {
+ var queryString = BuildQueryString(null, null, pageNumber, perPage);
+
+ var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/dns/zones?{queryString}");
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task CreateZoneAsync(DnsZoneCreate createModel)
+ {
+ if (createModel is null)
+ {
+ throw new ArgumentNullException(nameof(createModel));
+ }
+
+ var result = await HttpClient.PostAsJsonAsync($"{_orgRoute}/dns/zones", createModel, Constants.JsonSerializerOptions);
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task GetZoneAsync(DnsZoneId dnsZoneId)
+ {
+ var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/dns/zones/{dnsZoneId}", Constants.JsonSerializerOptions);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task UpdateZoneAsync(DnsZoneId dnsZoneId, PatchBuilder builder)
+ {
+ if (builder is null)
+ {
+ throw new ArgumentNullException(nameof(builder));
+ }
+
+ using var encoded = CreateJsonContent(builder.Send());
+ var result = await HttpClient.PatchAsync($"{_orgRoute}/dns/zones/{dnsZoneId}", encoded);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task DeleteZoneAsync(DnsZoneId dnsZoneId)
+ {
+ var result = await HttpClient.DeleteAsync($"{_orgRoute}/dns/zones/{dnsZoneId}");
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task> GetRecordsAsync(
+ DnsZoneId? dnsZoneId = null,
+ string? hostname = null,
+ int? pageNumber = null,
+ int? perPage = null)
+ {
+ var queryString = BuildQueryString(dnsZoneId, hostname, pageNumber, perPage);
+
+ var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/dns/records?{queryString}");
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task CreateRecordAsync(DnsRecordCreate createModel)
+ {
+ if (createModel is null)
+ {
+ throw new ArgumentNullException(nameof(createModel));
+ }
+
+ var result = await HttpClient.PostAsJsonAsync($"{_orgRoute}/dns/records", createModel, Constants.JsonSerializerOptions);
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task DeleteRecordsAsync(params DnsRecordId[] records)
+ {
+ using var content = CreateJsonContent(new
+ {
+ recordIds = records,
+ });
+
+ using var request = new HttpRequestMessage
+ {
+ Content = content,
+ Method = HttpMethod.Delete,
+ RequestUri = new Uri($"{HttpClient.BaseAddress}{_orgRoute}/dns/records"),
+ };
+
+ var result = await HttpClient.SendAsync(request);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model.DnsRecordsDeleted;
+ }
+
+ ///
+ public async Task DeleteRecordsAsync(IEnumerable records)
+ {
+ if (records is null)
+ {
+ throw new ArgumentNullException(nameof(records));
+ }
+
+ return await DeleteRecordsAsync(records.ToArray());
+ }
+
+ ///
+ public async Task GetRecordAsync(DnsRecordId dnsRecordId)
+ {
+ var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/dns/records/{dnsRecordId}", Constants.JsonSerializerOptions);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task UpdateRecordAsync(DnsRecordId dnsRecordId, PatchBuilder builder)
+ {
+ if (builder is null)
+ {
+ throw new ArgumentNullException(nameof(builder));
+ }
+
+ using var encoded = CreateJsonContent(builder.Send());
+ var result = await HttpClient.PatchAsync($"{_orgRoute}/dns/records/{dnsRecordId}", encoded);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task DeleteRecordAsync(DnsRecordId dnsRecordId)
+ {
+ var result = await HttpClient.DeleteAsync($"{_orgRoute}/dns/records/{dnsRecordId}");
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ private static string? BuildQueryString(DnsZoneId? dnsZoneId, string? hostname, int? pageNumber, int? perPage)
+ {
+ var queryString = HttpUtility.ParseQueryString(string.Empty);
+ if (dnsZoneId is not null)
+ {
+ queryString.Add("zoneId", dnsZoneId.ToString());
+ }
+
+ if (hostname is not null)
+ {
+ queryString.Add("hostname", hostname);
+ }
+
+ if (pageNumber is not null)
+ {
+ queryString.Add("page", pageNumber.ToString());
+ }
+
+ if (perPage is not null)
+ {
+ queryString.Add("per_page", perPage.ToString());
+ }
+
+ return queryString.ToString();
+ }
}
diff --git a/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs b/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs
new file mode 100644
index 0000000..0ade948
--- /dev/null
+++ b/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs
@@ -0,0 +1,245 @@
+using System.Collections.Generic;
+using System.Net.Http.Json;
+using System.Web;
+using Enclave.Sdk.Api.Clients.Interfaces;
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.EnrolledSystems;
+using Enclave.Sdk.Api.Data.EnrolledSystems.Enum;
+using Enclave.Sdk.Api.Data.Pagination;
+using Enclave.Sdk.Api.Data.PatchModel;
+
+namespace Enclave.Sdk.Api.Clients;
+
+///
+internal class EnrolledSystemsClient : ClientBase, IEnrolledSystemsClient
+{
+ private readonly string _orgRoute;
+
+ ///
+ /// Consutructor which will be called by when it's created.
+ ///
+ /// an instance of httpClient with a baseURL referencing the API.
+ /// The organisation API route.
+ public EnrolledSystemsClient(HttpClient httpClient, string orgRoute)
+ : base(httpClient)
+ {
+ _orgRoute = orgRoute;
+ }
+
+ ///
+ public async Task> GetSystemsAsync(
+ int? enrolmentKeyId = null,
+ string? searchTerm = null,
+ bool? includeDisabled = null,
+ SystemQuerySortMode? sortOrder = null,
+ string? dnsName = null,
+ int? pageNumber = null,
+ int? perPage = null)
+ {
+ var queryString = BuildQueryString(enrolmentKeyId, searchTerm, includeDisabled, sortOrder, dnsName, pageNumber, perPage);
+
+ var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/systems?{queryString}", Constants.JsonSerializerOptions);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task RevokeSystemsAsync(params SystemId[] systemIds)
+ {
+ using var content = CreateJsonContent(new
+ {
+ systemIds = systemIds,
+ });
+
+ using var request = new HttpRequestMessage
+ {
+ Content = content,
+ Method = HttpMethod.Delete,
+ RequestUri = new Uri($"{HttpClient.BaseAddress}{_orgRoute}/systems"),
+ };
+
+ var result = await HttpClient.SendAsync(request);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model.SystemsRevoked;
+ }
+
+ ///
+ public async Task RevokeSystemsAsync(IEnumerable systemIds)
+ {
+ return await RevokeSystemsAsync(systemIds.ToArray());
+ }
+
+ ///
+ public async Task GetAsync(SystemId systemId)
+ {
+ var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/systems/{systemId}", Constants.JsonSerializerOptions);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task UpdateAsync(SystemId systemId, PatchBuilder builder)
+ {
+ if (builder is null)
+ {
+ throw new ArgumentNullException(nameof(builder));
+ }
+
+ using var encoded = CreateJsonContent(builder.Send());
+ var result = await HttpClient.PatchAsync($"{_orgRoute}/systems/{systemId}", encoded);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task RevokeAsync(SystemId systemId)
+ {
+ var result = await HttpClient.DeleteAsync($"{_orgRoute}/systems/{systemId}");
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task EnableAsync(SystemId systemId)
+ {
+ var result = await HttpClient.PutAsync($"{_orgRoute}/systems/{systemId}/enable", null);
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task DisableAsync(SystemId systemId)
+ {
+ var result = await HttpClient.PutAsync($"{_orgRoute}/systems/{systemId}/disable", null);
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task BulkEnableAsync(params SystemId[] systemIds)
+ {
+ var requestModel = new
+ {
+ systemIds = systemIds,
+ };
+
+ var result = await HttpClient.PutAsJsonAsync($"{_orgRoute}/systems/enable", requestModel, Constants.JsonSerializerOptions);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model.SystemsUpdated;
+ }
+
+ ///
+ public async Task BulkEnableAsync(IEnumerable systemIds)
+ {
+ return await BulkEnableAsync(systemIds.ToArray());
+ }
+
+ ///
+ public async Task BulkDisableAsync(params SystemId[] systemIds)
+ {
+ var requestModel = new
+ {
+ systemIds = systemIds,
+ };
+
+ var result = await HttpClient.PutAsJsonAsync($"{_orgRoute}/systems/disable", requestModel, Constants.JsonSerializerOptions);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model.SystemsUpdated;
+ }
+
+ ///
+ public async Task BulkDisableAsync(IEnumerable systemIds)
+ {
+ return await BulkDisableAsync(systemIds.ToArray());
+ }
+
+ private static string? BuildQueryString(
+ int? enrolmentKeyId = null,
+ string? searchTerm = null,
+ bool? includeDisabled = null,
+ SystemQuerySortMode? sortOrder = null,
+ string? dnsName = null,
+ int? pageNumber = null,
+ int? perPage = null)
+ {
+ var queryString = HttpUtility.ParseQueryString(string.Empty);
+ if (enrolmentKeyId is not null)
+ {
+ queryString.Add("enrolment_key", enrolmentKeyId.ToString());
+ }
+
+ if (searchTerm is not null)
+ {
+ queryString.Add("search", searchTerm);
+ }
+
+ if (includeDisabled is not null)
+ {
+ queryString.Add("include_disabled", includeDisabled.ToString());
+ }
+
+ if (sortOrder is not null)
+ {
+ queryString.Add("sort", sortOrder.ToString());
+ }
+
+ if (dnsName is not null)
+ {
+ queryString.Add("dns", dnsName);
+ }
+
+ if (pageNumber is not null)
+ {
+ queryString.Add("page", pageNumber.ToString());
+ }
+
+ if (perPage is not null)
+ {
+ queryString.Add("per_page", perPage.ToString());
+ }
+
+ return queryString.ToString();
+ }
+}
diff --git a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs
index bc98e38..84a3f8d 100644
--- a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs
+++ b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs
@@ -1,14 +1,196 @@
+using System.Net.Http.Json;
+using System.Web;
using Enclave.Sdk.Api.Clients.Interfaces;
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.EnrolmentKeys;
+using Enclave.Sdk.Api.Data.EnrolmentKeys.Enum;
+using Enclave.Sdk.Api.Data.Pagination;
+using Enclave.Sdk.Api.Data.PatchModel;
namespace Enclave.Sdk.Api.Clients;
-public class EnrolmentKeysClient : ClientBase, IEnrolmentKeysClient
+///
+internal class EnrolmentKeysClient : ClientBase, IEnrolmentKeysClient
{
- private string _orgRoute;
+ private readonly string _orgRoute;
+ ///
+ /// Constructor which will be called by when it's created.
+ ///
+ /// an instance of httpClient with a baseURL referencing the API.
+ /// The organisation API route.
public EnrolmentKeysClient(HttpClient httpClient, string orgRoute)
: base(httpClient)
{
_orgRoute = orgRoute;
}
-}
+
+ ///
+ public async Task> GetEnrolmentKeysAsync(
+ string? searchTerm = null,
+ bool? includeDisabled = null,
+ EnrolmentKeySortOrder? sortOrder = null,
+ int? pageNumber = null,
+ int? perPage = null)
+ {
+ var queryString = BuildQueryString(searchTerm, includeDisabled, sortOrder, pageNumber, perPage);
+
+ var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/enrolment-keys?{queryString}");
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task CreateAsync(EnrolmentKeyCreate createModel)
+ {
+ if (createModel is null)
+ {
+ throw new ArgumentNullException(nameof(createModel));
+ }
+
+ var result = await HttpClient.PostAsJsonAsync($"{_orgRoute}/enrolment-keys", createModel, Constants.JsonSerializerOptions);
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task GetAsync(EnrolmentKeyId enrolmentKeyId)
+ {
+ var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}", Constants.JsonSerializerOptions);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task UpdateAsync(EnrolmentKeyId enrolmentKeyId, PatchBuilder builder)
+ {
+ if (builder is null)
+ {
+ throw new ArgumentNullException(nameof(builder));
+ }
+
+ using var encoded = CreateJsonContent(builder.Send());
+ var result = await HttpClient.PatchAsync($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}", encoded);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task EnableAsync(EnrolmentKeyId enrolmentKeyId)
+ {
+ var result = await HttpClient.PutAsync($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}/enable", null);
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task DisableAsync(EnrolmentKeyId enrolmentKeyId)
+ {
+ var result = await HttpClient.PutAsync($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}/disable", null);
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task BulkEnableAsync(params EnrolmentKeyId[] enrolmentKeys)
+ {
+ var requestModel = new
+ {
+ keyIds = enrolmentKeys,
+ };
+
+ var result = await HttpClient.PutAsJsonAsync($"{_orgRoute}/enrolment-keys/enable", requestModel, Constants.JsonSerializerOptions);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model.KeysModified;
+ }
+
+ ///
+ public async Task BulkEnableAsync(IEnumerable enrolmentKeys)
+ {
+ return await BulkEnableAsync(enrolmentKeys.ToArray());
+ }
+
+ ///
+ public async Task BulkDisableAsync(params EnrolmentKeyId[] enrolmentKeys)
+ {
+ var requestModel = new
+ {
+ keyIds = enrolmentKeys,
+ };
+
+ var result = await HttpClient.PutAsJsonAsync($"{_orgRoute}/enrolment-keys/disable", requestModel, Constants.JsonSerializerOptions);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model.KeysModified;
+ }
+
+ ///
+ public async Task BulkDisableAsync(IEnumerable enrolmentKeys)
+ {
+ return await BulkDisableAsync(enrolmentKeys.ToArray());
+ }
+
+ private static string? BuildQueryString(string? searchTerm, bool? includeDisabled, EnrolmentKeySortOrder? sortOrder, int? pageNumber, int? perPage)
+ {
+ var queryString = HttpUtility.ParseQueryString(string.Empty);
+ if (searchTerm is not null)
+ {
+ queryString.Add("search", searchTerm);
+ }
+
+ if (includeDisabled is not null)
+ {
+ queryString.Add("include_disabled", includeDisabled.ToString());
+ }
+
+ if (sortOrder is not null)
+ {
+ queryString.Add("sort", sortOrder.ToString());
+ }
+
+ if (pageNumber is not null)
+ {
+ queryString.Add("page", pageNumber.ToString());
+ }
+
+ if (perPage is not null)
+ {
+ queryString.Add("per_page", perPage.ToString());
+ }
+
+ return queryString.ToString();
+ }
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Clients/Interfaces/IAuthorityClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IAuthorityClient.cs
deleted file mode 100644
index 49b89d6..0000000
--- a/src/Enclave.Sdk/Clients/Interfaces/IAuthorityClient.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace Enclave.Sdk.Api.Clients.Interfaces;
-
-public interface IAuthorityClient
-{
-}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs
index c409dd2..ddedbcc 100644
--- a/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs
+++ b/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs
@@ -1,5 +1,112 @@
-namespace Enclave.Sdk.Api.Clients.Interfaces;
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.Dns;
+using Enclave.Sdk.Api.Data.Pagination;
+using Enclave.Sdk.Api.Data.PatchModel;
+namespace Enclave.Sdk.Api.Clients.Interfaces;
+
+///
+/// Provides operations to get, create, and manipulate DNS rules.
+///
public interface IDnsClient
{
+ ///
+ /// Gets a summary of DNS properties.
+ ///
+ /// A summary of DNS properties.
+ Task GetPropertiesSummaryAsync();
+
+ ///
+ /// Gets a paginated list of DNS zones.
+ ///
+ /// Which page number do you want to return.
+ /// How many items per page.
+ /// A paginated response model with links to get the previous, next, first and last pages.
+ Task> GetZonesAsync(int? pageNumber = null, int? perPage = null);
+
+ ///
+ /// Creates a DNS Zone using a Model.
+ ///
+ /// The model needed to create a DNS Zone.
+ /// The created DNS Zone as a .
+ Task CreateZoneAsync(DnsZoneCreate createModel);
+
+ ///
+ /// Gets the details of a specific DNS Zone.
+ ///
+ /// The DNS Zone ID that you want to get.
+ /// A full DNS Zone object.
+ Task GetZoneAsync(DnsZoneId dnsZoneId);
+
+ ///
+ /// Patch request to update a DNS Zone.
+ ///
+ /// The DNS Zone ID that you want to update.
+ /// An instance of used to setup our patch request.
+ /// A full DNS Zone object.
+ Task UpdateZoneAsync(DnsZoneId dnsZoneId, PatchBuilder builder);
+
+ ///
+ /// Delete a DNS Zone and it's associated record. This is irriversable.
+ ///
+ /// The DNS Zone ID that you want to update.
+ /// The deleted DNS Zone object.
+ Task DeleteZoneAsync(DnsZoneId dnsZoneId);
+
+ ///
+ /// Gets a paginated list of DNS records.
+ ///
+ /// The DNS Zone ID that you want to get.
+ /// A partial hostname search value.
+ /// Which page number do you want to return.
+ /// How many items per page.
+ /// A paginated response model with links to get the previous, next, first and last pages.
+ Task> GetRecordsAsync(
+ DnsZoneId? dnsZoneId = null,
+ string? hostname = null,
+ int? pageNumber = null,
+ int? perPage = null);
+
+ ///
+ /// Create a DNS Record using a model.
+ ///
+ /// The model needed to create a DNS Record.
+ /// The created DNS Record as .
+ Task CreateRecordAsync(DnsRecordCreate createModel);
+
+ ///
+ /// Delete multiple DNS Records.
+ ///
+ /// An Array of the Record Ids to delete.
+ /// The number of records deleted.
+ Task DeleteRecordsAsync(params DnsRecordId[] records);
+
+ ///
+ /// Delete multiple DNS Records.
+ ///
+ /// An IEnumerable of the Record Ids to delete.
+ /// The number of records deleted.
+ Task DeleteRecordsAsync(IEnumerable records);
+
+ ///
+ /// Get a detailed DNS Record.
+ ///
+ /// The id of the DNS Record you want to get.
+ /// A detailed DNS Record object.
+ Task GetRecordAsync(DnsRecordId dnsRecordId);
+
+ ///
+ /// Patch request to update a DNS Record.
+ ///
+ /// The DNS Record ID that you want to update.
+ /// An instance of used to setup our patch request.
+ /// A full DNS Record object.
+ Task UpdateRecordAsync(DnsRecordId dnsRecordId, PatchBuilder builder);
+
+ ///
+ /// Delete a single DNS Record.
+ ///
+ /// The DNS Record ID that you want to delete.
+ /// The deleted DNS Record object.
+ Task DeleteRecordAsync(DnsRecordId dnsRecordId);
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Clients/Interfaces/IEnrolledSystemsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IEnrolledSystemsClient.cs
new file mode 100644
index 0000000..d4547a5
--- /dev/null
+++ b/src/Enclave.Sdk/Clients/Interfaces/IEnrolledSystemsClient.cs
@@ -0,0 +1,111 @@
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.EnrolledSystems;
+using Enclave.Sdk.Api.Data.EnrolledSystems.Enum;
+using Enclave.Sdk.Api.Data.Pagination;
+using Enclave.Sdk.Api.Data.PatchModel;
+
+namespace Enclave.Sdk.Api.Clients.Interfaces;
+
+///
+/// Provides operations to get, create, and manipulate Enrolled Systems.
+///
+public interface IEnrolledSystemsClient
+{
+ ///
+ /// Gets a paginated list of Systems which can be searched and iterated upon.
+ ///
+ /// The Enrolment Key Id which the systems are associated to.
+ /// Search for systems with a partial match on description and system ID.
+ /// Should include disabled Systems.
+ /// Sort order for the pagination.
+ /// Searches for systems that will answer to the specified DNS name.
+ /// Which page number do you want to return.
+ /// How many per page.
+ /// A paginated response model with links to get the previous, next, first and last pages.
+ Task> GetSystemsAsync(
+ int? enrolmentKeyId = null,
+ string? searchTerm = null,
+ bool? includeDisabled = null,
+ SystemQuerySortMode? sortOrder = null,
+ string? dnsName = null,
+ int? pageNumber = null,
+ int? perPage = null);
+
+ ///
+ /// Permanetly revoke multiple systems.
+ ///
+ /// The System Ids to revoke.
+ /// The number of systems revoked.
+ Task RevokeSystemsAsync(params SystemId[] systemIds);
+
+ ///
+ /// Permanetly revoke multiple systems.
+ ///
+ /// The System Ids to revoke.
+ /// The number of systems revoked.
+ Task RevokeSystemsAsync(IEnumerable systemIds);
+
+ ///
+ /// Retrieve a Detailed System model.
+ ///
+ /// The SystemId to Get.
+ /// A Full System Model.
+ Task GetAsync(SystemId systemId);
+
+ ///
+ /// Update an Enrolled System.
+ ///
+ /// The Id of the Enrolled System to update.
+ /// An instance of used to setup our patch request.
+ /// An Enrolled System.
+ Task UpdateAsync(SystemId systemId, PatchBuilder builder);
+
+ ///
+ /// Revoke a system permanetly.
+ ///
+ /// The id of the Enrolled System to revoke.
+ /// The revoked Enrolled System.
+ Task RevokeAsync(SystemId systemId);
+
+ ///
+ /// Enable an Enrolled System.
+ ///
+ /// The Id of the Enrolled System to enable.
+ /// A detailed Enrolment Key.
+ Task EnableAsync(SystemId systemId);
+
+ ///
+ /// Disable an Enrolled System.
+ ///
+ /// The Id of the Enrolled System to disable.
+ /// A detailed Enrolment Key.
+ Task DisableAsync(SystemId systemId);
+
+ ///
+ /// Bulk enable mutliple Enrolled System.
+ ///
+ /// An array of Enrolled System Ids to enable.
+ /// The number of keys modified.
+ Task BulkEnableAsync(params SystemId[] systemIds);
+
+ ///
+ /// Bulk enable mutliple Enrolled System.
+ ///
+ /// An array of Enrolled System Ids to enable.
+ /// The number of keys modified.
+ Task BulkEnableAsync(IEnumerable systemIds);
+
+ ///
+ /// Bulk disable mutliple Enrolled System.
+ ///
+ /// An array of Enrolled System Ids to disable.
+ /// The number of keys modified.
+ Task BulkDisableAsync(params SystemId[] systemIds);
+
+ ///
+ /// Bulk disable mutliple Enrolled System.
+ ///
+ /// An array of Enrolled System Ids to disable.
+ /// The number of keys modified.
+ Task BulkDisableAsync(IEnumerable systemIds);
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs
index a11d9cd..43a11ab 100644
--- a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs
+++ b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs
@@ -1,5 +1,89 @@
-namespace Enclave.Sdk.Api.Clients.Interfaces;
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.EnrolmentKeys;
+using Enclave.Sdk.Api.Data.EnrolmentKeys.Enum;
+using Enclave.Sdk.Api.Data.Pagination;
+using Enclave.Sdk.Api.Data.PatchModel;
+namespace Enclave.Sdk.Api.Clients.Interfaces;
+
+///
+/// Provides operations to get, create, and manipulate Enrolment Keys.
+///
public interface IEnrolmentKeysClient
{
+ ///
+ /// Gets a paginated list of Enrolment Keys which can be searched and interated upon.
+ ///
+ /// A partial matching search term.
+ /// Include the disabled Enrolment Keys in the results.
+ /// Sort order for the pagination.
+ /// Which page number do you want to return.
+ /// How many Enrolment Keys per page.
+ /// A paginated response model with links to get the previous, next, first and last pages.
+ Task> GetEnrolmentKeysAsync(string? searchTerm = null, bool? includeDisabled = null, EnrolmentKeySortOrder? sortOrder = null, int? pageNumber = null, int? perPage = null);
+
+ ///
+ /// Creates an Enrolment Key using a Model.
+ ///
+ /// The model needed to create an Enrolment Key.
+ /// The created Enrolment Key as a .
+ Task CreateAsync(EnrolmentKeyCreate createModel);
+
+ ///
+ /// Gets a detailed Enrolment Key model.
+ ///
+ /// The Id of the Enrolment Key to get.
+ /// A detailed Enrolment Key.
+ Task GetAsync(EnrolmentKeyId enrolmentKeyId);
+
+ ///
+ /// Patch request to update the EnrolmentKey.
+ /// Use .
+ ///
+ /// The Id of the Enrolment Key to update.
+ /// An instance of used to setup our patch request.
+ /// A detailed Enrolment Key.
+ Task UpdateAsync(EnrolmentKeyId enrolmentKeyId, PatchBuilder builder);
+
+ ///
+ /// Enable an Enrolment Key.
+ ///
+ /// The Id of the Enrolment Key to enable.
+ /// A detailed Enrolment Key.
+ Task EnableAsync(EnrolmentKeyId enrolmentKeyId);
+
+ ///
+ /// Disable an Enrolment Key.
+ ///
+ /// The Id of the Enrolment Key to disable.
+ /// A detailed Enrolment Key.
+ Task DisableAsync(EnrolmentKeyId enrolmentKeyId);
+
+ ///
+ /// Bulk enable mutliple Enrolment Keys.
+ ///
+ /// An array of Enrolment Key Ids to enable.
+ /// The number of keys modified.
+ Task BulkEnableAsync(params EnrolmentKeyId[] enrolmentKeys);
+
+ ///
+ /// Bulk enable mutliple Enrolment Keys.
+ ///
+ /// An IEnumerable of Enrolment Key Ids to enable.
+ /// The number of keys modified.
+ Task BulkEnableAsync(IEnumerable enrolmentKeys);
+
+ ///
+ /// Bulk disable mutliple Enrolment Keys.
+ ///
+ /// An array of Enrolment Key Ids to disable.
+ /// The number of keys modified.
+ Task BulkDisableAsync(params EnrolmentKeyId[] enrolmentKeys);
+
+ ///
+ /// Bulk disable mutliple Enrolment Keys.
+ ///
+ /// An IEnumerable of Enrolment Key Ids to disable.
+ /// The number of keys modified.
+ Task BulkDisableAsync(IEnumerable enrolmentKeys);
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Clients/Interfaces/ILogsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/ILogsClient.cs
index 11595fd..e28c9a4 100644
--- a/src/Enclave.Sdk/Clients/Interfaces/ILogsClient.cs
+++ b/src/Enclave.Sdk/Clients/Interfaces/ILogsClient.cs
@@ -1,5 +1,18 @@
-namespace Enclave.Sdk.Api.Clients.Interfaces;
+using Enclave.Sdk.Api.Data.Logging;
+using Enclave.Sdk.Api.Data.Pagination;
+namespace Enclave.Sdk.Api.Clients.Interfaces;
+
+///
+/// Access and search for logs.
+///
public interface ILogsClient
{
+ ///
+ /// Gets a paginated list of logs which can be searched and interated upon.
+ ///
+ /// Which page number do you want to return.
+ /// How many per page.
+ /// A paginated response model with links to get the previous, next, first and last pages.
+ Task> GetLogsAsync(int? pageNumber = null, int? perPage = null);
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Clients/Interfaces/IOrganisationClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IOrganisationClient.cs
index 519151d..5cff80b 100644
--- a/src/Enclave.Sdk/Clients/Interfaces/IOrganisationClient.cs
+++ b/src/Enclave.Sdk/Clients/Interfaces/IOrganisationClient.cs
@@ -16,11 +16,6 @@ public interface IOrganisationClient
///
AccountOrganisation Organisation { get; }
- ///
- /// An instance of associated with the current organisaiton.
- ///
- IAuthorityClient Authority { get; }
-
///
/// An instance of associated with the current organisaiton.
///
@@ -42,9 +37,9 @@ public interface IOrganisationClient
IPoliciesClient Policies { get; }
///
- /// An instance of associated with the current organisaiton.
+ /// An instance of associated with the current organisaiton.
///
- ISystemsClient Systems { get; }
+ IEnrolledSystemsClient EnrolledSystems { get; }
///
/// An instance of associated with the current organisaiton.
@@ -94,9 +89,9 @@ public interface IOrganisationClient
///
/// Patch request to update the organisation.
- /// Use Builder.cs to help you generate the dictionary.
+ /// Use .
///
- /// An instance of used to setup our patch request.
+ /// An instance of used to setup our patch request.
/// The updated organisation.
/// Throws if builder is null.
Task UpdateAsync(PatchBuilder builder);
diff --git a/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs
index b3283e4..5f2d690 100644
--- a/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs
+++ b/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs
@@ -1,5 +1,114 @@
-namespace Enclave.Sdk.Api.Clients.Interfaces;
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.Pagination;
+using Enclave.Sdk.Api.Data.PatchModel;
+using Enclave.Sdk.Api.Data.Policies;
+using Enclave.Sdk.Api.Data.Policies.Enum;
+namespace Enclave.Sdk.Api.Clients.Interfaces;
+
+///
+/// Provides operations to get, create, and manipulate DNS rules.
+///
public interface IPoliciesClient
{
+ ///
+ /// Gets a paginated list of Policies which can be searched and iterated upon.
+ ///
+ /// A partial matching search term.
+ /// Include the disabled Policies in the results.
+ /// Sort order for the pagination.
+ /// Which page number do you want to return.
+ /// How many per page.
+ /// A paginated response model with links to get the previous, next, first and last pages.
+ Task> GetPoliciesAsync(
+ string? searchTerm = null,
+ bool? includeDisabled = null,
+ PolicySortOrder? sortOrder = null,
+ int? pageNumber = null,
+ int? perPage = null);
+
+ ///
+ /// Creates a Policy using a Model.
+ ///
+ /// The model needed to create a Policy.
+ /// The created .
+ Task CreateAsync(PolicyCreate createModel);
+
+ ///
+ /// Delete multiple Policies.
+ ///
+ /// The ids of the Policies you want to delete.
+ /// The number of deleted Policies.
+ Task DeletePoliciesAsync(params PolicyId[] policyIds);
+
+ ///
+ /// Delete multiple Policies.
+ ///
+ /// The ids of the Policies you want to delete.
+ /// The number of deleted Policies.
+ Task DeletePoliciesAsync(IEnumerable policyIds);
+
+ ///
+ /// Get a specific Policy.
+ ///
+ /// The Id of the Policy to get.
+ /// The .
+ Task GetAsync(PolicyId policyId);
+
+ ///
+ /// Patch request to update a Policy.
+ ///
+ /// The Id of the Policy to update.
+ /// An instance of used to setup our patch request.
+ /// The updated .
+ Task UpdateAsync(PolicyId policyId, PatchBuilder builder);
+
+ ///
+ /// Delete a Policy.
+ ///
+ /// The Id of the Policy to delete.
+ /// The deleted .
+ Task DeleteAsync(PolicyId policyId);
+
+ ///
+ /// Enable a Policy.
+ ///
+ /// The Id of the Policy to enable.
+ /// The enabled .
+ Task EnableAsync(PolicyId policyId);
+
+ ///
+ /// Disable a Policy.
+ ///
+ /// The Id of the Policy to disable.
+ /// The disabled .
+ Task DisableAsync(PolicyId policyId);
+
+ ///
+ /// Enable multiple Policies.
+ ///
+ /// The ids of the Policies you want to enable.
+ /// The number of enabled Policies.
+ Task EnablePoliciesAsync(params PolicyId[] policyIds);
+
+ ///
+ /// Enable multiple Policies.
+ ///
+ /// The ids of the Policies you want to enable.
+ /// The number of enabled Policies.
+ Task EnablePoliciesAsync(IEnumerable policyIds);
+
+ ///
+ /// Disable multiple Policies.
+ ///
+ /// The ids of the Policies you want to disable.
+ /// The number of disabled Policies.
+ Task DisablePoliciesAsync(params PolicyId[] policyIds);
+
+ ///
+ /// Disable multiple Policies.
+ ///
+ /// The ids of the Policies you want to disable.
+ /// The number of disabled Policies.
+ Task DisablePoliciesAsync(IEnumerable policyIds);
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Clients/Interfaces/ISystemsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/ISystemsClient.cs
deleted file mode 100644
index b0cf022..0000000
--- a/src/Enclave.Sdk/Clients/Interfaces/ISystemsClient.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace Enclave.Sdk.Api.Clients.Interfaces;
-
-public interface ISystemsClient
-{
-}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Clients/Interfaces/ITagsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/ITagsClient.cs
index 39647d1..d0e7039 100644
--- a/src/Enclave.Sdk/Clients/Interfaces/ITagsClient.cs
+++ b/src/Enclave.Sdk/Clients/Interfaces/ITagsClient.cs
@@ -14,7 +14,7 @@ public interface ITagsClient
/// A partial matching search term.
/// Sort order for the pagination.
/// Which page number do you want to return.
- /// How many tags per page.
+ /// How many per page.
/// A paginated response model with links to get the previous, next, first and last pages.
Task> GetAsync(string? searchTerm = null, TagQuerySortOrder? sortOrder = null, int? pageNumber = null, int? perPage = null);
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs
index aa34fdc..d0535e6 100644
--- a/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs
+++ b/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs
@@ -1,5 +1,85 @@
-namespace Enclave.Sdk.Api.Clients.Interfaces;
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.Pagination;
+using Enclave.Sdk.Api.Data.PatchModel;
+using Enclave.Sdk.Api.Data.UnaprrovedSystems;
+using Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum;
+namespace Enclave.Sdk.Api.Clients.Interfaces;
+
+///
+/// Provides operations to get, create, and manipulate Unapproved Systems.
+///
public interface IUnapprovedSystemsClient
{
+ ///
+ /// Gets a paginated list of Unapproved Systems which can be searched and interated upon.
+ ///
+ /// Filter by systems using the specified Enrolment Key.
+ /// A partial matching search term.
+ /// Sort order for the pagination.
+ /// Which page number do you want to return.
+ /// How many per page.
+ /// A paginated response model with links to get the previous, next, first and last pages.
+ Task> GetSystemsAsync(
+ int? enrolmentKeyId = null,
+ string? searchTerm = null,
+ UnapprovedSystemQuerySortMode? sortOrder = null,
+ int? pageNumber = null,
+ int? perPage = null);
+
+ ///
+ /// Permanetly decline multiple Unapproved Systems.
+ ///
+ /// System Ids to decline.
+ /// The number of systesm declined.
+ Task DeclineSystems(params SystemId[] systemIds);
+
+ ///
+ /// Permanetly decline multiple Unapproved Systems.
+ ///
+ /// System Ids to decline.
+ /// The number of systesm declined.
+ Task DeclineSystems(IEnumerable systemIds);
+
+ ///
+ /// Get the details of an Unapproved System.
+ ///
+ /// The system Id you want to get.
+ /// A Detailed Unapproved System Model.
+ Task GetAsync(SystemId systemId);
+
+ ///
+ /// Patch request to update an Unapproved System.
+ ///
+ /// The system Id you want to update.
+ /// An instance of used to setup our patch request.
+ /// An updated Detailed Unapproved System model.
+ Task UpdateAsync(SystemId systemId, PatchBuilder builder);
+
+ ///
+ /// Decline an Unapproved System.
+ ///
+ /// The system Id you want to decline.
+ /// The declined System.
+ Task DeclineAsync(SystemId systemId);
+
+ ///
+ /// Approve a System.
+ ///
+ /// The system Id you want to approve.
+ Task ApproveAsync(SystemId systemId);
+
+ ///
+ /// Approve multiple Unapproved Systems.
+ ///
+ /// System Ids to approve.
+ /// The number of systesm approved.
+ Task ApproveSystemsAsync(params SystemId[] systemIds);
+
+ ///
+ /// Approve multiple Unapproved Systems.
+ ///
+ /// System Ids to approve.
+ /// The number of systesm approved.
+ Task ApproveSystemsAsync(IEnumerable systemIds);
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Clients/LogsClient.cs b/src/Enclave.Sdk/Clients/LogsClient.cs
index 53e7df1..6ea546f 100644
--- a/src/Enclave.Sdk/Clients/LogsClient.cs
+++ b/src/Enclave.Sdk/Clients/LogsClient.cs
@@ -1,14 +1,52 @@
+using System.Net.Http.Json;
+using System.Web;
using Enclave.Sdk.Api.Clients.Interfaces;
+using Enclave.Sdk.Api.Data.Logging;
+using Enclave.Sdk.Api.Data.Pagination;
namespace Enclave.Sdk.Api.Clients;
-public class LogsClient : ClientBase, ILogsClient
+///
+internal class LogsClient : ClientBase, ILogsClient
{
- private string _orgRoute;
+ private readonly string _orgRoute;
+ ///
+ /// Constructor which will be called by when it's created.
+ ///
+ /// an instance of httpClient with a baseURL referencing the API.
+ /// the orgRoute which specifies the orgId.
public LogsClient(HttpClient httpClient, string orgRoute)
: base(httpClient)
{
_orgRoute = orgRoute;
}
+
+ ///
+ public async Task> GetLogsAsync(int? pageNumber = null, int? perPage = null)
+ {
+ var queryString = BuildQueryString(pageNumber, perPage);
+
+ var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/logs?{queryString}");
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ private static string? BuildQueryString(int? pageNumber, int? perPage)
+ {
+ var queryString = HttpUtility.ParseQueryString(string.Empty);
+ if (pageNumber is not null)
+ {
+ queryString.Add("page", pageNumber.ToString());
+ }
+
+ if (perPage is not null)
+ {
+ queryString.Add("per_page", perPage.ToString());
+ }
+
+ return queryString.ToString();
+ }
}
diff --git a/src/Enclave.Sdk/Clients/OrganisationClient.cs b/src/Enclave.Sdk/Clients/OrganisationClient.cs
index d876310..2a10d30 100644
--- a/src/Enclave.Sdk/Clients/OrganisationClient.cs
+++ b/src/Enclave.Sdk/Clients/OrganisationClient.cs
@@ -8,9 +8,9 @@
namespace Enclave.Sdk.Api.Clients;
///
-public class OrganisationClient : ClientBase, IOrganisationClient
+internal class OrganisationClient : ClientBase, IOrganisationClient
{
- private string _orgRoute;
+ private readonly string _orgRoute;
///
/// This constructor is called by when setting up the .
@@ -23,34 +23,39 @@ public OrganisationClient(HttpClient httpClient, AccountOrganisation currentOrga
{
Organisation = currentOrganisation;
_orgRoute = $"org/{Organisation.OrgId}";
+
+ Dns = new DnsClient(httpClient, _orgRoute);
+ EnrolmentKeys = new EnrolmentKeysClient(httpClient, _orgRoute);
+ Logs = new LogsClient(httpClient, _orgRoute);
+ Policies = new PoliciesClient(httpClient, _orgRoute);
+ EnrolledSystems = new EnrolledSystemsClient(httpClient, _orgRoute);
+ Tags = new TagsClient(httpClient, _orgRoute);
+ UnapprovedSystems = new UnapprovedSystemsClient(httpClient, _orgRoute);
}
///
public AccountOrganisation Organisation { get; }
///
- public IAuthorityClient Authority => throw new NotImplementedException();
-
- ///
- public IDnsClient Dns => throw new NotImplementedException();
+ public IDnsClient Dns { get; }
///
- public IEnrolmentKeysClient EnrolmentKeys => throw new NotImplementedException();
+ public IEnrolmentKeysClient EnrolmentKeys { get; }
///
- public ILogsClient Logs => throw new NotImplementedException();
+ public ILogsClient Logs { get; }
///
- public IPoliciesClient Policies => throw new NotImplementedException();
+ public IPoliciesClient Policies { get; }
///
- public ISystemsClient Systems => throw new NotImplementedException();
+ public IEnrolledSystemsClient EnrolledSystems { get; }
///
- public ITagsClient Tags => throw new NotImplementedException();
+ public ITagsClient Tags { get; }
///
- public IUnapprovedSystemsClient UnapprovedSystems => throw new NotImplementedException();
+ public IUnapprovedSystemsClient UnapprovedSystems { get; }
///
public async Task GetAsync()
@@ -68,10 +73,13 @@ public async Task UpdateAsync(PatchBuilder buil
if (builder is null)
{
throw new ArgumentNullException(nameof(builder));
- }
+ }
+
using var encoded = CreateJsonContent(builder.Send());
var result = await HttpClient.PatchAsync(_orgRoute, encoded);
+ result.EnsureSuccessStatusCode();
+
var model = await DeserialiseAsync(result.Content);
EnsureNotNull(model);
diff --git a/src/Enclave.Sdk/Clients/PoliciesClient.cs b/src/Enclave.Sdk/Clients/PoliciesClient.cs
index 0f6aafd..843a37c 100644
--- a/src/Enclave.Sdk/Clients/PoliciesClient.cs
+++ b/src/Enclave.Sdk/Clients/PoliciesClient.cs
@@ -1,14 +1,243 @@
-using Enclave.Sdk.Api.Clients.Interfaces;
+using System.Net.Http.Json;
+using System.Web;
+using Enclave.Sdk.Api.Clients.Interfaces;
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.Pagination;
+using Enclave.Sdk.Api.Data.PatchModel;
+using Enclave.Sdk.Api.Data.Policies;
+using Enclave.Sdk.Api.Data.Policies.Enum;
namespace Enclave.Sdk.Api.Clients;
-public class PoliciesClient : ClientBase, IPoliciesClient
+///
+internal class PoliciesClient : ClientBase, IPoliciesClient
{
- private string _orgRoute;
+ private readonly string _orgRoute;
+ ///
+ /// Constructor which will be called by when it's created.
+ /// It also calls the constructor.
+ ///
+ /// an instance of httpClient with a baseURL referencing the API.
+ /// The organisation API route.
public PoliciesClient(HttpClient httpClient, string orgRoute)
: base(httpClient)
{
_orgRoute = orgRoute;
}
-}
+
+ ///
+ public async Task> GetPoliciesAsync(
+ string? searchTerm = null,
+ bool? includeDisabled = null,
+ PolicySortOrder? sortOrder = null,
+ int? pageNumber = null,
+ int? perPage = null)
+ {
+ var queryString = BuildQueryString(searchTerm, includeDisabled, sortOrder, pageNumber, perPage);
+
+ var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/policies?{queryString}");
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task CreateAsync(PolicyCreate createModel)
+ {
+ if (createModel is null)
+ {
+ throw new ArgumentNullException(nameof(createModel));
+ }
+
+ var result = await HttpClient.PostAsJsonAsync($"{_orgRoute}/policies", createModel, Constants.JsonSerializerOptions);
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task DeletePoliciesAsync(params PolicyId[] policyIds)
+ {
+ using var content = CreateJsonContent(new
+ {
+ policyIds = policyIds,
+ });
+
+ using var request = new HttpRequestMessage
+ {
+ Content = content,
+ Method = HttpMethod.Delete,
+ RequestUri = new Uri($"{HttpClient.BaseAddress}{_orgRoute}/policies"),
+ };
+
+ var result = await HttpClient.SendAsync(request);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model.PoliciesDeleted;
+ }
+
+ ///
+ public async Task DeletePoliciesAsync(IEnumerable policyIds)
+ {
+ return await DeletePoliciesAsync(policyIds.ToArray());
+ }
+
+ ///
+ public async Task GetAsync(PolicyId policyId)
+ {
+ var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/policies/{policyId}", Constants.JsonSerializerOptions);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task UpdateAsync(PolicyId policyId, PatchBuilder builder)
+ {
+ if (builder is null)
+ {
+ throw new ArgumentNullException(nameof(builder));
+ }
+
+ using var encoded = CreateJsonContent(builder.Send());
+ var result = await HttpClient.PatchAsync($"{_orgRoute}/policies/{policyId}", encoded);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task DeleteAsync(PolicyId policyId)
+ {
+ var result = await HttpClient.DeleteAsync($"{_orgRoute}/policies/{policyId}");
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task EnableAsync(PolicyId policyId)
+ {
+ var result = await HttpClient.PutAsync($"{_orgRoute}/policies/{policyId}/enable", null);
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task DisableAsync(PolicyId policyId)
+ {
+ var result = await HttpClient.PutAsync($"{_orgRoute}/policies/{policyId}/disable", null);
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task EnablePoliciesAsync(params PolicyId[] policyIds)
+ {
+ var requestModel = new
+ {
+ policyIds = policyIds,
+ };
+
+ var result = await HttpClient.PutAsJsonAsync($"{_orgRoute}/policies/enable", requestModel, Constants.JsonSerializerOptions);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model.PoliciesUpdated;
+ }
+
+ ///
+ public async Task EnablePoliciesAsync(IEnumerable policyIds)
+ {
+ return await EnablePoliciesAsync(policyIds.ToArray());
+ }
+
+ ///
+ public async Task DisablePoliciesAsync(params PolicyId[] policyIds)
+ {
+ var requestModel = new
+ {
+ policyIds = policyIds,
+ };
+
+ var result = await HttpClient.PutAsJsonAsync($"{_orgRoute}/policies/disable", requestModel, Constants.JsonSerializerOptions);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model.PoliciesUpdated;
+ }
+
+ ///
+ public async Task DisablePoliciesAsync(IEnumerable policyIds)
+ {
+ return await DisablePoliciesAsync(policyIds.ToArray());
+ }
+
+ private static string? BuildQueryString(string? searchTerm, bool? includeDisabled, PolicySortOrder? sortOrder, int? pageNumber, int? perPage)
+ {
+ var queryString = HttpUtility.ParseQueryString(string.Empty);
+ if (searchTerm is not null)
+ {
+ queryString.Add("search", searchTerm);
+ }
+
+ if (includeDisabled is not null)
+ {
+ queryString.Add("include_disabled", includeDisabled.ToString());
+ }
+
+ if (sortOrder is not null)
+ {
+ queryString.Add("sort", sortOrder.ToString());
+ }
+
+ if (pageNumber is not null)
+ {
+ queryString.Add("page", pageNumber.ToString());
+ }
+
+ if (perPage is not null)
+ {
+ queryString.Add("per_page", perPage.ToString());
+ }
+
+ return queryString.ToString();
+ }
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Clients/SystemsClient.cs b/src/Enclave.Sdk/Clients/SystemsClient.cs
deleted file mode 100644
index fb4bc02..0000000
--- a/src/Enclave.Sdk/Clients/SystemsClient.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Enclave.Sdk.Api.Clients.Interfaces;
-
-namespace Enclave.Sdk.Api.Clients;
-
-public class SystemsClient : ClientBase, ISystemsClient
-{
- private string _orgRoute;
-
- public SystemsClient(HttpClient httpClient, string orgRoute)
- : base(httpClient)
- {
- _orgRoute = orgRoute;
- }
-}
diff --git a/src/Enclave.Sdk/Clients/TagsClient.cs b/src/Enclave.Sdk/Clients/TagsClient.cs
index 43eea63..835a9ff 100644
--- a/src/Enclave.Sdk/Clients/TagsClient.cs
+++ b/src/Enclave.Sdk/Clients/TagsClient.cs
@@ -1,18 +1,18 @@
+using System.Net.Http.Json;
+using System.Web;
using Enclave.Sdk.Api.Clients.Interfaces;
using Enclave.Sdk.Api.Data.Pagination;
using Enclave.Sdk.Api.Data.Tags;
-using System.Net.Http.Json;
-using System.Web;
namespace Enclave.Sdk.Api.Clients;
///
-public class TagsClient : ClientBase, ITagsClient
+internal class TagsClient : ClientBase, ITagsClient
{
- private string _orgRoute;
+ private readonly string _orgRoute;
///
- /// Consutructor which will be called by when it's created.
+ /// Constructor which will be called by when it's created.
///
/// an instance of httpClient with a baseURL referencing the API.
/// the orgRoute which specifies the orgId.
diff --git a/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs b/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs
index 5eebb5f..cd549e4 100644
--- a/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs
+++ b/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs
@@ -1,14 +1,190 @@
+using System.Net.Http.Json;
+using System.Web;
using Enclave.Sdk.Api.Clients.Interfaces;
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.Pagination;
+using Enclave.Sdk.Api.Data.PatchModel;
+using Enclave.Sdk.Api.Data.UnaprrovedSystems;
+using Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum;
namespace Enclave.Sdk.Api.Clients;
-public class UnapprovedSystemsClient : ClientBase, IUnapprovedSystemsClient
+///
+internal class UnapprovedSystemsClient : ClientBase, IUnapprovedSystemsClient
{
- private string _orgRoute;
+ private readonly string _orgRoute;
+ ///
+ /// This constructor is called by when setting up the .
+ /// It also calls the constructor.
+ ///
+ /// an instance of httpClient with a baseURL referencing the API.
+ /// The organisation API route.
public UnapprovedSystemsClient(HttpClient httpClient, string orgRoute)
: base(httpClient)
{
_orgRoute = orgRoute;
}
+
+ ///
+ public async Task> GetSystemsAsync(
+ int? enrolmentKeyId = null,
+ string? searchTerm = null,
+ UnapprovedSystemQuerySortMode? sortOrder = null,
+ int? pageNumber = null,
+ int? perPage = null)
+ {
+ var queryString = BuildQueryString(enrolmentKeyId, searchTerm, sortOrder, pageNumber, perPage);
+
+ var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/unapproved-systems?{queryString}");
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task DeclineSystems(params SystemId[] systemIds)
+ {
+ using var content = CreateJsonContent(new
+ {
+ systemIds = systemIds,
+ });
+
+ using var request = new HttpRequestMessage
+ {
+ Content = content,
+ Method = HttpMethod.Delete,
+ RequestUri = new Uri($"{HttpClient.BaseAddress}{_orgRoute}/unapproved-systems"),
+ };
+
+ var result = await HttpClient.SendAsync(request);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model.SystemsDeclined;
+ }
+
+ ///
+ public async Task DeclineSystems(IEnumerable systemIds)
+ {
+ return await DeclineSystems(systemIds.ToArray());
+ }
+
+ ///
+ public async Task GetAsync(SystemId systemId)
+ {
+ var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/unapproved-systems/{systemId}", Constants.JsonSerializerOptions);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task UpdateAsync(SystemId systemId, PatchBuilder builder)
+ {
+ if (builder is null)
+ {
+ throw new ArgumentNullException(nameof(builder));
+ }
+
+ using var encoded = CreateJsonContent(builder.Send());
+ var result = await HttpClient.PatchAsync($"{_orgRoute}/unapproved-systems/{systemId}", encoded);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task DeclineAsync(SystemId systemId)
+ {
+ var result = await HttpClient.DeleteAsync($"{_orgRoute}/unapproved-systems/{systemId}");
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model;
+ }
+
+ ///
+ public async Task ApproveAsync(SystemId systemId)
+ {
+ var result = await HttpClient.PutAsync($"{_orgRoute}/unapproved-systems/{systemId}/approve", null);
+
+ result.EnsureSuccessStatusCode();
+ }
+
+ ///
+ public async Task ApproveSystemsAsync(params SystemId[] systemIds)
+ {
+ var requestModel = new
+ {
+ systemIds = systemIds,
+ };
+
+ var result = await HttpClient.PutAsJsonAsync($"{_orgRoute}/unapproved-systems/approve", requestModel, Constants.JsonSerializerOptions);
+
+ result.EnsureSuccessStatusCode();
+
+ var model = await DeserialiseAsync(result.Content);
+
+ EnsureNotNull(model);
+
+ return model.SystemsApproved;
+ }
+
+ ///
+ public async Task ApproveSystemsAsync(IEnumerable systemIds)
+ {
+ return await ApproveSystemsAsync(systemIds.ToArray());
+ }
+
+ private static string? BuildQueryString(
+ int? enrolmentKeyId,
+ string? searchTerm,
+ UnapprovedSystemQuerySortMode? sortOrder,
+ int? pageNumber,
+ int? perPage)
+ {
+ var queryString = HttpUtility.ParseQueryString(string.Empty);
+ if (enrolmentKeyId is not null)
+ {
+ queryString.Add("enrolment_key", enrolmentKeyId.ToString());
+ }
+
+ if (searchTerm is not null)
+ {
+ queryString.Add("search", searchTerm);
+ }
+
+ if (sortOrder is not null)
+ {
+ queryString.Add("sort", sortOrder.ToString());
+ }
+
+ if (pageNumber is not null)
+ {
+ queryString.Add("page", pageNumber.ToString());
+ }
+
+ if (perPage is not null)
+ {
+ queryString.Add("per_page", perPage.ToString());
+ }
+
+ return queryString.ToString();
+ }
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Constants.cs b/src/Enclave.Sdk/Constants.cs
index b516ecd..5373998 100644
--- a/src/Enclave.Sdk/Constants.cs
+++ b/src/Enclave.Sdk/Constants.cs
@@ -1,18 +1,23 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Text.Json;
-using System.Threading.Tasks;
+using System.Text.Json;
+using System.Text.Json.Serialization;
namespace Enclave.Sdk.Api;
internal static class Constants
{
- public static JsonSerializerOptions JsonSerializerOptions { get; } = new JsonSerializerOptions
+ public static JsonSerializerOptions JsonSerializerOptions
{
- PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
- };
+ get
+ {
+ var options = new JsonSerializerOptions
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ };
+
+ options.Converters.Add(new JsonStringEnumConverter());
+ return options;
+ }
+ }
public const string ApiUrl = "https://api.enclave.io";
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/Account/AccountOrganisation.cs b/src/Enclave.Sdk/Data/Account/AccountOrganisation.cs
index a0dd9bc..c27e574 100644
--- a/src/Enclave.Sdk/Data/Account/AccountOrganisation.cs
+++ b/src/Enclave.Sdk/Data/Account/AccountOrganisation.cs
@@ -1,4 +1,6 @@
-namespace Enclave.Sdk.Api.Data.Account;
+using Enclave.Sdk.Api.Data.Organisations;
+
+namespace Enclave.Sdk.Api.Data.Account;
///
/// Contains the role an account has within an organisation.
@@ -29,5 +31,5 @@ public class AccountOrganisationTopLevel
///
/// The set of organisations.
///
- public List Orgs { get; init; } = default!;
+ public IReadOnlyList Orgs { get; init; } = Array.Empty();
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/Account/UserOrganisationRole.cs b/src/Enclave.Sdk/Data/Account/UserOrganisationRole.cs
index d5af46d..72fcb83 100644
--- a/src/Enclave.Sdk/Data/Account/UserOrganisationRole.cs
+++ b/src/Enclave.Sdk/Data/Account/UserOrganisationRole.cs
@@ -1,7 +1,17 @@
namespace Enclave.Sdk.Api.Data.Account;
+///
+/// The User roles.
+///
public enum UserOrganisationRole
{
+ ///
+ /// The owner of the organisation.
+ ///
Owner,
+
+ ///
+ /// An Admin of the organisaiton.
+ ///
Admin,
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/Dns/BulkDnsRecordDeleteResult.cs b/src/Enclave.Sdk/Data/Dns/BulkDnsRecordDeleteResult.cs
new file mode 100644
index 0000000..6d494b2
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Dns/BulkDnsRecordDeleteResult.cs
@@ -0,0 +1,12 @@
+namespace Enclave.Sdk.Api.Data.Dns;
+
+///
+/// Defines the result of a DNS Record bulk delete.
+///
+public class BulkDnsRecordDeleteResult
+{
+ ///
+ /// Specifies the number of DNS Records that were successfully deleted.
+ ///
+ public int DnsRecordsDeleted { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/Dns/DnsRecord.cs b/src/Enclave.Sdk/Data/Dns/DnsRecord.cs
new file mode 100644
index 0000000..a07e456
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Dns/DnsRecord.cs
@@ -0,0 +1,56 @@
+using Enclave.Sdk.Api.Data.EnrolledSystems;
+using Enclave.Sdk.Api.Data.SystemManagement;
+using Enclave.Sdk.Api.Data.Tags;
+
+namespace Enclave.Sdk.Api.Data.Dns;
+
+///
+/// Detailed model representing a DNS record.
+///
+public class DnsRecord
+{
+ ///
+ /// The ID of the record.
+ ///
+ public DnsRecordId Id { get; init; }
+
+ ///
+ /// The name of the record (without the zone).
+ ///
+ public string Name { get; init; } = default!;
+
+ ///
+ /// The type of DNS record.
+ ///
+ public string Type { get; init; } = default!;
+
+ ///
+ /// The ID of the DNS Zone to which this record belongs.
+ ///
+ public DnsZoneId ZoneId { get; init; }
+
+ ///
+ /// The name of the DNS Zone to which this record belongs.
+ ///
+ public string ZoneName { get; init; } = default!;
+
+ ///
+ /// The fully-qualified domain name of the record, including the zone name.
+ ///
+ public string Fqdn { get; init; } = default!;
+
+ ///
+ /// The set of tags to which this DNS name is applied.
+ ///
+ public IReadOnlyList Tags { get; init; } = Array.Empty();
+
+ ///
+ /// The set of systems to which this DNS name is applied.
+ ///
+ public IReadOnlyList? Systems { get; init; }
+
+ ///
+ /// Any provided notes for this record.
+ ///
+ public string? Notes { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/Dns/DnsRecordCreate.cs b/src/Enclave.Sdk/Data/Dns/DnsRecordCreate.cs
new file mode 100644
index 0000000..c209f70
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Dns/DnsRecordCreate.cs
@@ -0,0 +1,40 @@
+using System.ComponentModel;
+
+namespace Enclave.Sdk.Api.Data.Dns;
+
+///
+/// Record for creating a DNS model.
+///
+public class DnsRecordCreate
+{
+ ///
+ /// The name of the record to create. Use '@' for an apex record in the zone.
+ ///
+ public string Name { get; set; } = default!;
+
+ ///
+ /// The ID of the DNS zone this record should be added to.
+ ///
+ public DnsZoneId ZoneId { get; set; }
+
+ ///
+ /// The type of the DNS record (currently only "ENCLAVE" is supported).
+ ///
+ [DefaultValue("ENCLAVE")]
+ public string? Type { get; set; }
+
+ ///
+ /// The set of tags this name should apply to. All systems with one of these tags will get the name.
+ ///
+ public IReadOnlyList? Tags { get; set; }
+
+ ///
+ /// The set of systems to directly apply this name to.
+ ///
+ public IReadOnlyList? Systems { get; set; }
+
+ ///
+ /// Any notes or additional info for this record.
+ ///
+ public string? Notes { get; set; }
+}
diff --git a/src/Enclave.Sdk/Data/Dns/DnsRecordId.cs b/src/Enclave.Sdk/Data/Dns/DnsRecordId.cs
new file mode 100644
index 0000000..12423c4
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Dns/DnsRecordId.cs
@@ -0,0 +1,11 @@
+using TypedIds;
+
+namespace Enclave.Sdk.Api.Data.Dns;
+
+///
+/// An int backed Dns Record Id.
+///
+[TypedId(IdBackingType.Int)]
+public readonly partial struct DnsRecordId
+{
+}
diff --git a/src/Enclave.Sdk/Data/Dns/DnsRecordSummary.cs b/src/Enclave.Sdk/Data/Dns/DnsRecordSummary.cs
new file mode 100644
index 0000000..8a24104
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Dns/DnsRecordSummary.cs
@@ -0,0 +1,51 @@
+using Enclave.Sdk.Api.Data.EnrolledSystems;
+using Enclave.Sdk.Api.Data.SystemManagement;
+using Enclave.Sdk.Api.Data.Tags;
+
+namespace Enclave.Sdk.Api.Data.Dns;
+
+///
+/// Model representing a summary of a DNS record.
+///
+public class DnsRecordSummary
+{
+ ///
+ /// The ID of the record.
+ ///
+ public DnsRecordId Id { get; init; }
+
+ ///
+ /// The name of the record (without the zone).
+ ///
+ public string Name { get; init; } = default!;
+
+ ///
+ /// The type of DNS record.
+ ///
+ public string Type { get; init; } = default!;
+
+ ///
+ /// The ID of the DNS Zone to which this record belongs.
+ ///
+ public DnsZoneId ZoneId { get; init; }
+
+ ///
+ /// The name of the DNS Zone to which this record belongs.
+ ///
+ public string ZoneName { get; init; } = default!;
+
+ ///
+ /// The fully-qualified domain name of the record, including the zone name.
+ ///
+ public string Fqdn { get; init; } = default!;
+
+ ///
+ /// The set of tags to which this DNS name is applied.
+ ///
+ public IReadOnlyList Tags { get; init; } = Array.Empty();
+
+ ///
+ /// The set of systems to which this DNS name is applied.
+ ///
+ public IReadOnlyList? Systems { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/Dns/DnsSummary.cs b/src/Enclave.Sdk/Data/Dns/DnsSummary.cs
new file mode 100644
index 0000000..bf8ae47
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Dns/DnsSummary.cs
@@ -0,0 +1,17 @@
+namespace Enclave.Sdk.Api.Data.Dns;
+
+///
+/// Summary of DNS properties for the organisation.
+///
+public class DnsSummary
+{
+ ///
+ /// The number of zones in the organisation.
+ ///
+ public int ZoneCount { get; init; }
+
+ ///
+ /// The total number of DNS records in the organisation, across all zones.
+ ///
+ public int TotalRecordCount { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/Dns/DnsZone.cs b/src/Enclave.Sdk/Data/Dns/DnsZone.cs
new file mode 100644
index 0000000..6c8809a
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Dns/DnsZone.cs
@@ -0,0 +1,38 @@
+namespace Enclave.Sdk.Api.Data.Dns;
+
+///
+/// Detailed model representing a DNS zone.
+///
+public class DnsZone
+{
+ ///
+ /// The ID of the zone.
+ ///
+ public DnsZoneId Id { get; init; }
+
+ ///
+ /// The name of the zone.
+ ///
+ public string Name { get; init; } = default!;
+
+ ///
+ /// The point in time this zone was created.
+ ///
+ public DateTime Created { get; init; }
+
+ ///
+ /// The number of records in the zone.
+ ///
+ public int RecordCount { get; init; }
+
+ ///
+ /// The record counts broken down by type.
+ ///
+ // Public-facing APIs use the display name of the record type rather than the actual enum name. SeeDnsRecordTypeFormatConverter
+ public IReadOnlyDictionary? RecordTypeCounts { get; init; }
+
+ ///
+ /// Any provided notes for this zone.
+ /// s
+ public string? Notes { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/Dns/DnsZoneCreate.cs b/src/Enclave.Sdk/Data/Dns/DnsZoneCreate.cs
new file mode 100644
index 0000000..c461ba6
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Dns/DnsZoneCreate.cs
@@ -0,0 +1,17 @@
+namespace Enclave.Sdk.Api.Data.Dns;
+
+///
+/// The model for creating a new zone.
+///
+public class DnsZoneCreate
+{
+ ///
+ /// The name of the zone.
+ ///
+ public string Name { get; set; } = default!;
+
+ ///
+ /// Any notes for the zone.
+ ///
+ public string? Notes { get; set; }
+}
diff --git a/src/Enclave.Sdk/Data/Dns/DnsZoneId.cs b/src/Enclave.Sdk/Data/Dns/DnsZoneId.cs
new file mode 100644
index 0000000..19a491a
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Dns/DnsZoneId.cs
@@ -0,0 +1,11 @@
+using TypedIds;
+
+namespace Enclave.Sdk.Api.Data.Dns;
+
+///
+/// An int backed Dns Zone Id.
+///
+[TypedId(IdBackingType.Int)]
+public readonly partial struct DnsZoneId
+{
+}
diff --git a/src/Enclave.Sdk/Data/Dns/DnsZoneSummary.cs b/src/Enclave.Sdk/Data/Dns/DnsZoneSummary.cs
new file mode 100644
index 0000000..d7dca28
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Dns/DnsZoneSummary.cs
@@ -0,0 +1,33 @@
+namespace Enclave.Sdk.Api.Data.Dns;
+
+///
+/// Model representing a summary of a DNS record.
+///
+public class DnsZoneSummary
+{
+ ///
+ /// The ID of the zone.
+ ///
+ public DnsZoneId Id { get; init; }
+
+ ///
+ /// The name of the zone.
+ ///
+ public string Name { get; init; } = default!;
+
+ ///
+ /// The point in time this zone was created.
+ ///
+ public DateTime Created { get; init; }
+
+ ///
+ /// The number of records in the zone.
+ ///
+ public int RecordCount { get; init; }
+
+ ///
+ /// The record counts broken down by type.
+ ///
+ // Public-facing APIs use the display name of the record type rather than the actual enum name. SeeDnsRecordTypeFormatConverter
+ public IReadOnlyDictionary? RecordTypeCounts { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/EnrolledSystems/BulkSystemRevokedResult.cs b/src/Enclave.Sdk/Data/EnrolledSystems/BulkSystemRevokedResult.cs
new file mode 100644
index 0000000..69ea5b2
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolledSystems/BulkSystemRevokedResult.cs
@@ -0,0 +1,12 @@
+namespace Enclave.Sdk.Api.Data.EnrolledSystems;
+
+///
+/// The result of a bulk system revocation.
+///
+public class BulkSystemRevokedResult
+{
+ ///
+ /// How many systems were actually revoked.
+ ///
+ public int SystemsRevoked { get; set; }
+}
diff --git a/src/Enclave.Sdk/Data/EnrolledSystems/BulkSystemUpdateResult.cs b/src/Enclave.Sdk/Data/EnrolledSystems/BulkSystemUpdateResult.cs
new file mode 100644
index 0000000..9bdd241
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolledSystems/BulkSystemUpdateResult.cs
@@ -0,0 +1,12 @@
+namespace Enclave.Sdk.Api.Data.EnrolledSystems;
+
+///
+/// Defines the result of a bulk system update.
+///
+public class BulkSystemUpdateResult
+{
+ ///
+ /// The number of systems actually updated.
+ ///
+ public int SystemsUpdated { get; set; }
+}
diff --git a/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystem.cs b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystem.cs
new file mode 100644
index 0000000..b9f337b
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystem.cs
@@ -0,0 +1,105 @@
+using Enclave.Sdk.Api.Data.EnrolledSystems.Enum;
+using Enclave.Sdk.Api.Data.Tags;
+
+namespace Enclave.Sdk.Api.Data.EnrolledSystems;
+
+///
+/// A detailed model representing a single system.
+///
+public class EnrolledSystem
+{
+ ///
+ /// Unique ID for the System.
+ ///
+ public SystemId SystemId { get; init; } = default!;
+
+ ///
+ /// The configured description of the system.
+ ///
+ public string? Description { get; init; }
+
+ ///
+ /// The type of the system.
+ ///
+ public SystemType Type { get; init; }
+
+ ///
+ /// A value indicating the current state of the system from Enclave's perspective.
+ ///
+ public SystemState State { get; init; }
+
+ ///
+ /// Indicates a UTC timestamp when the system connected to the Enclave SaaS.
+ ///
+ public DateTime? ConnectedAt { get; init; }
+
+ ///
+ /// Indicates a UTC timestamp when Enclave last interacted with the system.
+ ///
+ public DateTime? LastSeen { get; init; }
+
+ ///
+ /// Contains a timestamp indicating when the system was enrolled into the account.
+ ///
+ public DateTime EnrolledAt { get; init; }
+
+ ///
+ /// The ID of the enrolment key used to enrol the system.
+ ///
+ public int EnrolmentKeyId { get; init; }
+
+ ///
+ /// The description of the enrolment key used to enrol the system.
+ ///
+ public string? EnrolmentKeyDescription { get; init; }
+
+ ///
+ /// Whether or not the system is enabled.
+ ///
+ public bool IsEnabled { get; init; }
+
+ ///
+ /// The IP address the system is connected from.
+ ///
+ public string? ConnectedFrom { get; init; }
+
+ ///
+ /// The locally-defined host name of the system.
+ ///
+ public string? Hostname { get; init; }
+
+ ///
+ /// The platform type for this system; possible values are Windows, Linux or Darwin.
+ ///
+ public string? PlatformType { get; init; }
+
+ ///
+ /// The version of the operating system.
+ ///
+ public string? OSVersion { get; init; }
+
+ ///
+ /// The Enclave product version.
+ ///
+ public string? EnclaveVersion { get; init; }
+
+ ///
+ /// The tags assigned to the system.
+ ///
+ public IReadOnlyList Tags { get; init; } = Array.Empty();
+
+ ///
+ /// The set of DNS entries applied to the system.
+ ///
+ public IReadOnlyList Dns { get; init; } = Array.Empty();
+
+ ///
+ /// Any additional notes attached to the system.
+ ///
+ public string? Notes { get; init; }
+
+ ///
+ /// Defines the number of minutes this system will be retained after a non-graceful disconnect.
+ ///
+ public int? DisconnectedRetentionMinutes { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs
new file mode 100644
index 0000000..a5fbc19
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs
@@ -0,0 +1,95 @@
+using Enclave.Sdk.Api.Data.EnrolledSystems.Enum;
+using Enclave.Sdk.Api.Data.Tags;
+
+namespace Enclave.Sdk.Api.Data.EnrolledSystems;
+
+///
+/// A basic model representing a single system.
+///
+public class EnrolledSystemSummary
+{
+ ///
+ /// Unique ID for the System.
+ ///
+ public SystemId SystemId { get; init; } = default!;
+
+ ///
+ /// The configured description of the system.
+ ///
+ public string? Description { get; init; }
+
+ ///
+ /// The type of the system.
+ ///
+ public SystemType Type { get; init; }
+
+ ///
+ /// A value indicating the current state of the system from Enclave's perspective.
+ ///
+ public SystemState State { get; init; }
+
+ ///
+ /// Indicates a UTC timestamp when the system connected to the Enclave SaaS.
+ ///
+ public DateTime? ConnectedAt { get; init; }
+
+ ///
+ /// Indicates a UTC timestamp when Enclave last interacted with the system.
+ ///
+ public DateTime? LastSeen { get; init; }
+
+ ///
+ /// Contains a timestamp indicating when the system was enrolled into the account.
+ ///
+ public DateTime EnrolledAt { get; init; }
+
+ ///
+ /// The ID of the enrolment key used to enrol the system.
+ ///
+ public int EnrolmentKeyId { get; init; }
+
+ ///
+ /// The description of the enrolment key used to enrol the system.
+ ///
+ public string EnrolmentKeyDescription { get; init; } = default!;
+
+ ///
+ /// Whether or not the system is enabled.
+ ///
+ public bool IsEnabled { get; init; }
+
+ ///
+ /// The IP address the system is connected from.
+ ///
+ public string? ConnectedFrom { get; init; }
+
+ ///
+ /// The locally-defined host name of the system.
+ ///
+ public string? Hostname { get; init; }
+
+ ///
+ /// The platform type for this system; possible values are Windows, Linux or Darwin.
+ ///
+ public string? PlatformType { get; init; }
+
+ ///
+ /// The version of the operating system.
+ ///
+ public string? OSVersion { get; init; }
+
+ ///
+ /// The Enclave product version.
+ ///
+ public string? EnclaveVersion { get; init; }
+
+ ///
+ /// The tags assigned to the system.
+ ///
+ public IReadOnlyList? Tags { get; init; }
+
+ ///
+ /// Defines the number of minutes this system will be retained after a non-graceful disconnect.
+ ///
+ public int? DisconnectedRetentionMinutes { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemQuerySortMode.cs b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemQuerySortMode.cs
new file mode 100644
index 0000000..9864272
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemQuerySortMode.cs
@@ -0,0 +1,27 @@
+namespace Enclave.Sdk.Api.Data.EnrolledSystems.Enum;
+
+///
+/// System Query Sort order used when making a System request.
+///
+public enum SystemQuerySortMode
+{
+ ///
+ /// Sort by recently enrolled.
+ ///
+ RecentlyEnrolled,
+
+ ///
+ /// Sort by recently connected.
+ ///
+ RecentlyConnected,
+
+ ///
+ /// Sort by description.
+ ///
+ Description,
+
+ ///
+ /// Sort by enrolment key.
+ ///
+ EnrolmentKeyUsed,
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemState.cs b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemState.cs
new file mode 100644
index 0000000..251bb3d
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemState.cs
@@ -0,0 +1,22 @@
+namespace Enclave.Sdk.Api.Data.EnrolledSystems.Enum;
+
+///
+/// The possible states of an enrolled system.
+///
+public enum SystemState
+{
+ ///
+ /// The system has been explicitly disabled.
+ ///
+ Disabled,
+
+ ///
+ /// The system is disconnected from the Enclave cloud services.
+ ///
+ Disconnected,
+
+ ///
+ /// The system is connected to Enclave cloud services.
+ ///
+ Connected,
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemType.cs b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemType.cs
new file mode 100644
index 0000000..bce91a5
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemType.cs
@@ -0,0 +1,19 @@
+namespace Enclave.Sdk.Api.Data.EnrolledSystems.Enum;
+
+///
+/// Defines the types of Systems.
+///
+public enum SystemType
+{
+ ///
+ /// For workstations, laptops, servers, and other systems that are relatively long-lived or manually provisioned.
+ /// Systems remain in your Enclave Organisation if they stop running.
+ ///
+ GeneralPurpose,
+
+ ///
+ /// For containers, kubernetes pods, and other systems that are temporary, short-lived or automatically provisioned.
+ /// Systems are automatically removed from your Enclave Organisation when they stop/disconnect.
+ ///
+ Ephemeral,
+}
diff --git a/src/Enclave.Sdk/Data/EnrolledSystems/SystemDnsEntry.cs b/src/Enclave.Sdk/Data/EnrolledSystems/SystemDnsEntry.cs
new file mode 100644
index 0000000..c84ff5c
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolledSystems/SystemDnsEntry.cs
@@ -0,0 +1,45 @@
+using Enclave.Sdk.Api.Data.Dns;
+using Enclave.Sdk.Api.Data.Tags;
+
+namespace Enclave.Sdk.Api.Data.EnrolledSystems;
+
+///
+/// Represents a single system DNS entry.
+///
+public class SystemDnsEntry
+{
+ ///
+ /// The FQDN (Fully Qualified Domain Name) of the entry.
+ ///
+ public string Fqdn { get; init; } = default!;
+
+ ///
+ /// The zone ID the DNS entry came from.
+ ///
+ public DnsZoneId? FromZoneId { get; init; }
+
+ ///
+ /// The zone Name the DNS entry came from.
+ ///
+ public string? FromZoneName { get; init; }
+
+ ///
+ /// The DNS record ID the DNS entry came from.
+ ///
+ public DnsRecordId? FromRecordId { get; init; }
+
+ ///
+ /// The DNS record name the DNS entry came from.
+ ///
+ public string? FromRecordName { get; init; }
+
+ ///
+ /// Indicates whether the DNS entry was directly assigned to this specific system.
+ ///
+ public bool FromDirectAssignment { get; init; }
+
+ ///
+ /// Contains the set of tags on the system that caused it to be assigned this name.
+ ///
+ public IReadOnlyList? Tags { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/BulkKeyActionResult.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/BulkKeyActionResult.cs
new file mode 100644
index 0000000..18a64d5
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolmentKeys/BulkKeyActionResult.cs
@@ -0,0 +1,12 @@
+namespace Enclave.Sdk.Api.Data.EnrolmentKeys;
+
+///
+/// Model for the result of a bulk enrolment key operation.
+///
+public class BulkKeyActionResult
+{
+ ///
+ /// Number of keys modified.
+ ///
+ public int KeysModified { get; set; }
+}
diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKey.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKey.cs
new file mode 100644
index 0000000..2e84c11
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKey.cs
@@ -0,0 +1,94 @@
+using Enclave.Sdk.Api.Data.EnrolmentKeys.Enum;
+using Enclave.Sdk.Api.Data.Tags;
+
+namespace Enclave.Sdk.Api.Data.EnrolmentKeys;
+
+///
+/// Represents a single Enclave Enrolment Key.
+///
+public class EnrolmentKey
+{
+ ///
+ /// The ID of the enrolment key.
+ ///
+ public EnrolmentKeyId Id { get; init; }
+
+ ///
+ /// The UTC timestamp when the key was created.
+ ///
+ public DateTime Created { get; init; }
+
+ ///
+ /// The UTC timestamp when the key was last used to enrol a system (null if never used).
+ ///
+ public DateTime? LastUsed { get; init; }
+
+ ///
+ /// The type of key; general purpose (default) or ephemeral (enrolled systems are automatically removed).
+ ///
+ public EnrolmentKeyType Type { get; init; }
+
+ ///
+ /// The approval mode for the key.
+ ///
+ public ApprovalMode ApprovalMode { get; init; }
+
+ ///
+ /// The status of the key.
+ ///
+ public EnrolmentKeyStatus Status => IsEnabled ?
+ UsesRemaining == 0 ?
+ EnrolmentKeyStatus.NoUsesRemaining : EnrolmentKeyStatus.Enabled
+ : EnrolmentKeyStatus.Disabled;
+
+ ///
+ /// The key value that can be used to enrol systems.
+ ///
+ public string Key { get; init; } = default!;
+
+ ///
+ /// The provided description of the key.
+ ///
+ public string Description { get; init; } = default!;
+
+ ///
+ /// Whether or not this key is enabled.
+ ///
+ public bool IsEnabled { get; init; }
+
+ ///
+ /// The number of uses remaining.
+ ///
+ public long UsesRemaining { get; init; }
+
+ ///
+ /// The number of systems enrolled with this key.
+ ///
+ public long EnrolledCount { get; init; }
+
+ ///
+ /// The number of unapproved systems enrolled with this key.
+ ///
+ public long UnapprovedCount { get; init; }
+
+ ///
+ /// The set of tags applied to the key.
+ ///
+ public IReadOnlyList? Tags { get; init; } = Array.Empty();
+
+ ///
+ /// Defines the number of minutes an ephemeral system enrolled with this key will be retained after a non-graceful disconnect.
+ /// Only has a value when the type is 'Ephemeral'.
+ ///
+ public int? DisconnectedRetentionMinutes { get; set; }
+
+ ///
+ /// The set of IP constraints for the key.
+ ///
+ public IReadOnlyList IpConstraints { get; init; } = Array.Empty();
+
+ ///
+ /// Any notes or additional info for this key.
+ ///
+ public string? Notes { get; init; }
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs
new file mode 100644
index 0000000..b422e7c
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs
@@ -0,0 +1,54 @@
+using System.ComponentModel;
+using Enclave.Sdk.Api.Data.EnrolmentKeys.Enum;
+
+namespace Enclave.Sdk.Api.Data.EnrolmentKeys;
+
+///
+/// Data required to create a new enrolment key.
+///
+public class EnrolmentKeyCreate
+{
+ ///
+ /// Defines the type of key being created, general purpose (default) or ephemeral (enrolled systems are automatically removed).
+ ///
+ [DefaultValue(EnrolmentKeyType.GeneralPurpose)]
+ public EnrolmentKeyType Type { get; set; } = EnrolmentKeyType.GeneralPurpose;
+
+ ///
+ /// The approval mode for the key, manual (default) or automatic.
+ ///
+ [DefaultValue(Enum.ApprovalMode.Manual)]
+ public ApprovalMode? ApprovalMode { get; set; } = Enum.ApprovalMode.Manual;
+
+ ///
+ /// A description for the key you are creating.
+ ///
+ public string Description { get; set; } = default!;
+
+ ///
+ /// The number of uses to start the key with. A value of -1 indicates no limit on the number of uses.
+ ///
+ [DefaultValue(-1)]
+ public int? UsesRemaining { get; set; } = -1;
+
+ ///
+ /// The set of IP Address constraints on the key.
+ ///
+ public List IpConstraints { get; set; } = new List();
+
+ ///
+ /// A set of tags automatically applied to systems enrolled with this key.
+ ///
+ public List Tags { get; set; } = new List();
+
+ ///
+ /// Defines the number of minutes an ephemeral system enrolled with this key will be retained after a non-graceful disconnect.
+ /// Only valid when key type is 'Ephemeral'. Default of 15 minutes.
+ ///
+ public int? DisconnectedRetentionMinutes { get; set; }
+
+ ///
+ /// Any additional notes to attach to the key.
+ ///
+ public string? Notes { get; set; }
+}
diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyId.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyId.cs
new file mode 100644
index 0000000..d26a553
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyId.cs
@@ -0,0 +1,11 @@
+using TypedIds;
+
+namespace Enclave.Sdk.Api.Data.EnrolmentKeys;
+
+///
+/// An int backed Enrolment Key Id.
+///
+[TypedId(IdBackingType.Int)]
+public partial struct EnrolmentKeyId
+{
+}
diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraint.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraint.cs
new file mode 100644
index 0000000..1826a08
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraint.cs
@@ -0,0 +1,17 @@
+namespace Enclave.Sdk.Api.Data.EnrolmentKeys;
+
+///
+/// Model for IP Address constraints.
+///
+public class EnrolmentKeyIpConstraint
+{
+ ///
+ /// The IP range.
+ ///
+ public string Range { get; init; } = default!;
+
+ ///
+ /// A description for the range.
+ ///
+ public string? Description { get; init; }
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs
new file mode 100644
index 0000000..dbf835c
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs
@@ -0,0 +1,72 @@
+using System.Net;
+
+namespace Enclave.Sdk.Api.Data.EnrolmentKeys;
+
+///
+/// Input model for IP Address constraints.
+///
+public class EnrolmentKeyIpConstraintInput
+{
+ ///
+ /// Constructor that takes a range as a CIDR notation.
+ ///
+ /// The IP range as a CIDR notation.
+ public EnrolmentKeyIpConstraintInput(string cidrNotation)
+ {
+ if (string.IsNullOrWhiteSpace(cidrNotation))
+ {
+ throw new ArgumentNullException(nameof(cidrNotation));
+ }
+
+ if (!cidrNotation.Contains('/', StringComparison.Ordinal))
+ {
+ throw new ArgumentException("Incorrect CIDR Format");
+ }
+
+ Range = cidrNotation;
+ }
+
+ ///
+ /// Constructor that takes an IPAddress object to fill the Range field.
+ ///
+ /// The IP Address to use as the Range.
+ public EnrolmentKeyIpConstraintInput(IPAddress ipAddress)
+ {
+ if (ipAddress is null)
+ {
+ throw new ArgumentNullException(nameof(ipAddress));
+ }
+
+ Range = ipAddress.ToString();
+ }
+
+ ///
+ /// Constructor that takes two IPAddress objects to fill the Range property.
+ ///
+ /// The start IP Address.
+ /// The end IP Address.
+ public EnrolmentKeyIpConstraintInput(IPAddress startAddress, IPAddress endAddress)
+ {
+ if (startAddress is null)
+ {
+ throw new ArgumentNullException(nameof(startAddress));
+ }
+
+ if (endAddress is null)
+ {
+ throw new ArgumentNullException(nameof(endAddress));
+ }
+
+ Range = $"{startAddress} - {endAddress}";
+ }
+
+ ///
+ /// The IP range.
+ ///
+ public string Range { get; }
+
+ ///
+ /// A description for the range.
+ ///
+ public string? Description { get; set; }
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeySummary.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeySummary.cs
new file mode 100644
index 0000000..7ecaf73
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeySummary.cs
@@ -0,0 +1,84 @@
+using Enclave.Sdk.Api.Data.EnrolmentKeys.Enum;
+using Enclave.Sdk.Api.Data.Tags;
+
+namespace Enclave.Sdk.Api.Data.EnrolmentKeys;
+
+///
+/// Represents a single Enclave Enrolment Key.
+///
+public class EnrolmentKeySummary
+{
+ ///
+ /// The ID of the enrolment key.
+ ///
+ public EnrolmentKeyId Id { get; init; }
+
+ ///
+ /// The UTC timestamp when the key was created.
+ ///
+ public DateTime Created { get; init; }
+
+ ///
+ /// The UTC timestamp when the key was last used to enrol a system (null if never used).
+ ///
+ public DateTime? LastUsed { get; init; }
+
+ ///
+ /// The type of key; general purpose (default) or ephemeral (enrolled systems are automatically removed).
+ ///
+ public EnrolmentKeyType Type { get; init; }
+
+ ///
+ /// The approval mode for the key.
+ ///
+ public ApprovalMode ApprovalMode { get; init; }
+
+ ///
+ /// The status of the key.
+ ///
+ public EnrolmentKeyStatus Status => IsEnabled ?
+ UsesRemaining == 0 ?
+ EnrolmentKeyStatus.NoUsesRemaining : EnrolmentKeyStatus.Enabled
+ : EnrolmentKeyStatus.Disabled;
+
+ ///
+ /// The key value that can be used to enrol systems.
+ ///
+ public string Key { get; init; } = default!;
+
+ ///
+ /// The provided description of the key.
+ ///
+ public string Description { get; init; } = default!;
+
+ ///
+ /// Whether or not this key is enabled.
+ ///
+ public bool IsEnabled { get; init; }
+
+ ///
+ /// The number of uses remaining.
+ ///
+ public long UsesRemaining { get; init; }
+
+ ///
+ /// The number of systems enrolled with this key.
+ ///
+ public long EnrolledCount { get; init; }
+
+ ///
+ /// The number of unapproved systems enrolled with this key.
+ ///
+ public long UnapprovedCount { get; init; }
+
+ ///
+ /// The set of tags applied to the key.
+ ///
+ public IReadOnlyList Tags { get; init; } = Array.Empty();
+
+ ///
+ /// Defines the number of minutes an ephemeral system enrolled with this key will be retained after a non-graceful disconnect.
+ /// Only has a value when the type is 'Ephemeral'.
+ ///
+ public int? DisconnectedRetentionMinutes { get; set; }
+}
diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs
new file mode 100644
index 0000000..8c3b64c
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs
@@ -0,0 +1,17 @@
+namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum;
+
+///
+/// System Approval Mode.
+///
+public enum ApprovalMode
+{
+ ///
+ /// Automatically approve systems.
+ ///
+ Automatic,
+
+ ///
+ /// Manually approve systems.
+ ///
+ Manual,
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeySortOrder.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeySortOrder.cs
new file mode 100644
index 0000000..fa62bef
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeySortOrder.cs
@@ -0,0 +1,27 @@
+namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum;
+
+///
+/// Enrolment Key Sort Order used when making an Enrolment Key request.
+///
+public enum EnrolmentKeySortOrder
+{
+ ///
+ /// Sort by Description.
+ ///
+ Description,
+
+ ///
+ /// Sort by Last Used.
+ ///
+ LastUsed,
+
+ ///
+ /// Sort By Approval Mode.
+ ///
+ ApprovalMode,
+
+ ///
+ /// Sort by Uses Remaining.
+ ///
+ UsesRemaining,
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyStatus.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyStatus.cs
new file mode 100644
index 0000000..95fe6c9
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyStatus.cs
@@ -0,0 +1,22 @@
+namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum;
+
+///
+/// The status of an enrolment key.
+///
+public enum EnrolmentKeyStatus
+{
+ ///
+ /// The key is disabled, so cannot be used.
+ ///
+ Disabled,
+
+ ///
+ /// The key is enabled, and can be used.
+ ///
+ Enabled,
+
+ ///
+ /// The key is enabled, but has no uses left, so cannot be used.
+ ///
+ NoUsesRemaining,
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs
new file mode 100644
index 0000000..35929bc
--- /dev/null
+++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs
@@ -0,0 +1,19 @@
+namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum;
+
+///
+/// Defines the types of Enrolment Keys.
+///
+public enum EnrolmentKeyType
+{
+ ///
+ /// For workstations, laptops, servers, and other systems that are relatively long-lived or manually provisioned.
+ /// Systems remain in your Enclave Organisation if they stop running.
+ ///
+ GeneralPurpose,
+
+ ///
+ /// For containers, kubernetes pods, and other systems that are temporary, short-lived or automatically provisioned.
+ /// Systems are automatically removed from your Enclave Organisation when they stop/disconnect.
+ ///
+ Ephemeral,
+}
diff --git a/src/Enclave.Sdk/Data/Organisations/Enum/BillingEventLevel.cs b/src/Enclave.Sdk/Data/Logging/Enum/ActivityLogLevel.cs
similarity index 52%
rename from src/Enclave.Sdk/Data/Organisations/Enum/BillingEventLevel.cs
rename to src/Enclave.Sdk/Data/Logging/Enum/ActivityLogLevel.cs
index 7b92bd8..11b52d6 100644
--- a/src/Enclave.Sdk/Data/Organisations/Enum/BillingEventLevel.cs
+++ b/src/Enclave.Sdk/Data/Logging/Enum/ActivityLogLevel.cs
@@ -1,22 +1,22 @@
-namespace Enclave.Sdk.Api.Data.Organisations.Enum;
+namespace Enclave.Sdk.Api.Data.Logging.Enum;
///
-/// Defines levels for billing events.
+/// Log Error Type.
///
-public enum BillingEventLevel
+public enum ActivityLogLevel
{
///
- /// Info.
+ /// Information log level.
///
Information,
///
- /// Warning.
+ /// Warning Log.
///
Warning,
///
- /// Error.
+ /// Error Log.
///
Error,
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/Logging/LogEntry.cs b/src/Enclave.Sdk/Data/Logging/LogEntry.cs
new file mode 100644
index 0000000..e40c6d5
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Logging/LogEntry.cs
@@ -0,0 +1,34 @@
+using Enclave.Sdk.Api.Data.Logging.Enum;
+
+namespace Enclave.Sdk.Api.Data.Logging;
+
+///
+/// Model for a single log entry.
+///
+public class LogEntry
+{
+ ///
+ /// The UTC timestamp of the log event.
+ ///
+ public DateTime TimeStamp { get; set; }
+
+ ///
+ /// The log level.
+ ///
+ public ActivityLogLevel Level { get; set; }
+
+ ///
+ /// The log message.
+ ///
+ public string Message { get; set; } = default!;
+
+ ///
+ /// The user responsible for the event (if known).
+ ///
+ public string? UserName { get; set; }
+
+ ///
+ /// The IP address from which the action was carried out.
+ ///
+ public string? IpAddress { get; set; }
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/Organisations/Enum/OrganisationPlan.cs b/src/Enclave.Sdk/Data/Organisations/Enum/OrganisationPlan.cs
index 8ed8025..c845afa 100644
--- a/src/Enclave.Sdk/Data/Organisations/Enum/OrganisationPlan.cs
+++ b/src/Enclave.Sdk/Data/Organisations/Enum/OrganisationPlan.cs
@@ -1,8 +1,22 @@
namespace Enclave.Sdk.Api.Data.Organisations.Enum;
+///
+/// An Enum describing the types of plan.
+///
public enum OrganisationPlan
{
+ ///
+ /// Starter Organisation Plan.
+ ///
Starter = 0,
+
+ ///
+ /// Pro Organisaiton Plan.
+ ///
Pro = 1,
+
+ ///
+ /// Business Organisaiton Plan.
+ ///
Business = 2,
}
diff --git a/src/Enclave.Sdk/Data/Organisations/Organisation.cs b/src/Enclave.Sdk/Data/Organisations/Organisation.cs
index e329646..16d3bf2 100644
--- a/src/Enclave.Sdk/Data/Organisations/Organisation.cs
+++ b/src/Enclave.Sdk/Data/Organisations/Organisation.cs
@@ -1,5 +1,4 @@
-using Enclave.Sdk.Api.Data.Account;
-using Enclave.Sdk.Api.Data.Organisations.Enum;
+using Enclave.Sdk.Api.Data.Organisations.Enum;
namespace Enclave.Sdk.Api.Data.Organisations;
diff --git a/src/Enclave.Sdk/Data/Organisations/OrganisationBillingEvent.cs b/src/Enclave.Sdk/Data/Organisations/OrganisationBillingEvent.cs
deleted file mode 100644
index e54d139..0000000
--- a/src/Enclave.Sdk/Data/Organisations/OrganisationBillingEvent.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using Enclave.Sdk.Api.Data.Organisations.Enum;
-
-namespace Enclave.Sdk.Api.Data.Organisations;
-
-///
-/// Defines the properties available for a billing event on an organisation.
-///
-public class OrganisationBillingEvent
-{
- ///
- /// The code indicating the billing event.
- ///
- public string Code { get; init; } = default!;
-
- ///
- /// A human-readable message describing the event.
- ///
- public string Message { get; init; } = default!;
-
- ///
- /// The event 'level'.
- ///
- public BillingEventLevel Level { get; init; }
-}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/Account/OrganisationId.cs b/src/Enclave.Sdk/Data/Organisations/OrganisationId.cs
similarity index 51%
rename from src/Enclave.Sdk/Data/Account/OrganisationId.cs
rename to src/Enclave.Sdk/Data/Organisations/OrganisationId.cs
index 5907c18..287aa09 100644
--- a/src/Enclave.Sdk/Data/Account/OrganisationId.cs
+++ b/src/Enclave.Sdk/Data/Organisations/OrganisationId.cs
@@ -1,9 +1,9 @@
using TypedIds;
-namespace Enclave.Sdk.Api.Data.Account;
+namespace Enclave.Sdk.Api.Data.Organisations;
///
-/// OrganisaitonId struct to distinguish between Id types.
+/// OrganisationId struct to distinguish between Id types.
///
[TypedId]
public readonly partial struct OrganisationId
diff --git a/src/Enclave.Sdk/Data/Organisations/OrganisationUser.cs b/src/Enclave.Sdk/Data/Organisations/OrganisationUser.cs
index 59b7519..03c2f41 100644
--- a/src/Enclave.Sdk/Data/Organisations/OrganisationUser.cs
+++ b/src/Enclave.Sdk/Data/Organisations/OrganisationUser.cs
@@ -38,7 +38,13 @@ public class OrganisationUser
public UserOrganisationRole Role { get; init; }
}
+///
+/// Top Level model for organisation user requests.
+///
public class OrganisationUsersTopLevel
{
+ ///
+ /// A list of Organisation Users.
+ ///
public IReadOnlyList? Users { get; init; }
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/Pagination/PaginatedResponseModel.cs b/src/Enclave.Sdk/Data/Pagination/PaginatedResponseModel.cs
index 6018bb9..17e9de4 100644
--- a/src/Enclave.Sdk/Data/Pagination/PaginatedResponseModel.cs
+++ b/src/Enclave.Sdk/Data/Pagination/PaginatedResponseModel.cs
@@ -9,15 +9,15 @@ public class PaginatedResponseModel
///
/// Metadata for the paginated data.
///
- public PaginationMetadata Metadata { get; init; }
+ public PaginationMetadata Metadata { get; init; } = default!;
///
/// The related links for the current page of data.
///
- public PaginationLinks Links { get; init; }
+ public PaginationLinks Links { get; init; } = default!;
///
/// The requested page of items.
///
- public IEnumerable Items { get; init; }
+ public IEnumerable Items { get; init; } = default!;
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/Pagination/PaginationLinks.cs b/src/Enclave.Sdk/Data/Pagination/PaginationLinks.cs
index d72c346..4445eae 100644
--- a/src/Enclave.Sdk/Data/Pagination/PaginationLinks.cs
+++ b/src/Enclave.Sdk/Data/Pagination/PaginationLinks.cs
@@ -8,7 +8,7 @@ public class PaginationLinks
///
/// The first page of data.
///
- public Uri First { get; init; }
+ public Uri? First { get; init; }
///
/// The previous page of data (or null if this is the first page).
@@ -23,5 +23,5 @@ public class PaginationLinks
///
/// The last page of data.
///
- public Uri Last { get; init; }
+ public Uri? Last { get; init; }
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/PatchBuilder.cs b/src/Enclave.Sdk/Data/PatchBuilder.cs
index 531a67e..d6e3d29 100644
--- a/src/Enclave.Sdk/Data/PatchBuilder.cs
+++ b/src/Enclave.Sdk/Data/PatchBuilder.cs
@@ -1,5 +1,5 @@
-using Enclave.Sdk.Api.Data.PatchModel;
-using System.Linq.Expressions;
+using System.Linq.Expressions;
+using Enclave.Sdk.Api.Data.PatchModel;
namespace Enclave.Sdk.Api.Data;
diff --git a/src/Enclave.Sdk/Data/PatchModel/SystemPatch.cs b/src/Enclave.Sdk/Data/PatchModel/EnrolledSystemPatch.cs
similarity index 85%
rename from src/Enclave.Sdk/Data/PatchModel/SystemPatch.cs
rename to src/Enclave.Sdk/Data/PatchModel/EnrolledSystemPatch.cs
index e309b1a..78d2287 100644
--- a/src/Enclave.Sdk/Data/PatchModel/SystemPatch.cs
+++ b/src/Enclave.Sdk/Data/PatchModel/EnrolledSystemPatch.cs
@@ -3,7 +3,7 @@
///
/// Defines the modifiable properties of a system.
///
-public class SystemPatch : IPatchModel
+public class EnrolledSystemPatch : IPatchModel
{
///
/// The system description.
@@ -18,7 +18,7 @@ public class SystemPatch : IPatchModel
///
/// The set of tags applied to the system.
///
- public string[]? Tags { get; set; }
+ public IReadOnlyList? Tags { get; set; }
///
/// Any notes or additional info for this system.
diff --git a/src/Enclave.Sdk/Data/PatchModel/EnrolmentKeyPatch.cs b/src/Enclave.Sdk/Data/PatchModel/EnrolmentKeyPatch.cs
new file mode 100644
index 0000000..ecf2476
--- /dev/null
+++ b/src/Enclave.Sdk/Data/PatchModel/EnrolmentKeyPatch.cs
@@ -0,0 +1,51 @@
+using Enclave.Sdk.Api.Data.EnrolmentKeys;
+using Enclave.Sdk.Api.Data.EnrolmentKeys.Enum;
+
+namespace Enclave.Sdk.Api.Data.PatchModel;
+
+///
+/// Defines the modifiable properties of an enrolment key.
+///
+public class EnrolmentKeyPatchModel : IPatchModel
+{
+ ///
+ /// The description for the key.
+ ///
+ public string? Description { get; set; }
+
+ ///
+ /// Whether the key is enabled (meaning it can be used) or disabled.
+ ///
+ public bool? IsEnabled { get; set; }
+
+ ///
+ /// The approval mode for the key, manual (default) or automatic.
+ ///
+ public ApprovalMode? ApprovalMode { get; set; }
+
+ ///
+ /// The number of uses remaining the key should have. A value of -1 indicates no limit on the number of uses.
+ ///
+ public int? UsesRemaining { get; set; }
+
+ ///
+ /// The set of IP Address constraints on the key.
+ ///
+ public IReadOnlyList? IpConstraints { get; set; }
+
+ ///
+ /// A set of tags automatically applied to systems enrolled with this key.
+ ///
+ public List Tags { get; set; } = new List();
+
+ ///
+ /// Defines the number of minutes an ephemeral system enrolled with this key will be retained after a non-graceful disconnect.
+ /// Only valid when key type is 'Ephemeral'.
+ ///
+ public int? DisconnectedRetentionMinutes { get; set; }
+
+ ///
+ /// Any notes or additional info for this key.
+ ///
+ public string? Notes { get; set; }
+}
diff --git a/src/Enclave.Sdk/Data/PatchModel/IPatchModel.cs b/src/Enclave.Sdk/Data/PatchModel/IPatchModel.cs
index 96e0059..2b3f768 100644
--- a/src/Enclave.Sdk/Data/PatchModel/IPatchModel.cs
+++ b/src/Enclave.Sdk/Data/PatchModel/IPatchModel.cs
@@ -1,5 +1,9 @@
namespace Enclave.Sdk.Api.Data.PatchModel;
+///
+/// An interface for use with a PatchBuilder.
+///
+[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1040:Avoid empty interfaces", Justification = "Useful for using PatchBuilder")]
public interface IPatchModel
{
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs b/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs
index 4cb526a..53479d8 100644
--- a/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs
+++ b/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs
@@ -1,4 +1,4 @@
-using Enclave.Sdk.Api.Data.Policy;
+using Enclave.Sdk.Api.Data.Policies;
namespace Enclave.Sdk.Api.Data.PatchModel;
@@ -20,17 +20,17 @@ public class PolicyPatch : IPatchModel
///
/// A set of sender tags.
///
- public string[]? SenderTags { get; set; }
+ public IReadOnlyList? SenderTags { get; set; }
///
/// A set of receiver tags.
///
- public string[]? ReceiverTags { get; set; }
+ public IReadOnlyList? ReceiverTags { get; set; }
///
/// The set of ACLs for the policy.
///
- public PolicyAclModel[]? Acls { get; set; }
+ public IReadOnlyList? Acls { get; set; }
///
/// Notes for the policy.
diff --git a/src/Enclave.Sdk/Data/PatchModel/UnapprovedSystemPatch.cs b/src/Enclave.Sdk/Data/PatchModel/UnapprovedSystemPatch.cs
new file mode 100644
index 0000000..6d5c829
--- /dev/null
+++ b/src/Enclave.Sdk/Data/PatchModel/UnapprovedSystemPatch.cs
@@ -0,0 +1,22 @@
+namespace Enclave.Sdk.Api.Data.PatchModel;
+
+///
+/// Patch model containing properties that can be updated.
+///
+public class UnapprovedSystemPatch : IPatchModel
+{
+ ///
+ /// The system description.
+ ///
+ public string? Description { get; set; }
+
+ ///
+ /// The set of tags applied to the system.
+ ///
+ public IReadOnlyList? Tags { get; set; }
+
+ ///
+ /// Any notes or additional info for this system.
+ ///
+ public string? Notes { get; set; }
+}
diff --git a/src/Enclave.Sdk/Data/Policies/BulkPolicyDeleteResult.cs b/src/Enclave.Sdk/Data/Policies/BulkPolicyDeleteResult.cs
new file mode 100644
index 0000000..89691a3
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Policies/BulkPolicyDeleteResult.cs
@@ -0,0 +1,12 @@
+namespace Enclave.Sdk.Api.Data.Policies;
+
+///
+/// Model for the result of a policy bulk delete operation.
+///
+public class BulkPolicyDeleteResult
+{
+ ///
+ /// The number of policies successfully deleted.
+ ///
+ public int PoliciesDeleted { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/Policies/BulkPolicyUpdateResult.cs b/src/Enclave.Sdk/Data/Policies/BulkPolicyUpdateResult.cs
new file mode 100644
index 0000000..024991a
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Policies/BulkPolicyUpdateResult.cs
@@ -0,0 +1,12 @@
+namespace Enclave.Sdk.Api.Data.Policies;
+
+///
+/// Defines the result of a bulk policy update.
+///
+public class BulkPolicyUpdateResult
+{
+ ///
+ /// The number of policies successfully updated.
+ ///
+ public int PoliciesUpdated { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs b/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs
new file mode 100644
index 0000000..a4d7bed
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs
@@ -0,0 +1,27 @@
+namespace Enclave.Sdk.Api.Data.Policies.Enum;
+
+///
+/// Defines the known protocols enforced in policy ACLs.
+///
+public enum PolicyAclProtocol
+{
+ ///
+ /// Any Protocol.
+ ///
+ Any,
+
+ ///
+ /// Tcp.
+ ///
+ Tcp,
+
+ ///
+ /// Udp.
+ ///
+ Udp,
+
+ ///
+ /// Icmp.
+ ///
+ Icmp,
+}
diff --git a/src/Enclave.Sdk/Data/Policies/Enum/PolicySortOrder.cs b/src/Enclave.Sdk/Data/Policies/Enum/PolicySortOrder.cs
new file mode 100644
index 0000000..c46565d
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Policies/Enum/PolicySortOrder.cs
@@ -0,0 +1,17 @@
+namespace Enclave.Sdk.Api.Data.Policies.Enum;
+
+///
+/// The sort order when making a Policy Request.
+///
+public enum PolicySortOrder
+{
+ ///
+ /// Sort by description.
+ ///
+ Description,
+
+ ///
+ /// Sort by recently created.
+ ///
+ RecentlyCreated,
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/Policies/Enum/PolicyState.cs b/src/Enclave.Sdk/Data/Policies/Enum/PolicyState.cs
new file mode 100644
index 0000000..dc83d13
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Policies/Enum/PolicyState.cs
@@ -0,0 +1,22 @@
+namespace Enclave.Sdk.Api.Data.Policies.Enum;
+
+///
+/// Defines the possible states of policies.
+///
+public enum PolicyState
+{
+ ///
+ /// Policy is disabled.
+ ///
+ Disabled,
+
+ ///
+ /// Policy is active.
+ ///
+ Active,
+
+ ///
+ /// Policy is enabled, but no traffic will flow, due to the lack of ACLs.
+ ///
+ InactiveNoAcls,
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/Policies/Policy.cs b/src/Enclave.Sdk/Data/Policies/Policy.cs
new file mode 100644
index 0000000..d1bc32f
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Policies/Policy.cs
@@ -0,0 +1,55 @@
+using Enclave.Sdk.Api.Data.Policies.Enum;
+using Enclave.Sdk.Api.Data.Tags;
+
+namespace Enclave.Sdk.Api.Data.Policies;
+
+///
+/// Represents a single policy.
+///
+public class Policy
+{
+ ///
+ /// The ID of the policy.
+ ///
+ public PolicyId Id { get; init; }
+
+ ///
+ /// The UTC timestamp when the policy was created.
+ ///
+ public DateTime Created { get; init; }
+
+ ///
+ /// The provided description of the policy.
+ ///
+ public string Description { get; init; } = default!;
+
+ ///
+ /// Whether or not this policy is enabled.
+ ///
+ public bool IsEnabled { get; init; }
+
+ ///
+ /// Indicates the state of the policy.
+ ///
+ public PolicyState State { get; init; }
+
+ ///
+ /// The sender-side tags.
+ ///
+ public IReadOnlyList SenderTags { get; init; } = Array.Empty();
+
+ ///
+ /// The receiver-side tags.
+ ///
+ public IReadOnlyList ReceiverTags { get; init; } = Array.Empty();
+
+ ///
+ /// Access control lists.
+ ///
+ public IReadOnlyList Acls { get; init; } = Array.Empty();
+
+ ///
+ /// Optional notes for the policy.
+ ///
+ public string? Notes { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/Policy/PolicyAclModel.cs b/src/Enclave.Sdk/Data/Policies/PolicyAcl.cs
similarity index 55%
rename from src/Enclave.Sdk/Data/Policy/PolicyAclModel.cs
rename to src/Enclave.Sdk/Data/Policies/PolicyAcl.cs
index 95ec7e5..82423d1 100644
--- a/src/Enclave.Sdk/Data/Policy/PolicyAclModel.cs
+++ b/src/Enclave.Sdk/Data/Policies/PolicyAcl.cs
@@ -1,22 +1,24 @@
-namespace Enclave.Sdk.Api.Data.Policy;
+using Enclave.Sdk.Api.Data.Policies.Enum;
+
+namespace Enclave.Sdk.Api.Data.Policies;
///
/// Model representing a single ACL entry for a policy.
///
-public class PolicyAclModel
+public class PolicyAcl
{
///
/// The protocol.
///
- public PolicyAclProtocol Protocol { get; set; }
+ public PolicyAclProtocol Protocol { get; init; }
///
/// The port range (or single port) for the ACL.
///
- public string? Ports { get; set; }
+ public string? Ports { get; init; }
///
/// An optional description.
///
- public string? Description { get; set; }
+ public string? Description { get; init; }
}
diff --git a/src/Enclave.Sdk/Data/Policies/PolicyCreate.cs b/src/Enclave.Sdk/Data/Policies/PolicyCreate.cs
new file mode 100644
index 0000000..bf5f99b
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Policies/PolicyCreate.cs
@@ -0,0 +1,40 @@
+using System.ComponentModel;
+
+namespace Enclave.Sdk.Api.Data.Policies;
+
+///
+/// Data required to create a new policy.
+///
+public class PolicyCreate
+{
+ ///
+ /// A description for the policy you are creating.
+ ///
+ public string Description { get; set; } = default!;
+
+ ///
+ /// Whether or not the policy is initially enabled.
+ ///
+ [DefaultValue(true)]
+ public bool IsEnabled { get; set; } = true;
+
+ ///
+ /// A set of sender tags.
+ ///
+ public List SenderTags { get; set; } = new List();
+
+ ///
+ /// A set of receiver tags.
+ ///
+ public List ReceiverTags { get; set; } = new List();
+
+ ///
+ /// The set of ACLs for the policy.
+ ///
+ public List Acls { get; set; } = new List();
+
+ ///
+ /// Optional notes for the policy.
+ ///
+ public string? Notes { get; set; }
+}
diff --git a/src/Enclave.Sdk/Data/Policies/PolicyId.cs b/src/Enclave.Sdk/Data/Policies/PolicyId.cs
new file mode 100644
index 0000000..6f8e191
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Policies/PolicyId.cs
@@ -0,0 +1,11 @@
+using TypedIds;
+
+namespace Enclave.Sdk.Api.Data.Policies;
+
+///
+/// An int backed Policy Id.
+///
+[TypedId(IdBackingType.Int)]
+public partial struct PolicyId
+{
+}
diff --git a/src/Enclave.Sdk/Data/Policy/PolicyAclProtocol.cs b/src/Enclave.Sdk/Data/Policy/PolicyAclProtocol.cs
deleted file mode 100644
index aeba45d..0000000
--- a/src/Enclave.Sdk/Data/Policy/PolicyAclProtocol.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Enclave.Sdk.Api.Data.Policy;
-
-public enum PolicyAclProtocol
-{
- Any,
- Tcp,
- Udp,
- Icmp
-}
diff --git a/src/Enclave.Sdk/Data/SystemId.cs b/src/Enclave.Sdk/Data/SystemId.cs
new file mode 100644
index 0000000..4156752
--- /dev/null
+++ b/src/Enclave.Sdk/Data/SystemId.cs
@@ -0,0 +1,11 @@
+using TypedIds;
+
+namespace Enclave.Sdk.Api.Data;
+
+///
+/// A String backed System Id.
+///
+[TypedId(IdBackingType.String)]
+public partial struct SystemId
+{
+}
diff --git a/src/Enclave.Sdk/Data/SystemManagement/SystemReference.cs b/src/Enclave.Sdk/Data/SystemManagement/SystemReference.cs
new file mode 100644
index 0000000..fa24d19
--- /dev/null
+++ b/src/Enclave.Sdk/Data/SystemManagement/SystemReference.cs
@@ -0,0 +1,39 @@
+using Enclave.Sdk.Api.Data.EnrolledSystems.Enum;
+
+namespace Enclave.Sdk.Api.Data.SystemManagement;
+
+///
+/// Defines a system reference model.
+///
+public class SystemReference
+{
+ ///
+ /// Contains the last connected IP of the system.
+ ///
+ public string? ConnectedFrom { get; init; }
+
+ ///
+ /// The System ID.
+ ///
+ public string Id { get; init; } = default!;
+
+ ///
+ /// The local hostname of the system (if known).
+ ///
+ public string? MachineName { get; init; }
+
+ ///
+ /// The set name of the system (if one was provided).
+ ///
+ public string? Name { get; init; }
+
+ ///
+ /// The System platform type (if known).
+ ///
+ public string? PlatformType { get; init; }
+
+ ///
+ /// The state of the system.
+ ///
+ public SystemState State { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/Tags/TagQuerySortOrder.cs b/src/Enclave.Sdk/Data/Tags/TagQuerySortOrder.cs
index d44057f..13c6d99 100644
--- a/src/Enclave.Sdk/Data/Tags/TagQuerySortOrder.cs
+++ b/src/Enclave.Sdk/Data/Tags/TagQuerySortOrder.cs
@@ -1,8 +1,22 @@
namespace Enclave.Sdk.Api.Data.Tags;
+///
+/// The sort order used for a Tag Query.
+///
public enum TagQuerySortOrder
{
+ ///
+ /// Sort Alphabetically.
+ ///
Alphabetical,
+
+ ///
+ /// Sort by recently used Tags.
+ ///
RecentlyUsed,
+
+ ///
+ /// Sort by number of Referenced Systems.
+ ///
ReferencedSystems,
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/Tags/TagReference.cs b/src/Enclave.Sdk/Data/Tags/TagReference.cs
new file mode 100644
index 0000000..fe5038d
--- /dev/null
+++ b/src/Enclave.Sdk/Data/Tags/TagReference.cs
@@ -0,0 +1,12 @@
+namespace Enclave.Sdk.Api.Data.Tags;
+
+///
+/// A referenced tag.
+///
+public class TagReference
+{
+ ///
+ /// The tag name.
+ ///
+ public string Tag { get; init; } = default!;
+}
diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/BulkUnapprovedSystemApproveResult.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/BulkUnapprovedSystemApproveResult.cs
new file mode 100644
index 0000000..c7fee7d
--- /dev/null
+++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/BulkUnapprovedSystemApproveResult.cs
@@ -0,0 +1,12 @@
+namespace Enclave.Sdk.Api.Data.UnaprrovedSystems;
+
+///
+/// The result of a bulk unapproved system approve operation.
+///
+public class BulkUnapprovedSystemApproveResult
+{
+ ///
+ /// The number of systems approved.
+ ///
+ public int SystemsApproved { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/BulkUnapprovedSystemDeclineResult.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/BulkUnapprovedSystemDeclineResult.cs
new file mode 100644
index 0000000..106bdd3
--- /dev/null
+++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/BulkUnapprovedSystemDeclineResult.cs
@@ -0,0 +1,12 @@
+namespace Enclave.Sdk.Api.Data.UnaprrovedSystems;
+
+ ///
+ /// The result of a bulk unapproved system decline operation.
+ ///
+public class BulkUnapprovedSystemDeclineResult
+{
+ ///
+ /// The number of systems declined.
+ ///
+ public int SystemsDeclined { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/SystemType.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/SystemType.cs
new file mode 100644
index 0000000..a69868d
--- /dev/null
+++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/SystemType.cs
@@ -0,0 +1,19 @@
+namespace Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum;
+
+///
+/// Defines the types of Enrolment Keys.
+///
+public enum SystemType
+{
+ ///
+ /// For workstations, laptops, servers, and other systems that are relatively long-lived or manually provisioned.
+ /// Systems remain in your Enclave Organisation if they stop running.
+ ///
+ GeneralPurpose,
+
+ ///
+ /// For containers, kubernetes pods, and other systems that are temporary, short-lived or automatically provisioned.
+ /// Systems are automatically removed from your Enclave Organisation when they stop/disconnect.
+ ///
+ Ephemeral,
+}
diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/UnapprovedSystemQuerySortMode.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/UnapprovedSystemQuerySortMode.cs
new file mode 100644
index 0000000..1453ff3
--- /dev/null
+++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/UnapprovedSystemQuerySortMode.cs
@@ -0,0 +1,22 @@
+namespace Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum;
+
+///
+/// Sort modes for unapproved systems.
+///
+public enum UnapprovedSystemQuerySortMode
+{
+ ///
+ /// Sort by the when the system was enrolled (most recent first).
+ ///
+ RecentlyEnrolled,
+
+ ///
+ /// Sort by the system description.
+ ///
+ Description,
+
+ ///
+ /// Sort by the name of enrolment key used.
+ ///
+ EnrolmentKeyUsed,
+}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs
new file mode 100644
index 0000000..5a4aa06
--- /dev/null
+++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs
@@ -0,0 +1,80 @@
+using Enclave.Sdk.Api.Data.Tags;
+using Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum;
+
+namespace Enclave.Sdk.Api.Data.UnaprrovedSystems;
+
+///
+/// Model representing an unapproved system.
+///
+public class UnapprovedSystem
+{
+ ///
+ /// The system ID.
+ ///
+ public SystemId SystemId { get; init; } = default!;
+
+ ///
+ /// The system type.
+ ///
+ public SystemType Type { get; init; }
+
+ ///
+ /// The system description (if one has been provided).
+ ///
+ public string? Description { get; init; }
+
+ ///
+ /// The IP address the system was enrolled from.
+ ///
+ public string EnrolledFrom { get; init; } = default!;
+
+ ///
+ /// The UTC timestamp when the system was enrolled.
+ ///
+ public DateTime EnrolledAt { get; init; }
+
+ ///
+ /// The set of tags assigned to the system (either manually or automatically from the key).
+ ///
+ public IReadOnlyList Tags { get; init; } = Array.Empty();
+
+ ///
+ /// The ID of the enrolment key used to enrol the system.
+ ///
+ public int EnrolmentKeyId { get; init; }
+
+ ///
+ /// The description of the enrolment key used to enrol the system.
+ ///
+ public string EnrolmentKeyDescription { get; init; } = default!;
+
+ ///
+ /// Any additional notes for the system.
+ ///
+ public string? Notes { get; init; }
+
+ ///
+ /// The locally-defined host name of the system.
+ ///
+ public string? Hostname { get; init; }
+
+ ///
+ /// The platform type for this system; possible values are Windows, Linux or MacOSX.
+ ///
+ public string? PlatformType { get; init; }
+
+ ///
+ /// The version of the operating system.
+ ///
+ public string? OSVersion { get; init; }
+
+ ///
+ /// The Enclave product version.
+ ///
+ public string? EnclaveVersion { get; init; }
+
+ ///
+ /// The IP address the system is connected from.
+ ///
+ public string? ConnectedFrom { get; init; }
+}
diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemSummary.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemSummary.cs
new file mode 100644
index 0000000..148bd73
--- /dev/null
+++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemSummary.cs
@@ -0,0 +1,75 @@
+using Enclave.Sdk.Api.Data.Tags;
+using Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum;
+
+namespace Enclave.Sdk.Api.Data.UnaprrovedSystems;
+
+///
+/// Model representing an unapproved system.
+///
+public class UnapprovedSystemSummary
+{
+ ///
+ /// The system ID.
+ ///
+ public SystemId SystemId { get; init; } = default!;
+
+ ///
+ /// The system type.
+ ///
+ public SystemType Type { get; init; }
+
+ ///
+ /// The system description (if one has been provided).
+ ///
+ public string? Description { get; init; }
+
+ ///
+ /// The IP address the system was enrolled from.
+ ///
+ public string EnrolledFrom { get; init; } = default!;
+
+ ///
+ /// The UTC timestamp when the system was enrolled.
+ ///
+ public DateTime EnrolledAt { get; init; }
+
+ ///
+ /// The set of tags assigned to the system (either manually or automatically from the key).
+ ///
+ public IReadOnlyList Tags { get; init; } = Array.Empty();
+
+ ///
+ /// The ID of the enrolment key used to enrol the system.
+ ///
+ public int EnrolmentKeyId { get; init; }
+
+ ///
+ /// The description of the enrolment key used to enrol the system.
+ ///
+ public string? EnrolmentKeyDescription { get; init; }
+
+ ///
+ /// The locally-defined host name of the system.
+ ///
+ public string? Hostname { get; init; }
+
+ ///
+ /// The platform type for this system; possible values are Windows, Linux or MacOSX.
+ ///
+ public string? PlatformType { get; init; }
+
+ ///
+ /// The version of the operating system.
+ ///
+ public string? OSVersion { get; init; }
+
+ ///
+ /// The Enclave product version.
+ ///
+ public string? EnclaveVersion { get; init; }
+
+ ///
+ /// The IP address the system is connected from.
+ ///
+ public string? ConnectedFrom { get; init; }
+}
diff --git a/src/Enclave.Sdk/Enclave.Sdk.Api.csproj b/src/Enclave.Sdk/Enclave.Sdk.Api.csproj
index 3e9595c..cfeb246 100644
--- a/src/Enclave.Sdk/Enclave.Sdk.Api.csproj
+++ b/src/Enclave.Sdk/Enclave.Sdk.Api.csproj
@@ -17,8 +17,12 @@
-
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
diff --git a/src/Enclave.Sdk/EnclaveClient.cs b/src/Enclave.Sdk/EnclaveClient.cs
index f4972b0..0ad177a 100644
--- a/src/Enclave.Sdk/EnclaveClient.cs
+++ b/src/Enclave.Sdk/EnclaveClient.cs
@@ -4,7 +4,6 @@
using System.Text.Json;
using Enclave.Sdk.Api.Clients;
using Enclave.Sdk.Api.Clients.Interfaces;
-using Enclave.Sdk.Api.Data;
using Enclave.Sdk.Api.Data.Account;
using Enclave.Sdk.Api.Handlers;
@@ -64,7 +63,7 @@ public EnclaveClient(EnclaveClientOptions options)
///
/// List of organisation containing the OrgId and Name and the users role in that organisation.
/// throws when the Api returns a null response.
- public async Task> GetOrganisationsAsync()
+ public async Task> GetOrganisationsAsync()
{
var organisations = await _httpClient.GetFromJsonAsync("/account/orgs", Constants.JsonSerializerOptions);
@@ -86,7 +85,7 @@ public IOrganisationClient CreateOrganisationClient(AccountOrganisation organisa
return new OrganisationClient(_httpClient, organisation);
}
- private EnclaveClientOptions? GetSettingsFile()
+ private static EnclaveClientOptions? GetSettingsFile()
{
var userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
@@ -105,6 +104,7 @@ public IOrganisationClient CreateOrganisationClient(AccountOrganisation organisa
}
}
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "Needed for lifecycle of consumer")]
private static HttpClient SetupHttpClient(EnclaveClientOptions options)
{
var httpClient = new HttpClient(new ProblemDetailsHttpMessageHandler())
diff --git a/src/Enclave.Sdk/EnclaveClientOptions.cs b/src/Enclave.Sdk/EnclaveClientOptions.cs
index 54c7d55..b1d48fd 100644
--- a/src/Enclave.Sdk/EnclaveClientOptions.cs
+++ b/src/Enclave.Sdk/EnclaveClientOptions.cs
@@ -1,6 +1,4 @@
-using System.Text.Json.Serialization;
-
-namespace Enclave.Sdk.Api;
+namespace Enclave.Sdk.Api;
///
/// A representation of options used when creating .
diff --git a/src/Enclave.Sdk/Exceptions/ProblemDetails.cs b/src/Enclave.Sdk/Exceptions/ProblemDetails.cs
index 26f044a..8c8edce 100644
--- a/src/Enclave.Sdk/Exceptions/ProblemDetails.cs
+++ b/src/Enclave.Sdk/Exceptions/ProblemDetails.cs
@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Text.Json.Serialization;
-using System.Threading.Tasks;
+using System.Text.Json.Serialization;
namespace Enclave.Sdk.Api.Exceptions;
diff --git a/src/Enclave.Sdk/Exceptions/ProblemDetailsException.cs b/src/Enclave.Sdk/Exceptions/ProblemDetailsException.cs
index af74bfc..676c931 100644
--- a/src/Enclave.Sdk/Exceptions/ProblemDetailsException.cs
+++ b/src/Enclave.Sdk/Exceptions/ProblemDetailsException.cs
@@ -1,15 +1,29 @@
namespace Enclave.Sdk.Api.Exceptions;
-internal class ProblemDetailsException : Exception
+///
+/// An Exception to display the details of an Http Problem Details.
+///
+public class ProblemDetailsException : Exception
{
+ ///
+ /// The Problem Details.
+ ///
public ProblemDetails ProblemDetails { get; }
+ ///
+ /// The HttpResponse message.
+ ///
public HttpResponseMessage Response { get; }
+ ///
+ /// Constructor for setting up the problem details exception.
+ ///
+ /// The problem details from the HTTP response.
+ /// The HTTP Response message.
public ProblemDetailsException(ProblemDetails problemDetails, HttpResponseMessage response)
- : base(problemDetails.Title)
+ : base(problemDetails?.Title)
{
- ProblemDetails = problemDetails;
+ ProblemDetails = problemDetails!;
Response = response;
}
}
\ No newline at end of file
diff --git a/src/Enclave.Sdk/Exceptions/ProblemDetailsJsonConverter.cs b/src/Enclave.Sdk/Exceptions/ProblemDetailsJsonConverter.cs
index 380c8ae..2fea2e4 100644
--- a/src/Enclave.Sdk/Exceptions/ProblemDetailsJsonConverter.cs
+++ b/src/Enclave.Sdk/Exceptions/ProblemDetailsJsonConverter.cs
@@ -1,11 +1,6 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using System.Text;
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization;
-using System.Threading.Tasks;
namespace Enclave.Sdk.Api.Exceptions;
diff --git a/src/Enclave.Sdk/Handlers/ProblemDetailsHttpMessageHandler.cs b/src/Enclave.Sdk/Handlers/ProblemDetailsHttpMessageHandler.cs
index 5bbedfb..b063236 100644
--- a/src/Enclave.Sdk/Handlers/ProblemDetailsHttpMessageHandler.cs
+++ b/src/Enclave.Sdk/Handlers/ProblemDetailsHttpMessageHandler.cs
@@ -7,7 +7,9 @@ internal sealed class ProblemDetailsHttpMessageHandler : DelegatingHandler
{
public ProblemDetailsHttpMessageHandler()
#pragma warning disable CA2000 // Dispose objects before losing scope
- : base(new HttpClientHandler()) { }
+ : base(new HttpClientHandler())
+ {
+ }
#pragma warning restore CA2000 // Dispose objects before losing scope
protected override async Task SendAsync(HttpRequestMessage request, CancellationToken ct)
diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs
new file mode 100644
index 0000000..86ae32d
--- /dev/null
+++ b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs
@@ -0,0 +1,559 @@
+using Enclave.Sdk.Api.Clients;
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.Dns;
+using Enclave.Sdk.Api.Data.Organisations;
+using Enclave.Sdk.Api.Data.Pagination;
+using Enclave.Sdk.Api.Data.PatchModel;
+using FluentAssertions;
+using NUnit.Framework;
+using System.Text.Json;
+using WireMock.FluentAssertions;
+using WireMock.RequestBuilders;
+using WireMock.ResponseBuilders;
+using WireMock.Server;
+
+namespace Enclave.Sdk.Api.Tests.Clients;
+
+public class DnsClientTests
+{
+ private DnsClient _dnsClient;
+ private WireMockServer _server;
+ private string _orgRoute;
+ private JsonSerializerOptions _serializerOptions = new()
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ };
+
+ [SetUp]
+ public void Setup()
+ {
+ _server = WireMockServer.Start();
+
+ var httpClient = new HttpClient
+ {
+ BaseAddress = new Uri(_server.Urls[0]),
+ };
+
+ var organisationId = OrganisationId.New();
+ _orgRoute = $"/org/{organisationId}";
+
+ _dnsClient = new DnsClient(httpClient, $"org/{organisationId}");
+ }
+
+ [Test]
+ public async Task Should_return_a_Dns_summary_when_calling_GetPropertiesSummaryAsync()
+ {
+ // Arrange
+ var response = new DnsSummary
+ {
+ TotalRecordCount = 12,
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _dnsClient.GetPropertiesSummaryAsync();
+
+ // Assert
+ result.TotalRecordCount.Should().Be(response.TotalRecordCount);
+ }
+
+ [Test]
+ public async Task Should_return_a_paginated_response_model_when_calling_GetZonesAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new DnsZoneSummary { Name = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/zones").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _dnsClient.GetZonesAsync();
+
+ // Assert
+ result.Should().NotBeNull();
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_page_quertString_when_calling_GetZonesAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new DnsZoneSummary { Name = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/zones").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var page = 12;
+
+ // Act
+ await _dnsClient.GetZonesAsync(pageNumber: page);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/dns/zones?page={page}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_per_page_quertString_when_calling_GetZonesAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new DnsZoneSummary { Name = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/zones").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var page = 12;
+
+ // Act
+ await _dnsClient.GetZonesAsync(perPage: page);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/dns/zones?per_page={page}");
+ }
+
+ [Test]
+ public async Task Should_return_a_full_dns_zone_when_calling_CreateZoneAsync()
+ {
+ // Arrange
+ var response = new DnsZone
+ {
+ Id = DnsZoneId.FromInt(123),
+ Name = "test",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/zones").UsingPost())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _dnsClient.CreateZoneAsync(new DnsZoneCreate());
+
+ // Assert
+ result.Should().NotBeNull();
+ result.Name.Should().Be(response.Name);
+ }
+
+ [Test]
+ public async Task Should_return_a_full_dns_zone_when_calling_GetZoneAsync()
+ {
+ // Arrange
+ var response = new DnsZone
+ {
+ Id = DnsZoneId.FromInt(123),
+ Name = "test",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/zones/{123}").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _dnsClient.GetZoneAsync(DnsZoneId.FromInt(123));
+
+ // Assert
+ result.Should().NotBeNull();
+ result.Name.Should().Be(response.Name);
+ }
+
+ [Test]
+ public async Task Should_return_a_full_dns_zone_when_calling_UpdateZoneAsync()
+ {
+ // Arrange
+ var response = new DnsZone
+ {
+ Id = DnsZoneId.FromInt(123),
+ Name = "New Name",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/zones/{123}").UsingPatch())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var builder = new PatchBuilder().Set(d => d.Name, "New Name");
+
+ // Act
+ var result = await _dnsClient.UpdateZoneAsync(DnsZoneId.FromInt(123), builder);
+
+ // Assert
+ result.Should().NotBeNull();
+ result.Name.Should().Be(response.Name);
+ }
+
+ [Test]
+ public async Task Should_return_a_full_dns_zone_when_calling_DeleteZoneAsync()
+ {
+ // Arrange
+ var response = new DnsZone
+ {
+ Id = DnsZoneId.FromInt(123),
+ Name = "New Name",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/zones/{123}").UsingDelete())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _dnsClient.DeleteZoneAsync(DnsZoneId.FromInt(123));
+
+ // Assert
+ result.Should().NotBeNull();
+ result.Name.Should().Be(response.Name);
+ }
+
+ [Test]
+ public async Task Should_return_a_paginated_response_model_when_calling_GetRecordsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new DnsRecordSummary { Name = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/records").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _dnsClient.GetRecordsAsync();
+
+ // Assert
+ result.Should().NotBeNull();
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_zoneId_quertString_when_calling_GetRecordsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new DnsRecordSummary { Name = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/records").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var zonedId = DnsZoneId.FromInt(12);
+
+ // Act
+ await _dnsClient.GetRecordsAsync(dnsZoneId: zonedId);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/dns/records?zoneId={zonedId}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_hostname_quertString_when_calling_GetRecordsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new DnsRecordSummary { Name = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/records").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var hostname = "name";
+
+ // Act
+ await _dnsClient.GetRecordsAsync(hostname: hostname);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/dns/records?hostname={hostname}");
+ }
+
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_page_quertString_when_calling_GetRecordsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new DnsRecordSummary { Name = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/records").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var page = 12;
+
+ // Act
+ await _dnsClient.GetRecordsAsync(pageNumber: page);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/dns/records?page={page}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_per_page_quertString_when_calling_GetRecordsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new DnsRecordSummary { Name = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/records").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var page = 12;
+
+ // Act
+ await _dnsClient.GetRecordsAsync(perPage: page);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/dns/records?per_page={page}");
+ }
+
+ [Test]
+ public async Task Should_return_a_full_dns_record_model_when_calling_CreateRecordAsync()
+ {
+ // Arrange
+ var response = new DnsRecord
+ {
+ Id = DnsRecordId.FromInt(123),
+ Name = "Name",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/records").UsingPost())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var createModel = new DnsRecordCreate
+ {
+ Name = "Name",
+ };
+
+ // Act
+ var result = await _dnsClient.CreateRecordAsync(createModel);
+
+ // Assert
+ result.Should().NotBeNull();
+ result.Id.Should().Be(response.Id);
+ }
+
+ [Test]
+ public async Task Should_return_number_of_deleted_records_when_calling_DeleteRecordsAsync()
+ {
+ // Arrange
+ var response = new BulkDnsRecordDeleteResult
+ {
+ DnsRecordsDeleted = 3,
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/records").UsingDelete())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var records = new DnsRecordId[] { DnsRecordId.FromInt(1), DnsRecordId.FromInt(2), DnsRecordId.FromInt(3) };
+
+
+ // Act
+ var result = await _dnsClient.DeleteRecordsAsync(records);
+
+ // Assert
+ result.Should().Be(3);
+ }
+
+ [Test]
+ public async Task Should_return_full_dns_record_when_calling_GetRecordAsync()
+ {
+ // Arrange
+ var id = DnsRecordId.FromInt(123);
+ var response = new DnsRecord
+ {
+ Id = id,
+ Name = "Name",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/records/{id}").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _dnsClient.GetRecordAsync(id);
+
+ // Assert
+ result.Should().NotBeNull();
+ result.Id.Should().Be(id);
+ }
+
+ [Test]
+ public async Task Should_return_full_dns_record_when_calling_UpdateRecordAsync()
+ {
+ // Arrange
+ var id = DnsRecordId.FromInt(123);
+ var response = new DnsRecord
+ {
+ Id = id,
+ Name = "New Name",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/records/{id}").UsingPatch())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var builder = new PatchBuilder().Set(d => d.Name, "New Name");
+
+ // Act
+ var result = await _dnsClient.UpdateRecordAsync(id, builder);
+
+ // Assert
+ result.Should().NotBeNull();
+ result.Name.Should().Be(response.Name);
+ }
+
+
+ [Test]
+ public async Task Should_return_full_dns_record_when_calling_DeleteRecord()
+ {
+ // Arrange
+ var id = DnsRecordId.FromInt(123);
+ var response = new DnsRecord
+ {
+ Id = id,
+ Name = "Name",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/dns/records/{id}").UsingDelete())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _dnsClient.DeleteRecordAsync(id);
+
+ // Assert
+ result.Should().NotBeNull();
+ result.Id.Should().Be(id);
+ }
+}
diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs
new file mode 100644
index 0000000..a5610a2
--- /dev/null
+++ b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs
@@ -0,0 +1,470 @@
+using Enclave.Sdk.Api.Clients;
+using Enclave.Sdk.Api.Data.Account;
+using Enclave.Sdk.Api.Data.EnrolledSystems;
+using Enclave.Sdk.Api.Data.Pagination;
+using FluentAssertions;
+using NUnit.Framework;
+using System.Text.Json;
+using WireMock.RequestBuilders;
+using WireMock.ResponseBuilders;
+using WireMock.Server;
+using WireMock.FluentAssertions;
+using Enclave.Sdk.Api.Data.EnrolledSystems.Enum;
+using Enclave.Sdk.Api.Data.Organisations;
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.PatchModel;
+
+namespace Enclave.Sdk.Api.Tests.Clients;
+
+public class EnrolledSystemClientTests
+{
+ private EnrolledSystemsClient _enrolledSystemsClient;
+ private WireMockServer _server;
+ private string _orgRoute;
+ private JsonSerializerOptions _serializerOptions = new()
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ };
+
+ [SetUp]
+ public void Setup()
+ {
+ _server = WireMockServer.Start();
+
+ var httpClient = new HttpClient
+ {
+ BaseAddress = new Uri(_server.Urls[0]),
+ };
+
+ var organisationId = OrganisationId.New();
+ _orgRoute = $"/org/{organisationId}";
+
+ _enrolledSystemsClient = new EnrolledSystemsClient(httpClient, $"org/{organisationId}");
+ }
+
+ [Test]
+ public async Task Should_return_a_paginated_response_model_when_calling_GetSystemsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new EnrolledSystemSummary { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _enrolledSystemsClient.GetSystemsAsync();
+
+ // Assert
+ result.Should().NotBeNull();
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_enrolment_key_quertString_when_calling_GetSystemsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new EnrolledSystemSummary { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var enrolmentKeyId = 123;
+
+ // Act
+ await _enrolledSystemsClient.GetSystemsAsync(enrolmentKeyId: enrolmentKeyId);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/systems?enrolment_key={enrolmentKeyId}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_search_quertString_when_calling_GetSystemsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new EnrolledSystemSummary { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var searchTerm = "term";
+
+ // Act
+ await _enrolledSystemsClient.GetSystemsAsync(searchTerm: searchTerm);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/systems?search={searchTerm}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_include_disabled_quertString_when_calling_GetSystemsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new EnrolledSystemSummary { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var includeDisabled = true;
+
+ // Act
+ await _enrolledSystemsClient.GetSystemsAsync(includeDisabled: includeDisabled);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/systems?include_disabled={includeDisabled}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_sort_quertString_when_calling_GetSystemsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new EnrolledSystemSummary { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var sortOrder = SystemQuerySortMode.RecentlyConnected;
+
+ // Act
+ await _enrolledSystemsClient.GetSystemsAsync(sortOrder: sortOrder);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/systems?sort={sortOrder}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_dns_quertString_when_calling_GetSystemsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new EnrolledSystemSummary { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var dnsName = "test.dns";
+
+ // Act
+ await _enrolledSystemsClient.GetSystemsAsync(dnsName: dnsName);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/systems?dns={dnsName}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_page_quertString_when_calling_GetSystemsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new EnrolledSystemSummary { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var page = 12;
+
+ // Act
+ await _enrolledSystemsClient.GetSystemsAsync(pageNumber: page);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/systems?page={page}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_per_page_quertString_when_calling_GetSystemsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new EnrolledSystemSummary { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var page = 12;
+
+ // Act
+ await _enrolledSystemsClient.GetSystemsAsync(perPage: page);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/systems?per_page={page}");
+ }
+
+ [Test]
+ public async Task Should_return_number_of_revoked_systems_when_calling_RevokeSystemsAsync()
+ {
+ // Arrange
+ var response = new BulkSystemRevokedResult
+ {
+ SystemsRevoked = 2,
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems").UsingDelete())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _enrolledSystemsClient.RevokeSystemsAsync(SystemId.FromString("asdf"), SystemId.FromString("asdf3"));
+
+ // Assert
+ result.Should().Be(2);
+ }
+
+ [Test]
+ public async Task Should_return_the_updated_system_when_calling_UpdateAsync()
+ {
+ // Arrange
+ var response = new EnrolledSystem
+ {
+ SystemId = SystemId.FromString("system1"),
+ Description = "new description",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems/{response.SystemId}").UsingPatch())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var builder = new PatchBuilder().Set(e => e.Description, "new description");
+
+ // Act
+ var result = await _enrolledSystemsClient.UpdateAsync(response.SystemId, builder);
+
+ // Assert
+ result.Should().NotBeNull();
+ result.Description.Should().Be(response.Description);
+ }
+
+ [Test]
+ public async Task Should_return_the_revoked_system_when_calling_RevokeAsync()
+ {
+ // Arrange
+ var response = new EnrolledSystem
+ {
+ SystemId = SystemId.FromString("system1"),
+ Description = "description",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems/{response.SystemId}").UsingDelete())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _enrolledSystemsClient.RevokeAsync(response.SystemId);
+
+ // Assert
+ result.Should().NotBeNull();
+ result.SystemId.Should().Be(response.SystemId);
+ }
+
+ [Test]
+ public async Task Should_return_the_enabled_system_when_calling_EnableAsync()
+ {
+ // Arrange
+ var response = new EnrolledSystem
+ {
+ SystemId = SystemId.FromString("system1"),
+ Description = "description",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems/{response.SystemId}/enable").UsingPut())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _enrolledSystemsClient.EnableAsync(response.SystemId);
+
+ // Assert
+ result.Should().NotBeNull();
+ result.SystemId.Should().Be(response.SystemId);
+ }
+
+ [Test]
+ public async Task Should_return_the_disabled_system_when_calling_DisableAsync()
+ {
+ // Arrange
+ var response = new EnrolledSystem
+ {
+ SystemId = SystemId.FromString("system1"),
+ Description = "description",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems/{response.SystemId}/disable").UsingPut())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _enrolledSystemsClient.DisableAsync(response.SystemId);
+
+ // Assert
+ result.Should().NotBeNull();
+ result.SystemId.Should().Be(response.SystemId);
+ }
+
+ [Test]
+ public async Task Should_return_number_of_enabled_systems_when_calling_BulkEnableAsync()
+ {
+ // Arrange
+ var response = new BulkSystemUpdateResult
+ {
+ SystemsUpdated = 2,
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems/enable").UsingPut())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _enrolledSystemsClient.BulkEnableAsync(SystemId.FromString("asdf"), SystemId.FromString("asdf3"));
+
+ // Assert
+ result.Should().Be(2);
+ }
+
+ [Test]
+ public async Task Should_return_number_of_disabled_systems_when_calling_BulkDisableAsync()
+ {
+ // Arrange
+ var response = new BulkSystemUpdateResult
+ {
+ SystemsUpdated = 2,
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/systems/disable").UsingPut())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _enrolledSystemsClient.BulkDisableAsync(SystemId.FromString("asdf"), SystemId.FromString("asdf3"));
+
+ // Assert
+ result.Should().Be(2);
+ }
+
+
+}
diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs
new file mode 100644
index 0000000..b830ed9
--- /dev/null
+++ b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs
@@ -0,0 +1,392 @@
+using Enclave.Sdk.Api.Clients;
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.EnrolmentKeys;
+using Enclave.Sdk.Api.Data.EnrolmentKeys.Enum;
+using Enclave.Sdk.Api.Data.Organisations;
+using Enclave.Sdk.Api.Data.Pagination;
+using Enclave.Sdk.Api.Data.PatchModel;
+using FluentAssertions;
+using NUnit.Framework;
+using System.Text.Json;
+using WireMock.FluentAssertions;
+using WireMock.RequestBuilders;
+using WireMock.ResponseBuilders;
+using WireMock.Server;
+
+namespace Enclave.Sdk.Api.Tests.Clients;
+
+public class EnrolmentKeyClientTests
+{
+ private EnrolmentKeysClient _enrolmentKeysClient;
+ private WireMockServer _server;
+ private string _orgRoute;
+ private JsonSerializerOptions _serializerOptions = new()
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ };
+
+ [SetUp]
+ public void Setup()
+ {
+ _server = WireMockServer.Start();
+
+ var httpClient = new HttpClient
+ {
+ BaseAddress = new Uri(_server.Urls[0]),
+ };
+
+
+ var organisationId = OrganisationId.New();
+ _orgRoute = $"/org/{organisationId}";
+
+ _enrolmentKeysClient = new EnrolmentKeysClient(httpClient, $"org/{organisationId}");
+ }
+
+ [Test]
+ public async Task Should_return_paginated_response_when_calling_GetEnrolmentKeysAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel()
+ {
+ Items = new List
+ {
+ new EnrolmentKeySummary(),
+ },
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _enrolmentKeysClient.GetEnrolmentKeysAsync();
+
+ // Assert
+ result.Should().NotBe(null);
+ result.Items.Should().HaveCount(1);
+
+ }
+
+ [Test]
+ public async Task Should_make_call_to_api_with_search_queryString_when_calling_GetEnrolmentKeysAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel()
+ {
+ Items = new List
+ {
+ new EnrolmentKeySummary(),
+ },
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var searchTerm = "term";
+
+ // Act
+ await _enrolmentKeysClient.GetEnrolmentKeysAsync(searchTerm: searchTerm);
+
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/enrolment-keys?search={searchTerm}");
+ }
+
+
+ [Test]
+ public async Task Should_make_call_to_api_with_include_disabled_queryString_when_calling_GetEnrolmentKeysAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel()
+ {
+ Items = new List
+ {
+ new EnrolmentKeySummary(),
+ },
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var includeDisabled = true;
+
+ // Act
+ await _enrolmentKeysClient.GetEnrolmentKeysAsync(includeDisabled: includeDisabled);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/enrolment-keys?include_disabled={includeDisabled}");
+ }
+
+ [Test]
+ public async Task Should_make_call_to_api_with_sort_queryString_when_calling_GetEnrolmentKeysAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel()
+ {
+ Items = new List
+ {
+ new EnrolmentKeySummary(),
+ },
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var sort = EnrolmentKeySortOrder.UsesRemaining;
+
+ // Act
+ await _enrolmentKeysClient.GetEnrolmentKeysAsync(sortOrder: sort);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/enrolment-keys?sort={sort}");
+ }
+
+ [Test]
+ public async Task Should_make_call_to_api_with_page_queryString_when_calling_GetEnrolmentKeysAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel()
+ {
+ Items = new List
+ {
+ new EnrolmentKeySummary(),
+ },
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var page = 2;
+
+ // Act
+ await _enrolmentKeysClient.GetEnrolmentKeysAsync(pageNumber: page);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/enrolment-keys?page={page}");
+ }
+
+ [Test]
+ public async Task Should_make_call_to_api_with_per_page_queryString_when_calling_GetEnrolmentKeysAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel()
+ {
+ Items = new List
+ {
+ new EnrolmentKeySummary(),
+ },
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var perPage = 2;
+
+ // Act
+ await _enrolmentKeysClient.GetEnrolmentKeysAsync(perPage: perPage);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/enrolment-keys?per_page={perPage}");
+ }
+
+ [Test]
+ public async Task Should_return_a_full_enrolment_key_model_when_calling_CreateAsync()
+ {
+ // Arrange
+ var response = new EnrolmentKey();
+
+ var createModel = new EnrolmentKeyCreate();
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys").UsingPost())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+
+
+ // Act
+ var result = await _enrolmentKeysClient.CreateAsync(createModel);
+
+ // Assert
+ result.Should().NotBeNull();
+ }
+
+ [Test]
+ public async Task Should_return_a_full_enrolment_key_model_when_calling_GetAsync()
+ {
+ // Arrange
+ var response = new EnrolmentKey();
+
+ var enrolmentKeyId = EnrolmentKeyId.FromInt(12);
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+
+
+ // Act
+ var result = await _enrolmentKeysClient.GetAsync(enrolmentKeyId);
+
+ // Assert
+ result.Should().NotBeNull();
+ }
+
+ [Test]
+ public async Task Should_return_a_full_enrolment_key_model_when_calling_UpdateAsync()
+ {
+ // Arrange
+ var response = new EnrolmentKey();
+
+ var enrolmentKeyId = EnrolmentKeyId.FromInt(12);
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}").UsingPatch())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var patchBuilder = new PatchBuilder().Set(e => e.Description, "New Value");
+
+
+ // Act
+ var result = await _enrolmentKeysClient.UpdateAsync(enrolmentKeyId, patchBuilder);
+
+ // Assert
+ result.Should().NotBeNull();
+ }
+
+ [Test]
+ public async Task Should_return_a_full_enrolment_key_model_when_calling_EnableAsync()
+ {
+ // Arrange
+ var response = new EnrolmentKey();
+
+ var enrolmentKeyId = EnrolmentKeyId.FromInt(12);
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}/enable").UsingPut())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _enrolmentKeysClient.EnableAsync(enrolmentKeyId);
+
+ // Assert
+ result.Should().NotBeNull();
+ }
+
+ [Test]
+ public async Task Should_return_a_full_enrolment_key_model_when_calling_DisableAsync()
+ {
+ // Arrange
+ var response = new EnrolmentKey();
+
+ var enrolmentKeyId = EnrolmentKeyId.FromInt(12);
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}/disable").UsingPut())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _enrolmentKeysClient.DisableAsync(enrolmentKeyId);
+
+ // Assert
+ result.Should().NotBeNull();
+ }
+
+ [Test]
+ public async Task Should_return_number_of_keys_modified_when_calling_BulkEnableAsync()
+ {
+ // Arrange
+ var response = new BulkKeyActionResult()
+ {
+ KeysModified = 2,
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys/enable").UsingPut())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var keys = new EnrolmentKeyId[] { EnrolmentKeyId.FromInt(1), EnrolmentKeyId.FromInt(2) };
+
+ // Act
+ var result = await _enrolmentKeysClient.BulkEnableAsync(keys);
+
+ // Assert
+ result.Should().Be(keys.Length);
+ }
+
+ [Test]
+ public async Task Should_return_number_of_keys_modified_when_calling_BulkDisableAsync()
+ {
+ // Arrange
+ var response = new BulkKeyActionResult()
+ {
+ KeysModified = 2,
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys/disable").UsingPut())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var keys = new EnrolmentKeyId[] { EnrolmentKeyId.FromInt(1), EnrolmentKeyId.FromInt(2) };
+
+ // Act
+ var result = await _enrolmentKeysClient.BulkDisableAsync(keys);
+
+ // Assert
+ result.Should().Be(keys.Length);
+ }
+}
diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/LogsClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/LogsClientTests.cs
new file mode 100644
index 0000000..50f3344
--- /dev/null
+++ b/tests/Enclave.Sdk.Api.Tests/Clients/LogsClientTests.cs
@@ -0,0 +1,125 @@
+using Enclave.Sdk.Api.Clients;
+using Enclave.Sdk.Api.Data.Logging;
+using Enclave.Sdk.Api.Data.Organisations;
+using Enclave.Sdk.Api.Data.Pagination;
+using NUnit.Framework;
+using System.Text.Json;
+using WireMock.RequestBuilders;
+using WireMock.ResponseBuilders;
+using WireMock.Server;
+using WireMock.FluentAssertions;
+using FluentAssertions;
+
+namespace Enclave.Sdk.Api.Tests.Clients;
+
+public class LogsClientTests
+{
+ private LogsClient _logsClient;
+ private WireMockServer _server;
+ private string _orgRoute;
+ private JsonSerializerOptions _serializerOptions = new JsonSerializerOptions
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ };
+
+ [SetUp]
+ public void Setup()
+ {
+ _server = WireMockServer.Start();
+
+ var httpClient = new HttpClient
+ {
+ BaseAddress = new Uri(_server.Urls[0]),
+ };
+
+ var organisationId = OrganisationId.New();
+ _orgRoute = $"/org/{organisationId}";
+
+
+ _logsClient = new LogsClient(httpClient, $"org/{organisationId}");
+ }
+
+ [Test]
+ public async Task Should_return_a_list_of_logs_in_pagination_format()
+ {
+ // Arrange
+ var responseModel = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new LogEntry { },
+ new LogEntry { },
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/logs").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithStatusCode(200)
+ .WithBody(JsonSerializer.Serialize(responseModel, _serializerOptions)));
+
+ // Act
+ var result = await _logsClient.GetLogsAsync();
+
+ // Assert
+ result.Should().NotBeNull();
+ result.Items.Should().NotBeNull();
+ }
+
+ [Test]
+ public async Task Should_make_call_to_api_with_page_queryString()
+ {
+ // Arrange
+ var pageNumber = 1;
+
+ var responseModel = new PaginatedResponseModel
+ {
+ Items = new List(),
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/logs").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithStatusCode(200)
+ .WithBody(JsonSerializer.Serialize(responseModel, _serializerOptions)));
+
+ // Act
+ var result = await _logsClient.GetLogsAsync(pageNumber: pageNumber);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/logs?page={pageNumber}");
+ }
+
+ [Test]
+ public async Task Should_make_call_to_api_with_per_page_queryString()
+ {
+ // Arrange
+ var perPage = 1;
+
+ var responseModel = new PaginatedResponseModel
+ {
+ Items = new List(),
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/logs").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithStatusCode(200)
+ .WithBody(JsonSerializer.Serialize(responseModel, _serializerOptions)));
+
+ // Act
+ var result = await _logsClient.GetLogsAsync(perPage: perPage);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/logs?per_page={perPage}");
+ }
+}
diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/PoliciesClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/PoliciesClientTests.cs
new file mode 100644
index 0000000..69533c2
--- /dev/null
+++ b/tests/Enclave.Sdk.Api.Tests/Clients/PoliciesClientTests.cs
@@ -0,0 +1,464 @@
+using Enclave.Sdk.Api.Clients;
+using Enclave.Sdk.Api.Data.Pagination;
+using Enclave.Sdk.Api.Data.Policies;
+using FluentAssertions;
+using NUnit.Framework;
+using System.Text.Json;
+using WireMock.RequestBuilders;
+using WireMock.ResponseBuilders;
+using WireMock.Server;
+using WireMock.FluentAssertions;
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.PatchModel;
+using Enclave.Sdk.Api.Data.Policies.Enum;
+using Enclave.Sdk.Api.Data.Organisations;
+
+namespace Enclave.Sdk.Api.Tests.Clients;
+
+public class PoliciesClientTests
+{
+ private PoliciesClient _policiesClient;
+ private WireMockServer _server;
+ private string _orgRoute;
+ private JsonSerializerOptions _serializerOptions = new()
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ };
+
+ [SetUp]
+ public void Setup()
+ {
+ _server = WireMockServer.Start();
+
+ var httpClient = new HttpClient
+ {
+ BaseAddress = new Uri(_server.Urls[0]),
+ };
+
+ var organisationId = OrganisationId.New();
+ _orgRoute = $"/org/{organisationId}";
+
+ _policiesClient = new PoliciesClient(httpClient, $"org/{organisationId}");
+ }
+
+ [Test]
+ public async Task Should_return_a_paginated_response_model_when_calling_GetPoliciesAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new Policy { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _policiesClient.GetPoliciesAsync();
+
+ // Assert
+ result.Should().NotBeNull();
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_include_disabled_quertString_when_calling_GetPoliciesAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new Policy { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var includeDisabled = true;
+
+ // Act
+ await _policiesClient.GetPoliciesAsync(includeDisabled: includeDisabled);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/policies?include_disabled={includeDisabled}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_search_quertString_when_calling_GetPoliciesAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new Policy { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var searchTerm = "term";
+
+ // Act
+ await _policiesClient.GetPoliciesAsync(searchTerm: searchTerm);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/policies?search={searchTerm}");
+ }
+
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_sort_quertString_when_calling_GetPoliciesAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new Policy { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var sortOrder = PolicySortOrder.RecentlyCreated;
+
+ // Act
+ await _policiesClient.GetPoliciesAsync(sortOrder: sortOrder);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/policies?sort={sortOrder}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_page_quertString_when_calling_GetPoliciesAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new Policy { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var page = 12;
+
+ // Act
+ await _policiesClient.GetPoliciesAsync(pageNumber: page);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/policies?page={page}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_per_page_quertString_when_calling_GetPoliciesAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new Policy { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var page = 12;
+
+ // Act
+ await _policiesClient.GetPoliciesAsync(perPage: page);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/policies?per_page={page}");
+ }
+
+ [Test]
+ public async Task Should_return_policy_model_when_calling_CreateAsync()
+ {
+ // Arrange
+ var response = new Policy
+ {
+ Description = "test",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies").UsingPost())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var createModel = new PolicyCreate
+ {
+ Description = "test",
+ };
+
+ // Act
+ var result = await _policiesClient.CreateAsync(createModel);
+
+ // Assert
+ result.Should().NotBeNull();
+ result.Description.Should().Be(response.Description);
+ }
+
+ [Test]
+ public async Task Should_return_number_of_deleted_policies_when_calling_DeletePoliciesAsync()
+ {
+ // Arrange
+ var response = new BulkPolicyDeleteResult
+ {
+ PoliciesDeleted = 3,
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies").UsingDelete())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _policiesClient.DeletePoliciesAsync(PolicyId.FromInt(2), PolicyId.FromInt(3), PolicyId.FromInt(5));
+
+ // Assert
+ result.Should().Be(3);
+ }
+
+ [Test]
+ public async Task Should_return_policy_model_when_calling_GetAsync()
+ {
+ // Arrange
+ var response = new Policy
+ {
+ Id = PolicyId.FromInt(12),
+ Description = "test",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies/{response.Id}").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _policiesClient.GetAsync(PolicyId.FromInt(12));
+
+ // Assert
+ result.Should().NotBeNull();
+ result.Description.Should().Be(response.Description);
+ }
+
+ [Test]
+ public async Task Should_return_policy_model_when_calling_UpdateAsync()
+ {
+ // Arrange
+ var response = new Policy
+ {
+ Id = PolicyId.FromInt(12),
+ Description = "test",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies/{response.Id}").UsingPatch())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var builder = new PatchBuilder().Set(p => p.IsEnabled, false);
+
+ // Act
+ var result = await _policiesClient.UpdateAsync(PolicyId.FromInt(12), builder);
+
+ // Assert
+ result.Should().NotBeNull();
+ result.Description.Should().Be(response.Description);
+ }
+
+ [Test]
+ public async Task Should_return_policy_model_when_calling_DeleteAsync()
+ {
+ // Arrange
+ var response = new Policy
+ {
+ Id = PolicyId.FromInt(12),
+ Description = "test",
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies/{response.Id}").UsingDelete())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _policiesClient.DeleteAsync(PolicyId.FromInt(12));
+
+ // Assert
+ result.Should().NotBeNull();
+ result.Description.Should().Be(response.Description);
+ }
+
+ [Test]
+ public async Task Should_return_policy_model_when_calling_EnableAsync()
+ {
+ // Arrange
+ var response = new Policy
+ {
+ Id = PolicyId.FromInt(12),
+ Description = "test",
+ IsEnabled = true,
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies/{response.Id}/enable").UsingPut())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _policiesClient.EnableAsync(PolicyId.FromInt(12));
+
+ // Assert
+ result.Should().NotBeNull();
+ result.IsEnabled.Should().Be(response.IsEnabled);
+ }
+
+ [Test]
+ public async Task Should_return_policy_model_when_calling_DisableAsync()
+ {
+ // Arrange
+ var response = new Policy
+ {
+ Id = PolicyId.FromInt(12),
+ Description = "test",
+ IsEnabled = false,
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies/{response.Id}/disable").UsingPut())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _policiesClient.DisableAsync(PolicyId.FromInt(12));
+
+ // Assert
+ result.Should().NotBeNull();
+ result.IsEnabled.Should().Be(response.IsEnabled);
+ }
+
+ [Test]
+ public async Task Should_return_number_of_deleted_policies_when_calling_EnablePoliciesAsync()
+ {
+ // Arrange
+ var response = new BulkPolicyUpdateResult
+ {
+ PoliciesUpdated = 3,
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies/enable").UsingPut())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _policiesClient.EnablePoliciesAsync(PolicyId.FromInt(2), PolicyId.FromInt(3), PolicyId.FromInt(5));
+
+ // Assert
+ result.Should().Be(3);
+ }
+
+ [Test]
+ public async Task Should_return_number_of_deleted_policies_when_calling_DisablePoliciesAsync()
+ {
+ // Arrange
+ var response = new BulkPolicyUpdateResult
+ {
+ PoliciesUpdated = 3,
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/policies/disable").UsingPut())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _policiesClient.DisablePoliciesAsync(PolicyId.FromInt(2), PolicyId.FromInt(3), PolicyId.FromInt(5));
+
+ // Assert
+ result.Should().Be(3);
+ }
+}
diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/TagClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/TagClientTests.cs
index 5675c01..8366a33 100644
--- a/tests/Enclave.Sdk.Api.Tests/Clients/TagClientTests.cs
+++ b/tests/Enclave.Sdk.Api.Tests/Clients/TagClientTests.cs
@@ -1,5 +1,6 @@
using System.Text.Json;
using Enclave.Sdk.Api.Clients;
+using Enclave.Sdk.Api.Data.Organisations;
using Enclave.Sdk.Api.Data.Pagination;
using Enclave.Sdk.Api.Data.Tags;
using FluentAssertions;
@@ -31,11 +32,11 @@ public void Setup()
BaseAddress = new Uri(_server.Urls[0]),
};
- var orgId = "testId";
+ var organisationId = OrganisationId.New();
+ _orgRoute = $"/org/{organisationId}";
- _orgRoute = $"/org/{orgId}";
- _tagClient = new TagsClient(httpClient, _orgRoute);
+ _tagClient = new TagsClient(httpClient, $"org/{organisationId}");
}
[Test]
diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs
new file mode 100644
index 0000000..df2cc8b
--- /dev/null
+++ b/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs
@@ -0,0 +1,371 @@
+using Enclave.Sdk.Api.Clients;
+using Enclave.Sdk.Api.Data.Pagination;
+using Enclave.Sdk.Api.Data.UnaprrovedSystems;
+using FluentAssertions;
+using NUnit.Framework;
+using System.Text.Json;
+using WireMock.Server;
+using WireMock.FluentAssertions;
+using WireMock.RequestBuilders;
+using WireMock.ResponseBuilders;
+using Enclave.Sdk.Api.Data;
+using Enclave.Sdk.Api.Data.PatchModel;
+using Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum;
+using Enclave.Sdk.Api.Data.Organisations;
+
+namespace Enclave.Sdk.Api.Tests.Clients;
+
+public class UnapprovedSystemsClientTests
+{
+ private UnapprovedSystemsClient _unapprovedSystemsClient;
+ private WireMockServer _server;
+ private string _orgRoute;
+ private JsonSerializerOptions _serializerOptions = new()
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ };
+
+ public UnapprovedSystemsClientTests()
+ {
+ _server = WireMockServer.Start();
+
+ var httpClient = new HttpClient
+ {
+ BaseAddress = new Uri(_server.Urls[0]),
+ };
+
+ var organisationId = OrganisationId.New();
+ _orgRoute = $"/org/{organisationId}";
+
+ _unapprovedSystemsClient = new UnapprovedSystemsClient(httpClient, $"org/{organisationId}");
+ }
+
+ [Test]
+ public async Task Should_return_a_paginated_response_model_when_calling_GetSystemsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new UnapprovedSystemSummary { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/unapproved-systems").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _unapprovedSystemsClient.GetSystemsAsync();
+
+ // Assert
+ result.Should().NotBeNull();
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_enrolment_key_quertString_when_calling_GetSystemsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new UnapprovedSystemSummary { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/unapproved-systems").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var enrolmentKeyId = 12;
+
+ // Act
+ await _unapprovedSystemsClient.GetSystemsAsync(enrolmentKeyId: enrolmentKeyId);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/unapproved-systems?enrolment_key={enrolmentKeyId}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_search_quertString_when_calling_GetSystemsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new UnapprovedSystemSummary { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/unapproved-systems").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var searchTerm = "term";
+
+ // Act
+ await _unapprovedSystemsClient.GetSystemsAsync(searchTerm: searchTerm);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/unapproved-systems?search={searchTerm}");
+ }
+
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_sort_quertString_when_calling_GetSystemsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new UnapprovedSystemSummary { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/unapproved-systems").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var sortOrder = UnapprovedSystemQuerySortMode.RecentlyEnrolled;
+
+ // Act
+ await _unapprovedSystemsClient.GetSystemsAsync(sortOrder: sortOrder);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/unapproved-systems?sort={sortOrder}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_page_quertString_when_calling_GetSystemsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new UnapprovedSystemSummary { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/unapproved-systems").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var page = 12;
+
+ // Act
+ await _unapprovedSystemsClient.GetSystemsAsync(pageNumber: page);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/unapproved-systems?page={page}");
+ }
+
+ [Test]
+ public async Task Should_make_a_call_to_api_with_per_page_quertString_when_calling_GetSystemsAsync()
+ {
+ // Arrange
+ var response = new PaginatedResponseModel
+ {
+ Items = new List
+ {
+ new UnapprovedSystemSummary { Description = "test"}
+ },
+ Links = new PaginationLinks(),
+ Metadata = new PaginationMetadata(),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/unapproved-systems").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var page = 12;
+
+ // Act
+ await _unapprovedSystemsClient.GetSystemsAsync(perPage: page);
+
+ // Assert
+ _server.Should().HaveReceivedACall().AtAbsoluteUrl($"{_server.Urls[0]}{_orgRoute}/unapproved-systems?per_page={page}");
+ }
+
+ [Test]
+ public async Task Should_return_number_of_declined_systems_when_calling_DeclineSystems()
+ {
+ var response = new BulkUnapprovedSystemDeclineResult
+ {
+ SystemsDeclined = 2,
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/unapproved-systems").UsingDelete())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _unapprovedSystemsClient.DeclineSystems(SystemId.FromString("system1"), SystemId.FromString("system2"));
+
+ // Assert
+ result.Should().Be(2);
+ }
+
+ [Test]
+ public async Task Should_return_unapproved_system_detail_model_when_calling_GetAsync()
+ {
+ // Arrange
+ var response = new UnapprovedSystem
+ {
+ SystemId = SystemId.FromString("newId"),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/unapproved-systems/{response.SystemId}").UsingGet())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _unapprovedSystemsClient.GetAsync(SystemId.FromString("newId"));
+
+ // Assert
+ result.Should().NotBeNull();
+ result.SystemId.Should().Be(response.SystemId);
+ }
+
+ [Test]
+ public async Task Should_return_unapproved_system_detail_model_when_calling_UpdateAsync()
+ {
+ // Arrange
+ var response = new UnapprovedSystem
+ {
+ SystemId = SystemId.FromString("newId"),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/unapproved-systems/{response.SystemId}").UsingPatch())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ var builder = new PatchBuilder().Set(u => u.Description, "New System");
+
+ // Act
+ var result = await _unapprovedSystemsClient.UpdateAsync(SystemId.FromString("newId"), builder);
+
+ // Assert
+ result.Should().NotBeNull();
+ result.SystemId.Should().Be(response.SystemId);
+ }
+
+ [Test]
+ public async Task Should_return_unapproved_system_detail_model_when_calling_DeclineAsync()
+ {
+ // Arrange
+ var response = new UnapprovedSystem
+ {
+ SystemId = SystemId.FromString("newId"),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/unapproved-systems/{response.SystemId}").UsingDelete())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _unapprovedSystemsClient.DeclineAsync(SystemId.FromString("newId"));
+
+ // Assert
+ result.Should().NotBeNull();
+ result.SystemId.Should().Be(response.SystemId);
+ }
+
+ [Test]
+ public async Task Should_not_throw_an_error_when_calling_ApproveAsync()
+ {
+ // Arrange
+ var response = new UnapprovedSystem
+ {
+ SystemId = SystemId.FromString("newId"),
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/unapproved-systems/{response.SystemId}/approve").UsingPut())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ await _unapprovedSystemsClient.ApproveAsync(SystemId.FromString("newId"));
+ }
+
+ [Test]
+ public async Task Should_return_number_of_approved_systems_when_calling_ApproveSystemsAsync()
+ {
+ var response = new BulkUnapprovedSystemApproveResult
+ {
+ SystemsApproved = 2,
+ };
+
+ _server
+ .Given(Request.Create().WithPath($"{_orgRoute}/unapproved-systems/approve").UsingPut())
+ .RespondWith(
+ Response.Create()
+ .WithSuccess()
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(JsonSerializer.Serialize(response, _serializerOptions)));
+
+ // Act
+ var result = await _unapprovedSystemsClient.ApproveSystemsAsync(SystemId.FromString("system1") , SystemId.FromString("system2"));
+
+ // Assert
+ result.Should().Be(2);
+ }
+}
\ No newline at end of file
diff --git a/tests/Enclave.Sdk.Api.Tests/EnclaveClientTests.cs b/tests/Enclave.Sdk.Api.Tests/EnclaveClientTests.cs
index 0091ac5..bdd1995 100644
--- a/tests/Enclave.Sdk.Api.Tests/EnclaveClientTests.cs
+++ b/tests/Enclave.Sdk.Api.Tests/EnclaveClientTests.cs
@@ -1,6 +1,6 @@
using System.Text.Json;
-using Enclave.Sdk.Api.Data;
using Enclave.Sdk.Api.Data.Account;
+using Enclave.Sdk.Api.Data.Organisations;
using FluentAssertions;
using NUnit.Framework;
using WireMock.RequestBuilders;