From 8b4e1ed37c4eaf22de92350004b0435dcc083fbc Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Thu, 25 Nov 2021 14:12:19 +0000 Subject: [PATCH 01/38] added models for enrolment keys --- src/Enclave.Sdk/Clients/ClientBase.cs | 1 - .../Clients/EnrolmentKeysClient.cs | 20 +++++ src/Enclave.Sdk/Constants.cs | 7 +- .../Data/EnrolmentKeys/EnrolmentKey.cs | 84 +++++++++++++++++++ .../Data/EnrolmentKeys/Enum/ApprovalMode.cs | 7 ++ .../Enum/EnrolmentKeySortOrder.cs | 9 ++ .../EnrolmentKeys/Enum/EnrolmentKeyStatus.cs | 22 +++++ .../EnrolmentKeys/Enum/EnrolmentKeyType.cs | 7 ++ src/Enclave.Sdk/Data/Tags/TagReference.cs | 12 +++ src/Enclave.Sdk/EnclaveClient.cs | 1 - src/Enclave.Sdk/EnclaveClientOptions.cs | 4 +- src/Enclave.Sdk/Exceptions/ProblemDetails.cs | 7 +- .../Exceptions/ProblemDetailsJsonConverter.cs | 7 +- 13 files changed, 165 insertions(+), 23 deletions(-) create mode 100644 src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKey.cs create mode 100644 src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs create mode 100644 src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeySortOrder.cs create mode 100644 src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyStatus.cs create mode 100644 src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs create mode 100644 src/Enclave.Sdk/Data/Tags/TagReference.cs diff --git a/src/Enclave.Sdk/Clients/ClientBase.cs b/src/Enclave.Sdk/Clients/ClientBase.cs index 3afbd75..5d37714 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; diff --git a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs index bc98e38..c8a5f4b 100644 --- a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs @@ -1,14 +1,34 @@ using Enclave.Sdk.Api.Clients.Interfaces; +using Enclave.Sdk.Api.Data.EnrolmentKeys; +using Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; +using Enclave.Sdk.Api.Data.Pagination; namespace Enclave.Sdk.Api.Clients; +/// public class EnrolmentKeysClient : ClientBase, IEnrolmentKeysClient { private 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 API public EnrolmentKeysClient(HttpClient httpClient, string orgRoute) : base(httpClient) { _orgRoute = orgRoute; } + + public async Task> GetEnrolmentKeys( + string? searchTerm = null, + bool includeDisabled = false, + EnrolmentKeySortOrder? sortOrder = null, + int? page = null, + int? perPage = null) + { + + } } diff --git a/src/Enclave.Sdk/Constants.cs b/src/Enclave.Sdk/Constants.cs index b516ecd..2ffe3d0 100644 --- a/src/Enclave.Sdk/Constants.cs +++ b/src/Enclave.Sdk/Constants.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.Json; -using System.Threading.Tasks; +using System.Text.Json; namespace Enclave.Sdk.Api; diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKey.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKey.cs new file mode 100644 index 0000000..1057875 --- /dev/null +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKey.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 EnrolmentKey +{ + /// + /// The ID of the enrolment key. + /// + public int Id { get; } + + /// + /// The UTC timestamp when the key was created. + /// + public DateTime Created { get; } + + /// + /// The UTC timestamp when the key was last used to enrol a system (null if never used). + /// + public DateTime? LastUsed { get; } + + /// + /// The type of key; general purpose (default) or ephemeral (enrolled systems are automatically removed). + /// + public EnrolmentKeyType Type { get; } + + /// + /// The approval mode for the key. + /// + public ApprovalMode ApprovalMode { get; } + + /// + /// 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; } = default!; + + /// + /// The provided description of the key. + /// + public string Description { get; } = default!; + + /// + /// Whether or not this key is enabled. + /// + public bool IsEnabled { get; } + + /// + /// The number of uses remaining. + /// + public long UsesRemaining { get; } + + /// + /// The number of systems enrolled with this key. + /// + public long EnrolledCount { get; } + + /// + /// The number of unapproved systems enrolled with this key. + /// + public long UnapprovedCount { get; } + + /// + /// The set of tags applied to the key. + /// + public IReadOnlyList? Tags { get; } + + /// + /// 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..bf1ddad --- /dev/null +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs @@ -0,0 +1,7 @@ +namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; + +public enum ApprovalMode +{ + Automatic, + 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..0da202c --- /dev/null +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeySortOrder.cs @@ -0,0 +1,9 @@ +namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; + +public enum EnrolmentKeySortOrder +{ + Description, + LastUsed, + ApprovalMode, + 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..11dcc59 --- /dev/null +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs @@ -0,0 +1,7 @@ +namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; + +public enum EnrolmentKeyType +{ + GeneralPurpose, + Ephemeral, +} diff --git a/src/Enclave.Sdk/Data/Tags/TagReference.cs b/src/Enclave.Sdk/Data/Tags/TagReference.cs new file mode 100644 index 0000000..ba4265f --- /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; } = default!; +} diff --git a/src/Enclave.Sdk/EnclaveClient.cs b/src/Enclave.Sdk/EnclaveClient.cs index d0d25b2..2437122 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; 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/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; From bceec81f7d686eff0c02205e7434da0f7af337c8 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Thu, 25 Nov 2021 16:45:03 +0000 Subject: [PATCH 02/38] Implimented API calls testing needed --- .../Clients/EnrolmentKeysClient.cs | 155 +++++++++++++++++- .../Interfaces/IEnrolmentKeysClient.cs | 72 +++++++- .../Clients/Interfaces/IOrganisationClient.cs | 4 +- src/Enclave.Sdk/Clients/OrganisationClient.cs | 3 +- .../Data/EnrolmentKeys/BulkKeyActionResult.cs | 12 ++ .../Data/EnrolmentKeys/EnrolmentKeyCreate.cs | 55 +++++++ .../EnrolmentKeyIpConstraintInput.cs | 17 ++ .../Data/EnrolmentKeys/FullEnrolmentKey.cs | 94 +++++++++++ ...{EnrolmentKey.cs => SimpleEnrolmentKey.cs} | 2 +- .../Data/PatchModel/EnrolmentKeyPatch.cs | 51 ++++++ 10 files changed, 457 insertions(+), 8 deletions(-) create mode 100644 src/Enclave.Sdk/Data/EnrolmentKeys/BulkKeyActionResult.cs create mode 100644 src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs create mode 100644 src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs create mode 100644 src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs rename src/Enclave.Sdk/Data/EnrolmentKeys/{EnrolmentKey.cs => SimpleEnrolmentKey.cs} (98%) create mode 100644 src/Enclave.Sdk/Data/PatchModel/EnrolmentKeyPatch.cs diff --git a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs index c8a5f4b..605b3e5 100644 --- a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs @@ -1,7 +1,11 @@ +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; @@ -22,13 +26,158 @@ public EnrolmentKeysClient(HttpClient httpClient, string orgRoute) _orgRoute = orgRoute; } - public async Task> GetEnrolmentKeys( + /// + public async Task> GetEnrolmentKeysAsync( string? searchTerm = null, bool includeDisabled = false, EnrolmentKeySortOrder? sortOrder = null, - int? page = 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 == 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(int enrolmentKeyId) + { + var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}", Constants.JsonSerializerOptions); + + EnsureNotNull(model); + + return model; + } + + /// + public async Task UpdateAsync(int 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); + + var model = await DeserialiseAsync(result.Content); + + EnsureNotNull(model); + + return model; + } + + /// + public async Task EnableAsync(int 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(int 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 int[] enrolmentKeys) + { + var requestModel = new + { + keyIds = enrolmentKeys, + }; + + using var content = CreateJsonContent(requestModel); + + var result = await HttpClient.PutAsync($"{_orgRoute}/enrolment-keys/enable", content); + + var model = await DeserialiseAsync(result.Content); + + EnsureNotNull(model); + + return model; + } + + /// + public async Task BulkDisableAsync(params int[] enrolmentKeys) + { + var requestModel = new + { + keyIds = enrolmentKeys, + }; + + using var content = CreateJsonContent(requestModel); + + var result = await HttpClient.PutAsync($"{_orgRoute}/enrolment-keys/disable", content); + + var model = await DeserialiseAsync(result.Content); + + EnsureNotNull(model); + + return model; + } + + 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/IEnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs index a11d9cd..2f7a7de 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs @@ -1,5 +1,75 @@ -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; + +/// +/// Perform CRUD operations on 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 enorlment keys in the results. + /// Sort order for the pagination. + /// Which page number do you want to return. + /// How many tags per page. + /// A paginated response model with links to get the previous, next, first and last pages. + Task> GetEnrolmentKeysAsync(string? searchTerm = null, bool includeDisabled = false, 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(int 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(int enrolmentKeyId, PatchBuilder builder); + + /// + /// Enable an Enrolment Key. + /// + /// The Id of the Enrolment Key to enable. + /// A detailed Enrolment Key. + Task EnableAsync(int enrolmentKeyId); + + /// + /// Disable an Enrolment Key. + /// + /// The Id of the Enrolment Key to disable. + /// A detailed Enrolment Key. + Task DisableAsync(int enrolmentKeyId); + + /// + /// Bulk enable mutliple Enrolment Keys. + /// + /// An array of Enrolment Key Ids to enable. + /// An object with the number of keys modified. + Task BulkEnableAsync(params int[] enrolmentKeys); + + /// + /// Bulk disable mutliple Enrolment Keys. + /// + /// An array of Enrolment Key Ids to disable. + /// An object with the number of keys modified. + Task BulkDisableAsync(params int[] enrolmentKeys); } \ 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 35a9bea..eb5aa67 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IOrganisationClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IOrganisationClient.cs @@ -94,9 +94,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/OrganisationClient.cs b/src/Enclave.Sdk/Clients/OrganisationClient.cs index 05d2b11..2cf3b7a 100644 --- a/src/Enclave.Sdk/Clients/OrganisationClient.cs +++ b/src/Enclave.Sdk/Clients/OrganisationClient.cs @@ -68,7 +68,8 @@ 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); 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/EnrolmentKeyCreate.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs new file mode 100644 index 0000000..08a6a17 --- /dev/null +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs @@ -0,0 +1,55 @@ +using Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; +using System.ComponentModel; + +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 string[]? Tags { get; set; } = Array.Empty(); + + /// + /// 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/EnrolmentKeyIpConstraintInput.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs new file mode 100644 index 0000000..38c729e --- /dev/null +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs @@ -0,0 +1,17 @@ +namespace Enclave.Sdk.Api.Data.EnrolmentKeys; + +/// +/// Input model for IP Address constraints. +/// +public class EnrolmentKeyIpConstraintInput +{ + /// + /// The IP range. + /// + public string Range { get; set; } = default!; + + /// + /// A description for the range. + /// + public string? Description { get; set; } +} \ No newline at end of file diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs new file mode 100644 index 0000000..62d0ca8 --- /dev/null +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.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 FullEnrolmentKey +{ + /// + /// The ID of the enrolment key. + /// + public int Id { get; } + + /// + /// The UTC timestamp when the key was created. + /// + public DateTime Created { get; } + + /// + /// The UTC timestamp when the key was last used to enrol a system (null if never used). + /// + public DateTime? LastUsed { get; } + + /// + /// The type of key; general purpose (default) or ephemeral (enrolled systems are automatically removed). + /// + public EnrolmentKeyType Type { get; } + + /// + /// The approval mode for the key. + /// + public ApprovalMode ApprovalMode { get; } + + /// + /// 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; } + + /// + /// The provided description of the key. + /// + public string Description { get; } + + /// + /// Whether or not this key is enabled. + /// + public bool IsEnabled { get; } + + /// + /// The number of uses remaining. + /// + public long UsesRemaining { get; } + + /// + /// The number of systems enrolled with this key. + /// + public long EnrolledCount { get; } + + /// + /// The number of unapproved systems enrolled with this key. + /// + public long UnapprovedCount { get; } + + /// + /// The set of tags applied to the key. + /// + public IReadOnlyList Tags { get; } + + /// + /// 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; } + + /// + /// Any notes or additional info for this key. + /// + public string? Notes { get; } +} \ No newline at end of file diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKey.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/SimpleEnrolmentKey.cs similarity index 98% rename from src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKey.cs rename to src/Enclave.Sdk/Data/EnrolmentKeys/SimpleEnrolmentKey.cs index 1057875..54ae46b 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKey.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/SimpleEnrolmentKey.cs @@ -6,7 +6,7 @@ namespace Enclave.Sdk.Api.Data.EnrolmentKeys; /// /// Represents a single Enclave Enrolment Key. /// -public class EnrolmentKey +public class SimpleEnrolmentKey { /// /// The ID of the enrolment key. diff --git a/src/Enclave.Sdk/Data/PatchModel/EnrolmentKeyPatch.cs b/src/Enclave.Sdk/Data/PatchModel/EnrolmentKeyPatch.cs new file mode 100644 index 0000000..345eb4a --- /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 List? IpConstraints { get; set; } + + /// + /// A set of tags automatically applied to systems enrolled with this key. + /// + public string[]? Tags { get; set; } + + /// + /// 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; } +} From 22a1c93c35fe274edabd1e2bcd2a52811eb3853c Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Thu, 25 Nov 2021 17:00:18 +0000 Subject: [PATCH 03/38] Added unit test file and now building enrolment key client in organisation clien --- .../Clients/EnrolmentKeysClient.cs | 2 +- src/Enclave.Sdk/Clients/OrganisationClient.cs | 4 +- .../Clients/EnrolmentKeyTests.cs | 44 +++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyTests.cs diff --git a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs index 605b3e5..9e63aca 100644 --- a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs @@ -19,7 +19,7 @@ public class EnrolmentKeysClient : ClientBase, IEnrolmentKeysClient /// It also calls the constructor. /// /// an instance of httpClient with a baseURL referencing the API. - /// The API + /// The organisation API route. public EnrolmentKeysClient(HttpClient httpClient, string orgRoute) : base(httpClient) { diff --git a/src/Enclave.Sdk/Clients/OrganisationClient.cs b/src/Enclave.Sdk/Clients/OrganisationClient.cs index 2cf3b7a..1bdbd1e 100644 --- a/src/Enclave.Sdk/Clients/OrganisationClient.cs +++ b/src/Enclave.Sdk/Clients/OrganisationClient.cs @@ -23,6 +23,8 @@ public OrganisationClient(HttpClient httpClient, AccountOrganisation currentOrga { Organisation = currentOrganisation; _orgRoute = $"org/{Organisation.OrgId}"; + + EnrolmentKeys = new EnrolmentKeysClient(httpClient, _orgRoute); } /// @@ -35,7 +37,7 @@ public OrganisationClient(HttpClient httpClient, AccountOrganisation currentOrga public IDnsClient Dns => throw new NotImplementedException(); /// - public IEnrolmentKeysClient EnrolmentKeys => throw new NotImplementedException(); + public IEnrolmentKeysClient EnrolmentKeys { get; } /// public ILogsClient Logs => throw new NotImplementedException(); diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyTests.cs new file mode 100644 index 0000000..778d8c9 --- /dev/null +++ b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyTests.cs @@ -0,0 +1,44 @@ +using Enclave.Sdk.Api.Clients; +using Enclave.Sdk.Api.Data.Account; +using NUnit.Framework; +using System.Net.WebSockets; +using System.Text.Json; +using WireMock.Server; + +namespace Enclave.Sdk.Api.Tests.Clients; + +public class EnrolmentKeyTests +{ + private EnrolmentKeysClient _enrolmentKeysClient; + 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 currentOrganisation = new AccountOrganisation + { + OrgId = OrganisationId.New(), + OrgName = "TestName", + Role = UserOrganisationRole.Admin, + }; + + _orgRoute = $"/org/{currentOrganisation.OrgId}"; + + // Not sure if this is the best way of doing this + var organisationClient = new OrganisationClient(httpClient, currentOrganisation); + _enrolmentKeysClient = (EnrolmentKeysClient)organisationClient.EnrolmentKeys; + } +} From f91706ffecd10300de9471da3d16e529229b9e22 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Fri, 26 Nov 2021 11:04:38 +0000 Subject: [PATCH 04/38] added unit tests and fixed a bug with boolean --- .../Clients/EnrolmentKeysClient.cs | 2 +- .../Interfaces/IEnrolmentKeysClient.cs | 2 +- .../Clients/EnrolmentKeyClientTests.cs | 224 ++++++++++++++++++ .../Clients/EnrolmentKeyTests.cs | 44 ---- 4 files changed, 226 insertions(+), 46 deletions(-) create mode 100644 tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs delete mode 100644 tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyTests.cs diff --git a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs index 9e63aca..84515d9 100644 --- a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs @@ -29,7 +29,7 @@ public EnrolmentKeysClient(HttpClient httpClient, string orgRoute) /// public async Task> GetEnrolmentKeysAsync( string? searchTerm = null, - bool includeDisabled = false, + bool? includeDisabled = null, EnrolmentKeySortOrder? sortOrder = null, int? pageNumber = null, int? perPage = null) diff --git a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs index 2f7a7de..20df441 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs @@ -20,7 +20,7 @@ public interface IEnrolmentKeysClient /// Which page number do you want to return. /// How many tags per page. /// A paginated response model with links to get the previous, next, first and last pages. - Task> GetEnrolmentKeysAsync(string? searchTerm = null, bool includeDisabled = false, EnrolmentKeySortOrder? sortOrder = null, int? pageNumber = null, int? perPage = null); + Task> GetEnrolmentKeysAsync(string? searchTerm = null, bool? includeDisabled = null, EnrolmentKeySortOrder? sortOrder = null, int? pageNumber = null, int? perPage = null); /// /// Creates an Enrolment Key using a Model. 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..1c338ec --- /dev/null +++ b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs @@ -0,0 +1,224 @@ +using Enclave.Sdk.Api.Clients; +using Enclave.Sdk.Api.Data.Account; +using Enclave.Sdk.Api.Data.EnrolmentKeys; +using Enclave.Sdk.Api.Data.Pagination; +using FluentAssertions; +using NUnit.Framework; +using System.Text.Json; +using WireMock.RequestBuilders; +using WireMock.ResponseBuilders; +using WireMock.FluentAssertions; +using WireMock.Server; +using Enclave.Sdk.Api.Data.PatchModel; +using Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; + +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 currentOrganisation = new AccountOrganisation + { + OrgId = OrganisationId.New(), + OrgName = "TestName", + Role = UserOrganisationRole.Admin, + }; + + _orgRoute = $"/org/{currentOrganisation.OrgId}"; + + // Not sure if this is the best way of doing this + var organisationClient = new OrganisationClient(httpClient, currentOrganisation); + _enrolmentKeysClient = (EnrolmentKeysClient)organisationClient.EnrolmentKeys; + } + + [Test] + public async Task Should_return_paginated_response_when_calling_GetEnrolmentKeysAsync() + { + // Arrange + var response = new PaginatedResponseModel() + { + Items = new List + { + new SimpleEnrolmentKey(), + }, + }; + + _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 SimpleEnrolmentKey(), + }, + }; + + _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 SimpleEnrolmentKey(), + }, + }; + + _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 SimpleEnrolmentKey(), + }, + }; + + _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 SimpleEnrolmentKey(), + }, + }; + + _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 SimpleEnrolmentKey(), + }, + }; + + _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}"); + } +} diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyTests.cs deleted file mode 100644 index 778d8c9..0000000 --- a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyTests.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Enclave.Sdk.Api.Clients; -using Enclave.Sdk.Api.Data.Account; -using NUnit.Framework; -using System.Net.WebSockets; -using System.Text.Json; -using WireMock.Server; - -namespace Enclave.Sdk.Api.Tests.Clients; - -public class EnrolmentKeyTests -{ - private EnrolmentKeysClient _enrolmentKeysClient; - 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 currentOrganisation = new AccountOrganisation - { - OrgId = OrganisationId.New(), - OrgName = "TestName", - Role = UserOrganisationRole.Admin, - }; - - _orgRoute = $"/org/{currentOrganisation.OrgId}"; - - // Not sure if this is the best way of doing this - var organisationClient = new OrganisationClient(httpClient, currentOrganisation); - _enrolmentKeysClient = (EnrolmentKeysClient)organisationClient.EnrolmentKeys; - } -} From b1d2e129a6244e458fd3646e11bb165275dffd7c Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Mon, 29 Nov 2021 10:40:20 +0000 Subject: [PATCH 05/38] Unit tests added now need to do local tests to ensure it's all functioning --- .../Clients/EnrolmentKeysClient.cs | 14 +- .../Interfaces/IEnrolmentKeysClient.cs | 8 +- src/Enclave.Sdk/Clients/OrganisationClient.cs | 2 + src/Enclave.Sdk/EnclaveClient.cs | 3 +- .../Clients/EnrolmentKeyClientTests.cs | 181 +++++++++++++++++- 5 files changed, 196 insertions(+), 12 deletions(-) diff --git a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs index 84515d9..a3890be 100644 --- a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs @@ -81,6 +81,8 @@ public async Task UpdateAsync(int enrolmentKeyId, PatchBuilder 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); @@ -113,7 +115,7 @@ public async Task DisableAsync(int enrolmentKeyId) } /// - public async Task BulkEnableAsync(params int[] enrolmentKeys) + public async Task BulkEnableAsync(params int[] enrolmentKeys) { var requestModel = new { @@ -124,15 +126,17 @@ public async Task BulkEnableAsync(params int[] enrolmentKey var result = await HttpClient.PutAsync($"{_orgRoute}/enrolment-keys/enable", content); + result.EnsureSuccessStatusCode(); + var model = await DeserialiseAsync(result.Content); EnsureNotNull(model); - return model; + return model.KeysModified; } /// - public async Task BulkDisableAsync(params int[] enrolmentKeys) + public async Task BulkDisableAsync(params int[] enrolmentKeys) { var requestModel = new { @@ -143,11 +147,13 @@ public async Task BulkDisableAsync(params int[] enrolmentKe var result = await HttpClient.PutAsync($"{_orgRoute}/enrolment-keys/disable", content); + result.EnsureSuccessStatusCode(); + var model = await DeserialiseAsync(result.Content); EnsureNotNull(model); - return model; + return model.KeysModified; } private static string? BuildQueryString(string? searchTerm, bool? includeDisabled, EnrolmentKeySortOrder? sortOrder, int? pageNumber, int? perPage) diff --git a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs index 20df441..2bb932f 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs @@ -63,13 +63,13 @@ public interface IEnrolmentKeysClient /// Bulk enable mutliple Enrolment Keys. /// /// An array of Enrolment Key Ids to enable. - /// An object with the number of keys modified. - Task BulkEnableAsync(params int[] enrolmentKeys); + /// The number of keys modified. + Task BulkEnableAsync(params int[] enrolmentKeys); /// /// Bulk disable mutliple Enrolment Keys. /// /// An array of Enrolment Key Ids to disable. - /// An object with the number of keys modified. - Task BulkDisableAsync(params int[] enrolmentKeys); + /// The number of keys modified. + Task BulkDisableAsync(params int[] enrolmentKeys); } \ No newline at end of file diff --git a/src/Enclave.Sdk/Clients/OrganisationClient.cs b/src/Enclave.Sdk/Clients/OrganisationClient.cs index 2d5303c..19fce6f 100644 --- a/src/Enclave.Sdk/Clients/OrganisationClient.cs +++ b/src/Enclave.Sdk/Clients/OrganisationClient.cs @@ -75,6 +75,8 @@ public async Task UpdateAsync(PatchBuilder buil 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/EnclaveClient.cs b/src/Enclave.Sdk/EnclaveClient.cs index 03a3eee..59a77ff 100644 --- a/src/Enclave.Sdk/EnclaveClient.cs +++ b/src/Enclave.Sdk/EnclaveClient.cs @@ -85,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); @@ -104,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/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs index 1c338ec..d4200d7 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs @@ -1,16 +1,17 @@ using Enclave.Sdk.Api.Clients; +using Enclave.Sdk.Api.Data; using Enclave.Sdk.Api.Data.Account; 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; using FluentAssertions; using NUnit.Framework; using System.Text.Json; +using WireMock.FluentAssertions; using WireMock.RequestBuilders; using WireMock.ResponseBuilders; -using WireMock.FluentAssertions; using WireMock.Server; -using Enclave.Sdk.Api.Data.PatchModel; -using Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; namespace Enclave.Sdk.Api.Tests.Clients; @@ -221,4 +222,178 @@ public async Task Should_make_call_to_api_with_per_page_queryString_when_calling // 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 FullEnrolmentKey(); + + 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 FullEnrolmentKey(); + + var enrolmentKeyId = 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 FullEnrolmentKey(); + + var enrolmentKeyId = 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 FullEnrolmentKey(); + + var enrolmentKeyId = 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 FullEnrolmentKey(); + + var enrolmentKeyId = 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 = 4, + }; + + _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 int[] { 1, 2, 3, 4 }; + + // 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 = 4, + }; + + _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 int[] { 1, 2, 3, 4 }; + + // Act + var result = await _enrolmentKeysClient.BulkDisableAsync(keys); + + // Assert + result.Should().Be(keys.Length); + } } From c9e618e10276b28afc7c95b85a6ca86f6dd8bf02 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Mon, 29 Nov 2021 11:36:18 +0000 Subject: [PATCH 06/38] Model cleanup now added init to all getters and jsoncovnerters to enums --- .../Data/Account/AccountOrganisation.cs | 6 ++-- .../Data/Account/UserOrganisationRole.cs | 5 +++- .../Data/EnrolmentKeys/Enum/ApprovalMode.cs | 5 +++- .../EnrolmentKeys/Enum/EnrolmentKeyStatus.cs | 5 +++- .../EnrolmentKeys/Enum/EnrolmentKeyType.cs | 5 +++- .../Data/EnrolmentKeys/FullEnrolmentKey.cs | 28 +++++++++---------- .../Data/EnrolmentKeys/SimpleEnrolmentKey.cs | 24 ++++++++-------- .../Organisations/Enum/BillingEventLevel.cs | 22 --------------- .../Organisations/Enum/OrganisationPlan.cs | 5 +++- .../Data/Organisations/Organisation.cs | 1 + .../Organisations/OrganisationBillingEvent.cs | 24 ---------------- src/Enclave.Sdk/Data/Tags/TagReference.cs | 2 +- src/Enclave.Sdk/EnclaveClient.cs | 2 +- 13 files changed, 53 insertions(+), 81 deletions(-) delete mode 100644 src/Enclave.Sdk/Data/Organisations/Enum/BillingEventLevel.cs delete mode 100644 src/Enclave.Sdk/Data/Organisations/OrganisationBillingEvent.cs diff --git a/src/Enclave.Sdk/Data/Account/AccountOrganisation.cs b/src/Enclave.Sdk/Data/Account/AccountOrganisation.cs index a0dd9bc..0113e20 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 System.Text.Json.Serialization; + +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; } = default!; } \ 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..582e543 100644 --- a/src/Enclave.Sdk/Data/Account/UserOrganisationRole.cs +++ b/src/Enclave.Sdk/Data/Account/UserOrganisationRole.cs @@ -1,5 +1,8 @@ -namespace Enclave.Sdk.Api.Data.Account; +using System.Text.Json.Serialization; +namespace Enclave.Sdk.Api.Data.Account; + +[JsonConverter(typeof(JsonStringEnumConverter))] public enum UserOrganisationRole { Owner, diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs index bf1ddad..305059a 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs @@ -1,5 +1,8 @@ -namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; +using System.Text.Json.Serialization; +namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; + +[JsonConverter(typeof(JsonStringEnumConverter))] public enum ApprovalMode { Automatic, diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyStatus.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyStatus.cs index 95fe6c9..606eca7 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyStatus.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyStatus.cs @@ -1,8 +1,11 @@ -namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; +using System.Text.Json.Serialization; + +namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; /// /// The status of an enrolment key. /// +[JsonConverter(typeof(JsonStringEnumConverter))] public enum EnrolmentKeyStatus { /// diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs index 11dcc59..bc05e16 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs @@ -1,5 +1,8 @@ -namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; +using System.Text.Json.Serialization; +namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; + +[JsonConverter(typeof(JsonStringEnumConverter))] public enum EnrolmentKeyType { GeneralPurpose, diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs index 62d0ca8..d367b9d 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs @@ -11,27 +11,27 @@ public class FullEnrolmentKey /// /// The ID of the enrolment key. /// - public int Id { get; } + public int Id { get; init; } /// /// The UTC timestamp when the key was created. /// - public DateTime Created { get; } + 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; } + public DateTime? LastUsed { get; init; } /// /// The type of key; general purpose (default) or ephemeral (enrolled systems are automatically removed). /// - public EnrolmentKeyType Type { get; } + public EnrolmentKeyType Type { get; init; } /// /// The approval mode for the key. /// - public ApprovalMode ApprovalMode { get; } + public ApprovalMode ApprovalMode { get; init; } /// /// The status of the key. @@ -44,37 +44,37 @@ public class FullEnrolmentKey /// /// The key value that can be used to enrol systems. /// - public string Key { get; } + public string Key { get; init; } /// /// The provided description of the key. /// - public string Description { get; } + public string Description { get; init; } /// /// Whether or not this key is enabled. /// - public bool IsEnabled { get; } + public bool IsEnabled { get; init; } /// /// The number of uses remaining. /// - public long UsesRemaining { get; } + public long UsesRemaining { get; init; } /// /// The number of systems enrolled with this key. /// - public long EnrolledCount { get; } + public long EnrolledCount { get; init; } /// /// The number of unapproved systems enrolled with this key. /// - public long UnapprovedCount { get; } + public long UnapprovedCount { get; init; } /// /// The set of tags applied to the key. /// - public IReadOnlyList Tags { get; } + public IReadOnlyList Tags { get; init; } /// /// Defines the number of minutes an ephemeral system enrolled with this key will be retained after a non-graceful disconnect. @@ -85,10 +85,10 @@ public class FullEnrolmentKey /// /// The set of IP constraints for the key. /// - public IReadOnlyList IpConstraints { get; } + public IReadOnlyList IpConstraints { get; init; } /// /// Any notes or additional info for this key. /// - public string? Notes { get; } + public string? Notes { get; init; } } \ No newline at end of file diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/SimpleEnrolmentKey.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/SimpleEnrolmentKey.cs index 54ae46b..1b094cc 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/SimpleEnrolmentKey.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/SimpleEnrolmentKey.cs @@ -11,27 +11,27 @@ public class SimpleEnrolmentKey /// /// The ID of the enrolment key. /// - public int Id { get; } + public int Id { get; init; } /// /// The UTC timestamp when the key was created. /// - public DateTime Created { get; } + 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; } + public DateTime? LastUsed { get; init; } /// /// The type of key; general purpose (default) or ephemeral (enrolled systems are automatically removed). /// - public EnrolmentKeyType Type { get; } + public EnrolmentKeyType Type { get; init; } /// /// The approval mode for the key. /// - public ApprovalMode ApprovalMode { get; } + public ApprovalMode ApprovalMode { get; init; } /// /// The status of the key. @@ -44,37 +44,37 @@ public class SimpleEnrolmentKey /// /// The key value that can be used to enrol systems. /// - public string Key { get; } = default!; + public string Key { get; init; } = default!; /// /// The provided description of the key. /// - public string Description { get; } = default!; + public string Description { get; init; } = default!; /// /// Whether or not this key is enabled. /// - public bool IsEnabled { get; } + public bool IsEnabled { get; init; } /// /// The number of uses remaining. /// - public long UsesRemaining { get; } + public long UsesRemaining { get; init; } /// /// The number of systems enrolled with this key. /// - public long EnrolledCount { get; } + public long EnrolledCount { get; init; } /// /// The number of unapproved systems enrolled with this key. /// - public long UnapprovedCount { get; } + public long UnapprovedCount { get; init; } /// /// The set of tags applied to the key. /// - public IReadOnlyList? Tags { get; } + public IReadOnlyList? Tags { get; init; } /// /// Defines the number of minutes an ephemeral system enrolled with this key will be retained after a non-graceful disconnect. diff --git a/src/Enclave.Sdk/Data/Organisations/Enum/BillingEventLevel.cs b/src/Enclave.Sdk/Data/Organisations/Enum/BillingEventLevel.cs deleted file mode 100644 index 7b92bd8..0000000 --- a/src/Enclave.Sdk/Data/Organisations/Enum/BillingEventLevel.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Enclave.Sdk.Api.Data.Organisations.Enum; - -/// -/// Defines levels for billing events. -/// -public enum BillingEventLevel -{ - /// - /// Info. - /// - Information, - - /// - /// Warning. - /// - Warning, - - /// - /// Error. - /// - Error, -} \ 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..a73c8b0 100644 --- a/src/Enclave.Sdk/Data/Organisations/Enum/OrganisationPlan.cs +++ b/src/Enclave.Sdk/Data/Organisations/Enum/OrganisationPlan.cs @@ -1,5 +1,8 @@ -namespace Enclave.Sdk.Api.Data.Organisations.Enum; +using System.Text.Json.Serialization; +namespace Enclave.Sdk.Api.Data.Organisations.Enum; + +[JsonConverter(typeof(JsonStringEnumConverter))] public enum OrganisationPlan { Starter = 0, diff --git a/src/Enclave.Sdk/Data/Organisations/Organisation.cs b/src/Enclave.Sdk/Data/Organisations/Organisation.cs index e329646..5f6f5ba 100644 --- a/src/Enclave.Sdk/Data/Organisations/Organisation.cs +++ b/src/Enclave.Sdk/Data/Organisations/Organisation.cs @@ -1,5 +1,6 @@ using Enclave.Sdk.Api.Data.Account; using Enclave.Sdk.Api.Data.Organisations.Enum; +using System.Text.Json.Serialization; 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/Tags/TagReference.cs b/src/Enclave.Sdk/Data/Tags/TagReference.cs index ba4265f..fe5038d 100644 --- a/src/Enclave.Sdk/Data/Tags/TagReference.cs +++ b/src/Enclave.Sdk/Data/Tags/TagReference.cs @@ -8,5 +8,5 @@ public class TagReference /// /// The tag name. /// - public string Tag { get; } = default!; + public string Tag { get; init; } = default!; } diff --git a/src/Enclave.Sdk/EnclaveClient.cs b/src/Enclave.Sdk/EnclaveClient.cs index 59a77ff..0ad177a 100644 --- a/src/Enclave.Sdk/EnclaveClient.cs +++ b/src/Enclave.Sdk/EnclaveClient.cs @@ -63,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); From 9604b6054c1f9565a76a4faa93eed240759310d6 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Mon, 29 Nov 2021 16:45:26 +0000 Subject: [PATCH 07/38] Started work on DNS client --- src/Enclave.Sdk/Clients/DNSClient.cs | 60 +++++++++++++++++++ .../Clients/EnrolmentKeysClient.cs | 2 +- .../Clients/Interfaces/IDnsClient.cs | 21 ++++++- src/Enclave.Sdk/Data/Dns/BasicDnsZone.cs | 39 ++++++++++++ src/Enclave.Sdk/Data/Dns/DnsSummary.cs | 23 +++++++ src/Enclave.Sdk/Data/Dns/DnsZoneCreate.cs | 17 ++++++ src/Enclave.Sdk/Data/Dns/DnsZoneId.cs | 8 +++ src/Enclave.Sdk/Data/Dns/FullDnsZone.cs | 38 ++++++++++++ 8 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 src/Enclave.Sdk/Data/Dns/BasicDnsZone.cs create mode 100644 src/Enclave.Sdk/Data/Dns/DnsSummary.cs create mode 100644 src/Enclave.Sdk/Data/Dns/DnsZoneCreate.cs create mode 100644 src/Enclave.Sdk/Data/Dns/DnsZoneId.cs create mode 100644 src/Enclave.Sdk/Data/Dns/FullDnsZone.cs diff --git a/src/Enclave.Sdk/Clients/DNSClient.cs b/src/Enclave.Sdk/Clients/DNSClient.cs index 73c8e42..fbc5b29 100644 --- a/src/Enclave.Sdk/Clients/DNSClient.cs +++ b/src/Enclave.Sdk/Clients/DNSClient.cs @@ -1,7 +1,12 @@ +using System.Net.Http.Json; +using System.Web; using Enclave.Sdk.Api.Clients.Interfaces; +using Enclave.Sdk.Api.Data.Dns; +using Enclave.Sdk.Api.Data.Pagination; namespace Enclave.Sdk.Api.Clients; +/// public class DnsClient : ClientBase, IDnsClient { private string _orgRoute; @@ -11,4 +16,59 @@ public DnsClient(HttpClient httpClient, string orgRoute) { _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(pageNumber, perPage); + + var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/dns/zones?{queryString}"); + + EnsureNotNull(model); + + return model; + } + + /// + public async Task CreateAsync(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; + } + + 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/EnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs index a3890be..ca19406 100644 --- a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs @@ -46,7 +46,7 @@ public async Task> GetEnrolmentKeysAs /// public async Task CreateAsync(EnrolmentKeyCreate createModel) { - if (createModel == null) + if (createModel is null) { throw new ArgumentNullException(nameof(createModel)); } diff --git a/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs index c409dd2..8f316fd 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs @@ -1,5 +1,24 @@ -namespace Enclave.Sdk.Api.Clients.Interfaces; +using Enclave.Sdk.Api.Data.Dns; +using Enclave.Sdk.Api.Data.Pagination; +namespace Enclave.Sdk.Api.Clients.Interfaces; + +/// +/// Perform CRUD operations on 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); } \ No newline at end of file diff --git a/src/Enclave.Sdk/Data/Dns/BasicDnsZone.cs b/src/Enclave.Sdk/Data/Dns/BasicDnsZone.cs new file mode 100644 index 0000000..039a0a8 --- /dev/null +++ b/src/Enclave.Sdk/Data/Dns/BasicDnsZone.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Enclave.Sdk.Api.Data.Dns; + +/// +/// Basic model representing a summary of a DNS record. +/// +public class BasicDnsZone +{ + /// + /// 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/Dns/DnsSummary.cs b/src/Enclave.Sdk/Data/Dns/DnsSummary.cs new file mode 100644 index 0000000..bedbcf7 --- /dev/null +++ b/src/Enclave.Sdk/Data/Dns/DnsSummary.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +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/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..421422b --- /dev/null +++ b/src/Enclave.Sdk/Data/Dns/DnsZoneId.cs @@ -0,0 +1,8 @@ +using TypedIds; + +namespace Enclave.Sdk.Api.Data.Dns; + +[TypedId(IdBackingType.Int)] +public partial struct DnsZoneId +{ +} diff --git a/src/Enclave.Sdk/Data/Dns/FullDnsZone.cs b/src/Enclave.Sdk/Data/Dns/FullDnsZone.cs new file mode 100644 index 0000000..cf05753 --- /dev/null +++ b/src/Enclave.Sdk/Data/Dns/FullDnsZone.cs @@ -0,0 +1,38 @@ +namespace Enclave.Sdk.Api.Data.Dns; + +/// +/// Detailed model representing a DNS zone. +/// +public class FullDnsZone +{ + /// + /// 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; } +} From dfb76da9f27883bcdd93ea05379036df37be3c4c Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Tue, 30 Nov 2021 13:11:16 +0000 Subject: [PATCH 08/38] Added all api endpoints for the DNS Api --- src/Enclave.Sdk/Clients/DNSClient.cs | 152 +++++++++++++++++- .../Clients/Interfaces/IDnsClient.cs | 79 ++++++++- src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs | 50 ++++++ .../Data/Dns/BulkDnsRecordDeleteResult.cs | 12 ++ src/Enclave.Sdk/Data/Dns/DnsRecordCreate.cs | 40 +++++ src/Enclave.Sdk/Data/Dns/DnsRecordId.cs | 8 + src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs | 56 +++++++ .../Data/System/ISystemReferenceModel.cs | 43 +++++ src/Enclave.Sdk/Data/System/SystemState.cs | 22 +++ 9 files changed, 458 insertions(+), 4 deletions(-) create mode 100644 src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs create mode 100644 src/Enclave.Sdk/Data/Dns/BulkDnsRecordDeleteResult.cs create mode 100644 src/Enclave.Sdk/Data/Dns/DnsRecordCreate.cs create mode 100644 src/Enclave.Sdk/Data/Dns/DnsRecordId.cs create mode 100644 src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs create mode 100644 src/Enclave.Sdk/Data/System/ISystemReferenceModel.cs create mode 100644 src/Enclave.Sdk/Data/System/SystemState.cs diff --git a/src/Enclave.Sdk/Clients/DNSClient.cs b/src/Enclave.Sdk/Clients/DNSClient.cs index fbc5b29..48a1558 100644 --- a/src/Enclave.Sdk/Clients/DNSClient.cs +++ b/src/Enclave.Sdk/Clients/DNSClient.cs @@ -1,8 +1,10 @@ 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; @@ -30,7 +32,7 @@ public async Task GetPropertiesSummaryAsync() /// public async Task> GetZonesAsync(int? pageNumber = null, int? perPage = null) { - var queryString = BuildQueryString(pageNumber, perPage); + var queryString = BuildQueryString(null, null, pageNumber, perPage); var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/dns/zones?{queryString}"); @@ -40,7 +42,7 @@ public async Task> GetZonesAsync(int? pageN } /// - public async Task CreateAsync(DnsZoneCreate createModel) + public async Task CreateZoneAsync(DnsZoneCreate createModel) { if (createModel is null) { @@ -56,7 +58,151 @@ public async Task CreateAsync(DnsZoneCreate createModel) return model; } - private static string? BuildQueryString(int? pageNumber, int? perPage) + /// + 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 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 (pageNumber is not null) diff --git a/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs index 8f316fd..4362b41 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs @@ -1,5 +1,7 @@ -using Enclave.Sdk.Api.Data.Dns; +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; @@ -21,4 +23,79 @@ public interface IDnsClient /// 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); + + /// + /// 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/Data/Dns/BasicDnsRecord.cs b/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs new file mode 100644 index 0000000..2a64da2 --- /dev/null +++ b/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs @@ -0,0 +1,50 @@ +using Enclave.Sdk.Api.Data.System; +using Enclave.Sdk.Api.Data.Tags; + +namespace Enclave.Sdk.Api.Data.Dns; + +/// +/// Basic model representing a summary of a DNS record. +/// +public class BasicDnsRecord +{ + /// + /// 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; } + + /// + /// The set of systems to which this DNS name is applied. + /// + public IReadOnlyList? Systems { get; init; } +} diff --git a/src/Enclave.Sdk/Data/Dns/BulkDnsRecordDeleteResult.cs b/src/Enclave.Sdk/Data/Dns/BulkDnsRecordDeleteResult.cs new file mode 100644 index 0000000..64ef82a --- /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; } +} 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..1a7cb9f --- /dev/null +++ b/src/Enclave.Sdk/Data/Dns/DnsRecordId.cs @@ -0,0 +1,8 @@ +using TypedIds; + +namespace Enclave.Sdk.Api.Data.Dns; + +[TypedId(IdBackingType.Int)] +public partial struct DnsRecordId +{ +} diff --git a/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs b/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs new file mode 100644 index 0000000..6ace1bb --- /dev/null +++ b/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs @@ -0,0 +1,56 @@ +using Enclave.Sdk.Api.Data.System; +using Enclave.Sdk.Api.Data.Tags; + +namespace Enclave.Sdk.Api.Data.Dns; + +/// +/// Detailed model representing a DNS record. +/// +public class FullDnsRecord +{ + + /// + /// 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; } + + /// + /// 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; } +} diff --git a/src/Enclave.Sdk/Data/System/ISystemReferenceModel.cs b/src/Enclave.Sdk/Data/System/ISystemReferenceModel.cs new file mode 100644 index 0000000..cbc7f81 --- /dev/null +++ b/src/Enclave.Sdk/Data/System/ISystemReferenceModel.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Enclave.Sdk.Api.Data.System; + +/// +/// Abstraction for a system reference model so we can mix placeholder and "actual" reference models. +/// +public interface ISystemReferenceModel +{ + /// + /// Contains the last connected IP of the system. + /// + string? ConnectedFrom { get; } + + /// + /// The System ID. + /// + string Id { get; } + + /// + /// The local hostname of the system (if known). + /// + string? MachineName { get; } + + /// + /// The set name of the system (if one was provided). + /// + string? Name { get; } + + /// + /// The System platform type (if known). + /// + string? PlatformType { get; } + + /// + /// The state of the system. + /// + SystemState State { get; } +} diff --git a/src/Enclave.Sdk/Data/System/SystemState.cs b/src/Enclave.Sdk/Data/System/SystemState.cs new file mode 100644 index 0000000..6cc246d --- /dev/null +++ b/src/Enclave.Sdk/Data/System/SystemState.cs @@ -0,0 +1,22 @@ +namespace Enclave.Sdk.Api.Data.System; + +/// +/// 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 From fcce990d4f1350bd3d3695fb9a9f4c398e7b83c5 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Tue, 30 Nov 2021 13:16:59 +0000 Subject: [PATCH 09/38] added query string builder options --- src/Enclave.Sdk/Clients/DNSClient.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Enclave.Sdk/Clients/DNSClient.cs b/src/Enclave.Sdk/Clients/DNSClient.cs index 48a1558..b8237d7 100644 --- a/src/Enclave.Sdk/Clients/DNSClient.cs +++ b/src/Enclave.Sdk/Clients/DNSClient.cs @@ -199,12 +199,21 @@ public async Task DeleteRecordAsync(DnsRecordId dnsRecordId) 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()); From 546917171778f336d4d50313d0b932296a947f60 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Tue, 30 Nov 2021 14:59:33 +0000 Subject: [PATCH 10/38] added unit tests, need to add a few more --- src/Enclave.Sdk/Clients/DNSClient.cs | 6 +- .../Clients/Interfaces/IDnsClient.cs | 6 +- src/Enclave.Sdk/Clients/OrganisationClient.cs | 3 +- src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs | 2 +- .../Data/Dns/BulkDnsRecordDeleteResult.cs | 2 +- src/Enclave.Sdk/Data/Dns/DnsRecordId.cs | 2 +- src/Enclave.Sdk/Data/Dns/DnsZoneId.cs | 2 +- src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs | 4 +- .../ISystemReferenceModel.cs | 8 +- .../SystemState.cs | 2 +- src/Enclave.Sdk/Enclave.Sdk.Api.csproj | 5 +- .../Clients/DnsClientTests.cs | 431 ++++++++++++++++++ 12 files changed, 455 insertions(+), 18 deletions(-) rename src/Enclave.Sdk/Data/{System => SystemManagement}/ISystemReferenceModel.cs (84%) rename src/Enclave.Sdk/Data/{System => SystemManagement}/SystemState.cs (89%) create mode 100644 tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs diff --git a/src/Enclave.Sdk/Clients/DNSClient.cs b/src/Enclave.Sdk/Clients/DNSClient.cs index b8237d7..95ec409 100644 --- a/src/Enclave.Sdk/Clients/DNSClient.cs +++ b/src/Enclave.Sdk/Clients/DNSClient.cs @@ -103,7 +103,11 @@ public async Task DeleteZoneAsync(DnsZoneId dnsZoneId) } /// - public async Task> GetRecordsAsync(DnsZoneId? dnsZoneId = null, string? hostname = null, int? pageNumber = null, int? perPage = null) + public async Task> GetRecordsAsync( + DnsZoneId? dnsZoneId = null, + string? hostname = null, + int? pageNumber = null, + int? perPage = null) { var queryString = BuildQueryString(dnsZoneId, hostname, pageNumber, perPage); diff --git a/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs index 4362b41..ddf8fa6 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs @@ -61,7 +61,11 @@ public interface IDnsClient /// 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) + Task> GetRecordsAsync( + DnsZoneId? dnsZoneId = null, + string? hostname = null, + int? pageNumber = null, + int? perPage = null); /// /// Create a DNS Record using a model. diff --git a/src/Enclave.Sdk/Clients/OrganisationClient.cs b/src/Enclave.Sdk/Clients/OrganisationClient.cs index 19fce6f..8ba617a 100644 --- a/src/Enclave.Sdk/Clients/OrganisationClient.cs +++ b/src/Enclave.Sdk/Clients/OrganisationClient.cs @@ -25,6 +25,7 @@ public OrganisationClient(HttpClient httpClient, AccountOrganisation currentOrga _orgRoute = $"org/{Organisation.OrgId}"; EnrolmentKeys = new EnrolmentKeysClient(httpClient, _orgRoute); + Dns = new DnsClient(httpClient, _orgRoute); } /// @@ -34,7 +35,7 @@ public OrganisationClient(HttpClient httpClient, AccountOrganisation currentOrga public IAuthorityClient Authority => throw new NotImplementedException(); /// - public IDnsClient Dns => throw new NotImplementedException(); + public IDnsClient Dns { get; } /// public IEnrolmentKeysClient EnrolmentKeys { get; } diff --git a/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs b/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs index 2a64da2..0eea7d2 100644 --- a/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs +++ b/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs @@ -1,4 +1,4 @@ -using Enclave.Sdk.Api.Data.System; +using Enclave.Sdk.Api.Data.SystemManagement; using Enclave.Sdk.Api.Data.Tags; namespace Enclave.Sdk.Api.Data.Dns; diff --git a/src/Enclave.Sdk/Data/Dns/BulkDnsRecordDeleteResult.cs b/src/Enclave.Sdk/Data/Dns/BulkDnsRecordDeleteResult.cs index 64ef82a..6d494b2 100644 --- a/src/Enclave.Sdk/Data/Dns/BulkDnsRecordDeleteResult.cs +++ b/src/Enclave.Sdk/Data/Dns/BulkDnsRecordDeleteResult.cs @@ -8,5 +8,5 @@ public class BulkDnsRecordDeleteResult /// /// Specifies the number of DNS Records that were successfully deleted. /// - public int DnsRecordsDeleted { get; } + public int DnsRecordsDeleted { get; init; } } diff --git a/src/Enclave.Sdk/Data/Dns/DnsRecordId.cs b/src/Enclave.Sdk/Data/Dns/DnsRecordId.cs index 1a7cb9f..0982fb0 100644 --- a/src/Enclave.Sdk/Data/Dns/DnsRecordId.cs +++ b/src/Enclave.Sdk/Data/Dns/DnsRecordId.cs @@ -3,6 +3,6 @@ namespace Enclave.Sdk.Api.Data.Dns; [TypedId(IdBackingType.Int)] -public partial struct DnsRecordId +public readonly partial struct DnsRecordId { } diff --git a/src/Enclave.Sdk/Data/Dns/DnsZoneId.cs b/src/Enclave.Sdk/Data/Dns/DnsZoneId.cs index 421422b..17694d4 100644 --- a/src/Enclave.Sdk/Data/Dns/DnsZoneId.cs +++ b/src/Enclave.Sdk/Data/Dns/DnsZoneId.cs @@ -3,6 +3,6 @@ namespace Enclave.Sdk.Api.Data.Dns; [TypedId(IdBackingType.Int)] -public partial struct DnsZoneId +public readonly partial struct DnsZoneId { } diff --git a/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs b/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs index 6ace1bb..d35dc30 100644 --- a/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs +++ b/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs @@ -1,4 +1,4 @@ -using Enclave.Sdk.Api.Data.System; +using Enclave.Sdk.Api.Data.SystemManagement; using Enclave.Sdk.Api.Data.Tags; namespace Enclave.Sdk.Api.Data.Dns; @@ -52,5 +52,5 @@ public class FullDnsRecord /// /// Any provided notes for this record. /// - public string? Notes { get; } + public string? Notes { get; init; } } diff --git a/src/Enclave.Sdk/Data/System/ISystemReferenceModel.cs b/src/Enclave.Sdk/Data/SystemManagement/ISystemReferenceModel.cs similarity index 84% rename from src/Enclave.Sdk/Data/System/ISystemReferenceModel.cs rename to src/Enclave.Sdk/Data/SystemManagement/ISystemReferenceModel.cs index cbc7f81..ad9179c 100644 --- a/src/Enclave.Sdk/Data/System/ISystemReferenceModel.cs +++ b/src/Enclave.Sdk/Data/SystemManagement/ISystemReferenceModel.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Enclave.Sdk.Api.Data.System; +namespace Enclave.Sdk.Api.Data.SystemManagement; /// /// Abstraction for a system reference model so we can mix placeholder and "actual" reference models. diff --git a/src/Enclave.Sdk/Data/System/SystemState.cs b/src/Enclave.Sdk/Data/SystemManagement/SystemState.cs similarity index 89% rename from src/Enclave.Sdk/Data/System/SystemState.cs rename to src/Enclave.Sdk/Data/SystemManagement/SystemState.cs index 6cc246d..646307b 100644 --- a/src/Enclave.Sdk/Data/System/SystemState.cs +++ b/src/Enclave.Sdk/Data/SystemManagement/SystemState.cs @@ -1,4 +1,4 @@ -namespace Enclave.Sdk.Api.Data.System; +namespace Enclave.Sdk.Api.Data.SystemManagement; /// /// The possible states of an enrolled system. diff --git a/src/Enclave.Sdk/Enclave.Sdk.Api.csproj b/src/Enclave.Sdk/Enclave.Sdk.Api.csproj index 3e9595c..e405a68 100644 --- a/src/Enclave.Sdk/Enclave.Sdk.Api.csproj +++ b/src/Enclave.Sdk/Enclave.Sdk.Api.csproj @@ -17,7 +17,10 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + 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..403a875 --- /dev/null +++ b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs @@ -0,0 +1,431 @@ +using Enclave.Sdk.Api.Clients; +using Enclave.Sdk.Api.Data; +using Enclave.Sdk.Api.Data.Account; +using Enclave.Sdk.Api.Data.Dns; +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 currentOrganisation = new AccountOrganisation + { + OrgId = OrganisationId.New(), + OrgName = "TestName", + Role = UserOrganisationRole.Admin, + }; + + _orgRoute = $"/org/{currentOrganisation.OrgId}"; + + // Not sure if this is the best way of doing this + var organisationClient = new OrganisationClient(httpClient, currentOrganisation); + _dnsClient = (DnsClient)organisationClient.Dns; + } + + [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 BasicDnsZone { 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 BasicDnsZone { 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 BasicDnsZone { 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 FullDnsZone + { + 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 FullDnsZone + { + 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 FullDnsZone + { + 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 FullDnsZone + { + 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 BasicDnsRecord { 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 BasicDnsRecord { 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 BasicDnsRecord { 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 BasicDnsRecord { 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 BasicDnsRecord { 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() + { + + } +} From 2564ead8289408f2c8a36a408a226218a37184b1 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Wed, 1 Dec 2021 13:01:30 +0000 Subject: [PATCH 11/38] finished unit tests for dns client (happy path) --- .../Clients/DnsClientTests.cs | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs index 403a875..660dd8f 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs @@ -426,6 +426,142 @@ public async Task Should_make_a_call_to_api_with_per_page_quertString_when_calli [Test] public async Task Should_return_a_full_dns_record_model_when_calling_CreateRecordAsync() { + // Arrange + var response = new FullDnsRecord + { + 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 FullDnsRecord + { + 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 FullDnsRecord + { + Id = id, + Name = "New 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))); + + 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 FullDnsRecord + { + 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); } } From 87736fc35bb9918a11a242e73ae621b57c36b731 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Wed, 1 Dec 2021 14:26:50 +0000 Subject: [PATCH 12/38] Added documentation --- src/Enclave.Sdk/Clients/DNSClient.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Enclave.Sdk/Clients/DNSClient.cs b/src/Enclave.Sdk/Clients/DNSClient.cs index 95ec409..7f3833d 100644 --- a/src/Enclave.Sdk/Clients/DNSClient.cs +++ b/src/Enclave.Sdk/Clients/DNSClient.cs @@ -13,6 +13,12 @@ public class DnsClient : ClientBase, IDnsClient { private 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 DnsClient(HttpClient httpClient, string orgRoute) : base(httpClient) { From cd20dd84e796cd782db19c0498b66108b58a5caa Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Wed, 1 Dec 2021 14:34:22 +0000 Subject: [PATCH 13/38] fixed unit test --- tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs index 660dd8f..a12b4d6 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs @@ -520,7 +520,7 @@ public async Task Should_return_full_dns_record_when_calling_UpdateRecordAsync() }; _server - .Given(Request.Create().WithPath($"{_orgRoute}/dns/records/{id}").UsingGet()) + .Given(Request.Create().WithPath($"{_orgRoute}/dns/records/{id}").UsingPatch()) .RespondWith( Response.Create() .WithSuccess() From 89f516f308567c75618d7d0008d5c75333a107f9 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Thu, 2 Dec 2021 12:07:30 +0000 Subject: [PATCH 14/38] Finished unapproved systems and started tests --- .../Interfaces/IUnapprovedSystemsClient.cs | 67 ++++++- src/Enclave.Sdk/Clients/OrganisationClient.cs | 3 +- .../Clients/UnapprovedSystemsClient.cs | 163 ++++++++++++++++++ .../Data/Account/AccountOrganisation.cs | 4 +- src/Enclave.Sdk/Data/Dns/BasicDnsZone.cs | 8 +- src/Enclave.Sdk/Data/Dns/DnsSummary.cs | 8 +- .../Data/Organisations/Organisation.cs | 1 - .../Data/PatchModel/UnapprovedSystemPatch.cs | 22 +++ .../BulkUnapprovedSystemApproveResult.cs | 12 ++ .../BulkUnapprovedSystemDeclineResult.cs | 12 ++ .../Data/UnaprrovedSystems/SystemType.cs | 7 + .../UnaprrovedSystems/UnapprovedSystem.cs | 74 ++++++++ .../UnapprovedSystemDetail.cs | 79 +++++++++ .../UnapprovedSystemQuerySortMode.cs | 22 +++ .../Clients/DnsClientTests.cs | 13 +- .../Clients/EnrolmentKeyClientTests.cs | 14 +- .../Clients/UnapprovedSystemsClientTests.cs | 31 ++++ .../EnclaveClientTests.cs | 1 - 18 files changed, 498 insertions(+), 43 deletions(-) create mode 100644 src/Enclave.Sdk/Data/PatchModel/UnapprovedSystemPatch.cs create mode 100644 src/Enclave.Sdk/Data/UnaprrovedSystems/BulkUnapprovedSystemApproveResult.cs create mode 100644 src/Enclave.Sdk/Data/UnaprrovedSystems/BulkUnapprovedSystemDeclineResult.cs create mode 100644 src/Enclave.Sdk/Data/UnaprrovedSystems/SystemType.cs create mode 100644 src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs create mode 100644 src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs create mode 100644 src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemQuerySortMode.cs create mode 100644 tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs diff --git a/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs index aa34fdc..e136f67 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs @@ -1,5 +1,70 @@ -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; +namespace Enclave.Sdk.Api.Clients.Interfaces; + +/// +/// Perform CRUD operations on 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 tags 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 string[] systemIds); + + /// + /// Get the details of an Unapproved System. + /// + /// The system Id you want to get. + /// A Detailed Unapproved System Model. + Task GetAsync(string 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(string systemId, PatchBuilder builder); + + /// + /// Decline an Unapproved System. + /// + /// The system Id you want to decline. + /// The declined System. + Task DeclineAsync(string systemId); + + /// + /// Approve a System. + /// + /// The system Id you want to approve. + Task ApproveAsync(string systemId); + + /// + /// Approve multiple Unapproved Systems. + /// + /// System Ids to approve. + /// The number of systesm approved. + Task ApproveSystemsAsync(params string[] systemIds); } \ No newline at end of file diff --git a/src/Enclave.Sdk/Clients/OrganisationClient.cs b/src/Enclave.Sdk/Clients/OrganisationClient.cs index 8ba617a..697def0 100644 --- a/src/Enclave.Sdk/Clients/OrganisationClient.cs +++ b/src/Enclave.Sdk/Clients/OrganisationClient.cs @@ -26,6 +26,7 @@ public OrganisationClient(HttpClient httpClient, AccountOrganisation currentOrga EnrolmentKeys = new EnrolmentKeysClient(httpClient, _orgRoute); Dns = new DnsClient(httpClient, _orgRoute); + UnapprovedSystems = new UnapprovedSystemsClient(httpClient, _orgRoute); } /// @@ -53,7 +54,7 @@ public OrganisationClient(HttpClient httpClient, AccountOrganisation currentOrga public ITagsClient Tags => throw new NotImplementedException(); /// - public IUnapprovedSystemsClient UnapprovedSystems => throw new NotImplementedException(); + public IUnapprovedSystemsClient UnapprovedSystems { get; } /// public async Task GetAsync() diff --git a/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs b/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs index 5eebb5f..8ec5dad 100644 --- a/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs @@ -1,14 +1,177 @@ +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; namespace Enclave.Sdk.Api.Clients; +/// public class UnapprovedSystemsClient : ClientBase, IUnapprovedSystemsClient { private 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 string[] 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 GetAsync(string systemId) + { + var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/unapproved-systems/{systemId}", Constants.JsonSerializerOptions); + + EnsureNotNull(model); + + return model; + } + + /// + public async Task UpdateAsync(string 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(string 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(string systemId) + { + var result = await HttpClient.PutAsync($"{_orgRoute}/unapproved-systems/{systemId}/approve", null); + + result.EnsureSuccessStatusCode(); + } + + /// + public async Task ApproveSystemsAsync(params string[] systemIds) + { + using var content = CreateJsonContent(new + { + systemIds = systemIds, + }); + + var result = await HttpClient.PutAsync($"{_orgRoute}/unapproved-systems/approve", content); + + result.EnsureSuccessStatusCode(); + + var model = await DeserialiseAsync(result.Content); + + EnsureNotNull(model); + + return model.SystemsApproved; + } + + 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/Data/Account/AccountOrganisation.cs b/src/Enclave.Sdk/Data/Account/AccountOrganisation.cs index 0113e20..40826e9 100644 --- a/src/Enclave.Sdk/Data/Account/AccountOrganisation.cs +++ b/src/Enclave.Sdk/Data/Account/AccountOrganisation.cs @@ -1,6 +1,4 @@ -using System.Text.Json.Serialization; - -namespace Enclave.Sdk.Api.Data.Account; +namespace Enclave.Sdk.Api.Data.Account; /// /// Contains the role an account has within an organisation. diff --git a/src/Enclave.Sdk/Data/Dns/BasicDnsZone.cs b/src/Enclave.Sdk/Data/Dns/BasicDnsZone.cs index 039a0a8..9a2a8cf 100644 --- a/src/Enclave.Sdk/Data/Dns/BasicDnsZone.cs +++ b/src/Enclave.Sdk/Data/Dns/BasicDnsZone.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Enclave.Sdk.Api.Data.Dns; +namespace Enclave.Sdk.Api.Data.Dns; /// /// Basic model representing a summary of a DNS record. diff --git a/src/Enclave.Sdk/Data/Dns/DnsSummary.cs b/src/Enclave.Sdk/Data/Dns/DnsSummary.cs index bedbcf7..bf8ae47 100644 --- a/src/Enclave.Sdk/Data/Dns/DnsSummary.cs +++ b/src/Enclave.Sdk/Data/Dns/DnsSummary.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Enclave.Sdk.Api.Data.Dns; +namespace Enclave.Sdk.Api.Data.Dns; /// /// Summary of DNS properties for the organisation. diff --git a/src/Enclave.Sdk/Data/Organisations/Organisation.cs b/src/Enclave.Sdk/Data/Organisations/Organisation.cs index 5f6f5ba..e329646 100644 --- a/src/Enclave.Sdk/Data/Organisations/Organisation.cs +++ b/src/Enclave.Sdk/Data/Organisations/Organisation.cs @@ -1,6 +1,5 @@ using Enclave.Sdk.Api.Data.Account; using Enclave.Sdk.Api.Data.Organisations.Enum; -using System.Text.Json.Serialization; namespace Enclave.Sdk.Api.Data.Organisations; diff --git a/src/Enclave.Sdk/Data/PatchModel/UnapprovedSystemPatch.cs b/src/Enclave.Sdk/Data/PatchModel/UnapprovedSystemPatch.cs new file mode 100644 index 0000000..71866ce --- /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 string[]? Tags { get; set; } + + /// + /// Any notes or additional info for this system. + /// + public string? Notes { get; set; } +} 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/SystemType.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/SystemType.cs new file mode 100644 index 0000000..fb67ee3 --- /dev/null +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/SystemType.cs @@ -0,0 +1,7 @@ +namespace Enclave.Sdk.Api.Data.UnaprrovedSystems; + +public enum SystemType +{ + GeneralPurpose, + Ephemeral, +} diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs new file mode 100644 index 0000000..b92e0bd --- /dev/null +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs @@ -0,0 +1,74 @@ +using Enclave.Sdk.Api.Data.Tags; + +namespace Enclave.Sdk.Api.Data.UnaprrovedSystems; + +/// +/// Model representing an unapproved system. +/// +public class UnapprovedSystem +{ + /// + /// The system ID. + /// + public string 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; } + + /// + /// 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/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs new file mode 100644 index 0000000..19f0456 --- /dev/null +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs @@ -0,0 +1,79 @@ +using Enclave.Sdk.Api.Data.Tags; + +namespace Enclave.Sdk.Api.Data.UnaprrovedSystems; + +/// +/// Model representing an unapproved system. +/// +public class UnapprovedSystemDetail +{ + /// + /// The system ID. + /// + public string 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; } + + /// + /// 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/UnapprovedSystemQuerySortMode.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemQuerySortMode.cs new file mode 100644 index 0000000..66ef208 --- /dev/null +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemQuerySortMode.cs @@ -0,0 +1,22 @@ +namespace Enclave.Sdk.Api.Data.UnaprrovedSystems; + +/// +/// 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/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs index a12b4d6..9e8b173 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs @@ -34,18 +34,9 @@ public void Setup() BaseAddress = new Uri(_server.Urls[0]), }; - var currentOrganisation = new AccountOrganisation - { - OrgId = OrganisationId.New(), - OrgName = "TestName", - Role = UserOrganisationRole.Admin, - }; - - _orgRoute = $"/org/{currentOrganisation.OrgId}"; + _orgRoute = $"/org/{OrganisationId.New()}"; - // Not sure if this is the best way of doing this - var organisationClient = new OrganisationClient(httpClient, currentOrganisation); - _dnsClient = (DnsClient)organisationClient.Dns; + _dnsClient = new DnsClient(httpClient, _orgRoute); } [Test] diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs index d4200d7..fdddde9 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs @@ -34,19 +34,11 @@ public void Setup() { BaseAddress = new Uri(_server.Urls[0]), }; - - var currentOrganisation = new AccountOrganisation - { - OrgId = OrganisationId.New(), - OrgName = "TestName", - Role = UserOrganisationRole.Admin, - }; - - _orgRoute = $"/org/{currentOrganisation.OrgId}"; + + _orgRoute = $"/org/{OrganisationId.New()}"; // Not sure if this is the best way of doing this - var organisationClient = new OrganisationClient(httpClient, currentOrganisation); - _enrolmentKeysClient = (EnrolmentKeysClient)organisationClient.EnrolmentKeys; + _enrolmentKeysClient = new EnrolmentKeysClient(httpClient, _orgRoute); } [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..f1f2240 --- /dev/null +++ b/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs @@ -0,0 +1,31 @@ +using Enclave.Sdk.Api.Clients; +using Enclave.Sdk.Api.Data.Account; +using System.Text.Json; +using WireMock.Server; + +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]), + }; + + _orgRoute = $"/org/{OrganisationId.New()}"; + + _unapprovedSystemsClient = new UnapprovedSystemsClient(httpClient, _orgRoute); + } +} diff --git a/tests/Enclave.Sdk.Api.Tests/EnclaveClientTests.cs b/tests/Enclave.Sdk.Api.Tests/EnclaveClientTests.cs index 0091ac5..b172e09 100644 --- a/tests/Enclave.Sdk.Api.Tests/EnclaveClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/EnclaveClientTests.cs @@ -1,5 +1,4 @@ using System.Text.Json; -using Enclave.Sdk.Api.Data; using Enclave.Sdk.Api.Data.Account; using FluentAssertions; using NUnit.Framework; From 3ab98f1528713ac411082bfceab8ecc5a1070ed3 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Thu, 2 Dec 2021 14:57:11 +0000 Subject: [PATCH 15/38] tests added and updated test logic for older clients --- .../Clients/DnsClientTests.cs | 5 +- .../Clients/EnrolmentKeyClientTests.cs | 9 +- .../Clients/TagClientTests.cs | 7 +- .../Clients/UnapprovedSystemsClientTests.cs | 345 +++++++++++++++++- 4 files changed, 354 insertions(+), 12 deletions(-) diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs index 9e8b173..d5838b2 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs @@ -34,9 +34,10 @@ public void Setup() BaseAddress = new Uri(_server.Urls[0]), }; - _orgRoute = $"/org/{OrganisationId.New()}"; + var organisationId = OrganisationId.New(); + _orgRoute = $"/org/{organisationId}"; - _dnsClient = new DnsClient(httpClient, _orgRoute); + _dnsClient = new DnsClient(httpClient, $"org/{organisationId}"); } [Test] diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs index fdddde9..54ed1ea 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs @@ -34,11 +34,12 @@ public void Setup() { BaseAddress = new Uri(_server.Urls[0]), }; - - _orgRoute = $"/org/{OrganisationId.New()}"; - // Not sure if this is the best way of doing this - _enrolmentKeysClient = new EnrolmentKeysClient(httpClient, _orgRoute); + + var organisationId = OrganisationId.New(); + _orgRoute = $"/org/{organisationId}"; + + _enrolmentKeysClient = new EnrolmentKeysClient(httpClient, $"org/{organisationId}"); } [Test] diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/TagClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/TagClientTests.cs index 5675c01..82f6001 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.Account; 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 index f1f2240..a372bca 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs @@ -1,7 +1,16 @@ using Enclave.Sdk.Api.Clients; using Enclave.Sdk.Api.Data.Account; +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; namespace Enclave.Sdk.Api.Tests.Clients; @@ -24,8 +33,338 @@ public UnapprovedSystemsClientTests() BaseAddress = new Uri(_server.Urls[0]), }; - _orgRoute = $"/org/{OrganisationId.New()}"; + var organisationId = OrganisationId.New(); + _orgRoute = $"/org/{organisationId}"; - _unapprovedSystemsClient = new UnapprovedSystemsClient(httpClient, _orgRoute); + _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 UnapprovedSystem { 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 UnapprovedSystem { 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 UnapprovedSystem { 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 UnapprovedSystem { 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 UnapprovedSystem { 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 UnapprovedSystem { 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("system1", "system2"); + + // Assert + result.Should().Be(2); + } + + [Test] + public async Task Should_return_unapproved_system_detail_model_when_calling_GetAsync() + { + // Arrange + var response = new UnapprovedSystemDetail + { + SystemId = "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("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 UnapprovedSystemDetail + { + SystemId = "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("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 UnapprovedSystemDetail + { + SystemId = "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("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 UnapprovedSystemDetail + { + SystemId = "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("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("system1", "system2"); + + // Assert + result.Should().Be(2); + } +} \ No newline at end of file From 766b9eb9acf5dff17b6e598ccef8c954748e987d Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Fri, 3 Dec 2021 10:01:14 +0000 Subject: [PATCH 16/38] Slight changes to structure and tested --- .../Clients/Interfaces/IUnapprovedSystemsClient.cs | 1 + src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs | 1 + .../Data/UnaprrovedSystems/Enum/SystemType.cs | 10 ++++++++++ .../{ => Enum}/UnapprovedSystemQuerySortMode.cs | 5 ++++- src/Enclave.Sdk/Data/UnaprrovedSystems/SystemType.cs | 7 ------- .../Data/UnaprrovedSystems/UnapprovedSystem.cs | 1 + .../Data/UnaprrovedSystems/UnapprovedSystemDetail.cs | 1 + .../Clients/UnapprovedSystemsClientTests.cs | 1 + 8 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/SystemType.cs rename src/Enclave.Sdk/Data/UnaprrovedSystems/{ => Enum}/UnapprovedSystemQuerySortMode.cs (75%) delete mode 100644 src/Enclave.Sdk/Data/UnaprrovedSystems/SystemType.cs diff --git a/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs index e136f67..bd967f7 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs @@ -2,6 +2,7 @@ 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; diff --git a/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs b/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs index 8ec5dad..ba74e19 100644 --- a/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs @@ -5,6 +5,7 @@ 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; 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..c3af9f1 --- /dev/null +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/SystemType.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum SystemType +{ + GeneralPurpose, + Ephemeral, +} diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemQuerySortMode.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/UnapprovedSystemQuerySortMode.cs similarity index 75% rename from src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemQuerySortMode.cs rename to src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/UnapprovedSystemQuerySortMode.cs index 66ef208..ee4295b 100644 --- a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemQuerySortMode.cs +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/UnapprovedSystemQuerySortMode.cs @@ -1,8 +1,11 @@ -namespace Enclave.Sdk.Api.Data.UnaprrovedSystems; +using System.Text.Json.Serialization; + +namespace Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum; /// /// Sort modes for unapproved systems. /// +[JsonConverter(typeof(JsonStringEnumConverter))] public enum UnapprovedSystemQuerySortMode { /// diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/SystemType.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/SystemType.cs deleted file mode 100644 index fb67ee3..0000000 --- a/src/Enclave.Sdk/Data/UnaprrovedSystems/SystemType.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Enclave.Sdk.Api.Data.UnaprrovedSystems; - -public enum SystemType -{ - GeneralPurpose, - Ephemeral, -} diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs index b92e0bd..22956d3 100644 --- a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs @@ -1,4 +1,5 @@ using Enclave.Sdk.Api.Data.Tags; +using Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum; namespace Enclave.Sdk.Api.Data.UnaprrovedSystems; diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs index 19f0456..7bd4868 100644 --- a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs @@ -1,4 +1,5 @@ using Enclave.Sdk.Api.Data.Tags; +using Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum; namespace Enclave.Sdk.Api.Data.UnaprrovedSystems; diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs index a372bca..000fea0 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs @@ -11,6 +11,7 @@ using WireMock.ResponseBuilders; using Enclave.Sdk.Api.Data; using Enclave.Sdk.Api.Data.PatchModel; +using Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum; namespace Enclave.Sdk.Api.Tests.Clients; From 726582fd364a213fd5d79b4b4686deaf3989980c Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Thu, 2 Dec 2021 16:56:26 +0000 Subject: [PATCH 17/38] Started work on policy client --- src/Enclave.Sdk/Clients/DNSClient.cs | 3 +- .../Clients/EnrolmentKeysClient.cs | 3 +- src/Enclave.Sdk/Clients/PoliciesClient.cs | 59 +++++++++++++++++++ src/Enclave.Sdk/Data/Policies/Policy.cs | 54 +++++++++++++++++ src/Enclave.Sdk/Data/Policies/PolicyAcl.cs | 22 +++++++ .../Data/Policies/PolicyAclProtocol.cs | 12 ++++ .../Data/Policies/PolicySortOrder.cs | 7 +++ src/Enclave.Sdk/Data/Policies/PolicyState.cs | 22 +++++++ 8 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 src/Enclave.Sdk/Data/Policies/Policy.cs create mode 100644 src/Enclave.Sdk/Data/Policies/PolicyAcl.cs create mode 100644 src/Enclave.Sdk/Data/Policies/PolicyAclProtocol.cs create mode 100644 src/Enclave.Sdk/Data/Policies/PolicySortOrder.cs create mode 100644 src/Enclave.Sdk/Data/Policies/PolicyState.cs diff --git a/src/Enclave.Sdk/Clients/DNSClient.cs b/src/Enclave.Sdk/Clients/DNSClient.cs index 7f3833d..90dd990 100644 --- a/src/Enclave.Sdk/Clients/DNSClient.cs +++ b/src/Enclave.Sdk/Clients/DNSClient.cs @@ -14,8 +14,7 @@ public class DnsClient : ClientBase, IDnsClient private string _orgRoute; /// - /// This constructor is called by when setting up the . - /// It also calls the constructor. + /// Consutructor which will be called by when it's created. /// /// an instance of httpClient with a baseURL referencing the API. /// The organisation API route. diff --git a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs index ca19406..fdb0bf0 100644 --- a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs @@ -15,8 +15,7 @@ public class EnrolmentKeysClient : ClientBase, IEnrolmentKeysClient private string _orgRoute; /// - /// This constructor is called by when setting up the . - /// It also calls the constructor. + /// Consutructor which will be called by when it's created. /// /// an instance of httpClient with a baseURL referencing the API. /// The organisation API route. diff --git a/src/Enclave.Sdk/Clients/PoliciesClient.cs b/src/Enclave.Sdk/Clients/PoliciesClient.cs index 0f6aafd..d804d29 100644 --- a/src/Enclave.Sdk/Clients/PoliciesClient.cs +++ b/src/Enclave.Sdk/Clients/PoliciesClient.cs @@ -1,14 +1,73 @@ using Enclave.Sdk.Api.Clients.Interfaces; +using Enclave.Sdk.Api.Data.Pagination; +using Enclave.Sdk.Api.Data.Policies; +using System.Net.Http.Json; +using System.Web; namespace Enclave.Sdk.Api.Clients; +/// public class PoliciesClient : ClientBase, IPoliciesClient { private string _orgRoute; + /// + /// Consutructor 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> GetPolicies( + 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; + } + + 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(); + } } diff --git a/src/Enclave.Sdk/Data/Policies/Policy.cs b/src/Enclave.Sdk/Data/Policies/Policy.cs new file mode 100644 index 0000000..e218ab8 --- /dev/null +++ b/src/Enclave.Sdk/Data/Policies/Policy.cs @@ -0,0 +1,54 @@ +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 int 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; } + + /// + /// 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; } + + /// + /// The receiver-side tags. + /// + public IReadOnlyList ReceiverTags { get; init; } + + /// + /// Access control lists. + /// + public IReadOnlyList Acls { get; init; } + + /// + /// Optional notes for the policy. + /// + public string? Notes { get; init; } +} diff --git a/src/Enclave.Sdk/Data/Policies/PolicyAcl.cs b/src/Enclave.Sdk/Data/Policies/PolicyAcl.cs new file mode 100644 index 0000000..a53226a --- /dev/null +++ b/src/Enclave.Sdk/Data/Policies/PolicyAcl.cs @@ -0,0 +1,22 @@ +namespace Enclave.Sdk.Api.Data.Policies; + +/// +/// Model representing a single ACL entry for a policy. +/// +public class PolicyAcl +{ + /// + /// The protocol. + /// + public PolicyAclProtocol Protocol { get; init; } + + /// + /// The port range (or single port) for the ACL. + /// + public string? Ports { get; init; } + + /// + /// An optional description. + /// + public string? Description { get; init; } +} diff --git a/src/Enclave.Sdk/Data/Policies/PolicyAclProtocol.cs b/src/Enclave.Sdk/Data/Policies/PolicyAclProtocol.cs new file mode 100644 index 0000000..9c6f0e2 --- /dev/null +++ b/src/Enclave.Sdk/Data/Policies/PolicyAclProtocol.cs @@ -0,0 +1,12 @@ +namespace Enclave.Sdk.Api.Data.Policies; + +/// +/// Defines the known protocols enforced in policy ACLs. +/// +public enum PolicyAclProtocol +{ + Any, + Tcp, + Udp, + Icmp +} diff --git a/src/Enclave.Sdk/Data/Policies/PolicySortOrder.cs b/src/Enclave.Sdk/Data/Policies/PolicySortOrder.cs new file mode 100644 index 0000000..dd868d1 --- /dev/null +++ b/src/Enclave.Sdk/Data/Policies/PolicySortOrder.cs @@ -0,0 +1,7 @@ +namespace Enclave.Sdk.Api.Data.Policies; + +public enum PolicySortOrder +{ + Description, + RecentlyCreated, +} \ No newline at end of file diff --git a/src/Enclave.Sdk/Data/Policies/PolicyState.cs b/src/Enclave.Sdk/Data/Policies/PolicyState.cs new file mode 100644 index 0000000..1ca05d4 --- /dev/null +++ b/src/Enclave.Sdk/Data/Policies/PolicyState.cs @@ -0,0 +1,22 @@ +namespace Enclave.Sdk.Api.Data.Policies; + +/// +/// 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 From 67b5d572456bc5ea315365e89a75248067913bc0 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Thu, 2 Dec 2021 17:14:55 +0000 Subject: [PATCH 18/38] further methods for policy client added --- .../Clients/Interfaces/IPoliciesClient.cs | 30 ++++++++++++- src/Enclave.Sdk/Clients/PoliciesClient.cs | 45 ++++++++++++++++++- .../Data/PatchModel/PolicyPatch.cs | 5 ++- .../Policies/BulkDnsRecordDeleteResult.cs | 12 +++++ src/Enclave.Sdk/Data/Policies/PolicyCreate.cs | 40 +++++++++++++++++ src/Enclave.Sdk/Data/Policy/PolicyAclModel.cs | 22 --------- .../Data/Policy/PolicyAclProtocol.cs | 9 ---- 7 files changed, 128 insertions(+), 35 deletions(-) create mode 100644 src/Enclave.Sdk/Data/Policies/BulkDnsRecordDeleteResult.cs create mode 100644 src/Enclave.Sdk/Data/Policies/PolicyCreate.cs delete mode 100644 src/Enclave.Sdk/Data/Policy/PolicyAclModel.cs delete mode 100644 src/Enclave.Sdk/Data/Policy/PolicyAclProtocol.cs diff --git a/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs index b3283e4..b5981d6 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs @@ -1,5 +1,33 @@ -namespace Enclave.Sdk.Api.Clients.Interfaces; +using Enclave.Sdk.Api.Data.Pagination; +using Enclave.Sdk.Api.Data.Policies; +namespace Enclave.Sdk.Api.Clients.Interfaces; + +/// +/// Perform CRUD operations on DNS rules. +/// public interface IPoliciesClient { + /// + /// Gets a paginated list of Policies which can be searched and interated 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 tags 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); } \ No newline at end of file diff --git a/src/Enclave.Sdk/Clients/PoliciesClient.cs b/src/Enclave.Sdk/Clients/PoliciesClient.cs index d804d29..4c9f6c8 100644 --- a/src/Enclave.Sdk/Clients/PoliciesClient.cs +++ b/src/Enclave.Sdk/Clients/PoliciesClient.cs @@ -24,7 +24,7 @@ public PoliciesClient(HttpClient httpClient, string orgRoute) } /// - public async Task> GetPolicies( + public async Task> GetPoliciesAsync( string? searchTerm = null, bool? includeDisabled = null, PolicySortOrder? sortOrder = null, @@ -40,6 +40,49 @@ public async Task> GetPolicies( 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 int[] 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; + } + private static string? BuildQueryString(string? searchTerm, bool? includeDisabled, PolicySortOrder? sortOrder, int? pageNumber, int? perPage) { var queryString = HttpUtility.ParseQueryString(string.Empty); diff --git a/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs b/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs index 4cb526a..b541a14 100644 --- a/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs +++ b/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs @@ -1,4 +1,5 @@ -using Enclave.Sdk.Api.Data.Policy; +using Enclave.Sdk.Api.Data.Policies; +using Enclave.Sdk.Api.Data.Policy; namespace Enclave.Sdk.Api.Data.PatchModel; @@ -30,7 +31,7 @@ public class PolicyPatch : IPatchModel /// /// The set of ACLs for the policy. /// - public PolicyAclModel[]? Acls { get; set; } + public PolicyAcl[]? Acls { get; set; } /// /// Notes for the policy. diff --git a/src/Enclave.Sdk/Data/Policies/BulkDnsRecordDeleteResult.cs b/src/Enclave.Sdk/Data/Policies/BulkDnsRecordDeleteResult.cs new file mode 100644 index 0000000..89691a3 --- /dev/null +++ b/src/Enclave.Sdk/Data/Policies/BulkDnsRecordDeleteResult.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/PolicyCreate.cs b/src/Enclave.Sdk/Data/Policies/PolicyCreate.cs new file mode 100644 index 0000000..367f8b5 --- /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 string[] SenderTags { get; set; } = Array.Empty(); + + /// + /// A set of receiver tags. + /// + public string[] ReceiverTags { get; set; } = Array.Empty(); + + /// + /// The set of ACLs for the policy. + /// + public PolicyAcl[] Acls { get; set; } = Array.Empty(); + + /// + /// Optional notes for the policy. + /// + public string? Notes { get; set; } +} diff --git a/src/Enclave.Sdk/Data/Policy/PolicyAclModel.cs b/src/Enclave.Sdk/Data/Policy/PolicyAclModel.cs deleted file mode 100644 index 95ec7e5..0000000 --- a/src/Enclave.Sdk/Data/Policy/PolicyAclModel.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Enclave.Sdk.Api.Data.Policy; - -/// -/// Model representing a single ACL entry for a policy. -/// -public class PolicyAclModel -{ - /// - /// The protocol. - /// - public PolicyAclProtocol Protocol { get; set; } - - /// - /// The port range (or single port) for the ACL. - /// - public string? Ports { get; set; } - - /// - /// An optional description. - /// - public string? Description { get; set; } -} 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 -} From 903d2547e3579d8cab3cdbc35a772303e3062a68 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Fri, 3 Dec 2021 11:05:23 +0000 Subject: [PATCH 19/38] Style changes to clients and now using correct put method along with finished policies client --- src/Enclave.Sdk/Clients/AuthorityClient.cs | 2 +- src/Enclave.Sdk/Clients/DNSClient.cs | 2 +- .../Clients/EnrolmentKeysClient.cs | 10 +- .../Clients/Interfaces/IPoliciesClient.cs | 61 ++++++++- src/Enclave.Sdk/Clients/LogsClient.cs | 2 +- src/Enclave.Sdk/Clients/OrganisationClient.cs | 2 +- src/Enclave.Sdk/Clients/PoliciesClient.cs | 116 +++++++++++++++++- src/Enclave.Sdk/Clients/SystemsClient.cs | 2 +- src/Enclave.Sdk/Clients/TagsClient.cs | 6 +- .../Clients/UnapprovedSystemsClient.cs | 8 +- ...eteResult.cs => BulkPolicyDeleteResult.cs} | 0 .../Data/Policies/BulkPolicyUpdateResult.cs | 12 ++ 12 files changed, 199 insertions(+), 24 deletions(-) rename src/Enclave.Sdk/Data/Policies/{BulkDnsRecordDeleteResult.cs => BulkPolicyDeleteResult.cs} (100%) create mode 100644 src/Enclave.Sdk/Data/Policies/BulkPolicyUpdateResult.cs diff --git a/src/Enclave.Sdk/Clients/AuthorityClient.cs b/src/Enclave.Sdk/Clients/AuthorityClient.cs index c413012..5483302 100644 --- a/src/Enclave.Sdk/Clients/AuthorityClient.cs +++ b/src/Enclave.Sdk/Clients/AuthorityClient.cs @@ -4,7 +4,7 @@ namespace Enclave.Sdk.Api.Clients; public class AuthorityClient : ClientBase, IAuthorityClient { - private string _orgRoute; + private readonly string _orgRoute; public AuthorityClient(HttpClient httpClient, string orgRoute) : base(httpClient) diff --git a/src/Enclave.Sdk/Clients/DNSClient.cs b/src/Enclave.Sdk/Clients/DNSClient.cs index 90dd990..29e89e3 100644 --- a/src/Enclave.Sdk/Clients/DNSClient.cs +++ b/src/Enclave.Sdk/Clients/DNSClient.cs @@ -11,7 +11,7 @@ namespace Enclave.Sdk.Api.Clients; /// public class DnsClient : ClientBase, IDnsClient { - private string _orgRoute; + private readonly string _orgRoute; /// /// Consutructor which will be called by when it's created. diff --git a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs index fdb0bf0..c915370 100644 --- a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs @@ -12,7 +12,7 @@ namespace Enclave.Sdk.Api.Clients; /// public class EnrolmentKeysClient : ClientBase, IEnrolmentKeysClient { - private string _orgRoute; + private readonly string _orgRoute; /// /// Consutructor which will be called by when it's created. @@ -121,9 +121,7 @@ public async Task BulkEnableAsync(params int[] enrolmentKeys) keyIds = enrolmentKeys, }; - using var content = CreateJsonContent(requestModel); - - var result = await HttpClient.PutAsync($"{_orgRoute}/enrolment-keys/enable", content); + var result = await HttpClient.PutAsJsonAsync($"{_orgRoute}/enrolment-keys/enable", requestModel, Constants.JsonSerializerOptions); result.EnsureSuccessStatusCode(); @@ -142,9 +140,7 @@ public async Task BulkDisableAsync(params int[] enrolmentKeys) keyIds = enrolmentKeys, }; - using var content = CreateJsonContent(requestModel); - - var result = await HttpClient.PutAsync($"{_orgRoute}/enrolment-keys/disable", content); + var result = await HttpClient.PutAsJsonAsync($"{_orgRoute}/enrolment-keys/disable", requestModel, Constants.JsonSerializerOptions); result.EnsureSuccessStatusCode(); diff --git a/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs index b5981d6..6aac1c7 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs @@ -1,4 +1,6 @@ -using Enclave.Sdk.Api.Data.Pagination; +using Enclave.Sdk.Api.Data; +using Enclave.Sdk.Api.Data.Pagination; +using Enclave.Sdk.Api.Data.PatchModel; using Enclave.Sdk.Api.Data.Policies; namespace Enclave.Sdk.Api.Clients.Interfaces; @@ -30,4 +32,61 @@ Task> GetPoliciesAsync( /// 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 int[] policyIds); + + /// + /// Get a specific Policy. + /// + /// The Id of the Policy to get. + /// The . + Task GetAsync(int 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(int policyId, PatchBuilder builder); + + /// + /// Delete a Policy. + /// + /// The Id of the Policy to delete. + /// The deleted . + Task DeleteAsync(int policyId); + + /// + /// Enable a Policy. + /// + /// The Id of the Policy to enable. + /// The enabled . + Task EnableAsync(int policyId); + + /// + /// Disable a Policy. + /// + /// The Id of the Policy to disable. + /// The disabled . + Task DisableAsync(int policyId); + + /// + /// Enable multiple Policies. + /// + /// The ids of the Policies you want to enable. + /// The number of enabled Policies. + Task EnablePoliciesAsync(params int[] policyIds); + + /// + /// Disable multiple Policies. + /// + /// The ids of the Policies you want to disable. + /// The number of disabled Policies. + Task DisablePoliciesAsync(params int[] policyIds); } \ No newline at end of file diff --git a/src/Enclave.Sdk/Clients/LogsClient.cs b/src/Enclave.Sdk/Clients/LogsClient.cs index 53e7df1..aaedef8 100644 --- a/src/Enclave.Sdk/Clients/LogsClient.cs +++ b/src/Enclave.Sdk/Clients/LogsClient.cs @@ -4,7 +4,7 @@ namespace Enclave.Sdk.Api.Clients; public class LogsClient : ClientBase, ILogsClient { - private string _orgRoute; + private readonly string _orgRoute; public LogsClient(HttpClient httpClient, string orgRoute) : base(httpClient) diff --git a/src/Enclave.Sdk/Clients/OrganisationClient.cs b/src/Enclave.Sdk/Clients/OrganisationClient.cs index 697def0..28d40a8 100644 --- a/src/Enclave.Sdk/Clients/OrganisationClient.cs +++ b/src/Enclave.Sdk/Clients/OrganisationClient.cs @@ -10,7 +10,7 @@ namespace Enclave.Sdk.Api.Clients; /// public class OrganisationClient : ClientBase, IOrganisationClient { - private string _orgRoute; + private readonly string _orgRoute; /// /// This constructor is called by when setting up the . diff --git a/src/Enclave.Sdk/Clients/PoliciesClient.cs b/src/Enclave.Sdk/Clients/PoliciesClient.cs index 4c9f6c8..4f371b4 100644 --- a/src/Enclave.Sdk/Clients/PoliciesClient.cs +++ b/src/Enclave.Sdk/Clients/PoliciesClient.cs @@ -1,15 +1,17 @@ -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 System.Net.Http.Json; -using System.Web; namespace Enclave.Sdk.Api.Clients; /// public class PoliciesClient : ClientBase, IPoliciesClient { - private string _orgRoute; + private readonly string _orgRoute; /// /// Consutructor which will be called by when it's created. @@ -83,6 +85,112 @@ public async Task DeletePoliciesAsync(params int[] policyIds) return model.PoliciesDeleted; } + /// + public async Task GetAsync(int policyId) + { + var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/policies/{policyId}", Constants.JsonSerializerOptions); + + EnsureNotNull(model); + + return model; + } + + /// + public async Task UpdateAsync(int 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(int 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(int 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(int 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 int[] 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 DisablePoliciesAsync(params int[] 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; + } + private static string? BuildQueryString(string? searchTerm, bool? includeDisabled, PolicySortOrder? sortOrder, int? pageNumber, int? perPage) { var queryString = HttpUtility.ParseQueryString(string.Empty); diff --git a/src/Enclave.Sdk/Clients/SystemsClient.cs b/src/Enclave.Sdk/Clients/SystemsClient.cs index fb4bc02..fd1a02c 100644 --- a/src/Enclave.Sdk/Clients/SystemsClient.cs +++ b/src/Enclave.Sdk/Clients/SystemsClient.cs @@ -4,7 +4,7 @@ namespace Enclave.Sdk.Api.Clients; public class SystemsClient : ClientBase, ISystemsClient { - private string _orgRoute; + private readonly string _orgRoute; public SystemsClient(HttpClient httpClient, string orgRoute) : base(httpClient) diff --git a/src/Enclave.Sdk/Clients/TagsClient.cs b/src/Enclave.Sdk/Clients/TagsClient.cs index 43eea63..44c1f9e 100644 --- a/src/Enclave.Sdk/Clients/TagsClient.cs +++ b/src/Enclave.Sdk/Clients/TagsClient.cs @@ -1,15 +1,15 @@ +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 { - private string _orgRoute; + private readonly string _orgRoute; /// /// Consutructor which will be called by when it's created. diff --git a/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs b/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs index ba74e19..7c740ea 100644 --- a/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs @@ -12,7 +12,7 @@ namespace Enclave.Sdk.Api.Clients; /// public class UnapprovedSystemsClient : ClientBase, IUnapprovedSystemsClient { - private string _orgRoute; + private readonly string _orgRoute; /// /// This constructor is called by when setting up the . @@ -124,12 +124,12 @@ public async Task ApproveAsync(string systemId) /// public async Task ApproveSystemsAsync(params string[] systemIds) { - using var content = CreateJsonContent(new + var requestModel = new { systemIds = systemIds, - }); + }; - var result = await HttpClient.PutAsync($"{_orgRoute}/unapproved-systems/approve", content); + var result = await HttpClient.PutAsJsonAsync($"{_orgRoute}/unapproved-systems/approve", requestModel, Constants.JsonSerializerOptions); result.EnsureSuccessStatusCode(); diff --git a/src/Enclave.Sdk/Data/Policies/BulkDnsRecordDeleteResult.cs b/src/Enclave.Sdk/Data/Policies/BulkPolicyDeleteResult.cs similarity index 100% rename from src/Enclave.Sdk/Data/Policies/BulkDnsRecordDeleteResult.cs rename to src/Enclave.Sdk/Data/Policies/BulkPolicyDeleteResult.cs 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; } +} From 4215594eaffe259a746ea24f23815f374d9b6ba8 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Fri, 3 Dec 2021 11:13:07 +0000 Subject: [PATCH 20/38] removed white space --- src/Enclave.Sdk/Clients/PoliciesClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Enclave.Sdk/Clients/PoliciesClient.cs b/src/Enclave.Sdk/Clients/PoliciesClient.cs index 4f371b4..fbe66ee 100644 --- a/src/Enclave.Sdk/Clients/PoliciesClient.cs +++ b/src/Enclave.Sdk/Clients/PoliciesClient.cs @@ -221,4 +221,4 @@ public async Task DisablePoliciesAsync(params int[] policyIds) return queryString.ToString(); } -} +} \ No newline at end of file From 08d76519f5d8558952c442fb897f04fcfb02a791 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Fri, 3 Dec 2021 11:46:27 +0000 Subject: [PATCH 21/38] Started unit testing --- .../Data/PatchModel/PolicyPatch.cs | 1 - .../Clients/PoliciesClientTests.cs | 225 ++++++++++++++++++ 2 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 tests/Enclave.Sdk.Api.Tests/Clients/PoliciesClientTests.cs diff --git a/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs b/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs index b541a14..49d462c 100644 --- a/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs +++ b/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs @@ -1,5 +1,4 @@ using Enclave.Sdk.Api.Data.Policies; -using Enclave.Sdk.Api.Data.Policy; namespace Enclave.Sdk.Api.Data.PatchModel; 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..5820f3c --- /dev/null +++ b/tests/Enclave.Sdk.Api.Tests/Clients/PoliciesClientTests.cs @@ -0,0 +1,225 @@ +using Enclave.Sdk.Api.Clients; +using Enclave.Sdk.Api.Data.Account; +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; + +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}"); + } +} From ce848209e67e46a67d54bd8d9938642cfb6cfde8 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Fri, 3 Dec 2021 12:26:16 +0000 Subject: [PATCH 22/38] Added unit tests --- .../Clients/PoliciesClientTests.cs | 238 ++++++++++++++++++ 1 file changed, 238 insertions(+) diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/PoliciesClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/PoliciesClientTests.cs index 5820f3c..83d749c 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/PoliciesClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/PoliciesClientTests.cs @@ -9,6 +9,8 @@ using WireMock.ResponseBuilders; using WireMock.Server; using WireMock.FluentAssertions; +using Enclave.Sdk.Api.Data; +using Enclave.Sdk.Api.Data.PatchModel; namespace Enclave.Sdk.Api.Tests.Clients; @@ -222,4 +224,240 @@ public async Task Should_make_a_call_to_api_with_per_page_quertString_when_calli // 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(2, 3, 5); + + // Assert + result.Should().Be(3); + } + + [Test] + public async Task Should_return_policy_model_when_calling_GetAsync() + { + // Arrange + var response = new Policy + { + Id = 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(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 = 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(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 = 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(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 = 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(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 = 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(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(2, 3, 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(2, 3, 5); + + // Assert + result.Should().Be(3); + } } From f7318de1aba24e5e9f7224ff635fa917ee9e7363 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Fri, 3 Dec 2021 12:40:08 +0000 Subject: [PATCH 23/38] Tested and working --- src/Enclave.Sdk/Clients/OrganisationClient.cs | 3 ++- .../Data/Policies/{ => Enum}/PolicyAclProtocol.cs | 5 ++++- src/Enclave.Sdk/Data/Policies/Enum/PolicySortOrder.cs | 10 ++++++++++ .../Data/Policies/{ => Enum}/PolicyState.cs | 5 ++++- src/Enclave.Sdk/Data/Policies/PolicySortOrder.cs | 7 ------- 5 files changed, 20 insertions(+), 10 deletions(-) rename src/Enclave.Sdk/Data/Policies/{ => Enum}/PolicyAclProtocol.cs (54%) create mode 100644 src/Enclave.Sdk/Data/Policies/Enum/PolicySortOrder.cs rename src/Enclave.Sdk/Data/Policies/{ => Enum}/PolicyState.cs (74%) delete mode 100644 src/Enclave.Sdk/Data/Policies/PolicySortOrder.cs diff --git a/src/Enclave.Sdk/Clients/OrganisationClient.cs b/src/Enclave.Sdk/Clients/OrganisationClient.cs index 28d40a8..3f671fc 100644 --- a/src/Enclave.Sdk/Clients/OrganisationClient.cs +++ b/src/Enclave.Sdk/Clients/OrganisationClient.cs @@ -27,6 +27,7 @@ public OrganisationClient(HttpClient httpClient, AccountOrganisation currentOrga EnrolmentKeys = new EnrolmentKeysClient(httpClient, _orgRoute); Dns = new DnsClient(httpClient, _orgRoute); UnapprovedSystems = new UnapprovedSystemsClient(httpClient, _orgRoute); + Policies = new PoliciesClient(httpClient, _orgRoute); } /// @@ -45,7 +46,7 @@ public OrganisationClient(HttpClient httpClient, AccountOrganisation currentOrga public ILogsClient Logs => throw new NotImplementedException(); /// - public IPoliciesClient Policies => throw new NotImplementedException(); + public IPoliciesClient Policies { get; } /// public ISystemsClient Systems => throw new NotImplementedException(); diff --git a/src/Enclave.Sdk/Data/Policies/PolicyAclProtocol.cs b/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs similarity index 54% rename from src/Enclave.Sdk/Data/Policies/PolicyAclProtocol.cs rename to src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs index 9c6f0e2..009c837 100644 --- a/src/Enclave.Sdk/Data/Policies/PolicyAclProtocol.cs +++ b/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs @@ -1,8 +1,11 @@ -namespace Enclave.Sdk.Api.Data.Policies; +using System.Text.Json.Serialization; + +namespace Enclave.Sdk.Api.Data.Policies; /// /// Defines the known protocols enforced in policy ACLs. /// +[JsonConverter(typeof(JsonStringEnumConverter))] public enum PolicyAclProtocol { Any, 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..4ae0dd1 --- /dev/null +++ b/src/Enclave.Sdk/Data/Policies/Enum/PolicySortOrder.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace Enclave.Sdk.Api.Data.Policies; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum PolicySortOrder +{ + Description, + RecentlyCreated, +} \ No newline at end of file diff --git a/src/Enclave.Sdk/Data/Policies/PolicyState.cs b/src/Enclave.Sdk/Data/Policies/Enum/PolicyState.cs similarity index 74% rename from src/Enclave.Sdk/Data/Policies/PolicyState.cs rename to src/Enclave.Sdk/Data/Policies/Enum/PolicyState.cs index 1ca05d4..43e2954 100644 --- a/src/Enclave.Sdk/Data/Policies/PolicyState.cs +++ b/src/Enclave.Sdk/Data/Policies/Enum/PolicyState.cs @@ -1,8 +1,11 @@ -namespace Enclave.Sdk.Api.Data.Policies; +using System.Text.Json.Serialization; + +namespace Enclave.Sdk.Api.Data.Policies; /// /// Defines the possible states of policies. /// +[JsonConverter(typeof(JsonStringEnumConverter))] public enum PolicyState { /// diff --git a/src/Enclave.Sdk/Data/Policies/PolicySortOrder.cs b/src/Enclave.Sdk/Data/Policies/PolicySortOrder.cs deleted file mode 100644 index dd868d1..0000000 --- a/src/Enclave.Sdk/Data/Policies/PolicySortOrder.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Enclave.Sdk.Api.Data.Policies; - -public enum PolicySortOrder -{ - Description, - RecentlyCreated, -} \ No newline at end of file From 1caa24f641eb2a9541ddf2217adbac678cfc1316 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Mon, 6 Dec 2021 13:46:58 +0000 Subject: [PATCH 24/38] Changes as Per PR #2 --- .../Clients/Interfaces/IEnrolmentKeysClient.cs | 4 ++-- .../Data/Account/AccountOrganisation.cs | 2 +- .../Data/EnrolmentKeys/EnrolmentKeyCreate.cs | 2 +- .../EnrolmentKeys/EnrolmentKeyIpConstraint.cs | 17 +++++++++++++++++ .../EnrolmentKeyIpConstraintInput.cs | 11 ++++++++++- .../Data/EnrolmentKeys/FullEnrolmentKey.cs | 2 +- 6 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraint.cs diff --git a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs index 2bb932f..c93ab0e 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs @@ -15,10 +15,10 @@ 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 enorlment keys in the results. + /// Include the disabled Enrolment Keys in the results. /// Sort order for the pagination. /// Which page number do you want to return. - /// How many tags per page. + /// 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); diff --git a/src/Enclave.Sdk/Data/Account/AccountOrganisation.cs b/src/Enclave.Sdk/Data/Account/AccountOrganisation.cs index 0113e20..57c8424 100644 --- a/src/Enclave.Sdk/Data/Account/AccountOrganisation.cs +++ b/src/Enclave.Sdk/Data/Account/AccountOrganisation.cs @@ -31,5 +31,5 @@ public class AccountOrganisationTopLevel /// /// The set of organisations. /// - public IReadOnlyList Orgs { get; init; } = default!; + public IReadOnlyList Orgs { get; init; } = Array.Empty(); } \ No newline at end of file diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs index 08a6a17..a18d9cc 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs @@ -40,7 +40,7 @@ public class EnrolmentKeyCreate /// /// A set of tags automatically applied to systems enrolled with this key. /// - public string[]? Tags { get; set; } = Array.Empty(); + 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. 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 index 38c729e..9acbb02 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs @@ -5,10 +5,19 @@ /// public class EnrolmentKeyIpConstraintInput { + /// + /// A mandatory constructor for creating the IP Constraint. + /// + /// The IP range. + public EnrolmentKeyIpConstraintInput(string range) + { + Range = range; + } + /// /// The IP range. /// - public string Range { get; set; } = default!; + public string Range { get; } = default!; /// /// A description for the range. diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs index d367b9d..cf2b3ea 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs @@ -85,7 +85,7 @@ public class FullEnrolmentKey /// /// The set of IP constraints for the key. /// - public IReadOnlyList IpConstraints { get; init; } + public IReadOnlyList IpConstraints { get; init; } = Array.Empty(); /// /// Any notes or additional info for this key. From 980e1908a9410691e9e9ffa02be470bc07927d11 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Mon, 6 Dec 2021 14:19:37 +0000 Subject: [PATCH 25/38] refactor to reflect PR #2 changes --- .../Clients/EnrolmentKeysClient.cs | 12 ++++---- .../Interfaces/IEnrolmentKeysClient.cs | 12 ++++---- .../Clients/Interfaces/IPoliciesClient.cs | 17 ++++++----- .../Interfaces/IUnapprovedSystemsClient.cs | 12 ++++---- src/Enclave.Sdk/Clients/PoliciesClient.cs | 17 ++++++----- .../Clients/UnapprovedSystemsClient.cs | 12 ++++---- src/Enclave.Sdk/Constants.cs | 17 +++++++++-- .../Data/Account/AccountOrganisation.cs | 4 ++- .../Data/Account/UserOrganisationRole.cs | 5 +--- src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs | 2 +- src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs | 2 +- .../Data/EnrolmentKeys/EnrolmentKeyCreate.cs | 7 ++--- .../Data/EnrolmentKeys/EnrolmentKeyId.cs | 8 +++++ .../Data/EnrolmentKeys/Enum/ApprovalMode.cs | 5 +--- .../EnrolmentKeys/Enum/EnrolmentKeyStatus.cs | 5 +--- .../EnrolmentKeys/Enum/EnrolmentKeyType.cs | 5 +--- .../Data/EnrolmentKeys/FullEnrolmentKey.cs | 8 ++--- .../Data/EnrolmentKeys/SimpleEnrolmentKey.cs | 4 +-- .../Organisations/Enum/OrganisationPlan.cs | 5 +--- .../OrganisationId.cs | 2 +- src/Enclave.Sdk/Data/PatchBuilder.cs | 4 +-- .../Data/PatchModel/DnsRecordPatch.cs | 4 +-- .../Data/PatchModel/EnrolmentKeyPatch.cs | 2 +- .../Data/PatchModel/PolicyPatch.cs | 6 ++-- .../Data/PatchModel/SystemPatch.cs | 2 +- .../Data/PatchModel/UnapprovedSystemPatch.cs | 2 +- .../Data/Policies/Enum/PolicyAclProtocol.cs | 5 +--- .../Data/Policies/Enum/PolicySortOrder.cs | 5 +--- .../Data/Policies/Enum/PolicyState.cs | 5 +--- src/Enclave.Sdk/Data/Policies/Policy.cs | 9 +++--- src/Enclave.Sdk/Data/Policies/PolicyAcl.cs | 4 ++- src/Enclave.Sdk/Data/Policies/PolicyCreate.cs | 6 ++-- src/Enclave.Sdk/Data/Policies/PolicyId.cs | 8 +++++ .../Data/UnaprrovedSystems/Enum/SystemType.cs | 5 +--- .../Enum/UnapprovedSystemQuerySortMode.cs | 5 +--- .../Data/UnaprrovedSystems/SystemId.cs | 8 +++++ .../UnaprrovedSystems/UnapprovedSystem.cs | 4 +-- .../UnapprovedSystemDetail.cs | 4 +-- .../Clients/DnsClientTests.cs | 2 +- .../Clients/EnrolmentKeyClientTests.cs | 18 ++++++------ .../Clients/PoliciesClientTests.cs | 29 ++++++++++--------- .../Clients/TagClientTests.cs | 2 +- .../Clients/UnapprovedSystemsClientTests.cs | 22 +++++++------- .../EnclaveClientTests.cs | 1 + 44 files changed, 168 insertions(+), 155 deletions(-) create mode 100644 src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyId.cs rename src/Enclave.Sdk/Data/{Account => Organisations}/OrganisationId.cs (78%) create mode 100644 src/Enclave.Sdk/Data/Policies/PolicyId.cs create mode 100644 src/Enclave.Sdk/Data/UnaprrovedSystems/SystemId.cs diff --git a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs index c915370..641501d 100644 --- a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs @@ -60,7 +60,7 @@ public async Task CreateAsync(EnrolmentKeyCreate createModel) } /// - public async Task GetAsync(int enrolmentKeyId) + public async Task GetAsync(EnrolmentKeyId enrolmentKeyId) { var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}", Constants.JsonSerializerOptions); @@ -70,7 +70,7 @@ public async Task GetAsync(int enrolmentKeyId) } /// - public async Task UpdateAsync(int enrolmentKeyId, PatchBuilder builder) + public async Task UpdateAsync(EnrolmentKeyId enrolmentKeyId, PatchBuilder builder) { if (builder is null) { @@ -90,7 +90,7 @@ public async Task UpdateAsync(int enrolmentKeyId, PatchBuilder } /// - public async Task EnableAsync(int enrolmentKeyId) + public async Task EnableAsync(EnrolmentKeyId enrolmentKeyId) { var result = await HttpClient.PutAsync($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}/enable", null); @@ -102,7 +102,7 @@ public async Task EnableAsync(int enrolmentKeyId) } /// - public async Task DisableAsync(int enrolmentKeyId) + public async Task DisableAsync(EnrolmentKeyId enrolmentKeyId) { var result = await HttpClient.PutAsync($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}/disable", null); @@ -114,7 +114,7 @@ public async Task DisableAsync(int enrolmentKeyId) } /// - public async Task BulkEnableAsync(params int[] enrolmentKeys) + public async Task BulkEnableAsync(params EnrolmentKeyId[] enrolmentKeys) { var requestModel = new { @@ -133,7 +133,7 @@ public async Task BulkEnableAsync(params int[] enrolmentKeys) } /// - public async Task BulkDisableAsync(params int[] enrolmentKeys) + public async Task BulkDisableAsync(params EnrolmentKeyId[] enrolmentKeys) { var requestModel = new { diff --git a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs index 2bb932f..6c6e467 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs @@ -34,7 +34,7 @@ public interface IEnrolmentKeysClient /// /// The Id of the Enrolment Key to get. /// A detailed Enrolment Key. - Task GetAsync(int enrolmentKeyId); + Task GetAsync(EnrolmentKeyId enrolmentKeyId); /// /// Patch request to update the EnrolmentKey. @@ -43,33 +43,33 @@ public interface IEnrolmentKeysClient /// The Id of the Enrolment Key to update. /// An instance of used to setup our patch request. /// A detailed Enrolment Key. - Task UpdateAsync(int enrolmentKeyId, PatchBuilder builder); + Task UpdateAsync(EnrolmentKeyId enrolmentKeyId, PatchBuilder builder); /// /// Enable an Enrolment Key. /// /// The Id of the Enrolment Key to enable. /// A detailed Enrolment Key. - Task EnableAsync(int enrolmentKeyId); + Task EnableAsync(EnrolmentKeyId enrolmentKeyId); /// /// Disable an Enrolment Key. /// /// The Id of the Enrolment Key to disable. /// A detailed Enrolment Key. - Task DisableAsync(int enrolmentKeyId); + 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 int[] enrolmentKeys); + Task BulkEnableAsync(params EnrolmentKeyId[] enrolmentKeys); /// /// Bulk disable mutliple Enrolment Keys. /// /// An array of Enrolment Key Ids to disable. /// The number of keys modified. - Task BulkDisableAsync(params int[] enrolmentKeys); + Task BulkDisableAsync(params EnrolmentKeyId[] enrolmentKeys); } \ No newline at end of file diff --git a/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs index 6aac1c7..f322dbd 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs @@ -2,6 +2,7 @@ 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; @@ -38,14 +39,14 @@ Task> GetPoliciesAsync( /// /// The ids of the Policies you want to delete. /// The number of deleted Policies. - Task DeletePoliciesAsync(params int[] policyIds); + Task DeletePoliciesAsync(params PolicyId[] policyIds); /// /// Get a specific Policy. /// /// The Id of the Policy to get. /// The . - Task GetAsync(int policyId); + Task GetAsync(PolicyId policyId); /// /// Patch request to update a Policy. @@ -53,40 +54,40 @@ Task> GetPoliciesAsync( /// The Id of the Policy to update. /// An instance of used to setup our patch request. /// The updated . - Task UpdateAsync(int policyId, PatchBuilder builder); + Task UpdateAsync(PolicyId policyId, PatchBuilder builder); /// /// Delete a Policy. /// /// The Id of the Policy to delete. /// The deleted . - Task DeleteAsync(int policyId); + Task DeleteAsync(PolicyId policyId); /// /// Enable a Policy. /// /// The Id of the Policy to enable. /// The enabled . - Task EnableAsync(int policyId); + Task EnableAsync(PolicyId policyId); /// /// Disable a Policy. /// /// The Id of the Policy to disable. /// The disabled . - Task DisableAsync(int policyId); + Task DisableAsync(PolicyId policyId); /// /// Enable multiple Policies. /// /// The ids of the Policies you want to enable. /// The number of enabled Policies. - Task EnablePoliciesAsync(params int[] policyIds); + Task EnablePoliciesAsync(params PolicyId[] policyIds); /// /// Disable multiple Policies. /// /// The ids of the Policies you want to disable. /// The number of disabled Policies. - Task DisablePoliciesAsync(params int[] policyIds); + Task DisablePoliciesAsync(params PolicyId[] policyIds); } \ 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 bd967f7..45e42db 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs @@ -32,14 +32,14 @@ Task> GetSystemsAsync( /// /// System Ids to decline. /// The number of systesm declined. - Task DeclineSystems(params string[] systemIds); + Task DeclineSystems(params SystemId[] systemIds); /// /// Get the details of an Unapproved System. /// /// The system Id you want to get. /// A Detailed Unapproved System Model. - Task GetAsync(string systemId); + Task GetAsync(SystemId systemId); /// /// Patch request to update an Unapproved System. @@ -47,25 +47,25 @@ Task> GetSystemsAsync( /// The system Id you want to update. /// An instance of used to setup our patch request. /// An updated Detailed Unapproved System model. - Task UpdateAsync(string systemId, PatchBuilder builder); + Task UpdateAsync(SystemId systemId, PatchBuilder builder); /// /// Decline an Unapproved System. /// /// The system Id you want to decline. /// The declined System. - Task DeclineAsync(string systemId); + Task DeclineAsync(SystemId systemId); /// /// Approve a System. /// /// The system Id you want to approve. - Task ApproveAsync(string systemId); + Task ApproveAsync(SystemId systemId); /// /// Approve multiple Unapproved Systems. /// /// System Ids to approve. /// The number of systesm approved. - Task ApproveSystemsAsync(params string[] systemIds); + Task ApproveSystemsAsync(params SystemId[] systemIds); } \ No newline at end of file diff --git a/src/Enclave.Sdk/Clients/PoliciesClient.cs b/src/Enclave.Sdk/Clients/PoliciesClient.cs index fbe66ee..5a3e480 100644 --- a/src/Enclave.Sdk/Clients/PoliciesClient.cs +++ b/src/Enclave.Sdk/Clients/PoliciesClient.cs @@ -5,6 +5,7 @@ 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; @@ -60,7 +61,7 @@ public async Task CreateAsync(PolicyCreate createModel) } /// - public async Task DeletePoliciesAsync(params int[] policyIds) + public async Task DeletePoliciesAsync(params PolicyId[] policyIds) { using var content = CreateJsonContent(new { @@ -86,7 +87,7 @@ public async Task DeletePoliciesAsync(params int[] policyIds) } /// - public async Task GetAsync(int policyId) + public async Task GetAsync(PolicyId policyId) { var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/policies/{policyId}", Constants.JsonSerializerOptions); @@ -96,7 +97,7 @@ public async Task GetAsync(int policyId) } /// - public async Task UpdateAsync(int policyId, PatchBuilder builder) + public async Task UpdateAsync(PolicyId policyId, PatchBuilder builder) { if (builder is null) { @@ -116,7 +117,7 @@ public async Task UpdateAsync(int policyId, PatchBuilder bu } /// - public async Task DeleteAsync(int policyId) + public async Task DeleteAsync(PolicyId policyId) { var result = await HttpClient.DeleteAsync($"{_orgRoute}/policies/{policyId}"); @@ -130,7 +131,7 @@ public async Task DeleteAsync(int policyId) } /// - public async Task EnableAsync(int policyId) + public async Task EnableAsync(PolicyId policyId) { var result = await HttpClient.PutAsync($"{_orgRoute}/policies/{policyId}/enable", null); @@ -142,7 +143,7 @@ public async Task EnableAsync(int policyId) } /// - public async Task DisableAsync(int policyId) + public async Task DisableAsync(PolicyId policyId) { var result = await HttpClient.PutAsync($"{_orgRoute}/policies/{policyId}/disable", null); @@ -154,7 +155,7 @@ public async Task DisableAsync(int policyId) } /// - public async Task EnablePoliciesAsync(params int[] policyIds) + public async Task EnablePoliciesAsync(params PolicyId[] policyIds) { var requestModel = new { @@ -173,7 +174,7 @@ public async Task EnablePoliciesAsync(params int[] policyIds) } /// - public async Task DisablePoliciesAsync(params int[] policyIds) + public async Task DisablePoliciesAsync(params PolicyId[] policyIds) { var requestModel = new { diff --git a/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs b/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs index 7c740ea..c8625a9 100644 --- a/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs @@ -44,7 +44,7 @@ public async Task> GetSystemsAsync( } /// - public async Task DeclineSystems(params string[] systemIds) + public async Task DeclineSystems(params SystemId[] systemIds) { using var content = CreateJsonContent(new { @@ -70,7 +70,7 @@ public async Task DeclineSystems(params string[] systemIds) } /// - public async Task GetAsync(string systemId) + public async Task GetAsync(SystemId systemId) { var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/unapproved-systems/{systemId}", Constants.JsonSerializerOptions); @@ -80,7 +80,7 @@ public async Task GetAsync(string systemId) } /// - public async Task UpdateAsync(string systemId, PatchBuilder builder) + public async Task UpdateAsync(SystemId systemId, PatchBuilder builder) { if (builder is null) { @@ -100,7 +100,7 @@ public async Task UpdateAsync(string systemId, PatchBuil } /// - public async Task DeclineAsync(string systemId) + public async Task DeclineAsync(SystemId systemId) { var result = await HttpClient.DeleteAsync($"{_orgRoute}/unapproved-systems/{systemId}"); @@ -114,7 +114,7 @@ public async Task DeclineAsync(string systemId) } /// - public async Task ApproveAsync(string systemId) + public async Task ApproveAsync(SystemId systemId) { var result = await HttpClient.PutAsync($"{_orgRoute}/unapproved-systems/{systemId}/approve", null); @@ -122,7 +122,7 @@ public async Task ApproveAsync(string systemId) } /// - public async Task ApproveSystemsAsync(params string[] systemIds) + public async Task ApproveSystemsAsync(params SystemId[] systemIds) { var requestModel = new { diff --git a/src/Enclave.Sdk/Constants.cs b/src/Enclave.Sdk/Constants.cs index 2ffe3d0..38af783 100644 --- a/src/Enclave.Sdk/Constants.cs +++ b/src/Enclave.Sdk/Constants.cs @@ -1,13 +1,24 @@ 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 40826e9..a9ad745 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. diff --git a/src/Enclave.Sdk/Data/Account/UserOrganisationRole.cs b/src/Enclave.Sdk/Data/Account/UserOrganisationRole.cs index 582e543..d5af46d 100644 --- a/src/Enclave.Sdk/Data/Account/UserOrganisationRole.cs +++ b/src/Enclave.Sdk/Data/Account/UserOrganisationRole.cs @@ -1,8 +1,5 @@ -using System.Text.Json.Serialization; +namespace Enclave.Sdk.Api.Data.Account; -namespace Enclave.Sdk.Api.Data.Account; - -[JsonConverter(typeof(JsonStringEnumConverter))] public enum UserOrganisationRole { Owner, diff --git a/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs b/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs index 0eea7d2..f59963e 100644 --- a/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs +++ b/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs @@ -41,7 +41,7 @@ public class BasicDnsRecord /// /// The set of tags to which this DNS name is applied. /// - public IReadOnlyList? Tags { get; init; } + public IReadOnlyList Tags { get; init; } = Array.Empty(); /// /// The set of systems to which this DNS name is applied. diff --git a/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs b/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs index d35dc30..ac1e91c 100644 --- a/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs +++ b/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs @@ -42,7 +42,7 @@ public class FullDnsRecord /// /// The set of tags to which this DNS name is applied. /// - public IReadOnlyList? Tags { get; init; } + public IReadOnlyList Tags { get; init; } = Array.Empty(); /// /// The set of systems to which this DNS name is applied. diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs index 08a6a17..663627b 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs @@ -1,5 +1,5 @@ -using Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; -using System.ComponentModel; +using System.ComponentModel; +using Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; namespace Enclave.Sdk.Api.Data.EnrolmentKeys; @@ -8,7 +8,6 @@ namespace Enclave.Sdk.Api.Data.EnrolmentKeys; /// public class EnrolmentKeyCreate { - /// /// Defines the type of key being created, general purpose (default) or ephemeral (enrolled systems are automatically removed). /// @@ -40,7 +39,7 @@ public class EnrolmentKeyCreate /// /// A set of tags automatically applied to systems enrolled with this key. /// - public string[]? Tags { get; set; } = Array.Empty(); + 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. diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyId.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyId.cs new file mode 100644 index 0000000..c651970 --- /dev/null +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyId.cs @@ -0,0 +1,8 @@ +using TypedIds; + +namespace Enclave.Sdk.Api.Data.EnrolmentKeys; + +[TypedId(IdBackingType.Int)] +public partial struct EnrolmentKeyId +{ +} diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs index 305059a..bf1ddad 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs @@ -1,8 +1,5 @@ -using System.Text.Json.Serialization; +namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; -namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; - -[JsonConverter(typeof(JsonStringEnumConverter))] public enum ApprovalMode { Automatic, diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyStatus.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyStatus.cs index 606eca7..95fe6c9 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyStatus.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyStatus.cs @@ -1,11 +1,8 @@ -using System.Text.Json.Serialization; - -namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; +namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; /// /// The status of an enrolment key. /// -[JsonConverter(typeof(JsonStringEnumConverter))] public enum EnrolmentKeyStatus { /// diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs index bc05e16..11dcc59 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs @@ -1,8 +1,5 @@ -using System.Text.Json.Serialization; +namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; -namespace Enclave.Sdk.Api.Data.EnrolmentKeys.Enum; - -[JsonConverter(typeof(JsonStringEnumConverter))] public enum EnrolmentKeyType { GeneralPurpose, diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs index d367b9d..54a990d 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs @@ -11,7 +11,7 @@ public class FullEnrolmentKey /// /// The ID of the enrolment key. /// - public int Id { get; init; } + public EnrolmentKeyId Id { get; init; } /// /// The UTC timestamp when the key was created. @@ -44,12 +44,12 @@ public class FullEnrolmentKey /// /// The key value that can be used to enrol systems. /// - public string Key { get; init; } + public string Key { get; init; } = default!; /// /// The provided description of the key. /// - public string Description { get; init; } + public string Description { get; init; } = default!; /// /// Whether or not this key is enabled. @@ -74,7 +74,7 @@ public class FullEnrolmentKey /// /// The set of tags applied to the key. /// - public IReadOnlyList Tags { get; init; } + 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. diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/SimpleEnrolmentKey.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/SimpleEnrolmentKey.cs index 1b094cc..c5e2b9d 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/SimpleEnrolmentKey.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/SimpleEnrolmentKey.cs @@ -11,7 +11,7 @@ public class SimpleEnrolmentKey /// /// The ID of the enrolment key. /// - public int Id { get; init; } + public EnrolmentKeyId Id { get; init; } /// /// The UTC timestamp when the key was created. @@ -74,7 +74,7 @@ public class SimpleEnrolmentKey /// /// The set of tags applied to the key. /// - public IReadOnlyList? Tags { get; init; } + 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. diff --git a/src/Enclave.Sdk/Data/Organisations/Enum/OrganisationPlan.cs b/src/Enclave.Sdk/Data/Organisations/Enum/OrganisationPlan.cs index a73c8b0..8ed8025 100644 --- a/src/Enclave.Sdk/Data/Organisations/Enum/OrganisationPlan.cs +++ b/src/Enclave.Sdk/Data/Organisations/Enum/OrganisationPlan.cs @@ -1,8 +1,5 @@ -using System.Text.Json.Serialization; +namespace Enclave.Sdk.Api.Data.Organisations.Enum; -namespace Enclave.Sdk.Api.Data.Organisations.Enum; - -[JsonConverter(typeof(JsonStringEnumConverter))] public enum OrganisationPlan { Starter = 0, diff --git a/src/Enclave.Sdk/Data/Account/OrganisationId.cs b/src/Enclave.Sdk/Data/Organisations/OrganisationId.cs similarity index 78% rename from src/Enclave.Sdk/Data/Account/OrganisationId.cs rename to src/Enclave.Sdk/Data/Organisations/OrganisationId.cs index 5907c18..d528681 100644 --- a/src/Enclave.Sdk/Data/Account/OrganisationId.cs +++ b/src/Enclave.Sdk/Data/Organisations/OrganisationId.cs @@ -1,6 +1,6 @@ using TypedIds; -namespace Enclave.Sdk.Api.Data.Account; +namespace Enclave.Sdk.Api.Data.Organisations; /// /// OrganisaitonId struct to distinguish between Id types. 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/DnsRecordPatch.cs b/src/Enclave.Sdk/Data/PatchModel/DnsRecordPatch.cs index 8412310..b2815cc 100644 --- a/src/Enclave.Sdk/Data/PatchModel/DnsRecordPatch.cs +++ b/src/Enclave.Sdk/Data/PatchModel/DnsRecordPatch.cs @@ -13,12 +13,12 @@ public class DnsRecordPatch : IPatchModel /// /// The set of tags to which this DNS name is applied. /// - public IReadOnlyList? Tags { get; set; } + public List? Tags { get; set; } /// /// The set of systems to which this DNS name is applied. /// - public IReadOnlyList? Systems { get; set; } + public List? Systems { get; set; } /// /// Any notes or additional info for this record. diff --git a/src/Enclave.Sdk/Data/PatchModel/EnrolmentKeyPatch.cs b/src/Enclave.Sdk/Data/PatchModel/EnrolmentKeyPatch.cs index 345eb4a..6c978eb 100644 --- a/src/Enclave.Sdk/Data/PatchModel/EnrolmentKeyPatch.cs +++ b/src/Enclave.Sdk/Data/PatchModel/EnrolmentKeyPatch.cs @@ -36,7 +36,7 @@ public class EnrolmentKeyPatchModel : IPatchModel /// /// A set of tags automatically applied to systems enrolled with this key. /// - public string[]? Tags { get; set; } + 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. diff --git a/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs b/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs index 49d462c..34d3316 100644 --- a/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs +++ b/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs @@ -20,17 +20,17 @@ public class PolicyPatch : IPatchModel /// /// A set of sender tags. /// - public string[]? SenderTags { get; set; } + public List SenderTags { get; set; } = new List(); /// /// A set of receiver tags. /// - public string[]? ReceiverTags { get; set; } + public List ReceiverTags { get; set; } = new List(); /// /// The set of ACLs for the policy. /// - public PolicyAcl[]? Acls { get; set; } + public List Acls { get; set; } = new List(); /// /// Notes for the policy. diff --git a/src/Enclave.Sdk/Data/PatchModel/SystemPatch.cs b/src/Enclave.Sdk/Data/PatchModel/SystemPatch.cs index e309b1a..fd74c51 100644 --- a/src/Enclave.Sdk/Data/PatchModel/SystemPatch.cs +++ b/src/Enclave.Sdk/Data/PatchModel/SystemPatch.cs @@ -18,7 +18,7 @@ public class SystemPatch : IPatchModel /// /// The set of tags applied to the system. /// - public string[]? Tags { get; set; } + public List Tags { get; set; } = new List(); /// /// Any notes or additional info for this system. diff --git a/src/Enclave.Sdk/Data/PatchModel/UnapprovedSystemPatch.cs b/src/Enclave.Sdk/Data/PatchModel/UnapprovedSystemPatch.cs index 71866ce..74d4cce 100644 --- a/src/Enclave.Sdk/Data/PatchModel/UnapprovedSystemPatch.cs +++ b/src/Enclave.Sdk/Data/PatchModel/UnapprovedSystemPatch.cs @@ -13,7 +13,7 @@ public class UnapprovedSystemPatch : IPatchModel /// /// The set of tags applied to the system. /// - public string[]? Tags { get; set; } + public List Tags { get; set; } = new List(); /// /// Any notes or additional info for this system. diff --git a/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs b/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs index 009c837..c7a4064 100644 --- a/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs +++ b/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs @@ -1,11 +1,8 @@ -using System.Text.Json.Serialization; - -namespace Enclave.Sdk.Api.Data.Policies; +namespace Enclave.Sdk.Api.Data.Policies.Enum; /// /// Defines the known protocols enforced in policy ACLs. /// -[JsonConverter(typeof(JsonStringEnumConverter))] public enum PolicyAclProtocol { Any, diff --git a/src/Enclave.Sdk/Data/Policies/Enum/PolicySortOrder.cs b/src/Enclave.Sdk/Data/Policies/Enum/PolicySortOrder.cs index 4ae0dd1..c6ad0d1 100644 --- a/src/Enclave.Sdk/Data/Policies/Enum/PolicySortOrder.cs +++ b/src/Enclave.Sdk/Data/Policies/Enum/PolicySortOrder.cs @@ -1,8 +1,5 @@ -using System.Text.Json.Serialization; +namespace Enclave.Sdk.Api.Data.Policies.Enum; -namespace Enclave.Sdk.Api.Data.Policies; - -[JsonConverter(typeof(JsonStringEnumConverter))] public enum PolicySortOrder { Description, diff --git a/src/Enclave.Sdk/Data/Policies/Enum/PolicyState.cs b/src/Enclave.Sdk/Data/Policies/Enum/PolicyState.cs index 43e2954..dc83d13 100644 --- a/src/Enclave.Sdk/Data/Policies/Enum/PolicyState.cs +++ b/src/Enclave.Sdk/Data/Policies/Enum/PolicyState.cs @@ -1,11 +1,8 @@ -using System.Text.Json.Serialization; - -namespace Enclave.Sdk.Api.Data.Policies; +namespace Enclave.Sdk.Api.Data.Policies.Enum; /// /// Defines the possible states of policies. /// -[JsonConverter(typeof(JsonStringEnumConverter))] public enum PolicyState { /// diff --git a/src/Enclave.Sdk/Data/Policies/Policy.cs b/src/Enclave.Sdk/Data/Policies/Policy.cs index e218ab8..3a54983 100644 --- a/src/Enclave.Sdk/Data/Policies/Policy.cs +++ b/src/Enclave.Sdk/Data/Policies/Policy.cs @@ -1,4 +1,5 @@ -using Enclave.Sdk.Api.Data.Tags; +using Enclave.Sdk.Api.Data.Policies.Enum; +using Enclave.Sdk.Api.Data.Tags; namespace Enclave.Sdk.Api.Data.Policies; @@ -10,7 +11,7 @@ public class Policy /// /// The ID of the policy. /// - public int Id { get; init; } + public PolicyId Id { get; init; } /// /// The UTC timestamp when the policy was created. @@ -35,12 +36,12 @@ public class Policy /// /// The sender-side tags. /// - public IReadOnlyList SenderTags { get; init; } + public IReadOnlyList SenderTags { get; init; } = Array.Empty(); /// /// The receiver-side tags. /// - public IReadOnlyList ReceiverTags { get; init; } + public IReadOnlyList ReceiverTags { get; init; } = Array.Empty(); /// /// Access control lists. diff --git a/src/Enclave.Sdk/Data/Policies/PolicyAcl.cs b/src/Enclave.Sdk/Data/Policies/PolicyAcl.cs index a53226a..82423d1 100644 --- a/src/Enclave.Sdk/Data/Policies/PolicyAcl.cs +++ b/src/Enclave.Sdk/Data/Policies/PolicyAcl.cs @@ -1,4 +1,6 @@ -namespace Enclave.Sdk.Api.Data.Policies; +using Enclave.Sdk.Api.Data.Policies.Enum; + +namespace Enclave.Sdk.Api.Data.Policies; /// /// Model representing a single ACL entry for a policy. diff --git a/src/Enclave.Sdk/Data/Policies/PolicyCreate.cs b/src/Enclave.Sdk/Data/Policies/PolicyCreate.cs index 367f8b5..bf5f99b 100644 --- a/src/Enclave.Sdk/Data/Policies/PolicyCreate.cs +++ b/src/Enclave.Sdk/Data/Policies/PolicyCreate.cs @@ -21,17 +21,17 @@ public class PolicyCreate /// /// A set of sender tags. /// - public string[] SenderTags { get; set; } = Array.Empty(); + public List SenderTags { get; set; } = new List(); /// /// A set of receiver tags. /// - public string[] ReceiverTags { get; set; } = Array.Empty(); + public List ReceiverTags { get; set; } = new List(); /// /// The set of ACLs for the policy. /// - public PolicyAcl[] Acls { get; set; } = Array.Empty(); + public List Acls { get; set; } = new List(); /// /// Optional notes for the policy. diff --git a/src/Enclave.Sdk/Data/Policies/PolicyId.cs b/src/Enclave.Sdk/Data/Policies/PolicyId.cs new file mode 100644 index 0000000..ecd7df8 --- /dev/null +++ b/src/Enclave.Sdk/Data/Policies/PolicyId.cs @@ -0,0 +1,8 @@ +using TypedIds; + +namespace Enclave.Sdk.Api.Data.Policies; + +[TypedId(IdBackingType.Int)] +public partial struct PolicyId +{ +} diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/SystemType.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/SystemType.cs index c3af9f1..9aa78a2 100644 --- a/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/SystemType.cs +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/SystemType.cs @@ -1,8 +1,5 @@ -using System.Text.Json.Serialization; +namespace Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum; -namespace Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum; - -[JsonConverter(typeof(JsonStringEnumConverter))] public enum SystemType { GeneralPurpose, diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/UnapprovedSystemQuerySortMode.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/UnapprovedSystemQuerySortMode.cs index ee4295b..1453ff3 100644 --- a/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/UnapprovedSystemQuerySortMode.cs +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/UnapprovedSystemQuerySortMode.cs @@ -1,11 +1,8 @@ -using System.Text.Json.Serialization; - -namespace Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum; +namespace Enclave.Sdk.Api.Data.UnaprrovedSystems.Enum; /// /// Sort modes for unapproved systems. /// -[JsonConverter(typeof(JsonStringEnumConverter))] public enum UnapprovedSystemQuerySortMode { /// diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/SystemId.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/SystemId.cs new file mode 100644 index 0000000..2906730 --- /dev/null +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/SystemId.cs @@ -0,0 +1,8 @@ +using TypedIds; + +namespace Enclave.Sdk.Api.Data.UnaprrovedSystems; + +[TypedId(IdBackingType.String)] +public partial struct SystemId +{ +} diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs index 22956d3..d6e149b 100644 --- a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs @@ -11,7 +11,7 @@ public class UnapprovedSystem /// /// The system ID. /// - public string SystemId { get; init; } = default!; + public SystemId SystemId { get; init; } = default!; /// /// The system type. @@ -36,7 +36,7 @@ public class UnapprovedSystem /// /// The set of tags assigned to the system (either manually or automatically from the key). /// - public IReadOnlyList? Tags { get; init; } + public IReadOnlyList Tags { get; init; } = Array.Empty(); /// /// The ID of the enrolment key used to enrol the system. diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs index 7bd4868..cd7d8af 100644 --- a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs @@ -11,7 +11,7 @@ public class UnapprovedSystemDetail /// /// The system ID. /// - public string SystemId { get; init; } = default!; + public SystemId SystemId { get; init; } = default!; /// /// The system type. @@ -36,7 +36,7 @@ public class UnapprovedSystemDetail /// /// The set of tags assigned to the system (either manually or automatically from the key). /// - public IReadOnlyList? Tags { get; init; } + public IReadOnlyList Tags { get; init; } = Array.Empty(); /// /// The ID of the enrolment key used to enrol the system. diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs index d5838b2..f1cd38e 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs @@ -1,7 +1,7 @@ using Enclave.Sdk.Api.Clients; using Enclave.Sdk.Api.Data; -using Enclave.Sdk.Api.Data.Account; 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; diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs index 54ed1ea..2e11759 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs @@ -1,8 +1,8 @@ using Enclave.Sdk.Api.Clients; using Enclave.Sdk.Api.Data; -using Enclave.Sdk.Api.Data.Account; 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; @@ -247,7 +247,7 @@ public async Task Should_return_a_full_enrolment_key_model_when_calling_GetAsync // Arrange var response = new FullEnrolmentKey(); - var enrolmentKeyId = 12; + var enrolmentKeyId = EnrolmentKeyId.FromInt(12); _server .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}").UsingGet()) @@ -272,7 +272,7 @@ public async Task Should_return_a_full_enrolment_key_model_when_calling_UpdateAs // Arrange var response = new FullEnrolmentKey(); - var enrolmentKeyId = 12; + var enrolmentKeyId = EnrolmentKeyId.FromInt(12); _server .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}").UsingPatch()) @@ -298,7 +298,7 @@ public async Task Should_return_a_full_enrolment_key_model_when_calling_EnableAs // Arrange var response = new FullEnrolmentKey(); - var enrolmentKeyId = 12; + var enrolmentKeyId = EnrolmentKeyId.FromInt(12); _server .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}/enable").UsingPut()) @@ -321,7 +321,7 @@ public async Task Should_return_a_full_enrolment_key_model_when_calling_DisableA // Arrange var response = new FullEnrolmentKey(); - var enrolmentKeyId = 12; + var enrolmentKeyId = EnrolmentKeyId.FromInt(12); _server .Given(Request.Create().WithPath($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}/disable").UsingPut()) @@ -344,7 +344,7 @@ public async Task Should_return_number_of_keys_modified_when_calling_BulkEnableA // Arrange var response = new BulkKeyActionResult() { - KeysModified = 4, + KeysModified = 2, }; _server @@ -355,7 +355,7 @@ public async Task Should_return_number_of_keys_modified_when_calling_BulkEnableA .WithHeader("Content-Type", "application/json") .WithBody(JsonSerializer.Serialize(response, _serializerOptions))); - var keys = new int[] { 1, 2, 3, 4 }; + var keys = new EnrolmentKeyId[] { EnrolmentKeyId.FromInt(1), EnrolmentKeyId.FromInt(2) }; // Act var result = await _enrolmentKeysClient.BulkEnableAsync(keys); @@ -370,7 +370,7 @@ public async Task Should_return_number_of_keys_modified_when_calling_BulkDisable // Arrange var response = new BulkKeyActionResult() { - KeysModified = 4, + KeysModified = 2, }; _server @@ -381,7 +381,7 @@ public async Task Should_return_number_of_keys_modified_when_calling_BulkDisable .WithHeader("Content-Type", "application/json") .WithBody(JsonSerializer.Serialize(response, _serializerOptions))); - var keys = new int[] { 1, 2, 3, 4 }; + var keys = new EnrolmentKeyId[] { EnrolmentKeyId.FromInt(1), EnrolmentKeyId.FromInt(2) }; // Act var result = await _enrolmentKeysClient.BulkDisableAsync(keys); diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/PoliciesClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/PoliciesClientTests.cs index 83d749c..69533c2 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/PoliciesClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/PoliciesClientTests.cs @@ -1,5 +1,4 @@ using Enclave.Sdk.Api.Clients; -using Enclave.Sdk.Api.Data.Account; using Enclave.Sdk.Api.Data.Pagination; using Enclave.Sdk.Api.Data.Policies; using FluentAssertions; @@ -11,6 +10,8 @@ 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; @@ -273,7 +274,7 @@ public async Task Should_return_number_of_deleted_policies_when_calling_DeletePo .WithBody(JsonSerializer.Serialize(response, _serializerOptions))); // Act - var result = await _policiesClient.DeletePoliciesAsync(2, 3, 5); + var result = await _policiesClient.DeletePoliciesAsync(PolicyId.FromInt(2), PolicyId.FromInt(3), PolicyId.FromInt(5)); // Assert result.Should().Be(3); @@ -285,7 +286,7 @@ public async Task Should_return_policy_model_when_calling_GetAsync() // Arrange var response = new Policy { - Id = 12, + Id = PolicyId.FromInt(12), Description = "test", }; @@ -298,7 +299,7 @@ public async Task Should_return_policy_model_when_calling_GetAsync() .WithBody(JsonSerializer.Serialize(response, _serializerOptions))); // Act - var result = await _policiesClient.GetAsync(12); + var result = await _policiesClient.GetAsync(PolicyId.FromInt(12)); // Assert result.Should().NotBeNull(); @@ -311,7 +312,7 @@ public async Task Should_return_policy_model_when_calling_UpdateAsync() // Arrange var response = new Policy { - Id = 12, + Id = PolicyId.FromInt(12), Description = "test", }; @@ -326,7 +327,7 @@ public async Task Should_return_policy_model_when_calling_UpdateAsync() var builder = new PatchBuilder().Set(p => p.IsEnabled, false); // Act - var result = await _policiesClient.UpdateAsync(12, builder); + var result = await _policiesClient.UpdateAsync(PolicyId.FromInt(12), builder); // Assert result.Should().NotBeNull(); @@ -339,7 +340,7 @@ public async Task Should_return_policy_model_when_calling_DeleteAsync() // Arrange var response = new Policy { - Id = 12, + Id = PolicyId.FromInt(12), Description = "test", }; @@ -352,7 +353,7 @@ public async Task Should_return_policy_model_when_calling_DeleteAsync() .WithBody(JsonSerializer.Serialize(response, _serializerOptions))); // Act - var result = await _policiesClient.DeleteAsync(12); + var result = await _policiesClient.DeleteAsync(PolicyId.FromInt(12)); // Assert result.Should().NotBeNull(); @@ -365,7 +366,7 @@ public async Task Should_return_policy_model_when_calling_EnableAsync() // Arrange var response = new Policy { - Id = 12, + Id = PolicyId.FromInt(12), Description = "test", IsEnabled = true, }; @@ -379,7 +380,7 @@ public async Task Should_return_policy_model_when_calling_EnableAsync() .WithBody(JsonSerializer.Serialize(response, _serializerOptions))); // Act - var result = await _policiesClient.EnableAsync(12); + var result = await _policiesClient.EnableAsync(PolicyId.FromInt(12)); // Assert result.Should().NotBeNull(); @@ -392,7 +393,7 @@ public async Task Should_return_policy_model_when_calling_DisableAsync() // Arrange var response = new Policy { - Id = 12, + Id = PolicyId.FromInt(12), Description = "test", IsEnabled = false, }; @@ -406,7 +407,7 @@ public async Task Should_return_policy_model_when_calling_DisableAsync() .WithBody(JsonSerializer.Serialize(response, _serializerOptions))); // Act - var result = await _policiesClient.DisableAsync(12); + var result = await _policiesClient.DisableAsync(PolicyId.FromInt(12)); // Assert result.Should().NotBeNull(); @@ -431,7 +432,7 @@ public async Task Should_return_number_of_deleted_policies_when_calling_EnablePo .WithBody(JsonSerializer.Serialize(response, _serializerOptions))); // Act - var result = await _policiesClient.EnablePoliciesAsync(2, 3, 5); + var result = await _policiesClient.EnablePoliciesAsync(PolicyId.FromInt(2), PolicyId.FromInt(3), PolicyId.FromInt(5)); // Assert result.Should().Be(3); @@ -455,7 +456,7 @@ public async Task Should_return_number_of_deleted_policies_when_calling_DisableP .WithBody(JsonSerializer.Serialize(response, _serializerOptions))); // Act - var result = await _policiesClient.DisablePoliciesAsync(2, 3, 5); + 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 82f6001..8366a33 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/TagClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/TagClientTests.cs @@ -1,6 +1,6 @@ using System.Text.Json; using Enclave.Sdk.Api.Clients; -using Enclave.Sdk.Api.Data.Account; +using Enclave.Sdk.Api.Data.Organisations; using Enclave.Sdk.Api.Data.Pagination; using Enclave.Sdk.Api.Data.Tags; using FluentAssertions; diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs index 000fea0..9f20c36 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs @@ -1,5 +1,4 @@ using Enclave.Sdk.Api.Clients; -using Enclave.Sdk.Api.Data.Account; using Enclave.Sdk.Api.Data.Pagination; using Enclave.Sdk.Api.Data.UnaprrovedSystems; using FluentAssertions; @@ -12,6 +11,7 @@ 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; @@ -242,7 +242,7 @@ public async Task Should_return_number_of_declined_systems_when_calling_DeclineS .WithBody(JsonSerializer.Serialize(response, _serializerOptions))); // Act - var result = await _unapprovedSystemsClient.DeclineSystems("system1", "system2"); + var result = await _unapprovedSystemsClient.DeclineSystems(SystemId.FromString("system1"), SystemId.FromString("system2")); // Assert result.Should().Be(2); @@ -254,7 +254,7 @@ public async Task Should_return_unapproved_system_detail_model_when_calling_GetA // Arrange var response = new UnapprovedSystemDetail { - SystemId = "newId", + SystemId = SystemId.FromString("newId"), }; _server @@ -266,7 +266,7 @@ public async Task Should_return_unapproved_system_detail_model_when_calling_GetA .WithBody(JsonSerializer.Serialize(response, _serializerOptions))); // Act - var result = await _unapprovedSystemsClient.GetAsync("newId"); + var result = await _unapprovedSystemsClient.GetAsync(SystemId.FromString("newId")); // Assert result.Should().NotBeNull(); @@ -279,7 +279,7 @@ public async Task Should_return_unapproved_system_detail_model_when_calling_Upda // Arrange var response = new UnapprovedSystemDetail { - SystemId = "newId", + SystemId = SystemId.FromString("newId"), }; _server @@ -293,7 +293,7 @@ public async Task Should_return_unapproved_system_detail_model_when_calling_Upda var builder = new PatchBuilder().Set(u => u.Description, "New System"); // Act - var result = await _unapprovedSystemsClient.UpdateAsync("newId", builder); + var result = await _unapprovedSystemsClient.UpdateAsync(SystemId.FromString("newId"), builder); // Assert result.Should().NotBeNull(); @@ -306,7 +306,7 @@ public async Task Should_return_unapproved_system_detail_model_when_calling_Decl // Arrange var response = new UnapprovedSystemDetail { - SystemId = "newId", + SystemId = SystemId.FromString("newId"), }; _server @@ -318,7 +318,7 @@ public async Task Should_return_unapproved_system_detail_model_when_calling_Decl .WithBody(JsonSerializer.Serialize(response, _serializerOptions))); // Act - var result = await _unapprovedSystemsClient.DeclineAsync("newId"); + var result = await _unapprovedSystemsClient.DeclineAsync(SystemId.FromString("newId")); // Assert result.Should().NotBeNull(); @@ -331,7 +331,7 @@ public async Task Should_not_throw_an_error_when_calling_ApproveAsync() // Arrange var response = new UnapprovedSystemDetail { - SystemId = "newId", + SystemId = SystemId.FromString("newId"), }; _server @@ -343,7 +343,7 @@ public async Task Should_not_throw_an_error_when_calling_ApproveAsync() .WithBody(JsonSerializer.Serialize(response, _serializerOptions))); // Act - await _unapprovedSystemsClient.ApproveAsync("newId"); + await _unapprovedSystemsClient.ApproveAsync(SystemId.FromString("newId")); } [Test] @@ -363,7 +363,7 @@ public async Task Should_return_number_of_approved_systems_when_calling_ApproveS .WithBody(JsonSerializer.Serialize(response, _serializerOptions))); // Act - var result = await _unapprovedSystemsClient.ApproveSystemsAsync("system1", "system2"); + var result = await _unapprovedSystemsClient.ApproveSystemsAsync(SystemId.FromString("system1") , SystemId.FromString("system2")); // Assert result.Should().Be(2); diff --git a/tests/Enclave.Sdk.Api.Tests/EnclaveClientTests.cs b/tests/Enclave.Sdk.Api.Tests/EnclaveClientTests.cs index b172e09..bdd1995 100644 --- a/tests/Enclave.Sdk.Api.Tests/EnclaveClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/EnclaveClientTests.cs @@ -1,5 +1,6 @@ using System.Text.Json; using Enclave.Sdk.Api.Data.Account; +using Enclave.Sdk.Api.Data.Organisations; using FluentAssertions; using NUnit.Framework; using WireMock.RequestBuilders; From b91d917608f6154f9567ed6b821f7e1894042719 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Mon, 6 Dec 2021 14:46:03 +0000 Subject: [PATCH 26/38] More PR changes from PR #2 --- src/Enclave.Sdk/Clients/AuthorityClient.cs | 2 +- src/Enclave.Sdk/Clients/ClientBase.cs | 2 +- src/Enclave.Sdk/Clients/DNSClient.cs | 13 ++++++++++- .../Clients/EnrolmentKeysClient.cs | 14 ++++++++++- .../Clients/Interfaces/IDnsClient.cs | 9 +++++++- .../Interfaces/IEnrolmentKeysClient.cs | 16 ++++++++++++- .../Clients/Interfaces/IPoliciesClient.cs | 23 ++++++++++++++++++- .../Interfaces/IUnapprovedSystemsClient.cs | 16 ++++++++++++- src/Enclave.Sdk/Clients/LogsClient.cs | 2 +- src/Enclave.Sdk/Clients/OrganisationClient.cs | 2 +- src/Enclave.Sdk/Clients/PoliciesClient.cs | 20 +++++++++++++++- src/Enclave.Sdk/Clients/SystemsClient.cs | 2 +- src/Enclave.Sdk/Clients/TagsClient.cs | 2 +- .../Clients/UnapprovedSystemsClient.cs | 14 ++++++++++- .../Data/Policies/Enum/PolicyAclProtocol.cs | 2 +- src/Enclave.Sdk/Enclave.Sdk.Api.csproj | 1 + 16 files changed, 125 insertions(+), 15 deletions(-) diff --git a/src/Enclave.Sdk/Clients/AuthorityClient.cs b/src/Enclave.Sdk/Clients/AuthorityClient.cs index 5483302..ec19132 100644 --- a/src/Enclave.Sdk/Clients/AuthorityClient.cs +++ b/src/Enclave.Sdk/Clients/AuthorityClient.cs @@ -2,7 +2,7 @@ namespace Enclave.Sdk.Api.Clients; -public class AuthorityClient : ClientBase, IAuthorityClient +internal class AuthorityClient : ClientBase, IAuthorityClient { private readonly string _orgRoute; diff --git a/src/Enclave.Sdk/Clients/ClientBase.cs b/src/Enclave.Sdk/Clients/ClientBase.cs index 5d37714..64f5a21 100644 --- a/src/Enclave.Sdk/Clients/ClientBase.cs +++ b/src/Enclave.Sdk/Clients/ClientBase.cs @@ -9,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. diff --git a/src/Enclave.Sdk/Clients/DNSClient.cs b/src/Enclave.Sdk/Clients/DNSClient.cs index 29e89e3..79df723 100644 --- a/src/Enclave.Sdk/Clients/DNSClient.cs +++ b/src/Enclave.Sdk/Clients/DNSClient.cs @@ -9,7 +9,7 @@ namespace Enclave.Sdk.Api.Clients; /// -public class DnsClient : ClientBase, IDnsClient +internal class DnsClient : ClientBase, IDnsClient { private readonly string _orgRoute; @@ -166,6 +166,17 @@ public async Task DeleteRecordsAsync(params DnsRecordId[] records) 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) { diff --git a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs index 641501d..0f1127f 100644 --- a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs @@ -10,7 +10,7 @@ namespace Enclave.Sdk.Api.Clients; /// -public class EnrolmentKeysClient : ClientBase, IEnrolmentKeysClient +internal class EnrolmentKeysClient : ClientBase, IEnrolmentKeysClient { private readonly string _orgRoute; @@ -132,6 +132,12 @@ public async Task BulkEnableAsync(params EnrolmentKeyId[] enrolmentKeys) return model.KeysModified; } + /// + public async Task BulkEnableAsync(IEnumerable enrolmentKeys) + { + return await BulkEnableAsync(enrolmentKeys.ToArray()); + } + /// public async Task BulkDisableAsync(params EnrolmentKeyId[] enrolmentKeys) { @@ -151,6 +157,12 @@ public async Task BulkDisableAsync(params EnrolmentKeyId[] enrolmentKeys) 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); diff --git a/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs index ddf8fa6..401ac21 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs @@ -6,7 +6,7 @@ namespace Enclave.Sdk.Api.Clients.Interfaces; /// -/// Perform CRUD operations on DNS rules. +/// Provides operations to get, create, and manipulate DNS rules. /// public interface IDnsClient { @@ -81,6 +81,13 @@ Task> GetRecordsAsync( /// 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. /// diff --git a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs index ae588ad..f1f0f68 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs @@ -7,7 +7,7 @@ namespace Enclave.Sdk.Api.Clients.Interfaces; /// -/// Perform CRUD operations on Enrolment Keys. +/// Provides operations to get, create, and manipulate Enrolment Keys. /// public interface IEnrolmentKeysClient { @@ -66,10 +66,24 @@ public interface IEnrolmentKeysClient /// 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/IPoliciesClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs index f322dbd..f4a4246 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs @@ -7,7 +7,7 @@ namespace Enclave.Sdk.Api.Clients.Interfaces; /// -/// Perform CRUD operations on DNS rules. +/// Provides operations to get, create, and manipulate DNS rules. /// public interface IPoliciesClient { @@ -41,6 +41,13 @@ Task> GetPoliciesAsync( /// 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. /// @@ -84,10 +91,24 @@ Task> GetPoliciesAsync( /// 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/IUnapprovedSystemsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs index 45e42db..ab78f45 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs @@ -7,7 +7,7 @@ namespace Enclave.Sdk.Api.Clients.Interfaces; /// -/// Perform CRUD operations on Unapproved Systems. +/// Provides operations to get, create, and manipulate Unapproved Systems. /// public interface IUnapprovedSystemsClient { @@ -34,6 +34,13 @@ Task> GetSystemsAsync( /// 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. /// @@ -68,4 +75,11 @@ Task> GetSystemsAsync( /// 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 aaedef8..35518a6 100644 --- a/src/Enclave.Sdk/Clients/LogsClient.cs +++ b/src/Enclave.Sdk/Clients/LogsClient.cs @@ -2,7 +2,7 @@ namespace Enclave.Sdk.Api.Clients; -public class LogsClient : ClientBase, ILogsClient +internal class LogsClient : ClientBase, ILogsClient { private readonly string _orgRoute; diff --git a/src/Enclave.Sdk/Clients/OrganisationClient.cs b/src/Enclave.Sdk/Clients/OrganisationClient.cs index 3f671fc..3c039ff 100644 --- a/src/Enclave.Sdk/Clients/OrganisationClient.cs +++ b/src/Enclave.Sdk/Clients/OrganisationClient.cs @@ -8,7 +8,7 @@ namespace Enclave.Sdk.Api.Clients; /// -public class OrganisationClient : ClientBase, IOrganisationClient +internal class OrganisationClient : ClientBase, IOrganisationClient { private readonly string _orgRoute; diff --git a/src/Enclave.Sdk/Clients/PoliciesClient.cs b/src/Enclave.Sdk/Clients/PoliciesClient.cs index 5a3e480..d029874 100644 --- a/src/Enclave.Sdk/Clients/PoliciesClient.cs +++ b/src/Enclave.Sdk/Clients/PoliciesClient.cs @@ -10,7 +10,7 @@ namespace Enclave.Sdk.Api.Clients; /// -public class PoliciesClient : ClientBase, IPoliciesClient +internal class PoliciesClient : ClientBase, IPoliciesClient { private readonly string _orgRoute; @@ -86,6 +86,12 @@ public async Task DeletePoliciesAsync(params PolicyId[] policyIds) return model.PoliciesDeleted; } + /// + public async Task DeletePoliciesAsync(IEnumerable policyIds) + { + return await DeletePoliciesAsync(policyIds.ToArray()); + } + /// public async Task GetAsync(PolicyId policyId) { @@ -173,6 +179,12 @@ public async Task EnablePoliciesAsync(params PolicyId[] policyIds) return model.PoliciesUpdated; } + /// + public async Task EnablePoliciesAsync(IEnumerable policyIds) + { + return await EnablePoliciesAsync(policyIds.ToArray()); + } + /// public async Task DisablePoliciesAsync(params PolicyId[] policyIds) { @@ -192,6 +204,12 @@ public async Task DisablePoliciesAsync(params PolicyId[] policyIds) 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); diff --git a/src/Enclave.Sdk/Clients/SystemsClient.cs b/src/Enclave.Sdk/Clients/SystemsClient.cs index fd1a02c..b629dad 100644 --- a/src/Enclave.Sdk/Clients/SystemsClient.cs +++ b/src/Enclave.Sdk/Clients/SystemsClient.cs @@ -2,7 +2,7 @@ namespace Enclave.Sdk.Api.Clients; -public class SystemsClient : ClientBase, ISystemsClient +internal class SystemsClient : ClientBase, ISystemsClient { private readonly string _orgRoute; diff --git a/src/Enclave.Sdk/Clients/TagsClient.cs b/src/Enclave.Sdk/Clients/TagsClient.cs index 44c1f9e..6d93fe2 100644 --- a/src/Enclave.Sdk/Clients/TagsClient.cs +++ b/src/Enclave.Sdk/Clients/TagsClient.cs @@ -7,7 +7,7 @@ namespace Enclave.Sdk.Api.Clients; /// -public class TagsClient : ClientBase, ITagsClient +internal class TagsClient : ClientBase, ITagsClient { private readonly string _orgRoute; diff --git a/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs b/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs index c8625a9..feae06a 100644 --- a/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs @@ -10,7 +10,7 @@ namespace Enclave.Sdk.Api.Clients; /// -public class UnapprovedSystemsClient : ClientBase, IUnapprovedSystemsClient +internal class UnapprovedSystemsClient : ClientBase, IUnapprovedSystemsClient { private readonly string _orgRoute; @@ -69,6 +69,12 @@ public async Task DeclineSystems(params SystemId[] systemIds) return model.SystemsDeclined; } + /// + public async Task DeclineSystems(IEnumerable systemIds) + { + return await DeclineSystems(systemIds.ToArray()); + } + /// public async Task GetAsync(SystemId systemId) { @@ -140,6 +146,12 @@ public async Task ApproveSystemsAsync(params SystemId[] systemIds) return model.SystemsApproved; } + /// + public async Task ApproveSystemsAsync(IEnumerable systemIds) + { + return await ApproveSystemsAsync(systemIds.ToArray()); + } + private static string? BuildQueryString( int? enrolmentKeyId, string? searchTerm, diff --git a/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs b/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs index c7a4064..880fb8a 100644 --- a/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs +++ b/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs @@ -8,5 +8,5 @@ public enum PolicyAclProtocol Any, Tcp, Udp, - Icmp + Icmp, } diff --git a/src/Enclave.Sdk/Enclave.Sdk.Api.csproj b/src/Enclave.Sdk/Enclave.Sdk.Api.csproj index e405a68..cfeb246 100644 --- a/src/Enclave.Sdk/Enclave.Sdk.Api.csproj +++ b/src/Enclave.Sdk/Enclave.Sdk.Api.csproj @@ -22,6 +22,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + From eed7be60372898c5993f511ccd4bb8a8dc279955 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Mon, 6 Dec 2021 15:02:34 +0000 Subject: [PATCH 27/38] Added constructors for generating the IP Ranges --- .../EnrolmentKeyIpConstraintInput.cs | 61 +++++++++++++++++-- src/Enclave.Sdk/Enclave.Sdk.Api.csproj | 1 + 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs index 9acbb02..d667d9d 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs @@ -1,4 +1,6 @@ -namespace Enclave.Sdk.Api.Data.EnrolmentKeys; +using System.Net; + +namespace Enclave.Sdk.Api.Data.EnrolmentKeys; /// /// Input model for IP Address constraints. @@ -6,12 +8,61 @@ public class EnrolmentKeyIpConstraintInput { /// - /// A mandatory constructor for creating the IP Constraint. + /// 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"); + } + + if (!IPNetwork.TryParse(cidrNotation, out var network)) + { + throw new ArgumentException("Incorrect CIDR Format"); + } + + Range = cidrNotation; + } + + /// + /// Constructor that takes an IPAddress object to fill the Range field. /// - /// The IP range. - public EnrolmentKeyIpConstraintInput(string range) + /// The IP Address to use as the Range. + public EnrolmentKeyIpConstraintInput(IPAddress ipAddress) { - Range = range; + 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}"; } /// diff --git a/src/Enclave.Sdk/Enclave.Sdk.Api.csproj b/src/Enclave.Sdk/Enclave.Sdk.Api.csproj index 3e9595c..c8eaa21 100644 --- a/src/Enclave.Sdk/Enclave.Sdk.Api.csproj +++ b/src/Enclave.Sdk/Enclave.Sdk.Api.csproj @@ -17,6 +17,7 @@ + From 47b2dbab5074b1429e8d3a7cd35b2ea26f6c5554 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Fri, 3 Dec 2021 15:15:18 +0000 Subject: [PATCH 28/38] Easier to understand model naming --- .../Clients/Interfaces/IDnsClient.cs | 22 ++-- .../Clients/Interfaces/IPoliciesClient.cs | 2 +- .../Clients/Interfaces/ISystemsClient.cs | 42 ++++++- .../Dns/{FullDnsRecord.cs => DnsRecord.cs} | 2 +- ...{BasicDnsRecord.cs => DnsRecordSummary.cs} | 4 +- .../Data/Dns/{FullDnsZone.cs => DnsZone.cs} | 2 +- .../{BasicDnsZone.cs => DnsZoneSummary.cs} | 4 +- .../{FullEnrolmentKey.cs => EnrolmentKey.cs} | 2 +- ...EnrolmentKey.cs => EnrolmentKeySummary.cs} | 2 +- .../BulkSystemRevokedResult.cs | 12 ++ .../Data/SystemManagement/EnclaveSystem.cs | 105 ++++++++++++++++++ .../Enum/SystemQuerySortMode.cs | 9 ++ .../{ => Enum}/SystemState.cs | 2 +- .../Data/SystemManagement/Enum/SystemType.cs | 7 ++ .../SystemManagement/ISystemReferenceModel.cs | 4 +- .../Data/SystemManagement/SystemDnsEntry.cs | 45 ++++++++ .../Data/SystemManagement/SystemSummary.cs | 95 ++++++++++++++++ .../UnaprrovedSystems/UnapprovedSystem.cs | 7 +- ...emDetail.cs => UnapprovedSystemSummary.cs} | 9 +- .../Clients/DnsClientTests.cs | 64 +++++------ .../Clients/EnrolmentKeyClientTests.cs | 46 ++++---- .../Clients/UnapprovedSystemsClientTests.cs | 44 ++++---- 22 files changed, 423 insertions(+), 108 deletions(-) rename src/Enclave.Sdk/Data/Dns/{FullDnsRecord.cs => DnsRecord.cs} (98%) rename src/Enclave.Sdk/Data/Dns/{BasicDnsRecord.cs => DnsRecordSummary.cs} (94%) rename src/Enclave.Sdk/Data/Dns/{FullDnsZone.cs => DnsZone.cs} (97%) rename src/Enclave.Sdk/Data/Dns/{BasicDnsZone.cs => DnsZoneSummary.cs} (91%) rename src/Enclave.Sdk/Data/EnrolmentKeys/{FullEnrolmentKey.cs => EnrolmentKey.cs} (98%) rename src/Enclave.Sdk/Data/EnrolmentKeys/{SimpleEnrolmentKey.cs => EnrolmentKeySummary.cs} (98%) create mode 100644 src/Enclave.Sdk/Data/SystemManagement/BulkSystemRevokedResult.cs create mode 100644 src/Enclave.Sdk/Data/SystemManagement/EnclaveSystem.cs create mode 100644 src/Enclave.Sdk/Data/SystemManagement/Enum/SystemQuerySortMode.cs rename src/Enclave.Sdk/Data/SystemManagement/{ => Enum}/SystemState.cs (88%) create mode 100644 src/Enclave.Sdk/Data/SystemManagement/Enum/SystemType.cs create mode 100644 src/Enclave.Sdk/Data/SystemManagement/SystemDnsEntry.cs create mode 100644 src/Enclave.Sdk/Data/SystemManagement/SystemSummary.cs rename src/Enclave.Sdk/Data/UnaprrovedSystems/{UnapprovedSystemDetail.cs => UnapprovedSystemSummary.cs} (89%) diff --git a/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs index 401ac21..0082f1c 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs @@ -22,21 +22,21 @@ public interface IDnsClient /// 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); + 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); + /// 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); + Task GetZoneAsync(DnsZoneId dnsZoneId); /// /// Patch request to update a DNS Zone. @@ -44,14 +44,14 @@ public interface IDnsClient /// 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); + 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); + Task DeleteZoneAsync(DnsZoneId dnsZoneId); /// /// Gets a paginated list of DNS records. @@ -61,7 +61,7 @@ public interface IDnsClient /// 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( + Task> GetRecordsAsync( DnsZoneId? dnsZoneId = null, string? hostname = null, int? pageNumber = null, @@ -72,7 +72,7 @@ Task> GetRecordsAsync( /// /// The model needed to create a DNS Record /// The created DNS Record as . - Task CreateRecordAsync(DnsRecordCreate createModel); + Task CreateRecordAsync(DnsRecordCreate createModel); /// /// Delete multiple DNS Records. @@ -93,7 +93,7 @@ Task> GetRecordsAsync( /// /// The id of the DNS Record you want to get. /// A detailed DNS Record object - Task GetRecordAsync(DnsRecordId dnsRecordId); + Task GetRecordAsync(DnsRecordId dnsRecordId); /// /// Patch request to update a DNS Record. @@ -101,12 +101,12 @@ Task> GetRecordsAsync( /// 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); + 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); + Task DeleteRecordAsync(DnsRecordId dnsRecordId); } \ No newline at end of file diff --git a/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs index f4a4246..2ab4024 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs @@ -12,7 +12,7 @@ namespace Enclave.Sdk.Api.Clients.Interfaces; public interface IPoliciesClient { /// - /// Gets a paginated list of Policies which can be searched and interated upon. + /// 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. diff --git a/src/Enclave.Sdk/Clients/Interfaces/ISystemsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/ISystemsClient.cs index b0cf022..66b54eb 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/ISystemsClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/ISystemsClient.cs @@ -1,5 +1,45 @@ -namespace Enclave.Sdk.Api.Clients.Interfaces; +using Enclave.Sdk.Api.Data.Pagination; +using Enclave.Sdk.Api.Data.SystemManagement; +using Enclave.Sdk.Api.Data.SystemManagement.Enum; +namespace Enclave.Sdk.Api.Clients.Interfaces; + +/// +/// Perform CRUD operations on Systems. +/// public interface ISystemsClient { + /// + /// 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 tags 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 RevokeSystems(params string[] systemIds); + + /// + /// Retrieve a Detailed System model. + /// + /// The SystemId to Get. + /// A Full System Model. + Task GetAsync(string systemId); } \ No newline at end of file diff --git a/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs b/src/Enclave.Sdk/Data/Dns/DnsRecord.cs similarity index 98% rename from src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs rename to src/Enclave.Sdk/Data/Dns/DnsRecord.cs index ac1e91c..ba7ceaa 100644 --- a/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs +++ b/src/Enclave.Sdk/Data/Dns/DnsRecord.cs @@ -6,7 +6,7 @@ namespace Enclave.Sdk.Api.Data.Dns; /// /// Detailed model representing a DNS record. /// -public class FullDnsRecord +public class DnsRecord { /// diff --git a/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs b/src/Enclave.Sdk/Data/Dns/DnsRecordSummary.cs similarity index 94% rename from src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs rename to src/Enclave.Sdk/Data/Dns/DnsRecordSummary.cs index f59963e..e42e2a1 100644 --- a/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs +++ b/src/Enclave.Sdk/Data/Dns/DnsRecordSummary.cs @@ -4,9 +4,9 @@ namespace Enclave.Sdk.Api.Data.Dns; /// -/// Basic model representing a summary of a DNS record. +/// Model representing a summary of a DNS record. /// -public class BasicDnsRecord +public class DnsRecordSummary { /// /// The ID of the record. diff --git a/src/Enclave.Sdk/Data/Dns/FullDnsZone.cs b/src/Enclave.Sdk/Data/Dns/DnsZone.cs similarity index 97% rename from src/Enclave.Sdk/Data/Dns/FullDnsZone.cs rename to src/Enclave.Sdk/Data/Dns/DnsZone.cs index cf05753..6c8809a 100644 --- a/src/Enclave.Sdk/Data/Dns/FullDnsZone.cs +++ b/src/Enclave.Sdk/Data/Dns/DnsZone.cs @@ -3,7 +3,7 @@ /// /// Detailed model representing a DNS zone. /// -public class FullDnsZone +public class DnsZone { /// /// The ID of the zone. diff --git a/src/Enclave.Sdk/Data/Dns/BasicDnsZone.cs b/src/Enclave.Sdk/Data/Dns/DnsZoneSummary.cs similarity index 91% rename from src/Enclave.Sdk/Data/Dns/BasicDnsZone.cs rename to src/Enclave.Sdk/Data/Dns/DnsZoneSummary.cs index 9a2a8cf..d7dca28 100644 --- a/src/Enclave.Sdk/Data/Dns/BasicDnsZone.cs +++ b/src/Enclave.Sdk/Data/Dns/DnsZoneSummary.cs @@ -1,9 +1,9 @@ namespace Enclave.Sdk.Api.Data.Dns; /// -/// Basic model representing a summary of a DNS record. +/// Model representing a summary of a DNS record. /// -public class BasicDnsZone +public class DnsZoneSummary { /// /// The ID of the zone. diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKey.cs similarity index 98% rename from src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs rename to src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKey.cs index 6723d9a..2e84c11 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/FullEnrolmentKey.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKey.cs @@ -6,7 +6,7 @@ namespace Enclave.Sdk.Api.Data.EnrolmentKeys; /// /// Represents a single Enclave Enrolment Key. /// -public class FullEnrolmentKey +public class EnrolmentKey { /// /// The ID of the enrolment key. diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/SimpleEnrolmentKey.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeySummary.cs similarity index 98% rename from src/Enclave.Sdk/Data/EnrolmentKeys/SimpleEnrolmentKey.cs rename to src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeySummary.cs index c5e2b9d..7ecaf73 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/SimpleEnrolmentKey.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeySummary.cs @@ -6,7 +6,7 @@ namespace Enclave.Sdk.Api.Data.EnrolmentKeys; /// /// Represents a single Enclave Enrolment Key. /// -public class SimpleEnrolmentKey +public class EnrolmentKeySummary { /// /// The ID of the enrolment key. diff --git a/src/Enclave.Sdk/Data/SystemManagement/BulkSystemRevokedResult.cs b/src/Enclave.Sdk/Data/SystemManagement/BulkSystemRevokedResult.cs new file mode 100644 index 0000000..70360e6 --- /dev/null +++ b/src/Enclave.Sdk/Data/SystemManagement/BulkSystemRevokedResult.cs @@ -0,0 +1,12 @@ +namespace Enclave.Sdk.Api.Data.SystemManagement; + +/// +/// 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/SystemManagement/EnclaveSystem.cs b/src/Enclave.Sdk/Data/SystemManagement/EnclaveSystem.cs new file mode 100644 index 0000000..936e2a0 --- /dev/null +++ b/src/Enclave.Sdk/Data/SystemManagement/EnclaveSystem.cs @@ -0,0 +1,105 @@ +using Enclave.Sdk.Api.Data.SystemManagement.Enum; +using Enclave.Sdk.Api.Data.Tags; + +namespace Enclave.Sdk.Api.Data.SystemManagement; + +/// +/// A detailed model representing a single system. +/// +public class EnclaveSystem +{ + /// + /// Unique ID for the System. + /// + public string 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; } + + /// + /// The set of DNS entries applied to the system. + /// + public IReadOnlyList Dns { get; init; } + + /// + /// 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/SystemManagement/Enum/SystemQuerySortMode.cs b/src/Enclave.Sdk/Data/SystemManagement/Enum/SystemQuerySortMode.cs new file mode 100644 index 0000000..4e37790 --- /dev/null +++ b/src/Enclave.Sdk/Data/SystemManagement/Enum/SystemQuerySortMode.cs @@ -0,0 +1,9 @@ +namespace Enclave.Sdk.Api.Data.SystemManagement.Enum; + +public enum SystemQuerySortMode +{ + RecentlyEnrolled, + RecentlyConnected, + Description, + EnrolmentKeyUsed, +} \ No newline at end of file diff --git a/src/Enclave.Sdk/Data/SystemManagement/SystemState.cs b/src/Enclave.Sdk/Data/SystemManagement/Enum/SystemState.cs similarity index 88% rename from src/Enclave.Sdk/Data/SystemManagement/SystemState.cs rename to src/Enclave.Sdk/Data/SystemManagement/Enum/SystemState.cs index 646307b..b5357cd 100644 --- a/src/Enclave.Sdk/Data/SystemManagement/SystemState.cs +++ b/src/Enclave.Sdk/Data/SystemManagement/Enum/SystemState.cs @@ -1,4 +1,4 @@ -namespace Enclave.Sdk.Api.Data.SystemManagement; +namespace Enclave.Sdk.Api.Data.SystemManagement.Enum; /// /// The possible states of an enrolled system. diff --git a/src/Enclave.Sdk/Data/SystemManagement/Enum/SystemType.cs b/src/Enclave.Sdk/Data/SystemManagement/Enum/SystemType.cs new file mode 100644 index 0000000..91d0191 --- /dev/null +++ b/src/Enclave.Sdk/Data/SystemManagement/Enum/SystemType.cs @@ -0,0 +1,7 @@ +namespace Enclave.Sdk.Api.Data.SystemManagement.Enum; + +public enum SystemType +{ + GeneralPurpose, + Ephemeral, +} diff --git a/src/Enclave.Sdk/Data/SystemManagement/ISystemReferenceModel.cs b/src/Enclave.Sdk/Data/SystemManagement/ISystemReferenceModel.cs index ad9179c..1a6521e 100644 --- a/src/Enclave.Sdk/Data/SystemManagement/ISystemReferenceModel.cs +++ b/src/Enclave.Sdk/Data/SystemManagement/ISystemReferenceModel.cs @@ -1,4 +1,6 @@ -namespace Enclave.Sdk.Api.Data.SystemManagement; +using Enclave.Sdk.Api.Data.SystemManagement.Enum; + +namespace Enclave.Sdk.Api.Data.SystemManagement; /// /// Abstraction for a system reference model so we can mix placeholder and "actual" reference models. diff --git a/src/Enclave.Sdk/Data/SystemManagement/SystemDnsEntry.cs b/src/Enclave.Sdk/Data/SystemManagement/SystemDnsEntry.cs new file mode 100644 index 0000000..85b6784 --- /dev/null +++ b/src/Enclave.Sdk/Data/SystemManagement/SystemDnsEntry.cs @@ -0,0 +1,45 @@ +using Enclave.Sdk.Api.Data.Dns; +using Enclave.Sdk.Api.Data.Tags; + +namespace Enclave.Sdk.Api.Data.SystemManagement; + +/// +/// 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/SystemManagement/SystemSummary.cs b/src/Enclave.Sdk/Data/SystemManagement/SystemSummary.cs new file mode 100644 index 0000000..0bf6723 --- /dev/null +++ b/src/Enclave.Sdk/Data/SystemManagement/SystemSummary.cs @@ -0,0 +1,95 @@ +using Enclave.Sdk.Api.Data.SystemManagement.Enum; +using Enclave.Sdk.Api.Data.Tags; + +namespace Enclave.Sdk.Api.Data.SystemManagement; + +/// +/// A basic model representing a single system. +/// +public class SystemSummary +{ + /// + /// Unique ID for the System. + /// + public string 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/UnaprrovedSystems/UnapprovedSystem.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs index d6e149b..5a4aa06 100644 --- a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystem.cs @@ -46,7 +46,12 @@ public class UnapprovedSystem /// /// The description of the enrolment key used to enrol the system. /// - public string? EnrolmentKeyDescription { get; init; } + 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. diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemSummary.cs similarity index 89% rename from src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs rename to src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemSummary.cs index cd7d8af..148bd73 100644 --- a/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemDetail.cs +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/UnapprovedSystemSummary.cs @@ -6,7 +6,7 @@ namespace Enclave.Sdk.Api.Data.UnaprrovedSystems; /// /// Model representing an unapproved system. /// -public class UnapprovedSystemDetail +public class UnapprovedSystemSummary { /// /// The system ID. @@ -46,12 +46,7 @@ public class UnapprovedSystemDetail /// /// 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; } + public string? EnrolmentKeyDescription { get; init; } /// /// The locally-defined host name of the system. diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs index f1cd38e..86ae32d 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/DnsClientTests.cs @@ -68,11 +68,11 @@ public async Task Should_return_a_Dns_summary_when_calling_GetPropertiesSummaryA public async Task Should_return_a_paginated_response_model_when_calling_GetZonesAsync() { // Arrange - var response = new PaginatedResponseModel + var response = new PaginatedResponseModel { - Items = new List + Items = new List { - new BasicDnsZone { Name = "test"} + new DnsZoneSummary { Name = "test"} }, Links = new PaginationLinks(), Metadata = new PaginationMetadata(), @@ -97,11 +97,11 @@ public async Task Should_return_a_paginated_response_model_when_calling_GetZones public async Task Should_make_a_call_to_api_with_page_quertString_when_calling_GetZonesAsync() { // Arrange - var response = new PaginatedResponseModel + var response = new PaginatedResponseModel { - Items = new List + Items = new List { - new BasicDnsZone { Name = "test"} + new DnsZoneSummary { Name = "test"} }, Links = new PaginationLinks(), Metadata = new PaginationMetadata(), @@ -128,11 +128,11 @@ public async Task Should_make_a_call_to_api_with_page_quertString_when_calling_G public async Task Should_make_a_call_to_api_with_per_page_quertString_when_calling_GetZonesAsync() { // Arrange - var response = new PaginatedResponseModel + var response = new PaginatedResponseModel { - Items = new List + Items = new List { - new BasicDnsZone { Name = "test"} + new DnsZoneSummary { Name = "test"} }, Links = new PaginationLinks(), Metadata = new PaginationMetadata(), @@ -159,7 +159,7 @@ public async Task Should_make_a_call_to_api_with_per_page_quertString_when_calli public async Task Should_return_a_full_dns_zone_when_calling_CreateZoneAsync() { // Arrange - var response = new FullDnsZone + var response = new DnsZone { Id = DnsZoneId.FromInt(123), Name = "test", @@ -185,7 +185,7 @@ public async Task Should_return_a_full_dns_zone_when_calling_CreateZoneAsync() public async Task Should_return_a_full_dns_zone_when_calling_GetZoneAsync() { // Arrange - var response = new FullDnsZone + var response = new DnsZone { Id = DnsZoneId.FromInt(123), Name = "test", @@ -211,7 +211,7 @@ public async Task Should_return_a_full_dns_zone_when_calling_GetZoneAsync() public async Task Should_return_a_full_dns_zone_when_calling_UpdateZoneAsync() { // Arrange - var response = new FullDnsZone + var response = new DnsZone { Id = DnsZoneId.FromInt(123), Name = "New Name", @@ -239,7 +239,7 @@ public async Task Should_return_a_full_dns_zone_when_calling_UpdateZoneAsync() public async Task Should_return_a_full_dns_zone_when_calling_DeleteZoneAsync() { // Arrange - var response = new FullDnsZone + var response = new DnsZone { Id = DnsZoneId.FromInt(123), Name = "New Name", @@ -265,11 +265,11 @@ public async Task Should_return_a_full_dns_zone_when_calling_DeleteZoneAsync() public async Task Should_return_a_paginated_response_model_when_calling_GetRecordsAsync() { // Arrange - var response = new PaginatedResponseModel + var response = new PaginatedResponseModel { - Items = new List + Items = new List { - new BasicDnsRecord { Name = "test"} + new DnsRecordSummary { Name = "test"} }, Links = new PaginationLinks(), Metadata = new PaginationMetadata(), @@ -294,11 +294,11 @@ public async Task Should_return_a_paginated_response_model_when_calling_GetRecor public async Task Should_make_a_call_to_api_with_zoneId_quertString_when_calling_GetRecordsAsync() { // Arrange - var response = new PaginatedResponseModel + var response = new PaginatedResponseModel { - Items = new List + Items = new List { - new BasicDnsRecord { Name = "test"} + new DnsRecordSummary { Name = "test"} }, Links = new PaginationLinks(), Metadata = new PaginationMetadata(), @@ -325,11 +325,11 @@ public async Task Should_make_a_call_to_api_with_zoneId_quertString_when_calling public async Task Should_make_a_call_to_api_with_hostname_quertString_when_calling_GetRecordsAsync() { // Arrange - var response = new PaginatedResponseModel + var response = new PaginatedResponseModel { - Items = new List + Items = new List { - new BasicDnsRecord { Name = "test"} + new DnsRecordSummary { Name = "test"} }, Links = new PaginationLinks(), Metadata = new PaginationMetadata(), @@ -357,11 +357,11 @@ public async Task Should_make_a_call_to_api_with_hostname_quertString_when_calli public async Task Should_make_a_call_to_api_with_page_quertString_when_calling_GetRecordsAsync() { // Arrange - var response = new PaginatedResponseModel + var response = new PaginatedResponseModel { - Items = new List + Items = new List { - new BasicDnsRecord { Name = "test"} + new DnsRecordSummary { Name = "test"} }, Links = new PaginationLinks(), Metadata = new PaginationMetadata(), @@ -388,11 +388,11 @@ public async Task Should_make_a_call_to_api_with_page_quertString_when_calling_G public async Task Should_make_a_call_to_api_with_per_page_quertString_when_calling_GetRecordsAsync() { // Arrange - var response = new PaginatedResponseModel + var response = new PaginatedResponseModel { - Items = new List + Items = new List { - new BasicDnsRecord { Name = "test"} + new DnsRecordSummary { Name = "test"} }, Links = new PaginationLinks(), Metadata = new PaginationMetadata(), @@ -419,7 +419,7 @@ public async Task Should_make_a_call_to_api_with_per_page_quertString_when_calli public async Task Should_return_a_full_dns_record_model_when_calling_CreateRecordAsync() { // Arrange - var response = new FullDnsRecord + var response = new DnsRecord { Id = DnsRecordId.FromInt(123), Name = "Name", @@ -478,7 +478,7 @@ public async Task Should_return_full_dns_record_when_calling_GetRecordAsync() { // Arrange var id = DnsRecordId.FromInt(123); - var response = new FullDnsRecord + var response = new DnsRecord { Id = id, Name = "Name", @@ -505,7 +505,7 @@ public async Task Should_return_full_dns_record_when_calling_UpdateRecordAsync() { // Arrange var id = DnsRecordId.FromInt(123); - var response = new FullDnsRecord + var response = new DnsRecord { Id = id, Name = "New Name", @@ -535,7 +535,7 @@ public async Task Should_return_full_dns_record_when_calling_DeleteRecord() { // Arrange var id = DnsRecordId.FromInt(123); - var response = new FullDnsRecord + var response = new DnsRecord { Id = id, Name = "Name", diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs index 2e11759..b830ed9 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolmentKeyClientTests.cs @@ -46,11 +46,11 @@ public void Setup() public async Task Should_return_paginated_response_when_calling_GetEnrolmentKeysAsync() { // Arrange - var response = new PaginatedResponseModel() + var response = new PaginatedResponseModel() { - Items = new List + Items = new List { - new SimpleEnrolmentKey(), + new EnrolmentKeySummary(), }, }; @@ -75,11 +75,11 @@ public async Task Should_return_paginated_response_when_calling_GetEnrolmentKeys public async Task Should_make_call_to_api_with_search_queryString_when_calling_GetEnrolmentKeysAsync() { // Arrange - var response = new PaginatedResponseModel() + var response = new PaginatedResponseModel() { - Items = new List + Items = new List { - new SimpleEnrolmentKey(), + new EnrolmentKeySummary(), }, }; @@ -104,11 +104,11 @@ public async Task Should_make_call_to_api_with_search_queryString_when_calling_G public async Task Should_make_call_to_api_with_include_disabled_queryString_when_calling_GetEnrolmentKeysAsync() { // Arrange - var response = new PaginatedResponseModel() + var response = new PaginatedResponseModel() { - Items = new List + Items = new List { - new SimpleEnrolmentKey(), + new EnrolmentKeySummary(), }, }; @@ -133,11 +133,11 @@ public async Task Should_make_call_to_api_with_include_disabled_queryString_when public async Task Should_make_call_to_api_with_sort_queryString_when_calling_GetEnrolmentKeysAsync() { // Arrange - var response = new PaginatedResponseModel() + var response = new PaginatedResponseModel() { - Items = new List + Items = new List { - new SimpleEnrolmentKey(), + new EnrolmentKeySummary(), }, }; @@ -162,11 +162,11 @@ public async Task Should_make_call_to_api_with_sort_queryString_when_calling_Get public async Task Should_make_call_to_api_with_page_queryString_when_calling_GetEnrolmentKeysAsync() { // Arrange - var response = new PaginatedResponseModel() + var response = new PaginatedResponseModel() { - Items = new List + Items = new List { - new SimpleEnrolmentKey(), + new EnrolmentKeySummary(), }, }; @@ -191,11 +191,11 @@ public async Task Should_make_call_to_api_with_page_queryString_when_calling_Get public async Task Should_make_call_to_api_with_per_page_queryString_when_calling_GetEnrolmentKeysAsync() { // Arrange - var response = new PaginatedResponseModel() + var response = new PaginatedResponseModel() { - Items = new List + Items = new List { - new SimpleEnrolmentKey(), + new EnrolmentKeySummary(), }, }; @@ -220,7 +220,7 @@ public async Task Should_make_call_to_api_with_per_page_queryString_when_calling public async Task Should_return_a_full_enrolment_key_model_when_calling_CreateAsync() { // Arrange - var response = new FullEnrolmentKey(); + var response = new EnrolmentKey(); var createModel = new EnrolmentKeyCreate(); @@ -245,7 +245,7 @@ public async Task Should_return_a_full_enrolment_key_model_when_calling_CreateAs public async Task Should_return_a_full_enrolment_key_model_when_calling_GetAsync() { // Arrange - var response = new FullEnrolmentKey(); + var response = new EnrolmentKey(); var enrolmentKeyId = EnrolmentKeyId.FromInt(12); @@ -270,7 +270,7 @@ public async Task Should_return_a_full_enrolment_key_model_when_calling_GetAsync public async Task Should_return_a_full_enrolment_key_model_when_calling_UpdateAsync() { // Arrange - var response = new FullEnrolmentKey(); + var response = new EnrolmentKey(); var enrolmentKeyId = EnrolmentKeyId.FromInt(12); @@ -296,7 +296,7 @@ public async Task Should_return_a_full_enrolment_key_model_when_calling_UpdateAs public async Task Should_return_a_full_enrolment_key_model_when_calling_EnableAsync() { // Arrange - var response = new FullEnrolmentKey(); + var response = new EnrolmentKey(); var enrolmentKeyId = EnrolmentKeyId.FromInt(12); @@ -319,7 +319,7 @@ public async Task Should_return_a_full_enrolment_key_model_when_calling_EnableAs public async Task Should_return_a_full_enrolment_key_model_when_calling_DisableAsync() { // Arrange - var response = new FullEnrolmentKey(); + var response = new EnrolmentKey(); var enrolmentKeyId = EnrolmentKeyId.FromInt(12); diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs index 9f20c36..df2cc8b 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/UnapprovedSystemsClientTests.cs @@ -44,11 +44,11 @@ public UnapprovedSystemsClientTests() public async Task Should_return_a_paginated_response_model_when_calling_GetSystemsAsync() { // Arrange - var response = new PaginatedResponseModel + var response = new PaginatedResponseModel { - Items = new List + Items = new List { - new UnapprovedSystem { Description = "test"} + new UnapprovedSystemSummary { Description = "test"} }, Links = new PaginationLinks(), Metadata = new PaginationMetadata(), @@ -73,11 +73,11 @@ public async Task Should_return_a_paginated_response_model_when_calling_GetSyste public async Task Should_make_a_call_to_api_with_enrolment_key_quertString_when_calling_GetSystemsAsync() { // Arrange - var response = new PaginatedResponseModel + var response = new PaginatedResponseModel { - Items = new List + Items = new List { - new UnapprovedSystem { Description = "test"} + new UnapprovedSystemSummary { Description = "test"} }, Links = new PaginationLinks(), Metadata = new PaginationMetadata(), @@ -104,11 +104,11 @@ public async Task Should_make_a_call_to_api_with_enrolment_key_quertString_when_ public async Task Should_make_a_call_to_api_with_search_quertString_when_calling_GetSystemsAsync() { // Arrange - var response = new PaginatedResponseModel + var response = new PaginatedResponseModel { - Items = new List + Items = new List { - new UnapprovedSystem { Description = "test"} + new UnapprovedSystemSummary { Description = "test"} }, Links = new PaginationLinks(), Metadata = new PaginationMetadata(), @@ -136,11 +136,11 @@ public async Task Should_make_a_call_to_api_with_search_quertString_when_calling public async Task Should_make_a_call_to_api_with_sort_quertString_when_calling_GetSystemsAsync() { // Arrange - var response = new PaginatedResponseModel + var response = new PaginatedResponseModel { - Items = new List + Items = new List { - new UnapprovedSystem { Description = "test"} + new UnapprovedSystemSummary { Description = "test"} }, Links = new PaginationLinks(), Metadata = new PaginationMetadata(), @@ -167,11 +167,11 @@ public async Task Should_make_a_call_to_api_with_sort_quertString_when_calling_G public async Task Should_make_a_call_to_api_with_page_quertString_when_calling_GetSystemsAsync() { // Arrange - var response = new PaginatedResponseModel + var response = new PaginatedResponseModel { - Items = new List + Items = new List { - new UnapprovedSystem { Description = "test"} + new UnapprovedSystemSummary { Description = "test"} }, Links = new PaginationLinks(), Metadata = new PaginationMetadata(), @@ -198,11 +198,11 @@ public async Task Should_make_a_call_to_api_with_page_quertString_when_calling_G public async Task Should_make_a_call_to_api_with_per_page_quertString_when_calling_GetSystemsAsync() { // Arrange - var response = new PaginatedResponseModel + var response = new PaginatedResponseModel { - Items = new List + Items = new List { - new UnapprovedSystem { Description = "test"} + new UnapprovedSystemSummary { Description = "test"} }, Links = new PaginationLinks(), Metadata = new PaginationMetadata(), @@ -252,7 +252,7 @@ public async Task Should_return_number_of_declined_systems_when_calling_DeclineS public async Task Should_return_unapproved_system_detail_model_when_calling_GetAsync() { // Arrange - var response = new UnapprovedSystemDetail + var response = new UnapprovedSystem { SystemId = SystemId.FromString("newId"), }; @@ -277,7 +277,7 @@ public async Task Should_return_unapproved_system_detail_model_when_calling_GetA public async Task Should_return_unapproved_system_detail_model_when_calling_UpdateAsync() { // Arrange - var response = new UnapprovedSystemDetail + var response = new UnapprovedSystem { SystemId = SystemId.FromString("newId"), }; @@ -304,7 +304,7 @@ public async Task Should_return_unapproved_system_detail_model_when_calling_Upda public async Task Should_return_unapproved_system_detail_model_when_calling_DeclineAsync() { // Arrange - var response = new UnapprovedSystemDetail + var response = new UnapprovedSystem { SystemId = SystemId.FromString("newId"), }; @@ -329,7 +329,7 @@ public async Task Should_return_unapproved_system_detail_model_when_calling_Decl public async Task Should_not_throw_an_error_when_calling_ApproveAsync() { // Arrange - var response = new UnapprovedSystemDetail + var response = new UnapprovedSystem { SystemId = SystemId.FromString("newId"), }; From 3f359ac4ae3add260d1140c794b3b481a61a83da Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Mon, 6 Dec 2021 11:10:37 +0000 Subject: [PATCH 29/38] All Enrolled Systems endpoints added, tests needed --- .../Clients/EnrolledSystemsClient.cs | 224 ++++++++++++++++++ .../Interfaces/IEnrolledSystemsClient.cs | 90 +++++++ .../Clients/Interfaces/IOrganisationClient.cs | 4 +- .../Clients/Interfaces/ISystemsClient.cs | 45 ---- src/Enclave.Sdk/Clients/OrganisationClient.cs | 3 +- src/Enclave.Sdk/Clients/SystemsClient.cs | 14 -- src/Enclave.Sdk/Data/Dns/DnsRecord.cs | 2 +- src/Enclave.Sdk/Data/Dns/DnsRecordSummary.cs | 2 +- .../BulkSystemRevokedResult.cs | 2 +- .../EnrolledSystems/BulkSystemUpdateResult.cs | 12 + .../EnrolledSystem.cs} | 4 +- .../EnrolledSystemSummary.cs} | 4 +- .../Enum/SystemQuerySortMode.cs | 2 +- .../Enum/SystemState.cs | 2 +- .../Enum/SystemType.cs | 2 +- .../ISystemReferenceModel.cs | 2 +- .../SystemDnsEntry.cs | 2 +- .../Clients/EnrolledSystemClientTests.cs | 11 + 18 files changed, 353 insertions(+), 74 deletions(-) create mode 100644 src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs create mode 100644 src/Enclave.Sdk/Clients/Interfaces/IEnrolledSystemsClient.cs delete mode 100644 src/Enclave.Sdk/Clients/Interfaces/ISystemsClient.cs delete mode 100644 src/Enclave.Sdk/Clients/SystemsClient.cs rename src/Enclave.Sdk/Data/{SystemManagement => EnrolledSystems}/BulkSystemRevokedResult.cs (82%) create mode 100644 src/Enclave.Sdk/Data/EnrolledSystems/BulkSystemUpdateResult.cs rename src/Enclave.Sdk/Data/{SystemManagement/EnclaveSystem.cs => EnrolledSystems/EnrolledSystem.cs} (97%) rename src/Enclave.Sdk/Data/{SystemManagement/SystemSummary.cs => EnrolledSystems/EnrolledSystemSummary.cs} (97%) rename src/Enclave.Sdk/Data/{SystemManagement => EnrolledSystems}/Enum/SystemQuerySortMode.cs (67%) rename src/Enclave.Sdk/Data/{SystemManagement => EnrolledSystems}/Enum/SystemState.cs (88%) rename src/Enclave.Sdk/Data/{SystemManagement => EnrolledSystems}/Enum/SystemType.cs (52%) rename src/Enclave.Sdk/Data/{SystemManagement => EnrolledSystems}/ISystemReferenceModel.cs (94%) rename src/Enclave.Sdk/Data/{SystemManagement => EnrolledSystems}/SystemDnsEntry.cs (96%) create mode 100644 tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs diff --git a/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs b/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs new file mode 100644 index 0000000..9178f66 --- /dev/null +++ b/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs @@ -0,0 +1,224 @@ +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; + +/// +public 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}"); + + EnsureNotNull(model); + + return model; + } + + /// + public async Task RevokeSystems(params string[] 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 GetAsync(string systemId) + { + var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/systems/{systemId}", Constants.JsonSerializerOptions); + + EnsureNotNull(model); + + return model; + } + + /// + public async Task UpdateAsync(string 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(string 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(int 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(int 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 string[] 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 BulkDisableAsync(params string[] 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; + } + + 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/Interfaces/IEnrolledSystemsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IEnrolledSystemsClient.cs new file mode 100644 index 0000000..9c078eb --- /dev/null +++ b/src/Enclave.Sdk/Clients/Interfaces/IEnrolledSystemsClient.cs @@ -0,0 +1,90 @@ +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; + +/// +/// Perform CRUD operations on 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 tags 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 RevokeSystems(params string[] systemIds); + + /// + /// Retrieve a Detailed System model. + /// + /// The SystemId to Get. + /// A Full System Model. + Task GetAsync(string 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(string systemId, PatchBuilder builder); + + /// + /// Revoke a system permanetly. + /// + /// The id of the Enrolled System to revoke. + /// The revoked Enrolled System. + Task RevokeAsync(string systemId); + + /// + /// Enable an Enrolled System. + /// + /// The Id of the Enrolled System to enable. + /// A detailed Enrolment Key. + Task EnableAsync(int systemId); + + /// + /// Disable an Enrolled System. + /// + /// The Id of the Enrolled System to disable. + /// A detailed Enrolment Key. + Task DisableAsync(int systemId); + + /// + /// Bulk enable mutliple Enrolled System. + /// + /// An array of Enrolled System Ids to enable. + /// The number of keys modified. + Task BulkEnableAsync(params string[] systemIds); + + /// + /// Bulk disable mutliple Enrolled System. + /// + /// An array of Enrolled System Ids to disable. + /// The number of keys modified. + Task BulkDisableAsync(params string[] systemIds); +} \ 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 828f38d..ee9f6be 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IOrganisationClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IOrganisationClient.cs @@ -42,9 +42,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. diff --git a/src/Enclave.Sdk/Clients/Interfaces/ISystemsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/ISystemsClient.cs deleted file mode 100644 index 66b54eb..0000000 --- a/src/Enclave.Sdk/Clients/Interfaces/ISystemsClient.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Enclave.Sdk.Api.Data.Pagination; -using Enclave.Sdk.Api.Data.SystemManagement; -using Enclave.Sdk.Api.Data.SystemManagement.Enum; - -namespace Enclave.Sdk.Api.Clients.Interfaces; - -/// -/// Perform CRUD operations on Systems. -/// -public interface ISystemsClient -{ - /// - /// 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 tags 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 RevokeSystems(params string[] systemIds); - - /// - /// Retrieve a Detailed System model. - /// - /// The SystemId to Get. - /// A Full System Model. - Task GetAsync(string systemId); -} \ No newline at end of file diff --git a/src/Enclave.Sdk/Clients/OrganisationClient.cs b/src/Enclave.Sdk/Clients/OrganisationClient.cs index 3c039ff..3955e48 100644 --- a/src/Enclave.Sdk/Clients/OrganisationClient.cs +++ b/src/Enclave.Sdk/Clients/OrganisationClient.cs @@ -27,6 +27,7 @@ public OrganisationClient(HttpClient httpClient, AccountOrganisation currentOrga EnrolmentKeys = new EnrolmentKeysClient(httpClient, _orgRoute); Dns = new DnsClient(httpClient, _orgRoute); UnapprovedSystems = new UnapprovedSystemsClient(httpClient, _orgRoute); + EnrolledSystems = new EnrolledSystemsClient(httpClient, _orgRoute); Policies = new PoliciesClient(httpClient, _orgRoute); } @@ -49,7 +50,7 @@ public OrganisationClient(HttpClient httpClient, AccountOrganisation currentOrga public IPoliciesClient Policies { get; } /// - public ISystemsClient Systems => throw new NotImplementedException(); + public IEnrolledSystemsClient EnrolledSystems { get; } /// public ITagsClient Tags => throw new NotImplementedException(); diff --git a/src/Enclave.Sdk/Clients/SystemsClient.cs b/src/Enclave.Sdk/Clients/SystemsClient.cs deleted file mode 100644 index b629dad..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; - -internal class SystemsClient : ClientBase, ISystemsClient -{ - private readonly string _orgRoute; - - public SystemsClient(HttpClient httpClient, string orgRoute) - : base(httpClient) - { - _orgRoute = orgRoute; - } -} diff --git a/src/Enclave.Sdk/Data/Dns/DnsRecord.cs b/src/Enclave.Sdk/Data/Dns/DnsRecord.cs index ba7ceaa..a138c41 100644 --- a/src/Enclave.Sdk/Data/Dns/DnsRecord.cs +++ b/src/Enclave.Sdk/Data/Dns/DnsRecord.cs @@ -1,4 +1,4 @@ -using Enclave.Sdk.Api.Data.SystemManagement; +using Enclave.Sdk.Api.Data.EnrolledSystems; using Enclave.Sdk.Api.Data.Tags; namespace Enclave.Sdk.Api.Data.Dns; diff --git a/src/Enclave.Sdk/Data/Dns/DnsRecordSummary.cs b/src/Enclave.Sdk/Data/Dns/DnsRecordSummary.cs index e42e2a1..04307bc 100644 --- a/src/Enclave.Sdk/Data/Dns/DnsRecordSummary.cs +++ b/src/Enclave.Sdk/Data/Dns/DnsRecordSummary.cs @@ -1,4 +1,4 @@ -using Enclave.Sdk.Api.Data.SystemManagement; +using Enclave.Sdk.Api.Data.EnrolledSystems; using Enclave.Sdk.Api.Data.Tags; namespace Enclave.Sdk.Api.Data.Dns; diff --git a/src/Enclave.Sdk/Data/SystemManagement/BulkSystemRevokedResult.cs b/src/Enclave.Sdk/Data/EnrolledSystems/BulkSystemRevokedResult.cs similarity index 82% rename from src/Enclave.Sdk/Data/SystemManagement/BulkSystemRevokedResult.cs rename to src/Enclave.Sdk/Data/EnrolledSystems/BulkSystemRevokedResult.cs index 70360e6..69ea5b2 100644 --- a/src/Enclave.Sdk/Data/SystemManagement/BulkSystemRevokedResult.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/BulkSystemRevokedResult.cs @@ -1,4 +1,4 @@ -namespace Enclave.Sdk.Api.Data.SystemManagement; +namespace Enclave.Sdk.Api.Data.EnrolledSystems; /// /// The result of a bulk system revocation. 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/SystemManagement/EnclaveSystem.cs b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystem.cs similarity index 97% rename from src/Enclave.Sdk/Data/SystemManagement/EnclaveSystem.cs rename to src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystem.cs index 936e2a0..05e8d81 100644 --- a/src/Enclave.Sdk/Data/SystemManagement/EnclaveSystem.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystem.cs @@ -1,12 +1,12 @@ using Enclave.Sdk.Api.Data.SystemManagement.Enum; using Enclave.Sdk.Api.Data.Tags; -namespace Enclave.Sdk.Api.Data.SystemManagement; +namespace Enclave.Sdk.Api.Data.EnrolledSystems; /// /// A detailed model representing a single system. /// -public class EnclaveSystem +public class EnrolledSystem { /// /// Unique ID for the System. diff --git a/src/Enclave.Sdk/Data/SystemManagement/SystemSummary.cs b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs similarity index 97% rename from src/Enclave.Sdk/Data/SystemManagement/SystemSummary.cs rename to src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs index 0bf6723..92723d1 100644 --- a/src/Enclave.Sdk/Data/SystemManagement/SystemSummary.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs @@ -1,12 +1,12 @@ using Enclave.Sdk.Api.Data.SystemManagement.Enum; using Enclave.Sdk.Api.Data.Tags; -namespace Enclave.Sdk.Api.Data.SystemManagement; +namespace Enclave.Sdk.Api.Data.EnrolledSystems; /// /// A basic model representing a single system. /// -public class SystemSummary +public class EnrolledSystemSummary { /// /// Unique ID for the System. diff --git a/src/Enclave.Sdk/Data/SystemManagement/Enum/SystemQuerySortMode.cs b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemQuerySortMode.cs similarity index 67% rename from src/Enclave.Sdk/Data/SystemManagement/Enum/SystemQuerySortMode.cs rename to src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemQuerySortMode.cs index 4e37790..60b233f 100644 --- a/src/Enclave.Sdk/Data/SystemManagement/Enum/SystemQuerySortMode.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemQuerySortMode.cs @@ -1,4 +1,4 @@ -namespace Enclave.Sdk.Api.Data.SystemManagement.Enum; +namespace Enclave.Sdk.Api.Data.EnrolledSystems.Enum; public enum SystemQuerySortMode { diff --git a/src/Enclave.Sdk/Data/SystemManagement/Enum/SystemState.cs b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemState.cs similarity index 88% rename from src/Enclave.Sdk/Data/SystemManagement/Enum/SystemState.cs rename to src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemState.cs index b5357cd..251bb3d 100644 --- a/src/Enclave.Sdk/Data/SystemManagement/Enum/SystemState.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemState.cs @@ -1,4 +1,4 @@ -namespace Enclave.Sdk.Api.Data.SystemManagement.Enum; +namespace Enclave.Sdk.Api.Data.EnrolledSystems.Enum; /// /// The possible states of an enrolled system. diff --git a/src/Enclave.Sdk/Data/SystemManagement/Enum/SystemType.cs b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemType.cs similarity index 52% rename from src/Enclave.Sdk/Data/SystemManagement/Enum/SystemType.cs rename to src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemType.cs index 91d0191..8af7fbc 100644 --- a/src/Enclave.Sdk/Data/SystemManagement/Enum/SystemType.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemType.cs @@ -1,4 +1,4 @@ -namespace Enclave.Sdk.Api.Data.SystemManagement.Enum; +namespace Enclave.Sdk.Api.Data.EnrolledSystems.Enum; public enum SystemType { diff --git a/src/Enclave.Sdk/Data/SystemManagement/ISystemReferenceModel.cs b/src/Enclave.Sdk/Data/EnrolledSystems/ISystemReferenceModel.cs similarity index 94% rename from src/Enclave.Sdk/Data/SystemManagement/ISystemReferenceModel.cs rename to src/Enclave.Sdk/Data/EnrolledSystems/ISystemReferenceModel.cs index 1a6521e..b162354 100644 --- a/src/Enclave.Sdk/Data/SystemManagement/ISystemReferenceModel.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/ISystemReferenceModel.cs @@ -1,6 +1,6 @@ using Enclave.Sdk.Api.Data.SystemManagement.Enum; -namespace Enclave.Sdk.Api.Data.SystemManagement; +namespace Enclave.Sdk.Api.Data.EnrolledSystems; /// /// Abstraction for a system reference model so we can mix placeholder and "actual" reference models. diff --git a/src/Enclave.Sdk/Data/SystemManagement/SystemDnsEntry.cs b/src/Enclave.Sdk/Data/EnrolledSystems/SystemDnsEntry.cs similarity index 96% rename from src/Enclave.Sdk/Data/SystemManagement/SystemDnsEntry.cs rename to src/Enclave.Sdk/Data/EnrolledSystems/SystemDnsEntry.cs index 85b6784..c84ff5c 100644 --- a/src/Enclave.Sdk/Data/SystemManagement/SystemDnsEntry.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/SystemDnsEntry.cs @@ -1,7 +1,7 @@ using Enclave.Sdk.Api.Data.Dns; using Enclave.Sdk.Api.Data.Tags; -namespace Enclave.Sdk.Api.Data.SystemManagement; +namespace Enclave.Sdk.Api.Data.EnrolledSystems; /// /// Represents a single system DNS entry. 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..c3de485 --- /dev/null +++ b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Enclave.Sdk.Api.Tests.Clients; + +internal class EnrolledSystemClientTests +{ +} From 131bf72162bf67c52fc0a6e49459f089d55d7073 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Mon, 6 Dec 2021 13:03:00 +0000 Subject: [PATCH 30/38] First set of unit tests added --- .../Data/EnrolledSystems/EnrolledSystem.cs | 2 +- .../EnrolledSystems/EnrolledSystemSummary.cs | 2 +- .../EnrolledSystems/ISystemReferenceModel.cs | 2 +- .../Clients/EnrolledSystemClientTests.cs | 289 +++++++++++++++++- 4 files changed, 286 insertions(+), 9 deletions(-) diff --git a/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystem.cs b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystem.cs index 05e8d81..9857a38 100644 --- a/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystem.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystem.cs @@ -1,4 +1,4 @@ -using Enclave.Sdk.Api.Data.SystemManagement.Enum; +using Enclave.Sdk.Api.Data.EnrolledSystems.Enum; using Enclave.Sdk.Api.Data.Tags; namespace Enclave.Sdk.Api.Data.EnrolledSystems; diff --git a/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs index 92723d1..344b6f9 100644 --- a/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs @@ -1,4 +1,4 @@ -using Enclave.Sdk.Api.Data.SystemManagement.Enum; +using Enclave.Sdk.Api.Data.EnrolledSystems.Enum; using Enclave.Sdk.Api.Data.Tags; namespace Enclave.Sdk.Api.Data.EnrolledSystems; diff --git a/src/Enclave.Sdk/Data/EnrolledSystems/ISystemReferenceModel.cs b/src/Enclave.Sdk/Data/EnrolledSystems/ISystemReferenceModel.cs index b162354..65374cb 100644 --- a/src/Enclave.Sdk/Data/EnrolledSystems/ISystemReferenceModel.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/ISystemReferenceModel.cs @@ -1,4 +1,4 @@ -using Enclave.Sdk.Api.Data.SystemManagement.Enum; +using Enclave.Sdk.Api.Data.EnrolledSystems.Enum; namespace Enclave.Sdk.Api.Data.EnrolledSystems; diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs index c3de485..b08b01e 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs @@ -1,11 +1,288 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +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; namespace Enclave.Sdk.Api.Tests.Clients; -internal class EnrolledSystemClientTests +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}"); + } + } From 45bc19811bf1e580c494790a96fe06a009fa578d Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Mon, 6 Dec 2021 15:40:52 +0000 Subject: [PATCH 31/38] Branch now builds --- src/Enclave.Sdk/Clients/DNSClient.cs | 40 +++++++++---------- .../Clients/EnrolledSystemsClient.cs | 4 +- .../Clients/EnrolmentKeysClient.cs | 24 +++++------ .../Interfaces/IEnrolmentKeysClient.cs | 14 +++---- .../Interfaces/IUnapprovedSystemsClient.cs | 8 ++-- .../Clients/UnapprovedSystemsClient.cs | 16 ++++---- .../Data/EnrolledSystems/EnrolledSystem.cs | 6 +-- .../Data/{UnaprrovedSystems => }/SystemId.cs | 2 +- .../Clients/EnrolledSystemClientTests.cs | 1 + 9 files changed, 59 insertions(+), 56 deletions(-) rename src/Enclave.Sdk/Data/{UnaprrovedSystems => }/SystemId.cs (63%) diff --git a/src/Enclave.Sdk/Clients/DNSClient.cs b/src/Enclave.Sdk/Clients/DNSClient.cs index 79df723..7b43dcc 100644 --- a/src/Enclave.Sdk/Clients/DNSClient.cs +++ b/src/Enclave.Sdk/Clients/DNSClient.cs @@ -35,11 +35,11 @@ public async Task GetPropertiesSummaryAsync() } /// - public async Task> GetZonesAsync(int? pageNumber = null, int? perPage = null) + 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}"); + var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/dns/zones?{queryString}"); EnsureNotNull(model); @@ -47,7 +47,7 @@ public async Task> GetZonesAsync(int? pageN } /// - public async Task CreateZoneAsync(DnsZoneCreate createModel) + public async Task CreateZoneAsync(DnsZoneCreate createModel) { if (createModel is null) { @@ -56,7 +56,7 @@ public async Task CreateZoneAsync(DnsZoneCreate createModel) var result = await HttpClient.PostAsJsonAsync($"{_orgRoute}/dns/zones", createModel, Constants.JsonSerializerOptions); - var model = await DeserialiseAsync(result.Content); + var model = await DeserialiseAsync(result.Content); EnsureNotNull(model); @@ -64,9 +64,9 @@ public async Task CreateZoneAsync(DnsZoneCreate createModel) } /// - public async Task GetZoneAsync(DnsZoneId dnsZoneId) + public async Task GetZoneAsync(DnsZoneId dnsZoneId) { - var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/dns/zones/{dnsZoneId}", Constants.JsonSerializerOptions); + var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/dns/zones/{dnsZoneId}", Constants.JsonSerializerOptions); EnsureNotNull(model); @@ -74,7 +74,7 @@ public async Task GetZoneAsync(DnsZoneId dnsZoneId) } /// - public async Task UpdateZoneAsync(DnsZoneId dnsZoneId, PatchBuilder builder) + public async Task UpdateZoneAsync(DnsZoneId dnsZoneId, PatchBuilder builder) { if (builder is null) { @@ -86,7 +86,7 @@ public async Task UpdateZoneAsync(DnsZoneId dnsZoneId, PatchBuilder result.EnsureSuccessStatusCode(); - var model = await DeserialiseAsync(result.Content); + var model = await DeserialiseAsync(result.Content); EnsureNotNull(model); @@ -94,13 +94,13 @@ public async Task UpdateZoneAsync(DnsZoneId dnsZoneId, PatchBuilder } /// - public async Task DeleteZoneAsync(DnsZoneId dnsZoneId) + public async Task DeleteZoneAsync(DnsZoneId dnsZoneId) { var result = await HttpClient.DeleteAsync($"{_orgRoute}/dns/zones/{dnsZoneId}"); result.EnsureSuccessStatusCode(); - var model = await DeserialiseAsync(result.Content); + var model = await DeserialiseAsync(result.Content); EnsureNotNull(model); @@ -108,7 +108,7 @@ public async Task DeleteZoneAsync(DnsZoneId dnsZoneId) } /// - public async Task> GetRecordsAsync( + public async Task> GetRecordsAsync( DnsZoneId? dnsZoneId = null, string? hostname = null, int? pageNumber = null, @@ -116,7 +116,7 @@ public async Task> GetRecordsAsync( { var queryString = BuildQueryString(dnsZoneId, hostname, pageNumber, perPage); - var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/dns/records?{queryString}"); + var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/dns/records?{queryString}"); EnsureNotNull(model); @@ -124,7 +124,7 @@ public async Task> GetRecordsAsync( } /// - public async Task CreateRecordAsync(DnsRecordCreate createModel) + public async Task CreateRecordAsync(DnsRecordCreate createModel) { if (createModel is null) { @@ -133,7 +133,7 @@ public async Task CreateRecordAsync(DnsRecordCreate createModel) var result = await HttpClient.PostAsJsonAsync($"{_orgRoute}/dns/records", createModel, Constants.JsonSerializerOptions); - var model = await DeserialiseAsync(result.Content); + var model = await DeserialiseAsync(result.Content); EnsureNotNull(model); @@ -178,9 +178,9 @@ public async Task DeleteRecordsAsync(IEnumerable records) } /// - public async Task GetRecordAsync(DnsRecordId dnsRecordId) + public async Task GetRecordAsync(DnsRecordId dnsRecordId) { - var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/dns/records/{dnsRecordId}", Constants.JsonSerializerOptions); + var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/dns/records/{dnsRecordId}", Constants.JsonSerializerOptions); EnsureNotNull(model); @@ -188,7 +188,7 @@ public async Task GetRecordAsync(DnsRecordId dnsRecordId) } /// - public async Task UpdateRecordAsync(DnsRecordId dnsRecordId, PatchBuilder builder) + public async Task UpdateRecordAsync(DnsRecordId dnsRecordId, PatchBuilder builder) { if (builder is null) { @@ -200,7 +200,7 @@ public async Task UpdateRecordAsync(DnsRecordId dnsRecordId, Patc result.EnsureSuccessStatusCode(); - var model = await DeserialiseAsync(result.Content); + var model = await DeserialiseAsync(result.Content); EnsureNotNull(model); @@ -208,13 +208,13 @@ public async Task UpdateRecordAsync(DnsRecordId dnsRecordId, Patc } /// - public async Task DeleteRecordAsync(DnsRecordId dnsRecordId) + public async Task DeleteRecordAsync(DnsRecordId dnsRecordId) { var result = await HttpClient.DeleteAsync($"{_orgRoute}/dns/records/{dnsRecordId}"); result.EnsureSuccessStatusCode(); - var model = await DeserialiseAsync(result.Content); + var model = await DeserialiseAsync(result.Content); EnsureNotNull(model); diff --git a/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs b/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs index 9178f66..955d18d 100644 --- a/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs @@ -1,3 +1,5 @@ +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; @@ -8,7 +10,7 @@ namespace Enclave.Sdk.Api.Clients; /// -public class EnrolledSystemsClient : ClientBase, IEnrolledSystemsClient +internal class EnrolledSystemsClient : ClientBase, IEnrolledSystemsClient { private readonly string _orgRoute; diff --git a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs index 0f1127f..7263131 100644 --- a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs @@ -26,7 +26,7 @@ public EnrolmentKeysClient(HttpClient httpClient, string orgRoute) } /// - public async Task> GetEnrolmentKeysAsync( + public async Task> GetEnrolmentKeysAsync( string? searchTerm = null, bool? includeDisabled = null, EnrolmentKeySortOrder? sortOrder = null, @@ -35,7 +35,7 @@ public async Task> GetEnrolmentKeysAs { var queryString = BuildQueryString(searchTerm, includeDisabled, sortOrder, pageNumber, perPage); - var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/enrolment-keys?{queryString}"); + var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/enrolment-keys?{queryString}"); EnsureNotNull(model); @@ -43,7 +43,7 @@ public async Task> GetEnrolmentKeysAs } /// - public async Task CreateAsync(EnrolmentKeyCreate createModel) + public async Task CreateAsync(EnrolmentKeyCreate createModel) { if (createModel is null) { @@ -52,7 +52,7 @@ public async Task CreateAsync(EnrolmentKeyCreate createModel) var result = await HttpClient.PostAsJsonAsync($"{_orgRoute}/enrolment-keys", createModel, Constants.JsonSerializerOptions); - var model = await DeserialiseAsync(result.Content); + var model = await DeserialiseAsync(result.Content); EnsureNotNull(model); @@ -60,9 +60,9 @@ public async Task CreateAsync(EnrolmentKeyCreate createModel) } /// - public async Task GetAsync(EnrolmentKeyId enrolmentKeyId) + public async Task GetAsync(EnrolmentKeyId enrolmentKeyId) { - var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}", Constants.JsonSerializerOptions); + var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}", Constants.JsonSerializerOptions); EnsureNotNull(model); @@ -70,7 +70,7 @@ public async Task GetAsync(EnrolmentKeyId enrolmentKeyId) } /// - public async Task UpdateAsync(EnrolmentKeyId enrolmentKeyId, PatchBuilder builder) + public async Task UpdateAsync(EnrolmentKeyId enrolmentKeyId, PatchBuilder builder) { if (builder is null) { @@ -82,7 +82,7 @@ public async Task UpdateAsync(EnrolmentKeyId enrolmentKeyId, P result.EnsureSuccessStatusCode(); - var model = await DeserialiseAsync(result.Content); + var model = await DeserialiseAsync(result.Content); EnsureNotNull(model); @@ -90,11 +90,11 @@ public async Task UpdateAsync(EnrolmentKeyId enrolmentKeyId, P } /// - public async Task EnableAsync(EnrolmentKeyId enrolmentKeyId) + public async Task EnableAsync(EnrolmentKeyId enrolmentKeyId) { var result = await HttpClient.PutAsync($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}/enable", null); - var model = await DeserialiseAsync(result.Content); + var model = await DeserialiseAsync(result.Content); EnsureNotNull(model); @@ -102,11 +102,11 @@ public async Task EnableAsync(EnrolmentKeyId enrolmentKeyId) } /// - public async Task DisableAsync(EnrolmentKeyId enrolmentKeyId) + public async Task DisableAsync(EnrolmentKeyId enrolmentKeyId) { var result = await HttpClient.PutAsync($"{_orgRoute}/enrolment-keys/{enrolmentKeyId}/disable", null); - var model = await DeserialiseAsync(result.Content); + var model = await DeserialiseAsync(result.Content); EnsureNotNull(model); diff --git a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs index f1f0f68..43a11ab 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IEnrolmentKeysClient.cs @@ -20,21 +20,21 @@ public interface IEnrolmentKeysClient /// 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); + 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); + /// 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); + Task GetAsync(EnrolmentKeyId enrolmentKeyId); /// /// Patch request to update the EnrolmentKey. @@ -43,21 +43,21 @@ public interface IEnrolmentKeysClient /// 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); + 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); + Task EnableAsync(EnrolmentKeyId enrolmentKeyId); /// /// Disable an Enrolment Key. /// /// The Id of the Enrolment Key to disable. /// A detailed Enrolment Key. - Task DisableAsync(EnrolmentKeyId enrolmentKeyId); + Task DisableAsync(EnrolmentKeyId enrolmentKeyId); /// /// Bulk enable mutliple Enrolment Keys. diff --git a/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs index ab78f45..006456e 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs @@ -20,7 +20,7 @@ public interface IUnapprovedSystemsClient /// Which page number do you want to return. /// How many tags per page. /// A paginated response model with links to get the previous, next, first and last pages. - Task> GetSystemsAsync( + Task> GetSystemsAsync( int? enrolmentKeyId = null, string? searchTerm = null, UnapprovedSystemQuerySortMode? sortOrder = null, @@ -46,7 +46,7 @@ Task> GetSystemsAsync( /// /// The system Id you want to get. /// A Detailed Unapproved System Model. - Task GetAsync(SystemId systemId); + Task GetAsync(SystemId systemId); /// /// Patch request to update an Unapproved System. @@ -54,14 +54,14 @@ Task> GetSystemsAsync( /// 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); + Task UpdateAsync(SystemId systemId, PatchBuilder builder); /// /// Decline an Unapproved System. /// /// The system Id you want to decline. /// The declined System. - Task DeclineAsync(SystemId systemId); + Task DeclineAsync(SystemId systemId); /// /// Approve a System. diff --git a/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs b/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs index feae06a..cd549e4 100644 --- a/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/UnapprovedSystemsClient.cs @@ -27,7 +27,7 @@ public UnapprovedSystemsClient(HttpClient httpClient, string orgRoute) } /// - public async Task> GetSystemsAsync( + public async Task> GetSystemsAsync( int? enrolmentKeyId = null, string? searchTerm = null, UnapprovedSystemQuerySortMode? sortOrder = null, @@ -36,7 +36,7 @@ public async Task> GetSystemsAsync( { var queryString = BuildQueryString(enrolmentKeyId, searchTerm, sortOrder, pageNumber, perPage); - var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/unapproved-systems?{queryString}"); + var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/unapproved-systems?{queryString}"); EnsureNotNull(model); @@ -76,9 +76,9 @@ public async Task DeclineSystems(IEnumerable systemIds) } /// - public async Task GetAsync(SystemId systemId) + public async Task GetAsync(SystemId systemId) { - var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/unapproved-systems/{systemId}", Constants.JsonSerializerOptions); + var model = await HttpClient.GetFromJsonAsync($"{_orgRoute}/unapproved-systems/{systemId}", Constants.JsonSerializerOptions); EnsureNotNull(model); @@ -86,7 +86,7 @@ public async Task GetAsync(SystemId systemId) } /// - public async Task UpdateAsync(SystemId systemId, PatchBuilder builder) + public async Task UpdateAsync(SystemId systemId, PatchBuilder builder) { if (builder is null) { @@ -98,7 +98,7 @@ public async Task UpdateAsync(SystemId systemId, PatchBu result.EnsureSuccessStatusCode(); - var model = await DeserialiseAsync(result.Content); + var model = await DeserialiseAsync(result.Content); EnsureNotNull(model); @@ -106,13 +106,13 @@ public async Task UpdateAsync(SystemId systemId, PatchBu } /// - public async Task DeclineAsync(SystemId systemId) + public async Task DeclineAsync(SystemId systemId) { var result = await HttpClient.DeleteAsync($"{_orgRoute}/unapproved-systems/{systemId}"); result.EnsureSuccessStatusCode(); - var model = await DeserialiseAsync(result.Content); + var model = await DeserialiseAsync(result.Content); EnsureNotNull(model); diff --git a/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystem.cs b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystem.cs index 9857a38..b9f337b 100644 --- a/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystem.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystem.cs @@ -11,7 +11,7 @@ public class EnrolledSystem /// /// Unique ID for the System. /// - public string SystemId { get; init; } = default!; + public SystemId SystemId { get; init; } = default!; /// /// The configured description of the system. @@ -86,12 +86,12 @@ public class EnrolledSystem /// /// The tags assigned to the system. /// - public IReadOnlyList Tags { get; init; } + public IReadOnlyList Tags { get; init; } = Array.Empty(); /// /// The set of DNS entries applied to the system. /// - public IReadOnlyList Dns { get; init; } + public IReadOnlyList Dns { get; init; } = Array.Empty(); /// /// Any additional notes attached to the system. diff --git a/src/Enclave.Sdk/Data/UnaprrovedSystems/SystemId.cs b/src/Enclave.Sdk/Data/SystemId.cs similarity index 63% rename from src/Enclave.Sdk/Data/UnaprrovedSystems/SystemId.cs rename to src/Enclave.Sdk/Data/SystemId.cs index 2906730..dafd624 100644 --- a/src/Enclave.Sdk/Data/UnaprrovedSystems/SystemId.cs +++ b/src/Enclave.Sdk/Data/SystemId.cs @@ -1,6 +1,6 @@ using TypedIds; -namespace Enclave.Sdk.Api.Data.UnaprrovedSystems; +namespace Enclave.Sdk.Api.Data; [TypedId(IdBackingType.String)] public partial struct SystemId diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs index b08b01e..e016eb9 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs @@ -10,6 +10,7 @@ using WireMock.Server; using WireMock.FluentAssertions; using Enclave.Sdk.Api.Data.EnrolledSystems.Enum; +using Enclave.Sdk.Api.Data.Organisations; namespace Enclave.Sdk.Api.Tests.Clients; From d3cf4cd63ea35bae19d1be13a84e38745194bc8e Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Mon, 6 Dec 2021 16:03:17 +0000 Subject: [PATCH 32/38] Changes as per PR #2 --- src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs | 4 ++-- .../Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs | 7 +------ src/Enclave.Sdk/Enclave.Sdk.Api.csproj | 1 - 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs index a18d9cc..c059b2a 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyCreate.cs @@ -35,12 +35,12 @@ public class EnrolmentKeyCreate /// /// The set of IP Address constraints on the key. /// - public List? IpConstraints { get; set; } = new List(); + 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(); + 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. diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs index d667d9d..dbf835c 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyIpConstraintInput.cs @@ -23,11 +23,6 @@ public EnrolmentKeyIpConstraintInput(string cidrNotation) throw new ArgumentException("Incorrect CIDR Format"); } - if (!IPNetwork.TryParse(cidrNotation, out var network)) - { - throw new ArgumentException("Incorrect CIDR Format"); - } - Range = cidrNotation; } @@ -68,7 +63,7 @@ public EnrolmentKeyIpConstraintInput(IPAddress startAddress, IPAddress endAddres /// /// The IP range. /// - public string Range { get; } = default!; + public string Range { get; } /// /// A description for the range. diff --git a/src/Enclave.Sdk/Enclave.Sdk.Api.csproj b/src/Enclave.Sdk/Enclave.Sdk.Api.csproj index c8eaa21..3e9595c 100644 --- a/src/Enclave.Sdk/Enclave.Sdk.Api.csproj +++ b/src/Enclave.Sdk/Enclave.Sdk.Api.csproj @@ -17,7 +17,6 @@ - From 99f0e5654835fd7df5894789e123c3057604ec01 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Tue, 7 Dec 2021 15:07:49 +0000 Subject: [PATCH 33/38] added unit tests --- .../Clients/EnrolledSystemsClient.cs | 35 +++- .../Interfaces/IEnrolledSystemsClient.cs | 41 +++- .../Clients/Interfaces/IPoliciesClient.cs | 2 +- .../Clients/Interfaces/ITagsClient.cs | 2 +- .../Interfaces/IUnapprovedSystemsClient.cs | 2 +- ...{SystemPatch.cs => EnrolledSystemPatch.cs} | 2 +- .../Clients/EnrolledSystemClientTests.cs | 181 ++++++++++++++++++ 7 files changed, 243 insertions(+), 22 deletions(-) rename src/Enclave.Sdk/Data/PatchModel/{SystemPatch.cs => EnrolledSystemPatch.cs} (93%) diff --git a/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs b/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs index 955d18d..d48343a 100644 --- a/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Net.Http.Json; using System.Web; using Enclave.Sdk.Api.Clients.Interfaces; @@ -45,7 +46,7 @@ public async Task> GetSystemsAsync } /// - public async Task RevokeSystems(params string[] systemIds) + public async Task RevokeSystemsAsync(params SystemId[] systemIds) { using var content = CreateJsonContent(new { @@ -71,7 +72,13 @@ public async Task RevokeSystems(params string[] systemIds) } /// - public async Task GetAsync(string systemId) + 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); @@ -81,7 +88,7 @@ public async Task GetAsync(string systemId) } /// - public async Task UpdateAsync(string systemId, PatchBuilder builder) + public async Task UpdateAsync(SystemId systemId, PatchBuilder builder) { if (builder is null) { @@ -101,7 +108,7 @@ public async Task UpdateAsync(string systemId, PatchBuilder - public async Task RevokeAsync(string systemId) + public async Task RevokeAsync(SystemId systemId) { var result = await HttpClient.DeleteAsync($"{_orgRoute}/systems/{systemId}"); @@ -115,7 +122,7 @@ public async Task RevokeAsync(string systemId) } /// - public async Task EnableAsync(int systemId) + public async Task EnableAsync(SystemId systemId) { var result = await HttpClient.PutAsync($"{_orgRoute}/systems/{systemId}/enable", null); @@ -127,7 +134,7 @@ public async Task EnableAsync(int systemId) } /// - public async Task DisableAsync(int systemId) + public async Task DisableAsync(SystemId systemId) { var result = await HttpClient.PutAsync($"{_orgRoute}/systems/{systemId}/disable", null); @@ -139,7 +146,7 @@ public async Task DisableAsync(int systemId) } /// - public async Task BulkEnableAsync(params string[] systemIds) + public async Task BulkEnableAsync(params SystemId[] systemIds) { var requestModel = new { @@ -158,7 +165,13 @@ public async Task BulkEnableAsync(params string[] systemIds) } /// - public async Task BulkDisableAsync(params string[] systemIds) + public async Task BulkEnableAsync(IEnumerable systemIds) + { + return await BulkEnableAsync(systemIds.ToArray()); + } + + /// + public async Task BulkDisableAsync(params SystemId[] systemIds) { var requestModel = new { @@ -176,6 +189,12 @@ public async Task BulkDisableAsync(params string[] systemIds) return model.SystemsUpdated; } + /// + public async Task BulkDisableAsync(IEnumerable systemIds) + { + return await BulkDisableAsync(systemIds.ToArray()); + } + private static string? BuildQueryString( int? enrolmentKeyId = null, string? searchTerm = null, diff --git a/src/Enclave.Sdk/Clients/Interfaces/IEnrolledSystemsClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IEnrolledSystemsClient.cs index 9c078eb..d4547a5 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IEnrolledSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IEnrolledSystemsClient.cs @@ -7,7 +7,7 @@ namespace Enclave.Sdk.Api.Clients.Interfaces; /// -/// Perform CRUD operations on Systems. +/// Provides operations to get, create, and manipulate Enrolled Systems. /// public interface IEnrolledSystemsClient { @@ -20,7 +20,7 @@ public interface IEnrolledSystemsClient /// 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 tags per page. + /// How many per page. /// A paginated response model with links to get the previous, next, first and last pages. Task> GetSystemsAsync( int? enrolmentKeyId = null, @@ -36,14 +36,21 @@ Task> GetSystemsAsync( /// /// The System Ids to revoke. /// The number of systems revoked. - Task RevokeSystems(params string[] systemIds); + 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(string systemId); + Task GetAsync(SystemId systemId); /// /// Update an Enrolled System. @@ -51,40 +58,54 @@ Task> GetSystemsAsync( /// The Id of the Enrolled System to update. /// An instance of used to setup our patch request. /// An Enrolled System. - Task UpdateAsync(string systemId, PatchBuilder builder); + Task UpdateAsync(SystemId systemId, PatchBuilder builder); /// /// Revoke a system permanetly. /// /// The id of the Enrolled System to revoke. /// The revoked Enrolled System. - Task RevokeAsync(string systemId); + Task RevokeAsync(SystemId systemId); /// /// Enable an Enrolled System. /// /// The Id of the Enrolled System to enable. /// A detailed Enrolment Key. - Task EnableAsync(int systemId); + Task EnableAsync(SystemId systemId); /// /// Disable an Enrolled System. /// /// The Id of the Enrolled System to disable. /// A detailed Enrolment Key. - Task DisableAsync(int systemId); + 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(params string[] systemIds); + 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(params string[] systemIds); + Task BulkDisableAsync(IEnumerable systemIds); } \ No newline at end of file diff --git a/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs index 2ab4024..5f2d690 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IPoliciesClient.cs @@ -18,7 +18,7 @@ public interface IPoliciesClient /// Include the disabled Policies in the results. /// 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> GetPoliciesAsync( string? searchTerm = null, 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 006456e..d0535e6 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IUnapprovedSystemsClient.cs @@ -18,7 +18,7 @@ public interface IUnapprovedSystemsClient /// 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> GetSystemsAsync( int? enrolmentKeyId = null, diff --git a/src/Enclave.Sdk/Data/PatchModel/SystemPatch.cs b/src/Enclave.Sdk/Data/PatchModel/EnrolledSystemPatch.cs similarity index 93% rename from src/Enclave.Sdk/Data/PatchModel/SystemPatch.cs rename to src/Enclave.Sdk/Data/PatchModel/EnrolledSystemPatch.cs index fd74c51..4d01fc0 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. diff --git a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs index e016eb9..a5610a2 100644 --- a/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs +++ b/tests/Enclave.Sdk.Api.Tests/Clients/EnrolledSystemClientTests.cs @@ -11,6 +11,8 @@ 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; @@ -286,4 +288,183 @@ public async Task Should_make_a_call_to_api_with_per_page_quertString_when_calli _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); + } + + } From 7fa31721232a17ddc4add1ace6c9ba4e2252e3af Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Tue, 7 Dec 2021 16:49:22 +0000 Subject: [PATCH 34/38] Unit tests added and system tested! --- src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs | 2 +- src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs | 2 +- src/Enclave.Sdk/Data/EnrolledSystems/ISystemReferenceModel.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs b/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs index d48343a..0ade948 100644 --- a/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolledSystemsClient.cs @@ -38,7 +38,7 @@ public async Task> GetSystemsAsync { var queryString = BuildQueryString(enrolmentKeyId, searchTerm, includeDisabled, sortOrder, dnsName, pageNumber, perPage); - var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/systems?{queryString}"); + var model = await HttpClient.GetFromJsonAsync>($"{_orgRoute}/systems?{queryString}", Constants.JsonSerializerOptions); EnsureNotNull(model); diff --git a/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs index 344b6f9..a5fbc19 100644 --- a/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/EnrolledSystemSummary.cs @@ -11,7 +11,7 @@ public class EnrolledSystemSummary /// /// Unique ID for the System. /// - public string SystemId { get; init; } = default!; + public SystemId SystemId { get; init; } = default!; /// /// The configured description of the system. diff --git a/src/Enclave.Sdk/Data/EnrolledSystems/ISystemReferenceModel.cs b/src/Enclave.Sdk/Data/EnrolledSystems/ISystemReferenceModel.cs index 65374cb..fa6334f 100644 --- a/src/Enclave.Sdk/Data/EnrolledSystems/ISystemReferenceModel.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/ISystemReferenceModel.cs @@ -15,7 +15,7 @@ public interface ISystemReferenceModel /// /// The System ID. /// - string Id { get; } + SystemId Id { get; } /// /// The local hostname of the system (if known). From 245bcdf83816847b9593fe937003bc684983b415 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Wed, 8 Dec 2021 13:15:50 +0000 Subject: [PATCH 35/38] Changes as per PR #5 --- src/Enclave.Sdk/Clients/DNSClient.cs | 2 +- src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs | 2 +- src/Enclave.Sdk/Clients/PoliciesClient.cs | 2 +- src/Enclave.Sdk/Clients/TagsClient.cs | 2 +- src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs | 2 +- src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs | 2 +- .../Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs | 12 ++++++++++++ .../Data/Organisations/Organisation.cs | 3 +-- .../Data/PatchModel/DnsRecordPatch.cs | 4 ++-- .../Data/PatchModel/EnrolmentKeyPatch.cs | 2 +- src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs | 6 +++--- src/Enclave.Sdk/Data/PatchModel/SystemPatch.cs | 2 +- .../Data/PatchModel/UnapprovedSystemPatch.cs | 2 +- src/Enclave.Sdk/Data/Policies/Policy.cs | 4 ++-- ...ystemReferenceModel.cs => SystemReference.cs} | 16 ++++++++-------- 15 files changed, 37 insertions(+), 26 deletions(-) rename src/Enclave.Sdk/Data/SystemManagement/{ISystemReferenceModel.cs => SystemReference.cs} (63%) diff --git a/src/Enclave.Sdk/Clients/DNSClient.cs b/src/Enclave.Sdk/Clients/DNSClient.cs index 79df723..7f31bda 100644 --- a/src/Enclave.Sdk/Clients/DNSClient.cs +++ b/src/Enclave.Sdk/Clients/DNSClient.cs @@ -14,7 +14,7 @@ internal class DnsClient : ClientBase, IDnsClient 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 organisation API route. diff --git a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs index 0f1127f..2a93a19 100644 --- a/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs +++ b/src/Enclave.Sdk/Clients/EnrolmentKeysClient.cs @@ -15,7 +15,7 @@ internal class EnrolmentKeysClient : ClientBase, IEnrolmentKeysClient 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 organisation API route. diff --git a/src/Enclave.Sdk/Clients/PoliciesClient.cs b/src/Enclave.Sdk/Clients/PoliciesClient.cs index d029874..843a37c 100644 --- a/src/Enclave.Sdk/Clients/PoliciesClient.cs +++ b/src/Enclave.Sdk/Clients/PoliciesClient.cs @@ -15,7 +15,7 @@ internal class PoliciesClient : ClientBase, IPoliciesClient private readonly string _orgRoute; /// - /// Consutructor which will be called by when it's created. + /// 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. diff --git a/src/Enclave.Sdk/Clients/TagsClient.cs b/src/Enclave.Sdk/Clients/TagsClient.cs index 6d93fe2..835a9ff 100644 --- a/src/Enclave.Sdk/Clients/TagsClient.cs +++ b/src/Enclave.Sdk/Clients/TagsClient.cs @@ -12,7 +12,7 @@ internal class TagsClient : ClientBase, ITagsClient 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/Data/Dns/BasicDnsRecord.cs b/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs index f59963e..391719f 100644 --- a/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs +++ b/src/Enclave.Sdk/Data/Dns/BasicDnsRecord.cs @@ -46,5 +46,5 @@ public class BasicDnsRecord /// /// The set of systems to which this DNS name is applied. /// - public IReadOnlyList? Systems { get; init; } + public IReadOnlyList? Systems { get; init; } } diff --git a/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs b/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs index ac1e91c..bfbd959 100644 --- a/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs +++ b/src/Enclave.Sdk/Data/Dns/FullDnsRecord.cs @@ -47,7 +47,7 @@ public class FullDnsRecord /// /// The set of systems to which this DNS name is applied. /// - public IReadOnlyList? Systems { get; init; } + public IReadOnlyList? Systems { get; init; } /// /// Any provided notes for this record. diff --git a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs index 11dcc59..35929bc 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeyType.cs @@ -1,7 +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/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/PatchModel/DnsRecordPatch.cs b/src/Enclave.Sdk/Data/PatchModel/DnsRecordPatch.cs index b2815cc..8412310 100644 --- a/src/Enclave.Sdk/Data/PatchModel/DnsRecordPatch.cs +++ b/src/Enclave.Sdk/Data/PatchModel/DnsRecordPatch.cs @@ -13,12 +13,12 @@ public class DnsRecordPatch : IPatchModel /// /// The set of tags to which this DNS name is applied. /// - public List? Tags { get; set; } + public IReadOnlyList? Tags { get; set; } /// /// The set of systems to which this DNS name is applied. /// - public List? Systems { get; set; } + public IReadOnlyList? Systems { get; set; } /// /// Any notes or additional info for this record. diff --git a/src/Enclave.Sdk/Data/PatchModel/EnrolmentKeyPatch.cs b/src/Enclave.Sdk/Data/PatchModel/EnrolmentKeyPatch.cs index 6c978eb..ecf2476 100644 --- a/src/Enclave.Sdk/Data/PatchModel/EnrolmentKeyPatch.cs +++ b/src/Enclave.Sdk/Data/PatchModel/EnrolmentKeyPatch.cs @@ -31,7 +31,7 @@ public class EnrolmentKeyPatchModel : IPatchModel /// /// The set of IP Address constraints on the key. /// - public List? IpConstraints { get; set; } + public IReadOnlyList? IpConstraints { get; set; } /// /// A set of tags automatically applied to systems enrolled with this key. diff --git a/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs b/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs index 34d3316..53479d8 100644 --- a/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs +++ b/src/Enclave.Sdk/Data/PatchModel/PolicyPatch.cs @@ -20,17 +20,17 @@ public class PolicyPatch : IPatchModel /// /// A set of sender tags. /// - public List SenderTags { get; set; } = new List(); + public IReadOnlyList? SenderTags { get; set; } /// /// A set of receiver tags. /// - public List ReceiverTags { get; set; } = new List(); + public IReadOnlyList? ReceiverTags { get; set; } /// /// The set of ACLs for the policy. /// - public List Acls { get; set; } = new List(); + public IReadOnlyList? Acls { get; set; } /// /// Notes for the policy. diff --git a/src/Enclave.Sdk/Data/PatchModel/SystemPatch.cs b/src/Enclave.Sdk/Data/PatchModel/SystemPatch.cs index fd74c51..a87292e 100644 --- a/src/Enclave.Sdk/Data/PatchModel/SystemPatch.cs +++ b/src/Enclave.Sdk/Data/PatchModel/SystemPatch.cs @@ -18,7 +18,7 @@ public class SystemPatch : IPatchModel /// /// The set of tags applied to the system. /// - public List Tags { get; set; } = new List(); + public IReadOnlyList? Tags { get; set; } /// /// Any notes or additional info for this system. diff --git a/src/Enclave.Sdk/Data/PatchModel/UnapprovedSystemPatch.cs b/src/Enclave.Sdk/Data/PatchModel/UnapprovedSystemPatch.cs index 74d4cce..6d5c829 100644 --- a/src/Enclave.Sdk/Data/PatchModel/UnapprovedSystemPatch.cs +++ b/src/Enclave.Sdk/Data/PatchModel/UnapprovedSystemPatch.cs @@ -13,7 +13,7 @@ public class UnapprovedSystemPatch : IPatchModel /// /// The set of tags applied to the system. /// - public List Tags { get; set; } = new List(); + public IReadOnlyList? Tags { get; set; } /// /// Any notes or additional info for this system. diff --git a/src/Enclave.Sdk/Data/Policies/Policy.cs b/src/Enclave.Sdk/Data/Policies/Policy.cs index 3a54983..d1bc32f 100644 --- a/src/Enclave.Sdk/Data/Policies/Policy.cs +++ b/src/Enclave.Sdk/Data/Policies/Policy.cs @@ -21,7 +21,7 @@ public class Policy /// /// The provided description of the policy. /// - public string Description { get; init; } + public string Description { get; init; } = default!; /// /// Whether or not this policy is enabled. @@ -46,7 +46,7 @@ public class Policy /// /// Access control lists. /// - public IReadOnlyList Acls { get; init; } + public IReadOnlyList Acls { get; init; } = Array.Empty(); /// /// Optional notes for the policy. diff --git a/src/Enclave.Sdk/Data/SystemManagement/ISystemReferenceModel.cs b/src/Enclave.Sdk/Data/SystemManagement/SystemReference.cs similarity index 63% rename from src/Enclave.Sdk/Data/SystemManagement/ISystemReferenceModel.cs rename to src/Enclave.Sdk/Data/SystemManagement/SystemReference.cs index ad9179c..a14eb27 100644 --- a/src/Enclave.Sdk/Data/SystemManagement/ISystemReferenceModel.cs +++ b/src/Enclave.Sdk/Data/SystemManagement/SystemReference.cs @@ -1,37 +1,37 @@ namespace Enclave.Sdk.Api.Data.SystemManagement; /// -/// Abstraction for a system reference model so we can mix placeholder and "actual" reference models. +/// Defines a system reference model. /// -public interface ISystemReferenceModel +public class SystemReference { /// /// Contains the last connected IP of the system. /// - string? ConnectedFrom { get; } + public string? ConnectedFrom { get; init; } /// /// The System ID. /// - string Id { get; } + public string Id { get; init; } /// /// The local hostname of the system (if known). /// - string? MachineName { get; } + public string? MachineName { get; init; } /// /// The set name of the system (if one was provided). /// - string? Name { get; } + public string? Name { get; init; } /// /// The System platform type (if known). /// - string? PlatformType { get; } + public string? PlatformType { get; init; } /// /// The state of the system. /// - SystemState State { get; } + public SystemState State { get; init; } } From 8d5427a82d90ebdefc19834a1bc174a8b88db75d Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Wed, 8 Dec 2021 14:41:58 +0000 Subject: [PATCH 36/38] Added LogClient --- .../Clients/Interfaces/ILogsClient.cs | 15 +++++++- src/Enclave.Sdk/Clients/LogsClient.cs | 38 +++++++++++++++++++ .../Data/Logging/Enum/ActivityLogLevel.cs | 8 ++++ src/Enclave.Sdk/Data/Logging/LogEntry.cs | 34 +++++++++++++++++ .../Data/Organisations/OrganisationId.cs | 2 +- 5 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 src/Enclave.Sdk/Data/Logging/Enum/ActivityLogLevel.cs create mode 100644 src/Enclave.Sdk/Data/Logging/LogEntry.cs 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/LogsClient.cs b/src/Enclave.Sdk/Clients/LogsClient.cs index 35518a6..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; +/// internal class LogsClient : ClientBase, ILogsClient { 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/Data/Logging/Enum/ActivityLogLevel.cs b/src/Enclave.Sdk/Data/Logging/Enum/ActivityLogLevel.cs new file mode 100644 index 0000000..70f0bd2 --- /dev/null +++ b/src/Enclave.Sdk/Data/Logging/Enum/ActivityLogLevel.cs @@ -0,0 +1,8 @@ +namespace Enclave.Sdk.Api.Data.Logging.Enum; + +public enum ActivityLogLevel +{ + Information, + Warning, + 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/OrganisationId.cs b/src/Enclave.Sdk/Data/Organisations/OrganisationId.cs index d528681..287aa09 100644 --- a/src/Enclave.Sdk/Data/Organisations/OrganisationId.cs +++ b/src/Enclave.Sdk/Data/Organisations/OrganisationId.cs @@ -3,7 +3,7 @@ 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 From 8d2ac93bdcf326294a1cf24d1cffbf1c2c1bf20a Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Wed, 8 Dec 2021 14:55:43 +0000 Subject: [PATCH 37/38] Added Logs tests --- .../Clients/LogsClientTests.cs | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 tests/Enclave.Sdk.Api.Tests/Clients/LogsClientTests.cs 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}"); + } +} From 7e979368932d60465b151b4f8e6a41d188e07cf1 Mon Sep 17 00:00:00 2001 From: Thomas Soulard Date: Mon, 13 Dec 2021 17:07:44 +0000 Subject: [PATCH 38/38] Cleaned up all warnings --- src/Enclave.Sdk/Clients/AuthorityClient.cs | 14 ------------- src/Enclave.Sdk/Clients/ClientBase.cs | 4 ++-- .../Clients/Interfaces/IAuthorityClient.cs | 5 ----- .../Clients/Interfaces/IDnsClient.cs | 4 ++-- .../Clients/Interfaces/IOrganisationClient.cs | 5 ----- src/Enclave.Sdk/Clients/OrganisationClient.cs | 15 +++++++------- src/Enclave.Sdk/Constants.cs | 1 - .../Data/Account/UserOrganisationRole.cs | 10 ++++++++++ src/Enclave.Sdk/Data/Dns/DnsRecord.cs | 1 - src/Enclave.Sdk/Data/Dns/DnsRecordId.cs | 3 +++ src/Enclave.Sdk/Data/Dns/DnsZoneId.cs | 3 +++ .../Enum/SystemQuerySortMode.cs | 18 +++++++++++++++++ .../Data/EnrolledSystems/Enum/SystemType.cs | 12 +++++++++++ .../Data/EnrolmentKeys/EnrolmentKeyId.cs | 3 +++ .../Data/EnrolmentKeys/Enum/ApprovalMode.cs | 10 ++++++++++ .../Enum/EnrolmentKeySortOrder.cs | 18 +++++++++++++++++ .../Data/Logging/Enum/ActivityLogLevel.cs | 14 +++++++++++++ .../Organisations/Enum/OrganisationPlan.cs | 14 +++++++++++++ .../Data/Organisations/OrganisationUser.cs | 6 ++++++ .../Data/Pagination/PaginatedResponseModel.cs | 6 +++--- .../Data/Pagination/PaginationLinks.cs | 4 ++-- .../Data/PatchModel/IPatchModel.cs | 4 ++++ .../Data/Policies/Enum/PolicyAclProtocol.cs | 15 ++++++++++++++ .../Data/Policies/Enum/PolicySortOrder.cs | 10 ++++++++++ src/Enclave.Sdk/Data/Policies/PolicyId.cs | 3 +++ src/Enclave.Sdk/Data/SystemId.cs | 3 +++ .../Data/SystemManagement/SystemReference.cs | 2 +- .../Data/Tags/TagQuerySortOrder.cs | 14 +++++++++++++ .../Data/UnaprrovedSystems/Enum/SystemType.cs | 12 +++++++++++ .../Exceptions/ProblemDetailsException.cs | 20 ++++++++++++++++--- .../ProblemDetailsHttpMessageHandler.cs | 4 +++- 31 files changed, 209 insertions(+), 48 deletions(-) delete mode 100644 src/Enclave.Sdk/Clients/AuthorityClient.cs delete mode 100644 src/Enclave.Sdk/Clients/Interfaces/IAuthorityClient.cs diff --git a/src/Enclave.Sdk/Clients/AuthorityClient.cs b/src/Enclave.Sdk/Clients/AuthorityClient.cs deleted file mode 100644 index ec19132..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; - -internal class AuthorityClient : ClientBase, IAuthorityClient -{ - private readonly 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 64f5a21..3fafe03 100644 --- a/src/Enclave.Sdk/Clients/ClientBase.cs +++ b/src/Enclave.Sdk/Clients/ClientBase.cs @@ -32,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) { @@ -51,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/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 0082f1c..ddedbcc 100644 --- a/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs +++ b/src/Enclave.Sdk/Clients/Interfaces/IDnsClient.cs @@ -70,7 +70,7 @@ Task> GetRecordsAsync( /// /// Create a DNS Record using a model. /// - /// The model needed to create a DNS Record + /// The model needed to create a DNS Record. /// The created DNS Record as . Task CreateRecordAsync(DnsRecordCreate createModel); @@ -92,7 +92,7 @@ Task> GetRecordsAsync( /// Get a detailed DNS Record. /// /// The id of the DNS Record you want to get. - /// A detailed DNS Record object + /// A detailed DNS Record object. Task GetRecordAsync(DnsRecordId dnsRecordId); /// diff --git a/src/Enclave.Sdk/Clients/Interfaces/IOrganisationClient.cs b/src/Enclave.Sdk/Clients/Interfaces/IOrganisationClient.cs index ee9f6be..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. /// diff --git a/src/Enclave.Sdk/Clients/OrganisationClient.cs b/src/Enclave.Sdk/Clients/OrganisationClient.cs index 3955e48..2a10d30 100644 --- a/src/Enclave.Sdk/Clients/OrganisationClient.cs +++ b/src/Enclave.Sdk/Clients/OrganisationClient.cs @@ -24,19 +24,18 @@ public OrganisationClient(HttpClient httpClient, AccountOrganisation currentOrga Organisation = currentOrganisation; _orgRoute = $"org/{Organisation.OrgId}"; - EnrolmentKeys = new EnrolmentKeysClient(httpClient, _orgRoute); Dns = new DnsClient(httpClient, _orgRoute); - UnapprovedSystems = new UnapprovedSystemsClient(httpClient, _orgRoute); - EnrolledSystems = new EnrolledSystemsClient(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 { get; } @@ -44,7 +43,7 @@ public OrganisationClient(HttpClient httpClient, AccountOrganisation currentOrga public IEnrolmentKeysClient EnrolmentKeys { get; } /// - public ILogsClient Logs => throw new NotImplementedException(); + public ILogsClient Logs { get; } /// public IPoliciesClient Policies { get; } @@ -53,7 +52,7 @@ public OrganisationClient(HttpClient httpClient, AccountOrganisation currentOrga public IEnrolledSystemsClient EnrolledSystems { get; } /// - public ITagsClient Tags => throw new NotImplementedException(); + public ITagsClient Tags { get; } /// public IUnapprovedSystemsClient UnapprovedSystems { get; } diff --git a/src/Enclave.Sdk/Constants.cs b/src/Enclave.Sdk/Constants.cs index 38af783..5373998 100644 --- a/src/Enclave.Sdk/Constants.cs +++ b/src/Enclave.Sdk/Constants.cs @@ -9,7 +9,6 @@ public static JsonSerializerOptions JsonSerializerOptions { get { - var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, 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/DnsRecord.cs b/src/Enclave.Sdk/Data/Dns/DnsRecord.cs index cba7800..a07e456 100644 --- a/src/Enclave.Sdk/Data/Dns/DnsRecord.cs +++ b/src/Enclave.Sdk/Data/Dns/DnsRecord.cs @@ -9,7 +9,6 @@ namespace Enclave.Sdk.Api.Data.Dns; /// public class DnsRecord { - /// /// The ID of the record. /// diff --git a/src/Enclave.Sdk/Data/Dns/DnsRecordId.cs b/src/Enclave.Sdk/Data/Dns/DnsRecordId.cs index 0982fb0..12423c4 100644 --- a/src/Enclave.Sdk/Data/Dns/DnsRecordId.cs +++ b/src/Enclave.Sdk/Data/Dns/DnsRecordId.cs @@ -2,6 +2,9 @@ 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/DnsZoneId.cs b/src/Enclave.Sdk/Data/Dns/DnsZoneId.cs index 17694d4..19a491a 100644 --- a/src/Enclave.Sdk/Data/Dns/DnsZoneId.cs +++ b/src/Enclave.Sdk/Data/Dns/DnsZoneId.cs @@ -2,6 +2,9 @@ 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/EnrolledSystems/Enum/SystemQuerySortMode.cs b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemQuerySortMode.cs index 60b233f..9864272 100644 --- a/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemQuerySortMode.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemQuerySortMode.cs @@ -1,9 +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/SystemType.cs b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemType.cs index 8af7fbc..bce91a5 100644 --- a/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemType.cs +++ b/src/Enclave.Sdk/Data/EnrolledSystems/Enum/SystemType.cs @@ -1,7 +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/EnrolmentKeys/EnrolmentKeyId.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyId.cs index c651970..d26a553 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyId.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/EnrolmentKeyId.cs @@ -2,6 +2,9 @@ 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/Enum/ApprovalMode.cs b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs index bf1ddad..8c3b64c 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/ApprovalMode.cs @@ -1,7 +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 index 0da202c..fa62bef 100644 --- a/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeySortOrder.cs +++ b/src/Enclave.Sdk/Data/EnrolmentKeys/Enum/EnrolmentKeySortOrder.cs @@ -1,9 +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/Logging/Enum/ActivityLogLevel.cs b/src/Enclave.Sdk/Data/Logging/Enum/ActivityLogLevel.cs index 70f0bd2..11b52d6 100644 --- a/src/Enclave.Sdk/Data/Logging/Enum/ActivityLogLevel.cs +++ b/src/Enclave.Sdk/Data/Logging/Enum/ActivityLogLevel.cs @@ -1,8 +1,22 @@ namespace Enclave.Sdk.Api.Data.Logging.Enum; +/// +/// Log Error Type. +/// public enum ActivityLogLevel { + /// + /// Information log level. + /// Information, + + /// + /// Warning Log. + /// Warning, + + /// + /// Error Log. + /// Error, } \ 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/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/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/Policies/Enum/PolicyAclProtocol.cs b/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs index 880fb8a..a4d7bed 100644 --- a/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs +++ b/src/Enclave.Sdk/Data/Policies/Enum/PolicyAclProtocol.cs @@ -5,8 +5,23 @@ /// 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 index c6ad0d1..c46565d 100644 --- a/src/Enclave.Sdk/Data/Policies/Enum/PolicySortOrder.cs +++ b/src/Enclave.Sdk/Data/Policies/Enum/PolicySortOrder.cs @@ -1,7 +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/PolicyId.cs b/src/Enclave.Sdk/Data/Policies/PolicyId.cs index ecd7df8..6f8e191 100644 --- a/src/Enclave.Sdk/Data/Policies/PolicyId.cs +++ b/src/Enclave.Sdk/Data/Policies/PolicyId.cs @@ -2,6 +2,9 @@ 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/SystemId.cs b/src/Enclave.Sdk/Data/SystemId.cs index dafd624..4156752 100644 --- a/src/Enclave.Sdk/Data/SystemId.cs +++ b/src/Enclave.Sdk/Data/SystemId.cs @@ -2,6 +2,9 @@ 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 index b2eb874..fa24d19 100644 --- a/src/Enclave.Sdk/Data/SystemManagement/SystemReference.cs +++ b/src/Enclave.Sdk/Data/SystemManagement/SystemReference.cs @@ -15,7 +15,7 @@ public class SystemReference /// /// The System ID. /// - public string Id { get; init; } + public string Id { get; init; } = default!; /// /// The local hostname of the system (if known). 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/UnaprrovedSystems/Enum/SystemType.cs b/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/SystemType.cs index 9aa78a2..a69868d 100644 --- a/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/SystemType.cs +++ b/src/Enclave.Sdk/Data/UnaprrovedSystems/Enum/SystemType.cs @@ -1,7 +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/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/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)