Skip to content

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
MZole committed Jul 16, 2024
1 parent 7d2895e commit 11eba91
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 158 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using Lombiq.OrchardCoreApiClient.Models;
using Lombiq.Tests.UI.Extensions;
using Lombiq.Tests.UI.Services;
using Newtonsoft.Json;
using OpenQA.Selenium;
using OrchardCore.Autoroute.Models;
using OrchardCore.ContentManagement;
Expand Down Expand Up @@ -78,13 +77,15 @@ public static async Task TestOrchardCoreApiClientBehaviorAsync(
Category = "UI Test Tenants - Edited",
};

using var apiClient = new ApiClient(new ApiClientSettings
var apiClientSettings = new ApiClientSettings
{
ClientId = clientId,
ClientSecret = clientSecret,
DefaultTenantUri = context.Scope.BaseUri,
DisableCertificateValidation = true,
});
};

using var tenantsApiClient = new TenantsApiClient(apiClientSettings);

const string defaultClientRecipe = "Lombiq.OrchardCoreApiClient.Tests.UI.OpenId";
context.Scope.AtataContext.Log.Info($"Executing the default client recipe \"{defaultClientRecipe}\": {isDefaultClient}");
Expand All @@ -102,11 +103,11 @@ public static async Task TestOrchardCoreApiClientBehaviorAsync(
await context.SignInDirectlyAsync();
}

await TestTenantCreateAsync(context, apiClient, createApiModel);
await TestTenantSetupAsync(context, apiClient, createApiModel, setupApiModel);
await TestTenantEditAsync(context, apiClient, editModel, setupApiModel);
await TestTenantDisableAsync(context, apiClient, editModel);
await TestTenantRemoveAsync(context, apiClient, editModel);
await TestTenantCreateAsync(context, tenantsApiClient, createApiModel);
await TestTenantSetupAsync(context, tenantsApiClient, createApiModel, setupApiModel);
await TestTenantEditAsync(context, tenantsApiClient, editModel, setupApiModel);
await TestTenantDisableAsync(context, tenantsApiClient, editModel);
await TestTenantRemoveAsync(context, tenantsApiClient, editModel);

var taxonomy = new ContentItem
{
Expand All @@ -119,14 +120,16 @@ public static async Task TestOrchardCoreApiClientBehaviorAsync(
taxonomy.Apply(taxonomyPart);
taxonomy.Apply(autoRoutePart);

taxonomy.ContentItemId = await TestContentCreateAsync(context, apiClient, taxonomy);
await TestContentGetAsync(apiClient, taxonomy);
await TestContentRemoveAsync(context, apiClient, taxonomy);
using var contentsApiClient = new ContentsApiClient(apiClientSettings);

taxonomy.ContentItemId = await TestContentCreateAsync(context, contentsApiClient, taxonomy);
await TestContentGetAsync(contentsApiClient, taxonomy);
await TestContentRemoveAsync(context, contentsApiClient, taxonomy);
}

private static async Task TestTenantCreateAsync(
UITestContext context,
ApiClient apiClient,
TenantsApiClient apiClient,
TenantApiModel createApiModel)
{
using (var response = await apiClient.OrchardCoreApi.CreateAsync(createApiModel))
Expand Down Expand Up @@ -161,7 +164,7 @@ private static async Task TestTenantCreateAsync(

private static async Task TestTenantSetupAsync(
UITestContext context,
ApiClient apiClient,
TenantsApiClient apiClient,
TenantApiModel createApiModel,
TenantSetupApiModel setupApiModel)
{
Expand All @@ -179,7 +182,7 @@ private static async Task TestTenantSetupAsync(

private static async Task TestTenantEditAsync(
UITestContext context,
ApiClient apiClient,
TenantsApiClient apiClient,
TenantApiModel editModel,
TenantSetupApiModel setupApiModel)
{
Expand All @@ -206,7 +209,7 @@ private static async Task TestTenantEditAsync(

private static async Task TestTenantDisableAsync(
UITestContext context,
ApiClient apiClient,
TenantsApiClient apiClient,
TenantApiModel editModel)
{
await apiClient.OrchardCoreApi.DisableAsync(editModel.Name);
Expand All @@ -219,7 +222,7 @@ private static async Task TestTenantDisableAsync(

private static async Task TestTenantRemoveAsync(
UITestContext context,
ApiClient apiClient,
TenantsApiClient apiClient,
TenantApiModel editModel)
{
await apiClient.OrchardCoreApi.RemoveAsync(editModel.Name);
Expand All @@ -231,12 +234,12 @@ private static async Task TestTenantRemoveAsync(

private static async Task<string> TestContentCreateAsync(
UITestContext context,
ApiClient apiClient,
ContentsApiClient apiClient,
ContentItem contentItem)
{
var response = await apiClient.OrchardCoreApi.CreateOrUpdateContentItemAsync(contentItem);
var contentItemIdFromAPI = JsonConvert.DeserializeObject<ContentItem>(response.Content).ContentItemId;
await context.GoToContentItemEditorByIdAsync(contentItemIdFromAPI);
var response = await apiClient.OrchardCoreApi.CreateOrUpdateAsync(contentItem);
var contentItemIdFromApi = JsonSerializer.Deserialize<ContentItem>(response.Content).ContentItemId;
await context.GoToContentItemEditorByIdAsync(contentItemIdFromApi);

context.Get(By.Id("TitlePart_Title")).GetValue().ShouldBe(contentItem.DisplayText);

Expand All @@ -246,38 +249,38 @@ private static async Task<string> TestContentCreateAsync(
context.Get(By.CssSelector("#TaxonomyPart_TermContentType option[selected]")).Text
.ShouldBe(contentItem.As<TaxonomyPart>().TermContentType);

return contentItemIdFromAPI;
return contentItemIdFromApi;
}

private static async Task TestContentGetAsync(
ApiClient apiClient,
ContentsApiClient apiClient,
ContentItem contentItem)
{
var response = await apiClient.OrchardCoreApi.GetContentItemAsync(contentItem.ContentItemId);
var contentItemFromAPI = JsonConvert.DeserializeObject<ContentItem>(response.Content);
var response = await apiClient.OrchardCoreApi.GetAsync(contentItem.ContentItemId);
var contentItemFromApi = JsonSerializer.Deserialize<ContentItem>(response.Content);

var document = JsonDocument.Parse(response.Content);

var contentItemFromAPIAutoroutePart = JsonConvert.DeserializeObject<AutoroutePart>(
var contentItemFromApiAutoroutePart = JsonSerializer.Deserialize<AutoroutePart>(
document.RootElement.GetProperty("AutoroutePart").GetRawText());
var contentItemFromAPITaxonomyPart = JsonConvert.DeserializeObject<TaxonomyPart>(
var contentItemFromApiTaxonomyPart = JsonSerializer.Deserialize<TaxonomyPart>(
document.RootElement.GetProperty("TaxonomyPart").GetRawText());

contentItemFromAPI.DisplayText.ShouldBe(contentItem.DisplayText);
contentItemFromAPI.ContentType.ShouldBe(contentItem.ContentType);
contentItemFromAPIAutoroutePart.RouteContainedItems.ShouldBe(contentItem.As<AutoroutePart>().RouteContainedItems);
contentItemFromAPITaxonomyPart.TermContentType.ShouldBe(contentItem.As<TaxonomyPart>().TermContentType);
contentItemFromApi.DisplayText.ShouldBe(contentItem.DisplayText);
contentItemFromApi.ContentType.ShouldBe(contentItem.ContentType);
contentItemFromApiAutoroutePart.RouteContainedItems.ShouldBe(contentItem.As<AutoroutePart>().RouteContainedItems);
contentItemFromApiTaxonomyPart.TermContentType.ShouldBe(contentItem.As<TaxonomyPart>().TermContentType);
}

private static async Task TestContentRemoveAsync(
UITestContext context,
ApiClient apiClient,
ContentsApiClient apiClient,
ContentItem contentItem)
{
await context.GoToContentItemListAsync();
context.Exists(By.XPath($"//a[contains(text(), '{contentItem.DisplayText}')]"));

await apiClient.OrchardCoreApi.RemoveContentItemAsync(contentItem.ContentItemId);
await apiClient.OrchardCoreApi.RemoveAsync(contentItem.ContentItemId);

context.Refresh();
context.Missing(By.XPath($"//a[contains(text(), '{contentItem.DisplayText}')]"));
Expand Down
74 changes: 41 additions & 33 deletions Lombiq.OrchardCoreApiClient/ApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,48 @@

namespace Lombiq.OrchardCoreApiClient;

public class ApiClient : ApiClient<IOrchardCoreApi>
public class TenantsApiClient : ApiClient<IOrchardCoreTenantsApi>
{
public ApiClient(ApiClientSettings apiClientSettings)
public TenantsApiClient(ApiClientSettings apiClientSettings)
: base(apiClientSettings)
{
}

public async Task CreateAndSetupTenantAsync(
TenantApiModel createApiViewModel,
TenantSetupApiModel setupApiViewModel)
{
if (!Timezones.TimezoneIds.Contains(setupApiViewModel.SiteTimeZone))
{
throw new ApiClientException(
$"Invalid timezone ID {setupApiViewModel.SiteTimeZone}. For the list of all valid timezone IDs " +
"follow this list: https://gist.github.com/jrolstad/5ca7d78dbfe182d7c1be");
}

try
{
using var response = await OrchardCoreApi.CreateAsync(createApiViewModel).ConfigureAwait(false);
await response.EnsureSuccessStatusCodeAsync();
}
catch (ApiException ex)
{
throw new ApiClientException("Tenant creation failed.", ex);
}

try
{
await OrchardCoreApi.SetupAsync(setupApiViewModel).ConfigureAwait(false);
}
catch (ApiException ex)
{
throw new ApiClientException("Tenant setup failed.", ex);
}
}
}

public class ContentsApiClient : ApiClient<IOrchardCoreContentsApi>
{
public ContentsApiClient(ApiClientSettings apiClientSettings)
: base(apiClientSettings)
{
}
Expand Down Expand Up @@ -74,37 +113,6 @@ public async Task<TResult> ExecuteWithRetryPolicyAsync<TResult>(
}
}

public async Task CreateAndSetupTenantAsync(
TenantApiModel createApiViewModel,
TenantSetupApiModel setupApiViewModel)
{
if (!Timezones.TimezoneIds.Contains(setupApiViewModel.SiteTimeZone))
{
throw new ApiClientException(
$"Invalid timezone ID {setupApiViewModel.SiteTimeZone}. For the list of all valid timezone IDs " +
"follow this list: https://gist.github.com/jrolstad/5ca7d78dbfe182d7c1be");
}

try
{
using var response = await OrchardCoreApi.CreateAsync(createApiViewModel).ConfigureAwait(false);
await response.EnsureSuccessStatusCodeAsync();
}
catch (ApiException ex)
{
throw new ApiClientException("Tenant creation failed.", ex);
}

try
{
await OrchardCoreApi.SetupAsync(setupApiViewModel).ConfigureAwait(false);
}
catch (ApiException ex)
{
throw new ApiClientException("Tenant setup failed.", ex);
}
}

public void Dispose()
{
Dispose(disposing: true);
Expand Down
98 changes: 6 additions & 92 deletions Lombiq.OrchardCoreApiClient/Interfaces/IOrchardCoreApi.cs
Original file line number Diff line number Diff line change
@@ -1,100 +1,14 @@
using Lombiq.OrchardCoreApiClient.Models;
using OrchardCore.ContentManagement;
using Refit;
using System.Threading.Tasks;
using static Lombiq.OrchardCoreApiClient.Constants.CommonHeaders;
using System.Diagnostics.CodeAnalysis;

namespace Lombiq.OrchardCoreApiClient.Interfaces;

/// <summary>
/// Interface representing the subset of APIs of Orchard Core.
/// Marker interface for representing the subset of APIs of Orchard Core.
/// </summary>
[SuppressMessage(
"Design",
"CA1040:Avoid empty interfaces",
Justification = "This is a marker interface used to identify all Orchard Core API interfaces.")]
public interface IOrchardCoreApi
{
/// <summary>
/// Create a new tenant in Orchard Core.
/// </summary>
/// <param name="createTenantParameters">
/// The necessary parameters to create a tenant: Name, RequestUrlPrefix etc.
/// </param>
/// <returns>The response of the tenant creation.</returns>
[Post("/api/tenants/create/")]
[Headers(AuthorizationBearer, RequestedWithXmlHttpRequest)]
Task<ApiResponse<string>> CreateAsync([Body(buffered: true)] TenantApiModel createTenantParameters);

/// <summary>
/// Setup the previously created tenant in Orchard Core.
/// </summary>
/// <param name="setupTenantParameters">
/// The necessary parameters to set up a tenant: Name, ConnectionString etc.
/// </param>
/// <returns>The response of the tenant setup.</returns>
[Post("/api/tenants/setup")]
[Headers(AuthorizationBearer, RequestedWithXmlHttpRequest)]
Task<ApiResponse<string>> SetupAsync([Body(buffered: true)] TenantSetupApiModel setupTenantParameters);

/// <summary>
/// Edit a previously created tenant in Orchard Core.
/// </summary>
/// <param name="editTenantParameters">The necessary parameter to edit a tenant: Name.</param>
/// <returns>The response of the tenant edit.</returns>
[Post("/api/tenants/edit")]
[Headers(AuthorizationBearer, RequestedWithXmlHttpRequest)]
Task<ApiResponse<string>> EditAsync([Body(buffered: true)] TenantApiModel editTenantParameters);

/// <summary>
/// Remove a previously created tenant in Orchard Core.
/// </summary>
/// <param name="tenantName">The necessary parameter to remove a tenant.</param>
/// <returns>The response of the tenant removal.</returns>
[Post("/api/tenants/remove/{tenantName}")]
[Headers(AuthorizationBearer, RequestedWithXmlHttpRequest)]
Task<ApiResponse<string>> RemoveAsync(string tenantName);

/// <summary>
/// Disable a previously created tenant in Orchard Core.
/// </summary>
/// <param name="tenantName">The necessary parameter to disable a tenant.</param>
/// <returns>The response of the tenant disable.</returns>
[Post("/api/tenants/disable/{tenantName}")]
[Headers(AuthorizationBearer, RequestedWithXmlHttpRequest)]
Task<ApiResponse<string>> DisableAsync(string tenantName);

/// <summary>
/// Enable a previously disabled tenant in Orchard Core.
/// </summary>
/// <param name="tenantName">The necessary parameter to enable a tenant.</param>
/// <returns>The response of the tenant enable.</returns>
[Post("/api/tenants/enable/{tenantName}")]
[Headers(AuthorizationBearer, RequestedWithXmlHttpRequest)]
Task<ApiResponse<string>> EnableAsync(string tenantName);

/// <summary>
/// Create or update a content item in Orchard Core.
/// </summary>
/// <param name="model">
/// The necessary parameters to create or update a content item: ContentType, Content etc.
/// </param>
/// <returns>The response of the content item creation.</returns>
[Post("/api/content")]
[Headers(AuthorizationBearer, RequestedWithXmlHttpRequest)]
Task<ApiResponse<string>> CreateOrUpdateContentItemAsync([Body(buffered: true)] ContentItem model);

/// <summary>
/// Get a previously created content item in Orchard Core.
/// </summary>
/// <param name="contentItemId">The necessary parameter to get a content item.</param>
/// <returns>The response of the content item query.</returns>
[Get("/api/content/{contentItemId}")]
[Headers(AuthorizationBearer, RequestedWithXmlHttpRequest)]
Task<ApiResponse<string>> GetContentItemAsync(string contentItemId);

/// <summary>
/// Remove a previously created content item in Orchard Core.
/// </summary>
/// <param name="contentItemId">The necessary parameter to remove a content item.</param>
/// <returns>The response of the content item removal.</returns>
[Delete("/api/content/{contentItemId}")]
[Headers(AuthorizationBearer, RequestedWithXmlHttpRequest)]
Task<ApiResponse<string>> RemoveContentItemAsync(string contentItemId);
}
Loading

0 comments on commit 11eba91

Please sign in to comment.