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