mirror of https://github.com/Squidex/squidex.git
67 changed files with 449 additions and 356 deletions
@ -0,0 +1,25 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Domain.Apps.Core.HandleRules; |
||||
|
using Squidex.Domain.Apps.Core.Rules; |
||||
|
|
||||
|
namespace Microsoft.Extensions.DependencyInjection |
||||
|
{ |
||||
|
public static class DependencyInjectionExtensions |
||||
|
{ |
||||
|
public static IServiceCollection AddRuleAction<TAction, THandler>(this IServiceCollection services) where THandler : class, IRuleActionHandler where TAction : RuleAction |
||||
|
{ |
||||
|
services.AddSingletonAs<THandler>() |
||||
|
.As<IRuleActionHandler>(); |
||||
|
|
||||
|
services.AddSingleton(new RuleActionRegistration(typeof(TAction))); |
||||
|
|
||||
|
return services; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,30 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using Squidex.Infrastructure; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Core.HandleRules |
|
||||
{ |
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)] |
|
||||
public sealed class RuleActionHandlerAttribute : Attribute |
|
||||
{ |
|
||||
public Type HandlerType { get; } |
|
||||
|
|
||||
public RuleActionHandlerAttribute(Type handlerType) |
|
||||
{ |
|
||||
Guard.NotNull(handlerType, nameof(handlerType)); |
|
||||
|
|
||||
HandlerType = handlerType; |
|
||||
|
|
||||
if (!typeof(IRuleActionHandler).IsAssignableFrom(handlerType)) |
|
||||
{ |
|
||||
throw new ArgumentException($"Handler type must implement {typeof(IRuleActionHandler)}.", nameof(handlerType)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.HandleRules |
||||
|
{ |
||||
|
public sealed class RuleActionRegistration |
||||
|
{ |
||||
|
public Type ActionType { get; } |
||||
|
|
||||
|
internal RuleActionRegistration(Type actionType) |
||||
|
{ |
||||
|
Guard.NotNull(actionType, nameof(actionType)); |
||||
|
|
||||
|
ActionType = actionType; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,175 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.ComponentModel.DataAnnotations; |
|
||||
using System.Linq; |
|
||||
using System.Reflection; |
|
||||
using Squidex.Domain.Apps.Core.Rules; |
|
||||
using Squidex.Infrastructure; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Core.HandleRules |
|
||||
{ |
|
||||
public static class RuleActionRegistry |
|
||||
{ |
|
||||
private const string ActionSuffix = "Action"; |
|
||||
private const string ActionSuffixV2 = "ActionV2"; |
|
||||
private static readonly HashSet<Type> ActionHandlerTypes = new HashSet<Type>(); |
|
||||
private static readonly Dictionary<string, RuleActionDefinition> ActionTypes = new Dictionary<string, RuleActionDefinition>(); |
|
||||
|
|
||||
public static IReadOnlyDictionary<string, RuleActionDefinition> Actions |
|
||||
{ |
|
||||
get { return ActionTypes; } |
|
||||
} |
|
||||
|
|
||||
public static IReadOnlyCollection<Type> ActionHandlers |
|
||||
{ |
|
||||
get { return ActionHandlerTypes; } |
|
||||
} |
|
||||
|
|
||||
static RuleActionRegistry() |
|
||||
{ |
|
||||
var actionTypes = |
|
||||
typeof(RuleActionRegistry).Assembly |
|
||||
.GetTypes() |
|
||||
.Where(x => typeof(RuleAction).IsAssignableFrom(x)) |
|
||||
.Where(x => x.GetCustomAttribute<RuleActionAttribute>() != null) |
|
||||
.Where(x => x.GetCustomAttribute<RuleActionHandlerAttribute>() != null) |
|
||||
.ToList(); |
|
||||
|
|
||||
foreach (var actionType in actionTypes) |
|
||||
{ |
|
||||
Add(actionType); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static void Add<T>() where T : RuleAction |
|
||||
{ |
|
||||
Add(typeof(T)); |
|
||||
} |
|
||||
|
|
||||
private static void Add(Type actionType) |
|
||||
{ |
|
||||
var metadata = actionType.GetCustomAttribute<RuleActionAttribute>(); |
|
||||
|
|
||||
if (metadata == null) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
var handlerAttribute = actionType.GetCustomAttribute<RuleActionHandlerAttribute>(); |
|
||||
|
|
||||
if (handlerAttribute == null) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
var name = GetActionName(actionType); |
|
||||
|
|
||||
var definition = |
|
||||
new RuleActionDefinition |
|
||||
{ |
|
||||
Type = actionType, |
|
||||
Display = metadata.Display, |
|
||||
Description = metadata.Description, |
|
||||
IconColor = metadata.IconColor, |
|
||||
IconImage = metadata.IconImage, |
|
||||
ReadMore = metadata.ReadMore |
|
||||
}; |
|
||||
|
|
||||
foreach (var property in actionType.GetProperties()) |
|
||||
{ |
|
||||
if (property.CanRead && property.CanWrite) |
|
||||
{ |
|
||||
var actionProperty = new RuleActionProperty { Name = property.Name.ToCamelCase(), Display = property.Name }; |
|
||||
|
|
||||
var display = property.GetCustomAttribute<DisplayAttribute>(); |
|
||||
|
|
||||
if (!string.IsNullOrWhiteSpace(display?.Name)) |
|
||||
{ |
|
||||
actionProperty.Display = display.Name; |
|
||||
} |
|
||||
|
|
||||
if (!string.IsNullOrWhiteSpace(display?.Description)) |
|
||||
{ |
|
||||
actionProperty.Description = display.Description; |
|
||||
} |
|
||||
|
|
||||
var type = property.PropertyType; |
|
||||
|
|
||||
if ((property.GetCustomAttribute<RequiredAttribute>() != null || (type.IsValueType && !IsNullable(type))) && type != typeof(bool) && type != typeof(bool?)) |
|
||||
{ |
|
||||
actionProperty.IsRequired = true; |
|
||||
} |
|
||||
|
|
||||
if (property.GetCustomAttribute<FormattableAttribute>() != null) |
|
||||
{ |
|
||||
actionProperty.IsFormattable = true; |
|
||||
} |
|
||||
|
|
||||
var dataType = property.GetCustomAttribute<DataTypeAttribute>()?.DataType; |
|
||||
|
|
||||
if (type == typeof(bool) || type == typeof(bool?)) |
|
||||
{ |
|
||||
actionProperty.Editor = RuleActionPropertyEditor.Checkbox; |
|
||||
} |
|
||||
else if (type == typeof(int) || type == typeof(int?)) |
|
||||
{ |
|
||||
actionProperty.Editor = RuleActionPropertyEditor.Number; |
|
||||
} |
|
||||
else if (dataType == DataType.Url) |
|
||||
{ |
|
||||
actionProperty.Editor = RuleActionPropertyEditor.Url; |
|
||||
} |
|
||||
else if (dataType == DataType.Password) |
|
||||
{ |
|
||||
actionProperty.Editor = RuleActionPropertyEditor.Password; |
|
||||
} |
|
||||
else if (dataType == DataType.EmailAddress) |
|
||||
{ |
|
||||
actionProperty.Editor = RuleActionPropertyEditor.Email; |
|
||||
} |
|
||||
else if (dataType == DataType.MultilineText) |
|
||||
{ |
|
||||
actionProperty.Editor = RuleActionPropertyEditor.TextArea; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
actionProperty.Editor = RuleActionPropertyEditor.Text; |
|
||||
} |
|
||||
|
|
||||
definition.Properties.Add(actionProperty); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
ActionTypes[name] = definition; |
|
||||
|
|
||||
ActionHandlerTypes.Add(actionType.GetCustomAttribute<RuleActionHandlerAttribute>().HandlerType); |
|
||||
} |
|
||||
|
|
||||
private static bool IsNullable(Type type) |
|
||||
{ |
|
||||
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); |
|
||||
} |
|
||||
|
|
||||
public static TypeNameRegistry MapRuleActions(this TypeNameRegistry typeNameRegistry) |
|
||||
{ |
|
||||
foreach (var actionType in ActionTypes.Values) |
|
||||
{ |
|
||||
typeNameRegistry.Map(actionType.Type, actionType.Type.Name); |
|
||||
} |
|
||||
|
|
||||
return typeNameRegistry; |
|
||||
} |
|
||||
|
|
||||
private static string GetActionName(Type type) |
|
||||
{ |
|
||||
return type.TypeName(false, ActionSuffix, ActionSuffixV2); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,17 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
namespace Squidex.Infrastructure |
||||
|
{ |
||||
|
public sealed class AutoAssembyTypeProvider<T> : ITypeProvider |
||||
|
{ |
||||
|
public void Map(TypeNameRegistry typeNameRegistry) |
||||
|
{ |
||||
|
typeNameRegistry.MapUnmapped(typeof(T).Assembly); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
namespace Squidex.Infrastructure |
||||
|
{ |
||||
|
public interface ITypeProvider |
||||
|
{ |
||||
|
void Map(TypeNameRegistry typeNameRegistry); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Linq; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Newtonsoft.Json; |
||||
|
using Squidex.Areas.Api.Controllers.Rules.Models; |
||||
|
using Squidex.Domain.Apps.Core.HandleRules; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.MongoDb; |
||||
|
using Squidex.Infrastructure.Tasks; |
||||
|
|
||||
|
namespace Squidex.Config.Domain |
||||
|
{ |
||||
|
public sealed class SerializationInitializer : IInitializable |
||||
|
{ |
||||
|
private readonly JsonSerializer jsonSerializer; |
||||
|
private readonly RuleRegistry ruleRegistry; |
||||
|
|
||||
|
public SerializationInitializer(JsonSerializer jsonSerializer, RuleRegistry ruleRegistry) |
||||
|
{ |
||||
|
this.jsonSerializer = jsonSerializer; |
||||
|
|
||||
|
this.ruleRegistry = ruleRegistry; |
||||
|
} |
||||
|
|
||||
|
public Task InitializeAsync(CancellationToken ct = default) |
||||
|
{ |
||||
|
BsonJsonConvention.Register(jsonSerializer); |
||||
|
|
||||
|
RuleActionConverter.Mapping = ruleRegistry.Actions.ToDictionary(x => x.Key, x => x.Value.Type); |
||||
|
|
||||
|
return TaskHelper.Done; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue