mirror of https://github.com/Squidex/squidex.git
77 changed files with 1856 additions and 2105 deletions
@ -1,24 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Squidex.Infrastructure; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Core.Rules.Actions |
|
||||
{ |
|
||||
[TypeName(nameof(AzureQueueAction))] |
|
||||
public sealed class AzureQueueAction : RuleAction |
|
||||
{ |
|
||||
public string ConnectionString { get; set; } |
|
||||
|
|
||||
public string Queue { get; set; } |
|
||||
|
|
||||
public override T Accept<T>(IRuleActionVisitor<T> visitor) |
|
||||
{ |
|
||||
return visitor.Visit(this); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,32 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Squidex.Infrastructure; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Core.Rules.Actions |
|
||||
{ |
|
||||
[TypeName(nameof(MediumAction))] |
|
||||
public sealed class MediumAction : RuleAction |
|
||||
{ |
|
||||
public string AccessToken { get; set; } |
|
||||
|
|
||||
public string Tags { get; set; } |
|
||||
|
|
||||
public string Title { get; set; } |
|
||||
|
|
||||
public string CanonicalUrl { get; set; } |
|
||||
|
|
||||
public string Content { get; set; } |
|
||||
|
|
||||
public bool IsHtml { get; set; } |
|
||||
|
|
||||
public override T Accept<T>(IRuleActionVisitor<T> visitor) |
|
||||
{ |
|
||||
return visitor.Visit(this); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,30 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Squidex.Domain.Apps.Core.Rules.Actions; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Core.Rules |
|
||||
{ |
|
||||
public interface IRuleActionVisitor<out T> |
|
||||
{ |
|
||||
T Visit(AlgoliaAction action); |
|
||||
|
|
||||
T Visit(AzureQueueAction action); |
|
||||
|
|
||||
T Visit(ElasticSearchAction action); |
|
||||
|
|
||||
T Visit(FastlyAction action); |
|
||||
|
|
||||
T Visit(MediumAction action); |
|
||||
|
|
||||
T Visit(SlackAction action); |
|
||||
|
|
||||
T Visit(TweetAction action); |
|
||||
|
|
||||
T Visit(WebhookAction action); |
|
||||
} |
|
||||
} |
|
||||
@ -1,173 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.Collections.Generic; |
|
||||
using System.Text.RegularExpressions; |
|
||||
using System.Threading.Tasks; |
|
||||
using Squidex.Domain.Apps.Core.Rules; |
|
||||
using Squidex.Domain.Apps.Core.Rules.Actions; |
|
||||
using Squidex.Infrastructure; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.Rules.Guards |
|
||||
{ |
|
||||
public sealed class RuleActionValidator : IRuleActionVisitor<Task<IEnumerable<ValidationError>>> |
|
||||
{ |
|
||||
public static Task<IEnumerable<ValidationError>> ValidateAsync(RuleAction action) |
|
||||
{ |
|
||||
Guard.NotNull(action, nameof(action)); |
|
||||
|
|
||||
var visitor = new RuleActionValidator(); |
|
||||
|
|
||||
return action.Accept(visitor); |
|
||||
} |
|
||||
|
|
||||
public Task<IEnumerable<ValidationError>> Visit(AlgoliaAction action) |
|
||||
{ |
|
||||
var errors = new List<ValidationError>(); |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(action.ApiKey)) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Api Key is required.", nameof(action.ApiKey))); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(action.AppId)) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Application ID is required.", nameof(action.AppId))); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(action.IndexName)) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Index name is required.", nameof(action.IndexName))); |
|
||||
} |
|
||||
|
|
||||
return Task.FromResult<IEnumerable<ValidationError>>(errors); |
|
||||
} |
|
||||
|
|
||||
public Task<IEnumerable<ValidationError>> Visit(AzureQueueAction action) |
|
||||
{ |
|
||||
var errors = new List<ValidationError>(); |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(action.ConnectionString)) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Connection string is required.", nameof(action.ConnectionString))); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(action.Queue)) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Queue name is required.", nameof(action.Queue))); |
|
||||
} |
|
||||
else if (!Regex.IsMatch(action.Queue, "^[a-z][a-z0-9]{2,}(\\-[a-z0-9]+)*$")) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Queue name must be valid azure queue name.", nameof(action.Queue))); |
|
||||
} |
|
||||
|
|
||||
return Task.FromResult<IEnumerable<ValidationError>>(errors); |
|
||||
} |
|
||||
|
|
||||
public Task<IEnumerable<ValidationError>> Visit(ElasticSearchAction action) |
|
||||
{ |
|
||||
var errors = new List<ValidationError>(); |
|
||||
|
|
||||
if (action.Host == null || !action.Host.IsAbsoluteUri) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Host is required and must be an absolute URL.", nameof(action.Host))); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(action.IndexType)) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Type name is required.", nameof(action.IndexType))); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(action.IndexName)) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Index name is required.", nameof(action.IndexName))); |
|
||||
} |
|
||||
|
|
||||
return Task.FromResult<IEnumerable<ValidationError>>(errors); |
|
||||
} |
|
||||
|
|
||||
public Task<IEnumerable<ValidationError>> Visit(FastlyAction action) |
|
||||
{ |
|
||||
var errors = new List<ValidationError>(); |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(action.ApiKey)) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Api Key is required.", nameof(action.ApiKey))); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(action.ServiceId)) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Service ID is required.", nameof(action.ServiceId))); |
|
||||
} |
|
||||
|
|
||||
return Task.FromResult<IEnumerable<ValidationError>>(errors); |
|
||||
} |
|
||||
|
|
||||
public Task<IEnumerable<ValidationError>> Visit(MediumAction action) |
|
||||
{ |
|
||||
var errors = new List<ValidationError>(); |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(action.AccessToken)) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Access token is required.", nameof(action.AccessToken))); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(action.Content)) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Content is required.", nameof(action.Content))); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(action.Title)) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Title is required.", nameof(action.Title))); |
|
||||
} |
|
||||
|
|
||||
return Task.FromResult<IEnumerable<ValidationError>>(errors); |
|
||||
} |
|
||||
|
|
||||
public Task<IEnumerable<ValidationError>> Visit(TweetAction action) |
|
||||
{ |
|
||||
var errors = new List<ValidationError>(); |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(action.AccessToken)) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Access Token is required.", nameof(action.AccessToken))); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(action.AccessSecret)) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Access Secret is required.", nameof(action.AccessSecret))); |
|
||||
} |
|
||||
|
|
||||
return Task.FromResult<IEnumerable<ValidationError>>(errors); |
|
||||
} |
|
||||
|
|
||||
public Task<IEnumerable<ValidationError>> Visit(SlackAction action) |
|
||||
{ |
|
||||
var errors = new List<ValidationError>(); |
|
||||
|
|
||||
if (action.WebhookUrl == null || !action.WebhookUrl.IsAbsoluteUri) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("Webhook URL is required and must be an absolute URL.", nameof(action.WebhookUrl))); |
|
||||
} |
|
||||
|
|
||||
return Task.FromResult<IEnumerable<ValidationError>>(errors); |
|
||||
} |
|
||||
|
|
||||
public Task<IEnumerable<ValidationError>> Visit(WebhookAction action) |
|
||||
{ |
|
||||
var errors = new List<ValidationError>(); |
|
||||
|
|
||||
if (action.Url == null || !action.Url.IsAbsoluteUri) |
|
||||
{ |
|
||||
errors.Add(new ValidationError("URL is required and must be an absolute URL.", nameof(action.Url))); |
|
||||
} |
|
||||
|
|
||||
return Task.FromResult<IEnumerable<ValidationError>>(errors); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,34 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using System.Text.RegularExpressions; |
||||
|
using Squidex.Domain.Apps.Core.Rules; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Rules.Action.AzureQueue |
||||
|
{ |
||||
|
public sealed class AzureQueueAction : RuleAction |
||||
|
{ |
||||
|
[Required] |
||||
|
[Display(Name = "Connection String", Description = "The connection string to the storage account.")] |
||||
|
public string ConnectionString { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[Display(Name = "Queue", Description = "The name of the queue.")] |
||||
|
public string Queue { get; set; } |
||||
|
|
||||
|
protected override IEnumerable<ValidationError> CustomValidate() |
||||
|
{ |
||||
|
if (!string.IsNullOrWhiteSpace(Queue) && !Regex.IsMatch(Queue, "^[a-z][a-z0-9]{2,}(\\-[a-z0-9]+)*$")) |
||||
|
{ |
||||
|
yield return new ValidationError("Queue must be valid azure queue name.", nameof(Queue)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.Caching.Memory; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
|
||||
|
#pragma warning disable RECS0108 // Warns about static fields in generic types
|
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Rules.Action |
||||
|
{ |
||||
|
internal sealed class ClientPool<TKey, TClient> |
||||
|
{ |
||||
|
private static readonly TimeSpan TTL = TimeSpan.FromMinutes(30); |
||||
|
private readonly MemoryCache memoryCache = new MemoryCache(Options.Create(new MemoryCacheOptions())); |
||||
|
private readonly Func<TKey, Task<TClient>> factory; |
||||
|
|
||||
|
public ClientPool(Func<TKey, TClient> factory) |
||||
|
{ |
||||
|
this.factory = x => Task.FromResult(factory(x)); |
||||
|
} |
||||
|
|
||||
|
public ClientPool(Func<TKey, Task<TClient>> factory) |
||||
|
{ |
||||
|
this.factory = factory; |
||||
|
} |
||||
|
|
||||
|
public TClient GetClient(TKey key) |
||||
|
{ |
||||
|
return GetClientAsync(key).Result; |
||||
|
} |
||||
|
|
||||
|
public async Task<TClient> GetClientAsync(TKey key) |
||||
|
{ |
||||
|
if (!memoryCache.TryGetValue<TClient>(key, out var client)) |
||||
|
{ |
||||
|
client = await factory(key); |
||||
|
|
||||
|
memoryCache.Set(key, client, TTL); |
||||
|
} |
||||
|
|
||||
|
return client; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Squidex.Domain.Apps.Core.Rules; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Rules.Action.Medium |
||||
|
{ |
||||
|
public sealed class MediumAction : RuleAction |
||||
|
{ |
||||
|
[Required] |
||||
|
[Display(Name = "Access Token", Description = "The self issued access token.")] |
||||
|
public string AccessToken { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[Display(Name = "Title", Description = "The title, used for the url.")] |
||||
|
public string Title { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[Display(Name = "Content", Description = "The content, either html or markdown.")] |
||||
|
public string Content { get; set; } |
||||
|
|
||||
|
[Display(Name = "Canonical Url", Description = "The original home of this content, if it was originally published elsewhere.")] |
||||
|
public string CanonicalUrl { get; set; } |
||||
|
|
||||
|
[Display(Name = "Tags", Description = "The optional comma separated list of tags.")] |
||||
|
public string Tags { get; set; } |
||||
|
|
||||
|
[Display(Name = "Is Html", Description = "Indicates whether the content is markdown or html.")] |
||||
|
public bool IsHtml { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,106 @@ |
|||||
|
// ==========================================================================
|
||||
|
// 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,34 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
||||
|
<DebugType>full</DebugType> |
||||
|
<DebugSymbols>True</DebugSymbols> |
||||
|
</PropertyGroup> |
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\Squidex.Domain.Apps.Core.Model\Squidex.Domain.Apps.Core.Model.csproj" /> |
||||
|
<ProjectReference Include="..\Squidex.Domain.Apps.Core.Operations\Squidex.Domain.Apps.Core.Operations.csproj" /> |
||||
|
<ProjectReference Include="..\Squidex.Infrastructure\Squidex.Infrastructure.csproj" /> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Algolia.Search" Version="5.1.0" /> |
||||
|
<PackageReference Include="CoreTweet" Version="0.9.0.415" /> |
||||
|
<PackageReference Include="Elasticsearch.Net" Version="6.2.0" /> |
||||
|
<PackageReference Include="Microsoft.OData.Core" Version="7.5.0" /> |
||||
|
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> |
||||
|
<PackageReference Include="NodaTime" Version="2.3.0" /> |
||||
|
<PackageReference Include="RefactoringEssentials" Version="5.6.0" /> |
||||
|
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2" /> |
||||
|
<PackageReference Include="System.Collections.Immutable" Version="1.4.0" /> |
||||
|
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" /> |
||||
|
<PackageReference Include="System.ValueTuple" Version="4.5.0" /> |
||||
|
<PackageReference Include="WindowsAzure.Storage" Version="9.3.1" /> |
||||
|
</ItemGroup> |
||||
|
<PropertyGroup> |
||||
|
<CodeAnalysisRuleSet>..\..\Squidex.ruleset</CodeAnalysisRuleSet> |
||||
|
</PropertyGroup> |
||||
|
<ItemGroup> |
||||
|
<AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" /> |
||||
|
</ItemGroup> |
||||
|
</Project> |
||||
@ -0,0 +1,30 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace Squidex.Infrastructure |
||||
|
{ |
||||
|
public sealed class AbsoluteUrlAttribute : ValidationAttribute |
||||
|
{ |
||||
|
public AbsoluteUrlAttribute() |
||||
|
: base(() => "The {0} field must be an absolute URL.") |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public override bool IsValid(object value) |
||||
|
{ |
||||
|
if (value is Uri uri && !uri.IsAbsoluteUri) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,42 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.ComponentModel.DataAnnotations; |
|
||||
using NJsonSchema.Annotations; |
|
||||
using Squidex.Domain.Apps.Core.Rules; |
|
||||
using Squidex.Domain.Apps.Core.Rules.Actions; |
|
||||
using Squidex.Infrastructure.Reflection; |
|
||||
|
|
||||
namespace Squidex.Areas.Api.Controllers.Rules.Models.Actions |
|
||||
{ |
|
||||
[JsonSchema("Algolia")] |
|
||||
public sealed class AlgoliaActionDto : RuleActionDto |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The application ID.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public string AppId { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The API key to grant access to Squidex.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public string ApiKey { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The name of the index.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public string IndexName { get; set; } |
|
||||
|
|
||||
public override RuleAction ToAction() |
|
||||
{ |
|
||||
return SimpleMapper.Map(this, new AlgoliaAction()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,36 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.ComponentModel.DataAnnotations; |
|
||||
using NJsonSchema.Annotations; |
|
||||
using Squidex.Domain.Apps.Core.Rules; |
|
||||
using Squidex.Domain.Apps.Core.Rules.Actions; |
|
||||
using Squidex.Infrastructure.Reflection; |
|
||||
|
|
||||
namespace Squidex.Areas.Api.Controllers.Rules.Models.Actions |
|
||||
{ |
|
||||
[JsonSchema("AzureQueue")] |
|
||||
public class AzureQueueActionDto : RuleActionDto |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The connection string to the storage account.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public string ConnectionString { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The queue name.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public string Queue { get; set; } |
|
||||
|
|
||||
public override RuleAction ToAction() |
|
||||
{ |
|
||||
return SimpleMapper.Map(this, new AzureQueueAction()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,53 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.ComponentModel.DataAnnotations; |
|
||||
using NJsonSchema.Annotations; |
|
||||
using Squidex.Domain.Apps.Core.Rules; |
|
||||
using Squidex.Domain.Apps.Core.Rules.Actions; |
|
||||
using Squidex.Infrastructure.Reflection; |
|
||||
|
|
||||
namespace Squidex.Areas.Api.Controllers.Rules.Models.Actions |
|
||||
{ |
|
||||
[JsonSchema("ElasticSearch")] |
|
||||
public sealed class ElasticSearchActionDto : RuleActionDto |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The host to the elastic search instance.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public Uri Host { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The name of the index.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public string IndexName { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The name of the index type.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public string IndexType { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The optional username for authentication.
|
|
||||
/// </summary>
|
|
||||
public string Username { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The optional password for authentication.
|
|
||||
/// </summary>
|
|
||||
public string Password { get; set; } |
|
||||
|
|
||||
public override RuleAction ToAction() |
|
||||
{ |
|
||||
return SimpleMapper.Map(this, new ElasticSearchAction()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,36 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.ComponentModel.DataAnnotations; |
|
||||
using NJsonSchema.Annotations; |
|
||||
using Squidex.Domain.Apps.Core.Rules; |
|
||||
using Squidex.Domain.Apps.Core.Rules.Actions; |
|
||||
using Squidex.Infrastructure.Reflection; |
|
||||
|
|
||||
namespace Squidex.Areas.Api.Controllers.Rules.Models.Actions |
|
||||
{ |
|
||||
[JsonSchema("Fastly")] |
|
||||
public sealed class FastlyActionDto : RuleActionDto |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The ID of the fastly service.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public string ServiceId { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The API key to grant access to Squidex.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public string ApiKey { get; set; } |
|
||||
|
|
||||
public override RuleAction ToAction() |
|
||||
{ |
|
||||
return SimpleMapper.Map(this, new FastlyAction()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,57 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.ComponentModel.DataAnnotations; |
|
||||
using NJsonSchema.Annotations; |
|
||||
using Squidex.Domain.Apps.Core.Rules; |
|
||||
using Squidex.Domain.Apps.Core.Rules.Actions; |
|
||||
using Squidex.Infrastructure.Reflection; |
|
||||
|
|
||||
namespace Squidex.Areas.Api.Controllers.Rules.Models.Actions |
|
||||
{ |
|
||||
[JsonSchema("Medium")] |
|
||||
public class MediumActionDto : RuleActionDto |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The self issued access token.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public string AccessToken { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The optional comma separated list of tags.
|
|
||||
/// </summary>
|
|
||||
public string Tags { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The title, used for the url.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public string Title { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The content, either html or markdown.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public string Content { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The original home of this content, if it was originally published elsewhere.
|
|
||||
/// </summary>
|
|
||||
public string CanonicalUrl { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Indicates whether the content is markdown or html.
|
|
||||
/// </summary>
|
|
||||
public bool IsHtml { get; set; } |
|
||||
|
|
||||
public override RuleAction ToAction() |
|
||||
{ |
|
||||
return SimpleMapper.Map(this, new MediumAction()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,36 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.ComponentModel.DataAnnotations; |
|
||||
using NJsonSchema.Annotations; |
|
||||
using Squidex.Domain.Apps.Core.Rules; |
|
||||
using Squidex.Domain.Apps.Core.Rules.Actions; |
|
||||
using Squidex.Infrastructure.Reflection; |
|
||||
|
|
||||
namespace Squidex.Areas.Api.Controllers.Rules.Models.Actions |
|
||||
{ |
|
||||
[JsonSchema("Slack")] |
|
||||
public sealed class SlackActionDto : RuleActionDto |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The slack webhook url.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public Uri WebhookUrl { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The text that is sent as message to slack.
|
|
||||
/// </summary>
|
|
||||
public string Text { get; set; } |
|
||||
|
|
||||
public override RuleAction ToAction() |
|
||||
{ |
|
||||
return SimpleMapper.Map(this, new SlackAction()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,41 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.ComponentModel.DataAnnotations; |
|
||||
using NJsonSchema.Annotations; |
|
||||
using Squidex.Domain.Apps.Core.Rules; |
|
||||
using Squidex.Domain.Apps.Core.Rules.Actions; |
|
||||
using Squidex.Infrastructure.Reflection; |
|
||||
|
|
||||
namespace Squidex.Areas.Api.Controllers.Rules.Models.Actions |
|
||||
{ |
|
||||
[JsonSchema("Tweet")] |
|
||||
public sealed class TweetActionDto : RuleActionDto |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The access token.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public string AccessToken { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The access secret.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public string AccessSecret { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The text that is sent as tweet to twitter.
|
|
||||
/// </summary>
|
|
||||
public string Text { get; set; } |
|
||||
|
|
||||
public override RuleAction ToAction() |
|
||||
{ |
|
||||
return SimpleMapper.Map(this, new TweetAction()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,36 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.ComponentModel.DataAnnotations; |
|
||||
using NJsonSchema.Annotations; |
|
||||
using Squidex.Domain.Apps.Core.Rules; |
|
||||
using Squidex.Domain.Apps.Core.Rules.Actions; |
|
||||
using Squidex.Infrastructure.Reflection; |
|
||||
|
|
||||
namespace Squidex.Areas.Api.Controllers.Rules.Models.Actions |
|
||||
{ |
|
||||
[JsonSchema("Webhook")] |
|
||||
public sealed class WebhookActionDto : RuleActionDto |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The url of the rule.
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public Uri Url { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The shared secret that is used to calculate the signature.
|
|
||||
/// </summary>
|
|
||||
public string SharedSecret { get; set; } |
|
||||
|
|
||||
public override RuleAction ToAction() |
|
||||
{ |
|
||||
return SimpleMapper.Map(this, new WebhookAction()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,68 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Squidex.Areas.Api.Controllers.Rules.Models.Actions; |
|
||||
using Squidex.Domain.Apps.Core.Rules; |
|
||||
using Squidex.Domain.Apps.Core.Rules.Actions; |
|
||||
using Squidex.Infrastructure.Reflection; |
|
||||
|
|
||||
namespace Squidex.Areas.Api.Controllers.Rules.Models.Converters |
|
||||
{ |
|
||||
public sealed class RuleActionDtoFactory : IRuleActionVisitor<RuleActionDto> |
|
||||
{ |
|
||||
private static readonly RuleActionDtoFactory Instance = new RuleActionDtoFactory(); |
|
||||
|
|
||||
private RuleActionDtoFactory() |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public static RuleActionDto Create(RuleAction properties) |
|
||||
{ |
|
||||
return properties.Accept(Instance); |
|
||||
} |
|
||||
|
|
||||
public RuleActionDto Visit(AlgoliaAction action) |
|
||||
{ |
|
||||
return SimpleMapper.Map(action, new AlgoliaActionDto()); |
|
||||
} |
|
||||
|
|
||||
public RuleActionDto Visit(AzureQueueAction action) |
|
||||
{ |
|
||||
return SimpleMapper.Map(action, new AzureQueueActionDto()); |
|
||||
} |
|
||||
|
|
||||
public RuleActionDto Visit(ElasticSearchAction action) |
|
||||
{ |
|
||||
return SimpleMapper.Map(action, new ElasticSearchActionDto()); |
|
||||
} |
|
||||
|
|
||||
public RuleActionDto Visit(FastlyAction action) |
|
||||
{ |
|
||||
return SimpleMapper.Map(action, new FastlyActionDto()); |
|
||||
} |
|
||||
|
|
||||
public RuleActionDto Visit(MediumAction action) |
|
||||
{ |
|
||||
return SimpleMapper.Map(action, new MediumActionDto()); |
|
||||
} |
|
||||
|
|
||||
public RuleActionDto Visit(SlackAction action) |
|
||||
{ |
|
||||
return SimpleMapper.Map(action, new SlackActionDto()); |
|
||||
} |
|
||||
|
|
||||
public RuleActionDto Visit(TweetAction action) |
|
||||
{ |
|
||||
return SimpleMapper.Map(action, new TweetActionDto()); |
|
||||
} |
|
||||
|
|
||||
public RuleActionDto Visit(WebhookAction action) |
|
||||
{ |
|
||||
return SimpleMapper.Map(action, new WebhookActionDto()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,29 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Linq; |
|
||||
using System.Runtime.Serialization; |
|
||||
using Newtonsoft.Json; |
|
||||
using Squidex.Domain.Apps.Core.Rules; |
|
||||
|
|
||||
namespace Squidex.Areas.Api.Controllers.Rules.Models |
|
||||
{ |
|
||||
[JsonConverter(typeof(JsonInheritanceConverter), "actionType", typeof(RuleActionDto))] |
|
||||
[KnownType(nameof(Subtypes))] |
|
||||
public abstract class RuleActionDto |
|
||||
{ |
|
||||
public abstract RuleAction ToAction(); |
|
||||
|
|
||||
public static Type[] Subtypes() |
|
||||
{ |
|
||||
var type = typeof(RuleActionDto); |
|
||||
|
|
||||
return type.Assembly.GetTypes().Where(type.IsAssignableFrom).ToArray(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,63 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using NJsonSchema; |
||||
|
using NSwag.SwaggerGeneration.Processors; |
||||
|
using NSwag.SwaggerGeneration.Processors.Contexts; |
||||
|
using Squidex.Domain.Apps.Core.Rules; |
||||
|
using Squidex.Domain.Apps.Rules.Actions; |
||||
|
|
||||
|
namespace Squidex.Areas.Api.Controllers.Rules.Models |
||||
|
{ |
||||
|
public sealed class RuleActionProcessor : IDocumentProcessor |
||||
|
{ |
||||
|
public async Task ProcessAsync(DocumentProcessorContext context) |
||||
|
{ |
||||
|
var schema = context.SchemaResolver.GetSchema(typeof(RuleAction), false); |
||||
|
|
||||
|
if (schema != null) |
||||
|
{ |
||||
|
var discriminator = new OpenApiDiscriminator |
||||
|
{ |
||||
|
JsonInheritanceConverter = new JsonInheritanceConverter("actionType", typeof(RuleAction)), |
||||
|
PropertyName = "actionType" |
||||
|
}; |
||||
|
|
||||
|
schema.DiscriminatorObject = discriminator; |
||||
|
schema.Properties["actionType"] = new JsonProperty |
||||
|
{ |
||||
|
Type = JsonObjectType.String, |
||||
|
IsRequired = true |
||||
|
}; |
||||
|
|
||||
|
foreach (var derived in RuleActionRegistry.Actions) |
||||
|
{ |
||||
|
var derivedSchema = await context.SchemaGenerator.GenerateAsync(derived.Value, context.SchemaResolver); |
||||
|
|
||||
|
var oldName = context.Document.Definitions.FirstOrDefault(x => x.Value == derivedSchema).Key; |
||||
|
|
||||
|
if (oldName != null) |
||||
|
{ |
||||
|
context.Document.Definitions.Remove(oldName); |
||||
|
context.Document.Definitions.Add(derived.Key, derivedSchema); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
RemoveFreezable(context, schema); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static void RemoveFreezable(DocumentProcessorContext context, JsonSchema4 schema) |
||||
|
{ |
||||
|
context.Document.Definitions.Remove("Freezable"); |
||||
|
|
||||
|
schema.AllOf.Clear(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
File diff suppressed because it is too large
Binary file not shown.
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 82 KiB |
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Loading…
Reference in new issue