mirror of https://github.com/Squidex/squidex.git
45 changed files with 779 additions and 501 deletions
@ -0,0 +1,21 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
|
|||
namespace Squidex.Domain.Apps.Core.HandleRules |
|||
{ |
|||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] |
|||
public sealed class RuleActionAttribute : Attribute |
|||
{ |
|||
public string Link { get; set; } |
|||
|
|||
public string Display { get; set; } |
|||
|
|||
public string Description { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
// ==========================================================================
|
|||
// 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, AllowMultiple = 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,42 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Squidex.Domain.Apps.Core.HandleRules; |
|||
using Squidex.Domain.Apps.Core.Rules; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Rules.Actions.Discourse |
|||
{ |
|||
[RuleActionHandler(typeof(DiscourseActionHandler))] |
|||
[RuleAction(Description = "")] |
|||
public sealed class DiscourseAction : RuleAction |
|||
{ |
|||
[AbsoluteUrl] |
|||
[Required] |
|||
[Display(Name = "Url", Description = "he url to the discourse server.")] |
|||
public Uri Url { get; set; } |
|||
|
|||
[Required] |
|||
[Display(Name = "Api Key", Description = "The api key.")] |
|||
public string ApiKey { get; set; } |
|||
|
|||
[Required] |
|||
[Display(Name = "Text", Description = "The text as markdown.")] |
|||
public string Text { get; set; } |
|||
|
|||
[Display(Name = "Title", Description = "The optional title when creating new topics.")] |
|||
public string Title { get; set; } |
|||
|
|||
[Display(Name = "Topic", Description = "The optional topic id.")] |
|||
public int? Topic { get; set; } |
|||
|
|||
[Display(Name = "Category", Description = "The optional category id.")] |
|||
public int? Category { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Net.Http; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Domain.Apps.Core.HandleRules; |
|||
using Squidex.Domain.Apps.Core.HandleRules.EnrichedEvents; |
|||
|
|||
namespace Squidex.Domain.Apps.Rules.Actions.Discourse |
|||
{ |
|||
public sealed class DiscourseActionHandler : RuleActionHandler<DiscourseAction, DiscourseJob> |
|||
{ |
|||
private readonly IHttpClientFactory httpClientFactory; |
|||
|
|||
public DiscourseActionHandler(RuleEventFormatter formatter, IHttpClientFactory httpClientFactory) |
|||
: base(formatter) |
|||
{ |
|||
this.httpClientFactory = httpClientFactory; |
|||
} |
|||
|
|||
protected override Task<(string Description, DiscourseJob Data)> CreateJobAsync(EnrichedEvent @event, DiscourseAction action) |
|||
{ |
|||
return base.CreateJobAsync(@event, action); |
|||
} |
|||
|
|||
protected override Task<(string Dump, Exception Exception)> ExecuteJobAsync(DiscourseJob job) |
|||
{ |
|||
using (var client = httpClientFactory.CreateClient()) |
|||
{ |
|||
// Foo
|
|||
} |
|||
|
|||
return Task.FromResult<(string Dump, Exception Exception)>((string.Empty, null)); |
|||
} |
|||
} |
|||
|
|||
public sealed class DiscourseJob |
|||
{ |
|||
public string RequestUrl { get; set; } |
|||
|
|||
public string RequestBody { get; set; } |
|||
} |
|||
} |
|||
@ -1,106 +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 Squidex.Domain.Apps.Core.HandleRules; |
|||
using Squidex.Domain.Apps.Core.Rules; |
|||
using Squidex.Domain.Apps.Rules.Action.Algolia; |
|||
using Squidex.Domain.Apps.Rules.Action.AzureQueue; |
|||
using Squidex.Domain.Apps.Rules.Action.ElasticSearch; |
|||
using Squidex.Domain.Apps.Rules.Action.Fastly; |
|||
using Squidex.Domain.Apps.Rules.Action.Medium; |
|||
using Squidex.Domain.Apps.Rules.Action.Slack; |
|||
using Squidex.Domain.Apps.Rules.Action.Twitter; |
|||
using Squidex.Domain.Apps.Rules.Action.Webhook; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Rules.Actions |
|||
{ |
|||
public static class RuleActionRegistry |
|||
{ |
|||
private const string Suffix = "Action"; |
|||
private static readonly HashSet<Type> ActionHandlerTypes = new HashSet<Type>(); |
|||
private static readonly Dictionary<string, Type> ActionTypes = new Dictionary<string, Type>(); |
|||
|
|||
public static IReadOnlyDictionary<string, Type> Actions |
|||
{ |
|||
get { return ActionTypes; } |
|||
} |
|||
|
|||
public static IReadOnlyCollection<Type> ActionHandlers |
|||
{ |
|||
get { return ActionHandlerTypes; } |
|||
} |
|||
|
|||
static RuleActionRegistry() |
|||
{ |
|||
Register< |
|||
AlgoliaAction, |
|||
AlgoliaActionHandler>(); |
|||
|
|||
Register< |
|||
AzureQueueAction, |
|||
AzureQueueActionHandler>(); |
|||
|
|||
Register< |
|||
ElasticSearchAction, |
|||
ElasticSearchActionHandler>(); |
|||
|
|||
Register< |
|||
FastlyAction, |
|||
FastlyActionHandler>(); |
|||
|
|||
Register< |
|||
MediumAction, |
|||
MediumActionHandler>(); |
|||
|
|||
Register< |
|||
SlackAction, |
|||
SlackActionHandler>(); |
|||
|
|||
Register< |
|||
TweetAction, |
|||
TweetActionHandler>(); |
|||
|
|||
Register< |
|||
WebhookAction, |
|||
WebhookActionHandler>(); |
|||
} |
|||
|
|||
public static void Register<TAction, THandler>() where TAction : RuleAction where THandler : IRuleActionHandler |
|||
{ |
|||
AddActionType<TAction>(); |
|||
AddActionHandler<THandler>(); |
|||
} |
|||
|
|||
private static void AddActionHandler<THandler>() where THandler : IRuleActionHandler |
|||
{ |
|||
ActionHandlerTypes.Add(typeof(THandler)); |
|||
} |
|||
|
|||
private static void AddActionType<TAction>() where TAction : RuleAction |
|||
{ |
|||
var name = typeof(TAction).Name; |
|||
|
|||
if (name.EndsWith(Suffix, StringComparison.Ordinal)) |
|||
{ |
|||
name = name.Substring(0, name.Length - Suffix.Length); |
|||
} |
|||
|
|||
ActionTypes.Add(name, typeof(TAction)); |
|||
} |
|||
|
|||
public static void RegisterTypes(TypeNameRegistry typeNameRegistry) |
|||
{ |
|||
foreach (var actionType in ActionTypes.Values) |
|||
{ |
|||
typeNameRegistry.Map(actionType, actionType.Name); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
|
|||
namespace Squidex.Domain.Apps.Rules.Actions |
|||
{ |
|||
public sealed class RuleElement |
|||
{ |
|||
public Type Type { get; } |
|||
|
|||
public string Link { get; set; } |
|||
|
|||
public string Display { get; } |
|||
|
|||
public string Description { get; } |
|||
|
|||
public RuleElement(Type type, string display, string description, string link = null) |
|||
{ |
|||
Type = type; |
|||
|
|||
Display = display; |
|||
Description = description; |
|||
|
|||
Link = link; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,92 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using Squidex.Domain.Apps.Core.HandleRules; |
|||
using Squidex.Domain.Apps.Core.Rules; |
|||
using Squidex.Domain.Apps.Core.Rules.Triggers; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Rules.Actions |
|||
{ |
|||
public static class RuleElementRegistry |
|||
{ |
|||
private const string Suffix = "Action"; |
|||
private static readonly HashSet<Type> ActionHandlerTypes = new HashSet<Type>(); |
|||
private static readonly Dictionary<string, RuleElement> ActionTypes = new Dictionary<string, RuleElement>(); |
|||
private static readonly Dictionary<string, RuleElement> TriggerTypes = new Dictionary<string, RuleElement>(); |
|||
|
|||
public static IReadOnlyDictionary<string, RuleElement> Actions |
|||
{ |
|||
get { return ActionTypes; } |
|||
} |
|||
|
|||
public static IReadOnlyDictionary<string, RuleElement> Triggers |
|||
{ |
|||
get { return TriggerTypes; } |
|||
} |
|||
|
|||
public static IReadOnlyCollection<Type> ActionHandlers |
|||
{ |
|||
get { return ActionHandlerTypes; } |
|||
} |
|||
|
|||
static RuleElementRegistry() |
|||
{ |
|||
TriggerTypes["ContentChanged"] = |
|||
new RuleElement( |
|||
typeof(ContentChangedTrigger), |
|||
"Content changed", |
|||
"Content changed like created, updated, published, unpublished..."); |
|||
|
|||
TriggerTypes["AssetChanged"] = |
|||
new RuleElement( |
|||
typeof(AssetChangedTrigger), |
|||
"Asset changed", |
|||
"Asset changed like created, updated, renamed..."); |
|||
|
|||
var actionTypes = |
|||
typeof(RuleElementRegistry).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) |
|||
{ |
|||
var name = actionType.Name; |
|||
|
|||
if (name.EndsWith(Suffix, StringComparison.Ordinal)) |
|||
{ |
|||
name = name.Substring(0, name.Length - Suffix.Length); |
|||
} |
|||
|
|||
var metadata = actionType.GetCustomAttribute<RuleActionAttribute>(); |
|||
|
|||
ActionTypes[name] = |
|||
new RuleElement(actionType, |
|||
metadata.Display, |
|||
metadata.Description, |
|||
metadata.Link); |
|||
|
|||
ActionHandlerTypes.Add(actionType.GetCustomAttribute<RuleActionHandlerAttribute>().HandlerType); |
|||
} |
|||
} |
|||
|
|||
public static void RegisterTypes(TypeNameRegistry typeNameRegistry) |
|||
{ |
|||
foreach (var actionType in ActionTypes.Values) |
|||
{ |
|||
typeNameRegistry.Map(actionType.Type, actionType.Type.Name); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace Squidex.Areas.Api.Controllers.Rules.Models |
|||
{ |
|||
public sealed class RuleElementDto |
|||
{ |
|||
/// <summary>
|
|||
/// Describes the action or trigger type.
|
|||
/// </summary>
|
|||
[Required] |
|||
public string Description { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// The label for the action or trigger type.
|
|||
/// </summary>
|
|||
[Required] |
|||
public string Display { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// The optional link to the product that is integrated.
|
|||
/// </summary>
|
|||
public string Link { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { ComponentFactoryResolver, ComponentRef, Input, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; |
|||
import { FormGroup } from '@angular/forms'; |
|||
|
|||
export class RuleActionContainer implements OnInit { |
|||
@Input() |
|||
public actionType: string; |
|||
|
|||
@Input() |
|||
public action: any; |
|||
|
|||
@Input() |
|||
public actionForm: FormGroup; |
|||
|
|||
@Input() |
|||
public actionFormSubmitted = false; |
|||
|
|||
@ViewChild('container', { read: ViewContainerRef }) |
|||
public entry: ViewContainerRef; |
|||
|
|||
private component: ComponentRef<any>; |
|||
|
|||
constructor( |
|||
private readonly componentFactoryResolver: ComponentFactoryResolver |
|||
) { |
|||
} |
|||
|
|||
public ngOnInit() { |
|||
const factories = Array.from(this.componentFactoryResolver['_factories'].values()); |
|||
const factory: any = factories.find((x: any) => x.selector === this.actionType); |
|||
|
|||
this.component = this.entry.createComponent(factory); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue