diff --git a/src/Auth0.ManagementApi/Clients/FlowsClient.cs b/src/Auth0.ManagementApi/Clients/FlowsClient.cs new file mode 100644 index 00000000..e3f25b79 --- /dev/null +++ b/src/Auth0.ManagementApi/Clients/FlowsClient.cs @@ -0,0 +1,295 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +using Newtonsoft.Json; + +using Auth0.ManagementApi.Models.Flow; +using Auth0.ManagementApi.Paging; + +namespace Auth0.ManagementApi.Clients +{ + public class FlowsClient : BaseClient, IFlowsClient + { + private readonly JsonConverter[] _flowsConverters = { new PagedListConverter("flows") }; + private readonly JsonConverter[] _flowVaultConnectionConverters = + { new PagedListConverter("connections") }; + private readonly JsonConverter[] _paginationFlowExecutionConverters = { new PagedListConverter("executions") }; + private readonly JsonConverter[] _checkpointPaginationFlowExecutionConverters = { new CheckpointPagedListConverter("executions") }; + + /// + /// Initializes a new instance of + /// + /// + /// + /// Default headers + public FlowsClient( + IManagementConnection connection, Uri baseUri, IDictionary defaultHeaders) : base( + connection, baseUri, defaultHeaders) + { + } + + /// + public Task> GetAllAsync(FlowGetRequest request, CancellationToken cancellationToken = default) + { + if (request == null) + throw new ArgumentNullException(nameof(request)); + + var queryStrings = new Dictionary(); + + if (request.Hydrate != null && request.Hydrate.Any()) + { + var hydrateValues = string.Join(",", request.Hydrate.Select( x => x.ToString().ToLower())); + queryStrings["hydrate"] = hydrateValues; + } + + if (request.PaginationInfo != null) + { + queryStrings["page"] = request.PaginationInfo.PageNo.ToString(); + queryStrings["per_page"] = request.PaginationInfo.PerPage.ToString(); + queryStrings["include_totals"] = request.PaginationInfo.IncludeTotals.ToString().ToLower(); + } + + return Connection.GetAsync>( + BuildUri("flows", queryStrings), + DefaultHeaders, + _flowsConverters, + cancellationToken); + } + + /// + public Task CreateAsync(FlowCreateRequest request, CancellationToken cancellationToken = default) + { + return Connection.SendAsync( + HttpMethod.Post, + BuildUri("flows"), + request, + DefaultHeaders, + cancellationToken: cancellationToken); + } + + /// + public Task GetAsync(FlowGetRequest request, CancellationToken cancellationToken = default) + { + if (request == null) + throw new ArgumentNullException(nameof(request)); + + if (string.IsNullOrEmpty(request.Id)) + throw new ArgumentNullException(nameof(request.Id)); + + var queryStrings = new Dictionary(); + + if (request.Hydrate != null && request.Hydrate.Any()) + { + var hydrateValues = string.Join(",", request.Hydrate.Select( x => x.ToString().ToLower())); + queryStrings["hydrate"] = hydrateValues; + } + + return Connection.GetAsync( + BuildUri($"flows/{EncodePath(request.Id)}", queryStrings), + DefaultHeaders, + null, + cancellationToken); + } + + /// + public Task UpdateAsync( + string id, FlowUpdateRequest request, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(id)) + { + throw new ArgumentNullException(nameof(id)); + } + + return Connection.SendAsync( + new HttpMethod("PATCH"), + BuildUri($"flows/{EncodePath(id)}"), + request, + DefaultHeaders, + cancellationToken: cancellationToken); + } + + /// + public Task DeleteAsync(string id, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(id)) + { + throw new ArgumentNullException(nameof(id)); + } + + return Connection.SendAsync( + HttpMethod.Delete, + BuildUri($"flows/{EncodePath(id)}"), + null, + DefaultHeaders, + cancellationToken: cancellationToken); + } + + /// + public Task> GetAllFlowVaultConnectionsAsync( + FlowVaultConnectionGetRequest request, CancellationToken cancellationToken = default) + { + if (request == null) + throw new ArgumentNullException(nameof(request)); + + var queryStrings = new Dictionary(); + + if (request.PaginationInfo != null) + { + queryStrings["page"] = request.PaginationInfo.PageNo.ToString(); + queryStrings["per_page"] = request.PaginationInfo.PerPage.ToString(); + queryStrings["include_totals"] = request.PaginationInfo.IncludeTotals.ToString().ToLower(); + } + + return Connection.GetAsync>( + BuildUri("flows/vault/connections", queryStrings), + DefaultHeaders, + _flowVaultConnectionConverters, + cancellationToken); + } + + /// + public Task CreateVaultConnectionAsync( + FlowVaultConnectionCreateRequest request, CancellationToken cancellationToken = default) + { + return Connection.SendAsync( + HttpMethod.Post, + BuildUri("flows/vault/connections"), + request, + DefaultHeaders, + cancellationToken: cancellationToken); + } + + /// + public Task GetFlowVaultConnectionAsync( + FlowVaultConnectionGetRequest request, CancellationToken cancellationToken = default) + { + if (request == null) + throw new ArgumentNullException(nameof(request)); + + if (string.IsNullOrEmpty(request.Id)) + throw new ArgumentNullException(nameof(request.Id)); + + return Connection.GetAsync( + BuildUri($"flows/vault/connections/{EncodePath(request.Id)}"), + DefaultHeaders, + null, + cancellationToken); + } + + /// + public Task UpdateFlowVaultConnectionAsync( + string id, + FlowVaultConnectionUpdateRequest request, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(id)) + { + throw new ArgumentNullException(nameof(id)); + } + + return Connection.SendAsync( + new HttpMethod("PATCH"), + BuildUri($"flows/vault/connections/{EncodePath(id)}"), + request, + DefaultHeaders, + cancellationToken: cancellationToken); + } + + /// + public Task DeleteFlowVaultConnectionAsync(string id, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(id)) + { + throw new ArgumentNullException(nameof(id)); + } + + return Connection.SendAsync( + HttpMethod.Delete, + BuildUri($"flows/vault/connections/{EncodePath(id)}"), + null, + DefaultHeaders, + cancellationToken: cancellationToken); + } + + /// + public Task> GetAllFlowExecutionsAsync(string flowId, PaginationInfo paginationInfo, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(flowId)) + throw new ArgumentNullException(nameof(flowId)); + + var queryStrings = new Dictionary(); + + if (paginationInfo != null) + { + queryStrings["page"] = paginationInfo.PageNo.ToString(); + queryStrings["per_page"] = paginationInfo.PerPage.ToString(); + queryStrings["include_totals"] = paginationInfo.IncludeTotals.ToString().ToLower(); + } + + return Connection.GetAsync>( + BuildUri($"flows/{EncodePath(flowId)}/executions", queryStrings), + DefaultHeaders, + _paginationFlowExecutionConverters, + cancellationToken); + } + + /// + public Task> GetAllFlowExecutionsAsync(string flowId, + CheckpointPaginationInfo paginationInfo, + CancellationToken cancellationToken = default) + { + var queryStrings = new Dictionary(); + + if(paginationInfo != null) + { + queryStrings["from"] = paginationInfo.From?.ToString(); + queryStrings["take"] = paginationInfo.Take.ToString(); + }; + return Connection.GetAsync>( + BuildUri($"flows/{EncodePath(flowId)}/executions", queryStrings), + DefaultHeaders, + _checkpointPaginationFlowExecutionConverters, + cancellationToken); + } + + /// + public Task GetFlowExecutionAsync( + string flowId, string executionId, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(flowId)) + throw new ArgumentNullException(nameof(flowId)); + + if (string.IsNullOrEmpty(executionId)) + throw new ArgumentNullException(nameof(executionId)); + + return Connection.GetAsync( + BuildUri($"flows/{EncodePath(flowId)}/executions/{EncodePath(executionId)}"), + DefaultHeaders, + null, + cancellationToken); + } + + /// + public Task DeleteFlowExecutionAsync( + string flowId, string executionId, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(flowId)) + throw new ArgumentNullException(nameof(flowId)); + + if (string.IsNullOrEmpty(executionId)) + throw new ArgumentNullException(nameof(executionId)); + + return Connection.SendAsync( + HttpMethod.Delete, + BuildUri($"flows/{EncodePath(flowId)}/executions/{EncodePath(executionId)}"), + null, + DefaultHeaders, + cancellationToken: cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Clients/IFlowsClient.cs b/src/Auth0.ManagementApi/Clients/IFlowsClient.cs new file mode 100644 index 00000000..53968f16 --- /dev/null +++ b/src/Auth0.ManagementApi/Clients/IFlowsClient.cs @@ -0,0 +1,143 @@ +using System.Threading; +using System.Threading.Tasks; +using Auth0.ManagementApi.Models.Flow; +using Auth0.ManagementApi.Paging; + +namespace Auth0.ManagementApi.Clients +{ + public interface IFlowsClient + { + /// + /// Get s + /// + /// + /// + /// of + Task> GetAllAsync(FlowGetRequest request, CancellationToken cancellationToken = default); + + /// + /// Create a . + /// + /// + /// + /// A + Task CreateAsync(FlowCreateRequest request, CancellationToken cancellationToken = default); + + /// + /// Get a . + /// + /// + /// + /// A + Task GetAsync(FlowGetRequest request, CancellationToken cancellationToken = default); + + /// + /// Update a + /// + /// Identifier of the flow to be updated + /// + /// + /// Updated + Task UpdateAsync(string id, FlowUpdateRequest request, CancellationToken cancellationToken = default); + + /// + /// Delete a + /// + /// Identifier of the flow to delete + /// + Task DeleteAsync(string id, CancellationToken cancellationToken = default); + + /// + /// Get list + /// + /// + /// + /// of + Task> GetAllFlowVaultConnectionsAsync( + FlowVaultConnectionGetRequest request, + CancellationToken cancellationToken = default); + + /// + /// Create a Flows Vault connection + /// + /// + /// + /// A + Task CreateVaultConnectionAsync( + FlowVaultConnectionCreateRequest request, + CancellationToken cancellationToken = default); + + /// + /// Get a . + /// + /// + /// + /// A + Task GetFlowVaultConnectionAsync( + FlowVaultConnectionGetRequest request, + CancellationToken cancellationToken = default); + + /// + /// Update a + /// + /// Identifier of the flow to be updated + /// + /// + /// Updated + Task UpdateFlowVaultConnectionAsync( + string id, + FlowVaultConnectionUpdateRequest request, + CancellationToken cancellationToken = default); + + /// + /// Delete a + /// + /// Identifier of the flow to delete + /// + Task DeleteFlowVaultConnectionAsync(string id, CancellationToken cancellationToken = default); + + /// + /// Get executions. + /// + /// Flow identifier for which we need to fetch the executions + /// + /// + /// list of + Task> GetAllFlowExecutionsAsync( + string flowId, + PaginationInfo paginationInfo, + CancellationToken cancellationToken = default); + + /// + /// Get executions. + /// + /// Flow identifier for which we need to fetch the executions + /// + /// + /// "/> list of + Task> GetAllFlowExecutionsAsync( + string flowId, + CheckpointPaginationInfo paginationInfo, + CancellationToken cancellationToken = default); + + /// + /// Get a . + /// + /// Flow identifier for which we need to fetch the execution + /// Flow execution ID + /// + /// + Task GetFlowExecutionAsync( + string flowId, + string executionId, + CancellationToken cancellationToken = default); + + /// + /// Delete a + /// + /// Flow identifier for which we need to fetch the execution + /// Flow execution ID + /// + Task DeleteFlowExecutionAsync(string flowId, string executionId, CancellationToken cancellationToken = default); + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/IManagementApiClient.cs b/src/Auth0.ManagementApi/IManagementApiClient.cs index 8cc96a12..1e661a5e 100644 --- a/src/Auth0.ManagementApi/IManagementApiClient.cs +++ b/src/Auth0.ManagementApi/IManagementApiClient.cs @@ -171,6 +171,11 @@ public interface IManagementApiClient : IDisposable /// IFormsClient FormsClient { get; } + /// + /// Contains all the methods to call the /flows endpoints. + /// + IFlowsClient FlowsClient { get; } + /// /// Update the Access Token used with every request. /// diff --git a/src/Auth0.ManagementApi/ManagementApiClient.cs b/src/Auth0.ManagementApi/ManagementApiClient.cs index 07a524df..0fbf11e0 100644 --- a/src/Auth0.ManagementApi/ManagementApiClient.cs +++ b/src/Auth0.ManagementApi/ManagementApiClient.cs @@ -176,6 +176,9 @@ public class ManagementApiClient : IManagementApiClient /// public IFormsClient FormsClient { get; } + /// + public IFlowsClient FlowsClient { get; } + private Dictionary DefaultHeaders { get; set; } /// @@ -230,6 +233,7 @@ public ManagementApiClient(string token, Uri baseUri, IManagementConnection mana Sessions = new SessionsClient(managementConnection, baseUri, DefaultHeaders); SelfServiceProfilesClient = new SelfServiceProfilesClient(managementConnection, baseUri, DefaultHeaders); FormsClient = new FormsClient(managementConnection, baseUri, DefaultHeaders); + FlowsClient = new FlowsClient(managementConnection, baseUri, DefaultHeaders); } /// diff --git a/src/Auth0.ManagementApi/Models/Flow/Flow.cs b/src/Auth0.ManagementApi/Models/Flow/Flow.cs new file mode 100644 index 00000000..cd624b22 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Flow/Flow.cs @@ -0,0 +1,32 @@ +using System; +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.Flow +{ + /// + /// Represents a Flow + /// + public class Flow + { + /// + /// format:flow-id + /// + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("actions")] + public dynamic Actions { get; set; } + + [JsonProperty("created_at")] + public DateTime? CreatedAt { get; set; } + + [JsonProperty("updated_at")] + public DateTime? UpdatedAt { get; set; } + + [JsonProperty("executed_at")] + public DateTime? ExecutedAt { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Flow/FlowCreateRequest.cs b/src/Auth0.ManagementApi/Models/Flow/FlowCreateRequest.cs new file mode 100644 index 00000000..6521b827 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Flow/FlowCreateRequest.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.Flow +{ + /// + /// Contains information required for creating a new flow + /// + public class FlowCreateRequest + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("actions")] + public dynamic Actions { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Flow/FlowExecution.cs b/src/Auth0.ManagementApi/Models/Flow/FlowExecution.cs new file mode 100644 index 00000000..1c3ec214 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Flow/FlowExecution.cs @@ -0,0 +1,62 @@ +using System; +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.Flow +{ + public class FlowExecution + { + /// + /// Flow execution identifier + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Trace ID + /// + [JsonProperty("trace_id")] + public string TraceId { get; set; } + + /// + /// Journey ID + /// + [JsonProperty("journey_id")] + public string JourneyId { get; set; } + + /// + /// Execution Status + /// + [JsonProperty("status")] + public string Status { get; set; } + + /// + /// Flow execution debug. + /// + [JsonProperty("debug")] + public dynamic Debug { get; set; } + + /// + /// The ISO 8601 formatted date when this flow execution was created. + /// + [JsonProperty("created_at")] + public DateTime? CreatedAt { get; set; } + + /// + /// The ISO 8601 formatted date when this flow execution was updated. + /// + [JsonProperty("updated_at")] + public DateTime? UpdatedAt { get; set; } + + /// + /// The ISO 8601 formatted date when this flow execution started. + /// + [JsonProperty("started_at")] + public DateTime? StartedAt { get; set; } + + /// + /// The ISO 8601 formatted date when this flow execution ended. + /// + [JsonProperty("ended_at")] + public DateTime? EndedAt { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Flow/FlowExecutionGetRequest.cs b/src/Auth0.ManagementApi/Models/Flow/FlowExecutionGetRequest.cs new file mode 100644 index 00000000..cdad86c2 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Flow/FlowExecutionGetRequest.cs @@ -0,0 +1,21 @@ +using Auth0.ManagementApi.Paging; + +namespace Auth0.ManagementApi.Models.Flow +{ + public class FlowExecutionGetRequest + { + public string FlowId { get; set; } + + public string ExecutionId { get; set; } + + /// + /// Hydration param + /// Possible values: [debug] + /// + public Hydrate[] Hydrate { get; set; } + + public PaginationInfo PaginationInfo { get; set; } + + public CheckpointPaginationInfo CheckpointPaginationInfo { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Flow/FlowGetRequest.cs b/src/Auth0.ManagementApi/Models/Flow/FlowGetRequest.cs new file mode 100644 index 00000000..fda731f0 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Flow/FlowGetRequest.cs @@ -0,0 +1,28 @@ +using Auth0.ManagementApi.Paging; + +namespace Auth0.ManagementApi.Models.Flow +{ + /// + /// Contains information required for getting a flow + /// + public class FlowGetRequest + { + public PaginationInfo PaginationInfo { get; set; } + + /// + /// Hydration param + /// Possible values: [form_count] + /// + public Hydrate[] Hydrate { get; set; } + + /// + /// Flag to filter by sync/async flows + /// + public bool? Synchronous { get; set; } + + /// + /// Flow identifier + /// + public string Id { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Flow/FlowUpdateRequest.cs b/src/Auth0.ManagementApi/Models/Flow/FlowUpdateRequest.cs new file mode 100644 index 00000000..54586a96 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Flow/FlowUpdateRequest.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.Flow +{ + /// + /// Contains information required for updating a flow + /// + public class FlowUpdateRequest + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("actions")] + public dynamic Actions { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Flow/FlowVaultConnection.cs b/src/Auth0.ManagementApi/Models/Flow/FlowVaultConnection.cs new file mode 100644 index 00000000..c83bb45a --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Flow/FlowVaultConnection.cs @@ -0,0 +1,59 @@ +using System; +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.Flow +{ + public class FlowVaultConnection + { + /// + /// Flows Vault Connection identifier. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Flows Vault Connection app identifier. + /// + [JsonProperty("app_id")] + public string AppId { get; set; } + + /// + /// Flows Vault Connection name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Flows Vault Connection custom account name. + /// + [JsonProperty("account_name")] + public string AccountName { get; set; } + + /// + /// Whether the Flows Vault Connection is configured. + /// + [JsonProperty("ready")] + public bool? Ready { get; set; } + + /// + /// The ISO 8601 formatted date when this Flows Vault Connection was created. + /// + [JsonProperty("created_at")] + public DateTime? CreatedAt { get; set; } + + /// + /// The ISO 8601 formatted date when this Flows Vault Connection was updated. + /// + [JsonProperty("updated_at")] + public DateTime? UpdatedAt { get; set; } + + /// + /// The ISO 8601 formatted date when this Flows Vault Connection was refreshed. + /// + [JsonProperty("refreshed_at")] + public DateTime? RefreshedAt { get; set; } + + [JsonProperty("fingerprint")] + public string Fingerprint { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Flow/FlowVaultConnectionCreateRequest.cs b/src/Auth0.ManagementApi/Models/Flow/FlowVaultConnectionCreateRequest.cs new file mode 100644 index 00000000..c6e2e9e9 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Flow/FlowVaultConnectionCreateRequest.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.Flow +{ + public class FlowVaultConnectionCreateRequest + { + [JsonProperty("app_id")] + public string AppId { get; set; } + + [JsonProperty("setup")] + public dynamic Setup { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Flow/FlowVaultConnectionGetRequest.cs b/src/Auth0.ManagementApi/Models/Flow/FlowVaultConnectionGetRequest.cs new file mode 100644 index 00000000..88099c05 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Flow/FlowVaultConnectionGetRequest.cs @@ -0,0 +1,20 @@ +using Auth0.ManagementApi.Paging; + +namespace Auth0.ManagementApi.Models.Flow +{ + /// + /// Contains information required for getting + /// + public class FlowVaultConnectionGetRequest + { + /// + /// Flow Vault Connection identifier, to be mentioned when we want to fetch a specific flow vault connection. + /// + public string Id { get; set; } + + /// + /// + /// + public PaginationInfo PaginationInfo { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Flow/FlowVaultConnectionUpdateRequest.cs b/src/Auth0.ManagementApi/Models/Flow/FlowVaultConnectionUpdateRequest.cs new file mode 100644 index 00000000..e96694ba --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Flow/FlowVaultConnectionUpdateRequest.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.Flow +{ + public class FlowVaultConnectionUpdateRequest + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("setup")] + public dynamic Setup { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Flow/Hydrate.cs b/src/Auth0.ManagementApi/Models/Flow/Hydrate.cs new file mode 100644 index 00000000..7e2b8c9b --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Flow/Hydrate.cs @@ -0,0 +1,17 @@ +using System.Runtime.Serialization; + +namespace Auth0.ManagementApi.Models.Flow +{ + /// + /// Hydration param + /// + public enum Hydrate + { + [EnumMember(Value = "form_count")] + FORM_COUNT, + + [EnumMember(Value = "debug")] + DEBUG, + + } +} \ No newline at end of file diff --git a/tests/Auth0.AuthenticationApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs b/tests/Auth0.AuthenticationApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs index fd1b0d19..d81ef89e 100644 --- a/tests/Auth0.AuthenticationApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs +++ b/tests/Auth0.AuthenticationApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs @@ -26,7 +26,8 @@ public static async Task CleanupAsync(ManagementApiClient client, CleanUpType ty new RolesCleanUpStrategy(client), new EncryptionKeysCleanupStrategy(client), new SelfServiceProviderCleanUpStrategy(client), - new FormsCleanUpStrategy(client) + new FormsCleanUpStrategy(client), + new FlowsCleanUpStrategy(client) }; var cleanUpStrategy = strategies.Single(s => s.Type == type); diff --git a/tests/Auth0.IntegrationTests.Shared/CleanUp/CleanUpType.cs b/tests/Auth0.IntegrationTests.Shared/CleanUp/CleanUpType.cs index fb19f582..2fe2e4a7 100644 --- a/tests/Auth0.IntegrationTests.Shared/CleanUp/CleanUpType.cs +++ b/tests/Auth0.IntegrationTests.Shared/CleanUp/CleanUpType.cs @@ -15,6 +15,7 @@ public enum CleanUpType LogStreams, EncryptionKeys, SelfServiceProvider, - Forms + Forms, + Flows } } \ No newline at end of file diff --git a/tests/Auth0.IntegrationTests.Shared/CleanUp/FlowsCleanUpStrategy.cs b/tests/Auth0.IntegrationTests.Shared/CleanUp/FlowsCleanUpStrategy.cs new file mode 100644 index 00000000..8e82cae2 --- /dev/null +++ b/tests/Auth0.IntegrationTests.Shared/CleanUp/FlowsCleanUpStrategy.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using Auth0.ManagementApi; + +namespace Auth0.IntegrationTests.Shared.CleanUp +{ + public class FlowsCleanUpStrategy : CleanUpStrategy + { + public FlowsCleanUpStrategy(ManagementApiClient apiClient) : base(CleanUpType.Flows, apiClient) + { + + } + + public override async Task Run(string id) + { + System.Diagnostics.Debug.WriteLine("Running FlowsCleanup"); + await ApiClient.FlowsClient.DeleteAsync(id); + } + } +} \ No newline at end of file diff --git a/tests/Auth0.ManagementApi.IntegrationTests/FlowsTest.cs b/tests/Auth0.ManagementApi.IntegrationTests/FlowsTest.cs new file mode 100644 index 00000000..0198ac2d --- /dev/null +++ b/tests/Auth0.ManagementApi.IntegrationTests/FlowsTest.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +using FluentAssertions; +using Xunit; + +using Auth0.IntegrationTests.Shared.CleanUp; +using Auth0.ManagementApi.IntegrationTests.Testing; +using Auth0.ManagementApi.Models.Flow; +using Auth0.ManagementApi.Paging; +using Auth0.IntegrationTests.Shared; +using Auth0.Tests.Shared; + +namespace Auth0.ManagementApi.IntegrationTests; + +public class FlowsTestFixture : TestBaseFixture +{ + public override async Task DisposeAsync() + { + foreach (KeyValuePair> entry in identifiers) + { + await ManagementTestBaseUtils.CleanupAsync(ApiClient, entry.Key, entry.Value); + } + + ApiClient.Dispose(); + } +} + +public class FlowsTest : IClassFixture +{ + FlowsTestFixture fixture; + + public FlowsTest(FlowsTestFixture fixture) + { + this.fixture = fixture; + } + + [Fact] + public async void Test_get_all_flows_throws_when_request_is_null() + { + await Assert.ThrowsAsync(() => fixture.ApiClient.FlowsClient.GetAllAsync(null)); + } + + [Fact] + public async void Test_get_flows_throws_when_request_is_null_when_id_is_null() + { + await Assert.ThrowsAsync(() => fixture.ApiClient.FlowsClient.GetAsync(null)); + await Assert.ThrowsAsync(() => fixture.ApiClient.FlowsClient.GetAsync(new FlowGetRequest())); + } + + [Fact] + public async void Test_update_flows_throws_when_id_is_null() + { + await Assert.ThrowsAsync( + () => fixture.ApiClient.FlowsClient.UpdateAsync(null, null)); + } + + [Fact] + public async void Test_delete_flow_throws_when_id_is_null() + { + await Assert.ThrowsAsync(() => fixture.ApiClient.FlowsClient.DeleteAsync(null)); + } + + [Fact] + public async void Test_get_all_flow_vault_connections_throws_when_request_is_null() + { + await Assert.ThrowsAsync( + () => fixture.ApiClient.FlowsClient.GetAllFlowVaultConnectionsAsync(null)); + } + + [Fact] + public async void Test_get_flow_vault_connections_throws_when_request_is_null_id_is_null() + { + await Assert.ThrowsAsync( + () => fixture.ApiClient.FlowsClient.GetFlowVaultConnectionAsync(null)); + await Assert.ThrowsAsync( + () => fixture.ApiClient.FlowsClient.GetFlowVaultConnectionAsync(new FlowVaultConnectionGetRequest())); + } + + [Fact] + public async void Test_update_flow_vault_connection_throws_when_id_is_null() + { + await Assert.ThrowsAsync( + () => fixture.ApiClient.FlowsClient.UpdateFlowVaultConnectionAsync( + null, new FlowVaultConnectionUpdateRequest())); + } + + [Fact] + public async void Test_delete_flow_vault_connection_throws_when_id_is_null() + { + await Assert.ThrowsAsync( + () => fixture.ApiClient.FlowsClient.DeleteFlowVaultConnectionAsync(null)); + } + + [Fact] + public async void Test_get_all_flow_executions_throws_when_request_is_null() + { + await Assert.ThrowsAsync( + () => fixture.ApiClient.FlowsClient.GetAllFlowExecutionsAsync(null, new PaginationInfo())); + await Assert.ThrowsAsync( + () => fixture.ApiClient.FlowsClient.GetAllFlowExecutionsAsync(null, new CheckpointPaginationInfo())); + } + + [Fact] + public async void Test_get_flow_executions_throws_when_id_execution_id_is_null() + { + await Assert.ThrowsAsync( + () => fixture.ApiClient.FlowsClient.GetFlowExecutionAsync(null, "executionId")); + await Assert.ThrowsAsync( + () => fixture.ApiClient.FlowsClient.GetFlowExecutionAsync("flowId", null)); + } + + [Fact] + public async void Test_flows_crud_sequence() + { + // Create a Flow + var createRequest = new FlowCreateRequest() + { + Name = "Test Flow", + Actions = System.Array.Empty() + }; + + var flow = await fixture.ApiClient.FlowsClient.CreateAsync(createRequest); + flow.Should().NotBeNull(); + flow.Name.Should().Be(createRequest.Name); + + // Update flow + var updateRequest = new FlowUpdateRequest() + { + Actions = null + }; + var updatedFlow = await fixture.ApiClient.FlowsClient.UpdateAsync(flow.Id, updateRequest); + updatedFlow.Should().NotBeNull(); + + // Get a Flow + var getFlow = await fixture.ApiClient.FlowsClient.GetAsync(new FlowGetRequest { Id = flow.Id, Hydrate = new [] + { + Hydrate.FORM_COUNT + }} + ); + getFlow.Should().NotBeNull(); + + // Delete a flow + await fixture.ApiClient.FlowsClient.DeleteAsync(flow.Id); + } + + [Fact] + public async void Test_flow_vault_connection_crud_sequence() + { + var createRequest = new FlowVaultConnectionCreateRequest() + { + AppId = "AUTH0", + Setup = new Dictionary() + { + { "type", "OAUTH_APP" }, + { "domain", TestBaseUtils.GetVariable("AUTH0_MANAGEMENT_API_URL")}, + { "client_id", TestBaseUtils.GetVariable("AUTH0_MANAGEMENT_API_CLIENT_ID") }, + { "client_secret", TestBaseUtils.GetVariable("AUTH0_MANAGEMENT_API_CLIENT_SECRET") } + }, + Name = "Auth0-test-connection" + }; + + var createdFlowVaultConnection = await fixture.ApiClient.FlowsClient.CreateVaultConnectionAsync(createRequest); + createdFlowVaultConnection.Should().NotBeNull(); + + // Update the flow vault connection + var updateRequest = new FlowVaultConnectionUpdateRequest() + { + Name = "Updated Name" + }; + + var updatedVaultConnection = + await fixture.ApiClient.FlowsClient.UpdateFlowVaultConnectionAsync(createdFlowVaultConnection.Id, updateRequest); + updatedVaultConnection.Should().NotBeNull(); + updatedVaultConnection.Name.Should().Be("Updated Name"); + + // Get all vault connections + var allFlowVaultConnections = + await fixture.ApiClient.FlowsClient.GetAllFlowVaultConnectionsAsync(new FlowVaultConnectionGetRequest()); + allFlowVaultConnections.Select( x => x.Id == createdFlowVaultConnection.Id).Should().NotBeNull(); + + // Get the newly created vault connection + var getRequest = new FlowVaultConnectionGetRequest() + { + Id = createdFlowVaultConnection.Id + }; + + var vaultConnection = await fixture.ApiClient.FlowsClient.GetFlowVaultConnectionAsync(getRequest); + vaultConnection.Should().NotBeNull(); + vaultConnection.Id.Should().Be(createdFlowVaultConnection.Id); + + // Delete the newly created vault connection + await fixture.ApiClient.FlowsClient.DeleteFlowVaultConnectionAsync(createdFlowVaultConnection.Id); + } + + [Fact] + public async void Test_flow_executions_crud_sequence() + { + // Given a flow + var createRequest = new FlowCreateRequest() + { + Name = "Flow for Test_flow_executions_crud_sequence", + Actions = System.Array.Empty() + }; + var newFlow = await fixture.ApiClient.FlowsClient.CreateAsync(createRequest); + newFlow.Should().NotBeNull(); + fixture.TrackIdentifier(CleanUpType.Flows, newFlow.Id); + + // Get all flow executions + var flowExecutions = + await fixture.ApiClient.FlowsClient.GetAllFlowExecutionsAsync(newFlow.Id, new PaginationInfo()); + + flowExecutions.Should().NotBeNull(); + } +} \ No newline at end of file diff --git a/tests/Auth0.ManagementApi.IntegrationTests/FormsTest.cs b/tests/Auth0.ManagementApi.IntegrationTests/FormsTest.cs index d5a5c442..0958f914 100644 --- a/tests/Auth0.ManagementApi.IntegrationTests/FormsTest.cs +++ b/tests/Auth0.ManagementApi.IntegrationTests/FormsTest.cs @@ -78,9 +78,9 @@ public async Task Test_forms_crud_sequence() }); allForms.Should().NotBeNull(); - allForms.Count.Should().Be(1); + allForms.Count.Should().BeGreaterThan(0); - var form = await fixture.ApiClient.FormsClient.GetAsync(new FormsGetRequest { Id = allForms.First().Id }); + var form = await fixture.ApiClient.FormsClient.GetAsync(new FormsGetRequest { Id = createdForm.Id }); form.Should().BeEquivalentTo(createdForm, options => options.ExcludingMissingMembers()); diff --git a/tests/Auth0.ManagementApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs b/tests/Auth0.ManagementApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs index 50c67a2f..683286e5 100644 --- a/tests/Auth0.ManagementApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs +++ b/tests/Auth0.ManagementApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs @@ -24,7 +24,8 @@ public static async Task CleanupAsync(ManagementApiClient client, CleanUpType ty new RolesCleanUpStrategy(client), new EncryptionKeysCleanupStrategy(client), new SelfServiceProviderCleanUpStrategy(client), - new FormsCleanUpStrategy(client) + new FormsCleanUpStrategy(client), + new FlowsCleanUpStrategy(client) }; var cleanUpStrategy = strategies.Single(s => s.Type == type);