Browse Source

Temp.

pull/380/head
Sebastian Stehle 7 years ago
parent
commit
e6f84fe88d
  1. 20
      src/Squidex.Domain.Apps.Entities/Contents/ContentEnricher.cs
  2. 50
      src/Squidex.Domain.Apps.Entities/Contents/ContextExtensions.cs
  3. 47
      src/Squidex.Domain.Apps.Entities/Context.cs
  4. 10
      src/Squidex.Domain.Apps.Entities/IContextProvider.cs
  5. 6
      src/Squidex.Web/ApiController.cs
  6. 25
      src/Squidex.Web/ApiPermissionAttribute.cs
  7. 18
      src/Squidex.Web/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs
  8. 10
      src/Squidex.Web/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs
  9. 27
      src/Squidex.Web/ContextExtensions.cs
  10. 30
      src/Squidex.Web/ContextProvider.cs
  11. 2
      src/Squidex.Web/EntityCreatedDto.cs
  12. 4
      src/Squidex.Web/ErrorDto.cs
  13. 22
      src/Squidex.Web/PermissionExtensions.cs
  14. 8
      src/Squidex.Web/Pipeline/ApiCostsFilter.cs
  15. 19
      src/Squidex.Web/Pipeline/AppResolver.cs
  16. 10
      src/Squidex.Web/Pipeline/RequestLogPerformanceMiddleware.cs
  17. 4
      src/Squidex.Web/Resource.cs
  18. 2
      src/Squidex.Web/ResourceLink.cs
  19. 2
      src/Squidex.Web/Squidex.Web.csproj
  20. 6
      src/Squidex.Web/UrlHelperExtensions.cs

20
src/Squidex.Domain.Apps.Entities/Contents/ContentEnricher.cs

@ -21,10 +21,15 @@ namespace Squidex.Domain.Apps.Entities.Contents
{ {
private const string DefaultColor = StatusColors.Draft; private const string DefaultColor = StatusColors.Draft;
private readonly IContentWorkflow contentWorkflow; private readonly IContentWorkflow contentWorkflow;
private readonly IContextProvider contextProvider;
public ContentEnricher(IContentWorkflow contentWorkflow) public ContentEnricher(IContentWorkflow contentWorkflow, IContextProvider contextProvider)
{ {
Guard.NotNull(contentWorkflow, nameof(contentWorkflow));
Guard.NotNull(contextProvider, nameof(contextProvider));
this.contentWorkflow = contentWorkflow; this.contentWorkflow = contentWorkflow;
this.contextProvider = contextProvider;
} }
public async Task<IEnrichedContentEntity> EnrichAsync(IContentEntity content) public async Task<IEnrichedContentEntity> EnrichAsync(IContentEntity content)
@ -51,8 +56,12 @@ namespace Squidex.Domain.Apps.Entities.Contents
var result = SimpleMapper.Map(content, new ContentEntity()); var result = SimpleMapper.Map(content, new ContentEntity());
await ResolveColorAsync(content, result, cache); await ResolveColorAsync(content, result, cache);
await ResolveNextsAsync(content, result);
await ResolveCanUpdateAsync(content, result); if (ShouldEnrichWithStatuses())
{
await ResolveNextsAsync(content, result);
await ResolveCanUpdateAsync(content, result);
}
results.Add(result); results.Add(result);
} }
@ -61,6 +70,11 @@ namespace Squidex.Domain.Apps.Entities.Contents
} }
} }
private bool ShouldEnrichWithStatuses()
{
return contextProvider.Context.IsFrontendClient || contextProvider.Context.IsResolveFlow();
}
private async Task ResolveCanUpdateAsync(IContentEntity content, ContentEntity result) private async Task ResolveCanUpdateAsync(IContentEntity content, ContentEntity result)
{ {
result.CanUpdate = await contentWorkflow.CanUpdateAsync(content); result.CanUpdate = await contentWorkflow.CanUpdateAsync(content);

50
src/Squidex.Domain.Apps.Entities/Contents/ContextExtensions.cs

@ -0,0 +1,50 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Domain.Apps.Entities.Contents
{
public static class ContextExtensions
{
private static readonly char[] Separators = { ',', ';' };
public static bool IsUnpublished(this Context context)
{
return context.Headers.ContainsKey("X-Unpublished");
}
public static Context WithUnpublished(this Context context)
{
context.Headers["X-Unpublished"] = "1";
return context;
}
public static bool IsFlatten(this Context context)
{
return context.Headers.ContainsKey("X-Flatten");
}
public static Context WithFlatten(this Context context)
{
context.Headers["X-Flatten"] = "1";
return context;
}
public static bool IsResolveFlow(this Context context)
{
return context.Headers.ContainsKey("X-ResolveFlow");
}
public static Context WithResolveFlow(this Context context)
{
context.Headers["X-ResolveFlow"] = "1";
return context;
}
}
}

47
src/Squidex.Domain.Apps.Entities/Context.cs

@ -0,0 +1,47 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using System.Security.Claims;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Infrastructure.Security;
using Squidex.Shared.Identity;
namespace Squidex.Domain.Apps.Entities
{
public sealed class Context
{
public IAppEntity App { get; set; }
public ClaimsPrincipal User { get; set; }
public PermissionSet Permissions { get; set; }
public IDictionary<string, string> Headers { get; } = new Dictionary<string, string>();
public Context()
{
}
public Context(ClaimsPrincipal user, IAppEntity app)
{
User = user;
if (user != null)
{
Permissions = user.Permissions();
}
App = app;
}
public bool IsFrontendClient
{
get { return User != null && User.IsInClient("squidex-frontend"); }
}
}
}

10
src/Squidex.Web/IAppFeature.cs → src/Squidex.Domain.Apps.Entities/IContextProvider.cs

@ -1,16 +1,14 @@
// ========================================================================== // ==========================================================================
// Squidex Headless CMS // Squidex Headless CMS
// ========================================================================== // ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt) // Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Squidex.Domain.Apps.Entities.Apps; namespace Squidex.Domain.Apps.Entities
namespace Squidex.Web
{ {
public interface IAppFeature public interface IContextProvider
{ {
IAppEntity App { get; } Context Context { get; }
} }
} }

6
src/Squidex.Web/ApiController.cs

@ -26,14 +26,14 @@ namespace Squidex.Web
{ {
get get
{ {
var appFeature = HttpContext.Features.Get<IAppFeature>(); var app = HttpContext.Context().App;
if (appFeature == null) if (app == null)
{ {
throw new InvalidOperationException("Not in a app context."); throw new InvalidOperationException("Not in a app context.");
} }
return appFeature.App; return app;
} }
} }

25
src/Squidex.Web/ApiPermissionAttribute.cs

@ -36,23 +36,26 @@ namespace Squidex.Web
{ {
if (permissionIds.Length > 0) if (permissionIds.Length > 0)
{ {
var set = context.HttpContext.User.Permissions(); var permissions = context.HttpContext.Context().Permissions;
var hasPermission = false; var hasPermission = false;
foreach (var permissionId in permissionIds) if (permissions != null)
{ {
var id = permissionId; foreach (var permissionId in permissionIds)
foreach (var routeParam in context.RouteData.Values)
{ {
id = id.Replace($"{{{routeParam.Key}}}", routeParam.Value?.ToString()); var id = permissionId;
}
if (set.Allows(new Permission(id))) foreach (var routeParam in context.RouteData.Values)
{ {
hasPermission = true; id = id.Replace($"{{{routeParam.Key}}}", routeParam.Value?.ToString());
break; }
if (permissions.Allows(new Permission(id)))
{
hasPermission = true;
break;
}
} }
} }

18
src/Squidex.Web/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs

@ -7,7 +7,6 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities;
using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -17,20 +16,15 @@ namespace Squidex.Web.CommandMiddlewares
{ {
public sealed class EnrichWithAppIdCommandMiddleware : ICommandMiddleware public sealed class EnrichWithAppIdCommandMiddleware : ICommandMiddleware
{ {
private readonly IHttpContextAccessor httpContextAccessor; private readonly IContextProvider contextProvider;
public EnrichWithAppIdCommandMiddleware(IHttpContextAccessor httpContextAccessor) public EnrichWithAppIdCommandMiddleware(IContextProvider contextProvider)
{ {
this.httpContextAccessor = httpContextAccessor; this.contextProvider = contextProvider;
} }
public Task HandleAsync(CommandContext context, Func<Task> next) public Task HandleAsync(CommandContext context, Func<Task> next)
{ {
if (httpContextAccessor.HttpContext == null)
{
return next();
}
if (context.Command is IAppCommand appCommand && appCommand.AppId == null) if (context.Command is IAppCommand appCommand && appCommand.AppId == null)
{ {
var appId = GetAppId(); var appId = GetAppId();
@ -50,14 +44,14 @@ namespace Squidex.Web.CommandMiddlewares
private NamedId<Guid> GetAppId() private NamedId<Guid> GetAppId()
{ {
var appFeature = httpContextAccessor.HttpContext.Features.Get<IAppFeature>(); var context = contextProvider.Context;
if (appFeature?.App == null) if (context.App == null)
{ {
throw new InvalidOperationException("Cannot resolve app."); throw new InvalidOperationException("Cannot resolve app.");
} }
return appFeature.App.NamedId(); return context.App.NamedId();
} }
} }
} }

10
src/Squidex.Web/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs

@ -63,16 +63,6 @@ namespace Squidex.Web.CommandMiddlewares
appId = appCommand.AppId; appId = appCommand.AppId;
} }
if (appId == null)
{
var appFeature = actionContextAccessor.ActionContext.HttpContext.Features.Get<IAppFeature>();
if (appFeature?.App != null)
{
appId = appFeature.App.NamedId();
}
}
if (appId != null) if (appId != null)
{ {
var routeValues = actionContextAccessor.ActionContext.RouteData.Values; var routeValues = actionContextAccessor.ActionContext.RouteData.Values;

27
src/Squidex.Web/ContextExtensions.cs

@ -0,0 +1,27 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.AspNetCore.Http;
using Squidex.Domain.Apps.Entities;
namespace Squidex.Web
{
public static class ContextExtensions
{
public static Context Context(this HttpContext httpContext)
{
var result = httpContext.Features.Get<Context>();
if (result == null)
{
httpContext.Features.Set(new Context { User = httpContext.User });
}
return result;
}
}
}

30
src/Squidex.Web/ContextProvider.cs

@ -0,0 +1,30 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.AspNetCore.Http;
using Squidex.Domain.Apps.Entities;
using Squidex.Infrastructure;
namespace Squidex.Web
{
public sealed class ContextProvider : IContextProvider
{
private readonly IHttpContextAccessor httpContextAccessor;
public Context Context
{
get { return httpContextAccessor.HttpContext.Context(); }
}
public ContextProvider(IHttpContextAccessor httpContextAccessor)
{
Guard.NotNull(httpContextAccessor, nameof(httpContextAccessor));
this.httpContextAccessor = httpContextAccessor;
}
}
}

2
src/Squidex.Web/EntityCreatedDto.cs

@ -15,7 +15,7 @@ namespace Squidex.Web
[Required] [Required]
[Display(Description = "Id of the created entity.")] [Display(Description = "Id of the created entity.")]
public string Id { get; set; } public string Id { get; set; }
[Display(Description = "The new version of the entity.")] [Display(Description = "The new version of the entity.")]
public long Version { get; set; } public long Version { get; set; }

4
src/Squidex.Web/ErrorDto.cs

@ -14,10 +14,10 @@ namespace Squidex.Web
[Required] [Required]
[Display(Description = "Error message.")] [Display(Description = "Error message.")]
public string Message { get; set; } public string Message { get; set; }
[Display(Description = "Detailed error messages.")] [Display(Description = "Detailed error messages.")]
public string[] Details { get; set; } public string[] Details { get; set; }
[Display(Description = "Status code of the http response.")] [Display(Description = "Status code of the http response.")]
public int? StatusCode { get; set; } = 400; public int? StatusCode { get; set; } = 400;
} }

22
src/Squidex.Web/PermissionExtensions.cs

@ -7,34 +7,14 @@
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Squidex.Infrastructure.Security; using Squidex.Infrastructure.Security;
using Squidex.Shared.Identity;
namespace Squidex.Web namespace Squidex.Web
{ {
public static class PermissionExtensions public static class PermissionExtensions
{ {
private sealed class PermissionFeature
{
public PermissionSet Permissions { get; }
public PermissionFeature(PermissionSet permissions)
{
Permissions = permissions;
}
}
public static PermissionSet Permissions(this HttpContext httpContext) public static PermissionSet Permissions(this HttpContext httpContext)
{ {
var feature = httpContext.Features.Get<PermissionFeature>(); return httpContext.Context().Permissions;
if (feature == null)
{
feature = new PermissionFeature(httpContext.User.Permissions());
httpContext.Features.Set(feature);
}
return feature.Permissions;
} }
public static bool HasPermission(this HttpContext httpContext, Permission permission, PermissionSet permissions = null) public static bool HasPermission(this HttpContext httpContext, Permission permission, PermissionSet permissions = null)

8
src/Squidex.Web/Pipeline/ApiCostsFilter.cs

@ -47,15 +47,15 @@ namespace Squidex.Web.Pipeline
{ {
context.HttpContext.Features.Set<IApiCostsFeature>(FilterDefinition); context.HttpContext.Features.Set<IApiCostsFeature>(FilterDefinition);
var appFeature = context.HttpContext.Features.Get<IAppFeature>(); var app = context.HttpContext.Context().App;
if (appFeature?.App != null && FilterDefinition.Weight > 0) if (app != null && FilterDefinition.Weight > 0)
{ {
var appId = appFeature.App.Id.ToString(); var appId = app.Id.ToString();
using (Profiler.Trace("CheckUsage")) using (Profiler.Trace("CheckUsage"))
{ {
var plan = appPlansProvider.GetPlanForApp(appFeature.App); var plan = appPlansProvider.GetPlanForApp(app);
var usage = await usageTracker.GetMonthlyCallsAsync(appId, DateTime.Today); var usage = await usageTracker.GetMonthlyCallsAsync(appId, DateTime.Today);

19
src/Squidex.Web/Pipeline/AppResolver.cs

@ -23,16 +23,6 @@ namespace Squidex.Web.Pipeline
{ {
private readonly IAppProvider appProvider; private readonly IAppProvider appProvider;
public class AppFeature : IAppFeature
{
public IAppEntity App { get; }
public AppFeature(IAppEntity app)
{
App = app;
}
}
public AppResolver(IAppProvider appProvider) public AppResolver(IAppProvider appProvider)
{ {
this.appProvider = appProvider; this.appProvider = appProvider;
@ -76,15 +66,16 @@ namespace Squidex.Web.Pipeline
} }
} }
var set = user.Permissions(); var permissionset = user.Permissions();
if (!set.Includes(Permissions.ForApp(Permissions.App, appName))&& !AllowAnonymous(context)) context.HttpContext.Context().App = app;
context.HttpContext.Context().Permissions = permissions;
if (!permissionset.Includes(Permissions.ForApp(Permissions.App, appName)) && !AllowAnonymous(context))
{ {
context.Result = new NotFoundResult(); context.Result = new NotFoundResult();
return; return;
} }
context.HttpContext.Features.Set<IAppFeature>(new AppFeature(app));
} }
await next(); await next();

10
src/Squidex.Web/Pipeline/RequestLogPerformanceMiddleware.cs

@ -47,9 +47,9 @@ namespace Squidex.Web.Pipeline
} }
} }
private static void LogFilters(HttpContext context, IObjectWriter c) private static void LogFilters(HttpContext httpContext, IObjectWriter c)
{ {
var app = context.Features.Get<IAppFeature>()?.App; var app = httpContext.Context().App;
if (app != null) if (app != null)
{ {
@ -57,21 +57,21 @@ namespace Squidex.Web.Pipeline
c.WriteProperty("appName", app.Name); c.WriteProperty("appName", app.Name);
} }
var userId = context.User.OpenIdSubject(); var userId = httpContext.User.OpenIdSubject();
if (!string.IsNullOrWhiteSpace(userId)) if (!string.IsNullOrWhiteSpace(userId))
{ {
c.WriteProperty(nameof(userId), userId); c.WriteProperty(nameof(userId), userId);
} }
var clientId = context.User.OpenIdClientId(); var clientId = httpContext.User.OpenIdClientId();
if (!string.IsNullOrWhiteSpace(clientId)) if (!string.IsNullOrWhiteSpace(clientId))
{ {
c.WriteProperty(nameof(clientId), clientId); c.WriteProperty(nameof(clientId), clientId);
} }
var costs = context.Features.Get<IApiCostsFeature>()?.Weight ?? 0; var costs = httpContext.Features.Get<IApiCostsFeature>()?.Weight ?? 0;
c.WriteProperty(nameof(costs), costs); c.WriteProperty(nameof(costs), costs);
} }

4
src/Squidex.Web/Resource.cs

@ -5,10 +5,10 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Newtonsoft.Json;
using Squidex.Infrastructure;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using Squidex.Infrastructure;
namespace Squidex.Web namespace Squidex.Web
{ {

2
src/Squidex.Web/ResourceLink.cs

@ -17,7 +17,7 @@ namespace Squidex.Web
[Required] [Required]
[Display(Description = "The link method.")] [Display(Description = "The link method.")]
public string Method { get; set; } public string Method { get; set; }
[Required] [Required]
[Display(Description = "Additional data about the link.")] [Display(Description = "Additional data about the link.")]

2
src/Squidex.Web/Squidex.Web.csproj

@ -9,6 +9,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Squidex.Domain.Apps.Entities\Squidex.Domain.Apps.Entities.csproj" /> <ProjectReference Include="..\Squidex.Domain.Apps.Entities\Squidex.Domain.Apps.Entities.csproj" />

6
src/Squidex.Web/UrlHelperExtensions.cs

@ -5,8 +5,10 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.AspNetCore.Mvc;
using System; using System;
using Microsoft.AspNetCore.Mvc;
#pragma warning disable RECS0108 // Warns about static fields in generic types
namespace Squidex.Web namespace Squidex.Web
{ {
@ -22,7 +24,7 @@ namespace Squidex.Web
var name = typeof(T).Name; var name = typeof(T).Name;
if (name.EndsWith(suffix)) if (name.EndsWith(suffix, StringComparison.Ordinal))
{ {
name = name.Substring(0, name.Length - suffix.Length); name = name.Substring(0, name.Length - suffix.Length);
} }

Loading…
Cancel
Save