mirror of https://github.com/Squidex/squidex.git
Browse Source
* Simplify api permissions and improve performance with simple caching. * Schema resolver tests. * IDentity server improvements. * Set base url. * Code cleanup and tests fixed.pull/520/head
committed by
GitHub
74 changed files with 1130 additions and 569 deletions
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<Lazy /> |
|||
</Weavers> |
|||
@ -0,0 +1,26 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="Lazy" minOccurs="0" maxOccurs="1" type="xs:anyType" /> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,17 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Web |
|||
{ |
|||
public interface ISchemaFeature |
|||
{ |
|||
NamedId<Guid> SchemaId { get; } |
|||
} |
|||
} |
|||
@ -1,64 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Microsoft.AspNetCore.Http; |
|||
using Squidex.Infrastructure.Security; |
|||
using AllPermissions = Squidex.Shared.Permissions; |
|||
|
|||
namespace Squidex.Web |
|||
{ |
|||
public static class PermissionExtensions |
|||
{ |
|||
public static PermissionSet Permissions(this HttpContext httpContext) |
|||
{ |
|||
return httpContext.Context().Permissions; |
|||
} |
|||
|
|||
public static bool Includes(this HttpContext httpContext, Permission permission, PermissionSet? additional = null) |
|||
{ |
|||
return httpContext.Permissions().Includes(permission) || additional?.Includes(permission) == true; |
|||
} |
|||
|
|||
public static bool Includes(this ApiController controller, Permission permission, PermissionSet? additional = null) |
|||
{ |
|||
return controller.HttpContext.Includes(permission) || additional?.Includes(permission) == true; |
|||
} |
|||
|
|||
public static bool HasPermission(this HttpContext httpContext, Permission permission, PermissionSet? additional = null) |
|||
{ |
|||
return httpContext.Permissions().Allows(permission) || additional?.Allows(permission) == true; |
|||
} |
|||
|
|||
public static bool HasPermission(this ApiController controller, Permission permission, PermissionSet? additional = null) |
|||
{ |
|||
return controller.HttpContext.HasPermission(permission) || additional?.Allows(permission) == true; |
|||
} |
|||
|
|||
public static bool HasPermission(this ApiController controller, string id, string app = Permission.Any, string schema = Permission.Any, PermissionSet? additional = null) |
|||
{ |
|||
if (app == Permission.Any) |
|||
{ |
|||
if (controller.RouteData.Values.TryGetValue("app", out var value) && value is string s) |
|||
{ |
|||
app = s; |
|||
} |
|||
} |
|||
|
|||
if (schema == Permission.Any) |
|||
{ |
|||
if (controller.RouteData.Values.TryGetValue("name", out var value) && value is string s) |
|||
{ |
|||
schema = s; |
|||
} |
|||
} |
|||
|
|||
var permission = AllPermissions.ForApp(id, app, schema); |
|||
|
|||
return controller.HasPermission(permission, additional); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Microsoft.AspNetCore.Builder; |
|||
|
|||
namespace Squidex.Web.Pipeline |
|||
{ |
|||
public static class AccessTokenQueryExtensions |
|||
{ |
|||
public static void UseAccessTokenQueryString(this IApplicationBuilder app) |
|||
{ |
|||
app.UseMiddleware<AccessTokenQueryMiddleware>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Microsoft.Net.Http.Headers; |
|||
|
|||
namespace Squidex.Web.Pipeline |
|||
{ |
|||
public sealed class AccessTokenQueryMiddleware |
|||
{ |
|||
private readonly RequestDelegate next; |
|||
|
|||
public AccessTokenQueryMiddleware(RequestDelegate next) |
|||
{ |
|||
this.next = next; |
|||
} |
|||
|
|||
public Task InvokeAsync(HttpContext context) |
|||
{ |
|||
var request = context.Request; |
|||
|
|||
if (!string.IsNullOrWhiteSpace(request.Headers[HeaderNames.Authorization]) && request.Query.TryGetValue("access_token", out var token)) |
|||
{ |
|||
request.Headers[HeaderNames.Authorization] = token; |
|||
} |
|||
|
|||
return next(context); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Web.Pipeline |
|||
{ |
|||
public sealed class SchemaFeature : ISchemaFeature |
|||
{ |
|||
public NamedId<Guid> SchemaId { get; } |
|||
|
|||
public SchemaFeature(NamedId<Guid> schemaId) |
|||
{ |
|||
SchemaId = schemaId; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Filters; |
|||
using Squidex.Domain.Apps.Entities; |
|||
using Squidex.Domain.Apps.Entities.Schemas; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Web.Pipeline |
|||
{ |
|||
public sealed class SchemaResolver : IAsyncActionFilter |
|||
{ |
|||
private readonly IAppProvider appProvider; |
|||
|
|||
public SchemaResolver(IAppProvider appProvider) |
|||
{ |
|||
Guard.NotNull(appProvider); |
|||
|
|||
this.appProvider = appProvider; |
|||
} |
|||
|
|||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) |
|||
{ |
|||
var appId = context.HttpContext.Features.Get<IAppFeature>()?.AppId.Id ?? default; |
|||
|
|||
if (appId != default) |
|||
{ |
|||
var schemaIdOrName = context.RouteData.Values["name"]?.ToString(); |
|||
|
|||
if (!string.IsNullOrWhiteSpace(schemaIdOrName)) |
|||
{ |
|||
var schema = await GetSchemaAsync(appId, schemaIdOrName); |
|||
|
|||
if (schema == null) |
|||
{ |
|||
context.Result = new NotFoundResult(); |
|||
return; |
|||
} |
|||
|
|||
context.HttpContext.Features.Set<ISchemaFeature>(new SchemaFeature(schema.NamedId())); |
|||
} |
|||
} |
|||
|
|||
await next(); |
|||
} |
|||
|
|||
private Task<ISchemaEntity?> GetSchemaAsync(Guid appId, string schemaIdOrName) |
|||
{ |
|||
if (Guid.TryParse(schemaIdOrName, out var id)) |
|||
{ |
|||
return appProvider.GetSchemaAsync(appId, id); |
|||
} |
|||
else |
|||
{ |
|||
return appProvider.GetSchemaAsync(appId, schemaIdOrName); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,242 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Lazy; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.Security; |
|||
using P = Squidex.Shared.Permissions; |
|||
|
|||
namespace Squidex.Web |
|||
{ |
|||
public sealed class Resources |
|||
{ |
|||
private readonly Dictionary<(string, string), bool> schemaPermissions = new Dictionary<(string, string), bool>(); |
|||
|
|||
// Contents
|
|||
public bool CanReadContent(string schema) => IsAllowedForSchema(P.AppContentsRead, schema); |
|||
|
|||
public bool CanCreateContent(string schema) => IsAllowedForSchema(P.AppContentsCreate, schema); |
|||
|
|||
public bool CanCreateContentVersion(string schema) => IsAllowedForSchema(P.AppContentsVersionCreate, schema); |
|||
|
|||
public bool CanDeleteContent(string schema) => IsAllowedForSchema(P.AppContentsDelete, schema); |
|||
|
|||
public bool CanDeleteContentVersion(string schema) => IsAllowedForSchema(P.AppContentsVersionDelete, schema); |
|||
|
|||
public bool CanUpdateContent(string schema) => IsAllowedForSchema(P.AppContentsUpdate, schema); |
|||
|
|||
public bool CanUpdateContentPartial(string schema) => IsAllowedForSchema(P.AppContentsUpdatePartial, schema); |
|||
|
|||
// Schemas
|
|||
public bool CanUpdateSchema(string schema) => IsAllowedForSchema(P.AppSchemasDelete, schema); |
|||
|
|||
public bool CanUpdateSchemaScripts(string schema) => IsAllowedForSchema(P.AppSchemasScripts, schema); |
|||
|
|||
public bool CanPublishSchema(string schema) => IsAllowedForSchema(P.AppSchemasPublish, schema); |
|||
|
|||
public bool CanDeleteSchema(string schema) => IsAllowedForSchema(P.AppSchemasDelete, schema); |
|||
|
|||
[Lazy] |
|||
public bool CanCreateSchema => IsAllowed(P.AppSchemasUpdate); |
|||
|
|||
// Contributors
|
|||
[Lazy] |
|||
public bool CanAssignContributor => IsAllowed(P.AppContributorsAssign); |
|||
|
|||
[Lazy] |
|||
public bool CanRevokeContributor => IsAllowed(P.AppContributorsRevoke); |
|||
|
|||
// Workflows
|
|||
[Lazy] |
|||
public bool CanCreateWorkflow => IsAllowed(P.AppWorkflowsCreate); |
|||
|
|||
[Lazy] |
|||
public bool CanUpdateWorkflow => IsAllowed(P.AppWorkflowsUpdate); |
|||
|
|||
[Lazy] |
|||
public bool CanDeleteWorkflow => IsAllowed(P.AppWorkflowsDelete); |
|||
|
|||
// Roles
|
|||
[Lazy] |
|||
public bool CanCreateRole => IsAllowed(P.AppRolesCreate); |
|||
|
|||
[Lazy] |
|||
public bool CanUpdateRole => IsAllowed(P.AppRolesUpdate); |
|||
|
|||
[Lazy] |
|||
public bool CanDeleteRole => IsAllowed(P.AppRolesDelete); |
|||
|
|||
// Languages
|
|||
[Lazy] |
|||
public bool CanCreateLanguage => IsAllowed(P.AppLanguagesCreate); |
|||
|
|||
[Lazy] |
|||
public bool CanUpdateLanguage => IsAllowed(P.AppLanguagesUpdate); |
|||
|
|||
[Lazy] |
|||
public bool CanDeleteLanguage => IsAllowed(P.AppLanguagesDelete); |
|||
|
|||
// Patterns
|
|||
[Lazy] |
|||
public bool CanCreatePattern => IsAllowed(P.AppClientsCreate); |
|||
|
|||
[Lazy] |
|||
public bool CanUpdatePattern => IsAllowed(P.AppPatternsUpdate); |
|||
|
|||
[Lazy] |
|||
public bool CanDeletePattern => IsAllowed(P.AppPatternsDelete); |
|||
|
|||
// Clients
|
|||
[Lazy] |
|||
public bool CanCreateClient => IsAllowed(P.AppClientsCreate); |
|||
|
|||
[Lazy] |
|||
public bool CanUpdateClient => IsAllowed(P.AppClientsUpdate); |
|||
|
|||
[Lazy] |
|||
public bool CanDeleteClient => IsAllowed(P.AppClientsDelete); |
|||
|
|||
// Rules
|
|||
[Lazy] |
|||
public bool CanDisableRule => IsAllowed(P.AppRulesDisable); |
|||
|
|||
[Lazy] |
|||
public bool CanCreateRule => IsAllowed(P.AppRulesCreate); |
|||
|
|||
[Lazy] |
|||
public bool CanUpdateRule => IsAllowed(P.AppRulesUpdate); |
|||
|
|||
[Lazy] |
|||
public bool CanDeleteRule => IsAllowed(P.AppRulesDelete); |
|||
|
|||
[Lazy] |
|||
public bool CanReadRuleEvents => IsAllowed(P.AppRulesEvents); |
|||
|
|||
// Users
|
|||
[Lazy] |
|||
public bool CanReadUsers => IsAllowed(P.AdminUsersRead); |
|||
|
|||
[Lazy] |
|||
public bool CanCreateUser => IsAllowed(P.AdminUsersCreate); |
|||
|
|||
[Lazy] |
|||
public bool CanLockUser => IsAllowed(P.AdminUsersLock); |
|||
|
|||
[Lazy] |
|||
public bool CanUnlockUser => IsAllowed(P.AdminUsersUnlock); |
|||
|
|||
[Lazy] |
|||
public bool CanUpdateUser => IsAllowed(P.AdminUsersUpdate); |
|||
|
|||
// Assets
|
|||
[Lazy] |
|||
public bool CanUploadAsset => IsAllowed(P.AppAssetsUpload); |
|||
|
|||
[Lazy] |
|||
public bool CanCreateAsset => IsAllowed(P.AppAssetsCreate); |
|||
|
|||
[Lazy] |
|||
public bool CanDeleteAsset => IsAllowed(P.AppAssetsDelete); |
|||
|
|||
[Lazy] |
|||
public bool CanUpdateAsset => IsAllowed(P.AppAssetsUpdate); |
|||
|
|||
[Lazy] |
|||
public bool CanReadAssets => IsAllowed(P.AppAssetsRead); |
|||
|
|||
// Events
|
|||
[Lazy] |
|||
public bool CanReadEvents => IsAllowed(P.AdminEventsRead); |
|||
|
|||
[Lazy] |
|||
public bool CanManageEvents => IsAllowed(P.AdminEventsManage); |
|||
|
|||
// Orleans
|
|||
[Lazy] |
|||
public bool CanReadOrleans => IsAllowed(P.AdminOrleans); |
|||
|
|||
// Backups
|
|||
[Lazy] |
|||
public bool CanRestoreBackup => IsAllowed(P.AdminEventsRead); |
|||
|
|||
[Lazy] |
|||
public bool CanCreateBackup => IsAllowed(P.AppBackupsCreate); |
|||
|
|||
[Lazy] |
|||
public bool CanDeleteBackup => IsAllowed(P.AppBackupsDelete); |
|||
|
|||
[Lazy] |
|||
public string? App => GetAppName(); |
|||
|
|||
public ApiController Controller { get; } |
|||
|
|||
public PermissionSet Permissions { get; } |
|||
|
|||
public Resources(ApiController controller) |
|||
{ |
|||
Controller = controller; |
|||
|
|||
Permissions = controller.HttpContext.Context().Permissions; |
|||
} |
|||
|
|||
public string Url<T>(Func<T?, string> action, object? values = null) where T : ApiController |
|||
{ |
|||
return Controller.Url(action, values); |
|||
} |
|||
|
|||
public bool IsUser(string userId) |
|||
{ |
|||
var subject = Controller.User.OpenIdSubject(); |
|||
|
|||
return string.Equals(subject, userId, StringComparison.OrdinalIgnoreCase); |
|||
} |
|||
|
|||
public bool Includes(Permission permission, PermissionSet? additional = null) |
|||
{ |
|||
return Permissions.Includes(permission) || additional?.Includes(permission) == true; |
|||
} |
|||
|
|||
public bool IsAllowedForSchema(string id, string schema) |
|||
{ |
|||
return schemaPermissions.GetOrAdd((id, schema), k => IsAllowed(k.Item1, "*", k.Item2)); |
|||
} |
|||
|
|||
public bool IsAllowed(string id, string app = Permission.Any, string schema = Permission.Any, PermissionSet? additional = null) |
|||
{ |
|||
if (app == Permission.Any) |
|||
{ |
|||
var falback = App; |
|||
|
|||
if (!string.IsNullOrWhiteSpace(falback)) |
|||
{ |
|||
app = falback; |
|||
} |
|||
} |
|||
|
|||
if (schema == Permission.Any) |
|||
{ |
|||
var falback = Controller.HttpContext.Features.Get<ISchemaFeature>()?.SchemaId.Name; |
|||
|
|||
if (!string.IsNullOrWhiteSpace(falback)) |
|||
{ |
|||
schema = falback; |
|||
} |
|||
} |
|||
|
|||
var permission = P.ForApp(id, app, schema); |
|||
|
|||
return Permissions.Allows(permission) || additional?.Allows(permission) == true; |
|||
} |
|||
|
|||
private string? GetAppName() |
|||
{ |
|||
return Controller.HttpContext.Context().App?.Name; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading.Tasks; |
|||
using IdentityServer4.Extensions; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Microsoft.Extensions.Options; |
|||
using Squidex.Web; |
|||
|
|||
namespace Squidex.Areas.Api.Config |
|||
{ |
|||
public sealed class IdentityServerPathMiddleware |
|||
{ |
|||
private readonly UrlsOptions urlsOptions; |
|||
private readonly RequestDelegate next; |
|||
|
|||
public IdentityServerPathMiddleware(IOptions<UrlsOptions> urlsOptions, RequestDelegate next) |
|||
{ |
|||
this.urlsOptions = urlsOptions.Value; |
|||
|
|||
this.next = next; |
|||
} |
|||
|
|||
public Task InvokeAsync(HttpContext context) |
|||
{ |
|||
context.SetIdentityServerOrigin(urlsOptions.BaseUrl); |
|||
context.SetIdentityServerBasePath(Constants.IdentityServerPrefix); |
|||
|
|||
return next(context); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,151 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Security.Claims; |
|||
using System.Threading.Tasks; |
|||
using FakeItEasy; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Abstractions; |
|||
using Microsoft.AspNetCore.Mvc.Filters; |
|||
using Microsoft.AspNetCore.Routing; |
|||
using Squidex.Domain.Apps.Core.Schemas; |
|||
using Squidex.Domain.Apps.Entities; |
|||
using Squidex.Domain.Apps.Entities.Schemas; |
|||
using Squidex.Infrastructure; |
|||
using Xunit; |
|||
|
|||
#pragma warning disable IDE0017 // Simplify object initialization
|
|||
|
|||
namespace Squidex.Web.Pipeline |
|||
{ |
|||
public class SchemaResolverTests |
|||
{ |
|||
private readonly IAppProvider appProvider = A.Fake<IAppProvider>(); |
|||
private readonly HttpContext httpContext = new DefaultHttpContext(); |
|||
private readonly ActionContext actionContext; |
|||
private readonly ActionExecutingContext actionExecutingContext; |
|||
private readonly ActionExecutionDelegate next; |
|||
private readonly ClaimsIdentity user = new ClaimsIdentity(); |
|||
private readonly NamedId<Guid> schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); |
|||
private readonly NamedId<Guid> appId = NamedId.Of(Guid.NewGuid(), "my-app"); |
|||
private readonly SchemaResolver sut; |
|||
private bool isNextCalled; |
|||
|
|||
public SchemaResolverTests() |
|||
{ |
|||
actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor |
|||
{ |
|||
EndpointMetadata = new List<object>() |
|||
}); |
|||
|
|||
actionExecutingContext = new ActionExecutingContext(actionContext, new List<IFilterMetadata>(), new Dictionary<string, object>(), this); |
|||
actionExecutingContext.HttpContext = httpContext; |
|||
actionExecutingContext.HttpContext.User = new ClaimsPrincipal(user); |
|||
|
|||
next = () => |
|||
{ |
|||
isNextCalled = true; |
|||
|
|||
return Task.FromResult<ActionExecutedContext?>(null); |
|||
}; |
|||
|
|||
sut = new SchemaResolver(appProvider); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_return_not_found_if_schema_not_found() |
|||
{ |
|||
actionExecutingContext.HttpContext.Features.Set<IAppFeature>(new AppFeature(appId)); |
|||
actionContext.RouteData.Values["name"] = schemaId.Id.ToString(); |
|||
|
|||
A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false)) |
|||
.Returns(Task.FromResult<ISchemaEntity?>(null)); |
|||
|
|||
await sut.OnActionExecutionAsync(actionExecutingContext, next); |
|||
|
|||
Assert.IsType<NotFoundResult>(actionExecutingContext.Result); |
|||
Assert.False(isNextCalled); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_resolve_schema_from_id() |
|||
{ |
|||
actionExecutingContext.HttpContext.Features.Set<IAppFeature>(new AppFeature(appId)); |
|||
actionContext.RouteData.Values["name"] = schemaId.Id.ToString(); |
|||
|
|||
var schema = CreateSchema(); |
|||
|
|||
A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false)) |
|||
.Returns(schema); |
|||
|
|||
await sut.OnActionExecutionAsync(actionExecutingContext, next); |
|||
|
|||
Assert.Equal(schemaId, actionContext.HttpContext.Features.Get<ISchemaFeature>().SchemaId); |
|||
Assert.True(isNextCalled); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_resolve_schema_from_name() |
|||
{ |
|||
actionExecutingContext.HttpContext.Features.Set<IAppFeature>(new AppFeature(appId)); |
|||
actionContext.RouteData.Values["name"] = schemaId.Name; |
|||
|
|||
var schema = CreateSchema(); |
|||
|
|||
A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Name)) |
|||
.Returns(schema); |
|||
|
|||
await sut.OnActionExecutionAsync(actionExecutingContext, next); |
|||
|
|||
Assert.Equal(schemaId, actionContext.HttpContext.Features.Get<ISchemaFeature>().SchemaId); |
|||
Assert.True(isNextCalled); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_do_nothing_if_app_feature_not_set() |
|||
{ |
|||
actionExecutingContext.RouteData.Values["name"] = schemaId.Name; |
|||
|
|||
await sut.OnActionExecutionAsync(actionExecutingContext, next); |
|||
|
|||
Assert.True(isNextCalled); |
|||
|
|||
A.CallTo(() => appProvider.GetAppAsync(A<string>._)) |
|||
.MustNotHaveHappened(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_do_nothing_if_parameter_not_set() |
|||
{ |
|||
actionExecutingContext.HttpContext.Features.Set<IAppFeature>(new AppFeature(appId)); |
|||
actionExecutingContext.RouteData.Values.Remove("name"); |
|||
|
|||
await sut.OnActionExecutionAsync(actionExecutingContext, next); |
|||
|
|||
Assert.True(isNextCalled); |
|||
|
|||
A.CallTo(() => appProvider.GetAppAsync(A<string>._)) |
|||
.MustNotHaveHappened(); |
|||
} |
|||
|
|||
private ISchemaEntity CreateSchema() |
|||
{ |
|||
var schemaEntity = A.Fake<ISchemaEntity>(); |
|||
|
|||
A.CallTo(() => schemaEntity.SchemaDef) |
|||
.Returns(new Schema(schemaId.Name)); |
|||
|
|||
A.CallTo(() => schemaEntity.Id) |
|||
.Returns(schemaId.Id); |
|||
|
|||
return schemaEntity; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue