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 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.contextProvider = contextProvider;
}
public async Task<IEnrichedContentEntity> EnrichAsync(IContentEntity content)
@ -51,8 +56,12 @@ namespace Squidex.Domain.Apps.Entities.Contents
var result = SimpleMapper.Map(content, new ContentEntity());
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);
}
@ -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)
{
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
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Squidex.Domain.Apps.Entities.Apps;
namespace Squidex.Web
namespace Squidex.Domain.Apps.Entities
{
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
{
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.");
}
return appFeature.App;
return app;
}
}

25
src/Squidex.Web/ApiPermissionAttribute.cs

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

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

@ -7,7 +7,6 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Squidex.Domain.Apps.Entities;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure;
@ -17,20 +16,15 @@ namespace Squidex.Web.CommandMiddlewares
{
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)
{
if (httpContextAccessor.HttpContext == null)
{
return next();
}
if (context.Command is IAppCommand appCommand && appCommand.AppId == null)
{
var appId = GetAppId();
@ -50,14 +44,14 @@ namespace Squidex.Web.CommandMiddlewares
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.");
}
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;
}
if (appId == null)
{
var appFeature = actionContextAccessor.ActionContext.HttpContext.Features.Get<IAppFeature>();
if (appFeature?.App != null)
{
appId = appFeature.App.NamedId();
}
}
if (appId != null)
{
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]
[Display(Description = "Id of the created entity.")]
public string Id { get; set; }
[Display(Description = "The new version of the entity.")]
public long Version { get; set; }

4
src/Squidex.Web/ErrorDto.cs

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

22
src/Squidex.Web/PermissionExtensions.cs

@ -7,34 +7,14 @@
using Microsoft.AspNetCore.Http;
using Squidex.Infrastructure.Security;
using Squidex.Shared.Identity;
namespace Squidex.Web
{
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)
{
var feature = httpContext.Features.Get<PermissionFeature>();
if (feature == null)
{
feature = new PermissionFeature(httpContext.User.Permissions());
httpContext.Features.Set(feature);
}
return feature.Permissions;
return httpContext.Context().Permissions;
}
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);
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"))
{
var plan = appPlansProvider.GetPlanForApp(appFeature.App);
var plan = appPlansProvider.GetPlanForApp(app);
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;
public class AppFeature : IAppFeature
{
public IAppEntity App { get; }
public AppFeature(IAppEntity app)
{
App = app;
}
}
public AppResolver(IAppProvider 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();
return;
}
context.HttpContext.Features.Set<IAppFeature>(new AppFeature(app));
}
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)
{
@ -57,21 +57,21 @@ namespace Squidex.Web.Pipeline
c.WriteProperty("appName", app.Name);
}
var userId = context.User.OpenIdSubject();
var userId = httpContext.User.OpenIdSubject();
if (!string.IsNullOrWhiteSpace(userId))
{
c.WriteProperty(nameof(userId), userId);
}
var clientId = context.User.OpenIdClientId();
var clientId = httpContext.User.OpenIdClientId();
if (!string.IsNullOrWhiteSpace(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);
}

4
src/Squidex.Web/Resource.cs

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

2
src/Squidex.Web/ResourceLink.cs

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

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

@ -9,6 +9,8 @@
</PropertyGroup>
<ItemGroup>
<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>
<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.
// ==========================================================================
using Microsoft.AspNetCore.Mvc;
using System;
using Microsoft.AspNetCore.Mvc;
#pragma warning disable RECS0108 // Warns about static fields in generic types
namespace Squidex.Web
{
@ -22,7 +24,7 @@ namespace Squidex.Web
var name = typeof(T).Name;
if (name.EndsWith(suffix))
if (name.EndsWith(suffix, StringComparison.Ordinal))
{
name = name.Substring(0, name.Length - suffix.Length);
}

Loading…
Cancel
Save