Browse Source

Started with medium action handler.

pull/306/head
Sebastian 8 years ago
parent
commit
59d16b18a8
  1. 1
      src/Squidex.Domain.Apps.Core.Model/Contents/NamedContentData.cs
  2. 36
      src/Squidex.Domain.Apps.Core.Model/Rules/Actions/MediumAction.cs
  3. 2
      src/Squidex.Domain.Apps.Core.Model/Rules/IRuleActionVisitor.cs
  4. 1
      src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs
  5. 137
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/MediumActionHandler.cs
  6. 18
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/IContentResolver.cs
  7. 94
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs
  8. 27
      src/Squidex.Domain.Apps.Entities/Rules/Guards/RuleActionValidator.cs
  9. 2
      src/Squidex.Domain.Apps.Entities/Rules/RuleEnqueuer.cs
  10. 2
      src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchemaNestedField.cs
  11. 2
      src/Squidex.Domain.Apps.Events/Schemas/SchemaCreatedNestedField.cs
  12. 1
      src/Squidex.Infrastructure/Validate.cs
  13. 67
      src/Squidex/Areas/Api/Controllers/Rules/Models/Actions/MediumactionDto.cs
  14. 5
      src/Squidex/Areas/Api/Controllers/Rules/Models/Converters/RuleActionDtoFactory.cs
  15. 3
      src/Squidex/Config/Domain/RuleServices.cs
  16. 1
      src/Squidex/Program.cs
  17. 2
      src/Squidex/WebStartup.cs
  18. 1
      src/Squidex/app/features/rules/declarations.ts
  19. 2
      src/Squidex/app/features/rules/module.ts
  20. 112
      src/Squidex/app/features/rules/pages/rules/actions/medium-action.component.html
  21. 6
      src/Squidex/app/features/rules/pages/rules/actions/medium-action.component.scss
  22. 57
      src/Squidex/app/features/rules/pages/rules/actions/medium-action.component.ts
  23. 7
      src/Squidex/app/features/rules/pages/rules/rule-wizard.component.html
  24. 3
      src/Squidex/app/shared/services/rules.service.ts
  25. 5
      src/Squidex/app/theme/_rules.scss
  26. 4
      src/Squidex/app/theme/icomoon/demo-files/demo.css
  27. 1116
      src/Squidex/app/theme/icomoon/demo.html
  28. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.eot
  29. 1
      src/Squidex/app/theme/icomoon/fonts/icomoon.svg
  30. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.ttf
  31. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.woff
  32. 2215
      src/Squidex/app/theme/icomoon/selection.json
  33. 289
      src/Squidex/app/theme/icomoon/style.css

1
src/Squidex.Domain.Apps.Core.Model/Contents/NamedContentData.cs

@ -6,7 +6,6 @@
// ==========================================================================
using System;
using System.Collections.Generic;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.Contents

36
src/Squidex.Domain.Apps.Core.Model/Rules/Actions/MediumAction.cs

@ -0,0 +1,36 @@
// ==========================================================================
// 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 Author { get; set; }
public string Publication { 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);
}
}
}

2
src/Squidex.Domain.Apps.Core.Model/Rules/IRuleActionVisitor.cs

@ -19,6 +19,8 @@ namespace Squidex.Domain.Apps.Core.Rules
T Visit(FastlyAction action);
T Visit(MediumAction action);
T Visit(SlackAction action);
T Visit(WebhookAction action);

1
src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs

@ -9,7 +9,6 @@ using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using Squidex.Infrastructure;

137
src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/MediumActionHandler.cs

@ -0,0 +1,137 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
#pragma warning disable SA1649 // File name must match first type name
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Squidex.Domain.Apps.Core.Rules.Actions;
using Squidex.Domain.Apps.Events;
using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Http;
namespace Squidex.Domain.Apps.Core.HandleRules.Actions
{
public sealed class MediumJob
{
public string RequestUrl { get; set; }
public string RequestBody { get; set; }
public string AccessToken { get; set; }
}
public sealed class MediumActionHandler : RuleActionHandler<MediumAction, MediumJob>
{
private const string Description = "Post to medium";
private readonly RuleEventFormatter formatter;
public MediumActionHandler(RuleEventFormatter formatter)
{
Guard.NotNull(formatter, nameof(formatter));
this.formatter = formatter;
}
protected override async Task<(string Description, MediumJob Data)> CreateJobAsync(Envelope<AppEvent> @event, string eventName, MediumAction action)
{
var requestUrl =
!string.IsNullOrWhiteSpace(action.Author) ?
$"https://api.medium.com/v1/users/{action.Author}/posts" :
$"https://api.medium.com/v1/publication/{action.Publication}/posts";
var requestBody =
new JObject(
new JProperty("title", await formatter.FormatStringAsync(action.Title, @event)),
new JProperty("contentFormat", action.IsHtml ? "html" : "markdown"),
new JProperty("content", await formatter.FormatStringAsync(action.Content, @event)),
new JProperty("canonicalUrl", await formatter.FormatStringAsync(action.CanonicalUrl, @event)),
new JProperty("tags", await ParseTagsAsync(@event, action)));
var ruleJob = new MediumJob
{
AccessToken = action.AccessToken,
RequestUrl = requestUrl,
RequestBody = requestBody.ToString(Formatting.Indented)
};
return (Description, ruleJob);
}
private async Task<JArray> ParseTagsAsync(Envelope<AppEvent> @event, MediumAction action)
{
if (string.IsNullOrWhiteSpace(action.Tags))
{
return null;
}
string[] tags;
try
{
var jsonTags = await formatter.FormatStringAsync(action.Tags, @event);
tags = JsonConvert.DeserializeObject<string[]>(jsonTags);
}
catch
{
tags = action.Tags.Split(',');
}
return new JArray(tags);
}
protected override async Task<(string Dump, Exception Exception)> ExecuteJobAsync(MediumJob job)
{
var requestBody = job.RequestBody;
var requestMessage = BuildRequest(job, requestBody);
HttpResponseMessage response = null;
try
{
response = await HttpClientPool.GetHttpClient().SendAsync(requestMessage);
var responseString = await response.Content.ReadAsStringAsync();
var requestDump = DumpFormatter.BuildDump(requestMessage, response, requestBody, responseString, TimeSpan.Zero, false);
Exception ex = null;
if (!response.IsSuccessStatusCode)
{
ex = new HttpRequestException($"Response code does not indicate success: {(int)response.StatusCode} ({response.StatusCode}).");
}
return (requestDump, ex);
}
catch (Exception ex)
{
var requestDump = DumpFormatter.BuildDump(requestMessage, response, requestBody, ex.ToString(), TimeSpan.Zero, false);
return (requestDump, ex);
}
}
private static HttpRequestMessage BuildRequest(MediumJob job, string requestBody)
{
var request = new HttpRequestMessage(HttpMethod.Post, job.RequestUrl)
{
Content = new StringContent(requestBody, Encoding.UTF8, "application/json")
};
request.Headers.Add("Accept", "application/json");
request.Headers.Add("Accept-Charset", "utf-8");
request.Headers.Add("Authorization", $"Bearer {job.AccessToken}");
return request;
}
}
}

18
src/Squidex.Domain.Apps.Core.Operations/HandleRules/IContentResolver.cs

@ -0,0 +1,18 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Contents;
namespace Squidex.Domain.Apps.Core.HandleRules
{
public interface IContentResolver
{
Task<NamedContentData> GetContentDataAsync(Guid id);
}
}

94
src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs

@ -17,6 +17,7 @@ using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Events;
using Squidex.Domain.Apps.Events.Contents;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Caching;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Shared.Users;
@ -36,13 +37,18 @@ namespace Squidex.Domain.Apps.Core.HandleRules
private const string UserNamePlaceholder = "$USER_NAME";
private const string UserEmailPlaceholder = "$USER_EMAIL";
private static readonly Regex ContentDataPlaceholder = new Regex(@"\$CONTENT_DATA(\.([0-9A-Za-z\-_]*)){2,}", RegexOptions.Compiled);
private static readonly Regex ContentDataPlaceholderV2 = new Regex(@"\$\{CONTENT_DATA(\.([0-9A-Za-z\-_]*)){2,}\}", RegexOptions.Compiled);
private static readonly TimeSpan UserCacheDuration = TimeSpan.FromMinutes(10);
private readonly JsonSerializer serializer;
private readonly IRuleUrlGenerator urlGenerator;
private readonly IMemoryCache memoryCache;
private readonly IUserResolver userResolver;
public RuleEventFormatter(JsonSerializer serializer, IRuleUrlGenerator urlGenerator, IMemoryCache memoryCache, IUserResolver userResolver)
public RuleEventFormatter(
JsonSerializer serializer,
IRuleUrlGenerator urlGenerator,
IMemoryCache memoryCache,
IUserResolver userResolver)
{
Guard.NotNull(memoryCache, nameof(memoryCache));
Guard.NotNull(serializer, nameof(serializer));
@ -70,6 +76,11 @@ namespace Squidex.Domain.Apps.Core.HandleRules
public async virtual Task<string> FormatStringAsync(string text, Envelope<AppEvent> @event)
{
if (string.IsNullOrWhiteSpace(text))
{
return text;
}
var sb = new StringBuilder(text);
if (@event.Headers.Contains(CommonHeaders.Timestamp))
@ -173,55 +184,68 @@ namespace Squidex.Domain.Apps.Core.HandleRules
private static string ReplaceData(NamedContentData data, string text)
{
return ContentDataPlaceholder.Replace(text, match =>
text = ContentDataPlaceholder.Replace(text, match =>
{
var captures = match.Groups[2].Captures;
return Replace(data, match);
});
var path = new string[captures.Count];
text = ContentDataPlaceholderV2.Replace(text, match =>
{
return Replace(data, match);
});
for (var i = 0; i < path.Length; i++)
{
path[i] = captures[i].Value;
}
return text;
}
if (!data.TryGetValue(path[0], out var field))
{
return Undefined;
}
private static string Replace(NamedContentData data, Match match)
{
var captures = match.Groups[2].Captures;
var path = new string[captures.Count];
for (var i = 0; i < path.Length; i++)
{
path[i] = captures[i].Value;
}
if (!field.TryGetValue(path[1], out var value))
if (!data.TryGetValue(path[0], out var field))
{
return Undefined;
}
if (!field.TryGetValue(path[1], out var value))
{
return Undefined;
}
for (var j = 2; j < path.Length; j++)
{
if (value is JObject obj && obj.TryGetValue(path[j], out value))
{
return Undefined;
continue;
}
for (var j = 2; j < path.Length; j++)
if (value is JArray arr && int.TryParse(path[j], out var idx) && idx >= 0 && idx < arr.Count)
{
if (value is JObject obj && obj.TryGetValue(path[j], out value))
{
continue;
}
if (value is JArray arr && int.TryParse(path[j], out var idx) && idx >= 0 && idx < arr.Count)
{
value = arr[idx];
}
else
{
return Undefined;
}
value = arr[idx];
}
if (value == null || value.Type == JTokenType.Null || value.Type == JTokenType.Undefined)
else
{
return Undefined;
}
}
if (value is JValue jValue && jValue != null)
{
return jValue.Value.ToString();
}
if (value == null || value.Type == JTokenType.Null || value.Type == JTokenType.Undefined)
{
return Undefined;
}
return value?.ToString(Formatting.Indented) ?? Undefined;
});
if (value is JValue jValue && jValue != null)
{
return jValue.Value.ToString();
}
return value?.ToString(Formatting.Indented) ?? Undefined;
}
private Task<IUser> FindUserAsync(RefToken actor)

27
src/Squidex.Domain.Apps.Entities/Rules/Guards/RuleActionValidator.cs

@ -107,6 +107,33 @@ namespace Squidex.Domain.Apps.Entities.Rules.Guards
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.Author) && !string.IsNullOrWhiteSpace(action.Publication))
{
errors.Add(new ValidationError("Author or publication id is required.", nameof(action.Author), nameof(action.Publication)));
}
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.Content)));
}
return Task.FromResult<IEnumerable<ValidationError>>(errors);
}
public Task<IEnumerable<ValidationError>> Visit(SlackAction action)
{
var errors = new List<ValidationError>();

2
src/Squidex.Domain.Apps.Entities/Rules/RuleEnqueuer.cs

@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.Rules
{
public sealed class RuleEnqueuer : IEventConsumer
{
private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(2);
private static readonly TimeSpan CacheDuration = TimeSpan.FromSeconds(10);
private readonly IRuleEventRepository ruleEventRepository;
private readonly IAppProvider appProvider;
private readonly IMemoryCache cache;

2
src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchemaNestedField.cs

@ -5,8 +5,6 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Squidex.Domain.Apps.Core.Schemas;
namespace Squidex.Domain.Apps.Entities.Schemas.Commands
{
public sealed class CreateSchemaNestedField : CreateSchemaFieldBase

2
src/Squidex.Domain.Apps.Events/Schemas/SchemaCreatedNestedField.cs

@ -5,8 +5,6 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Squidex.Domain.Apps.Core.Schemas;
namespace Squidex.Domain.Apps.Events.Schemas
{
public sealed class SchemaCreatedNestedField : SchemaCreatedFieldBase

1
src/Squidex.Infrastructure/Validate.cs

@ -7,7 +7,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Squidex.Infrastructure

67
src/Squidex/Areas/Api/Controllers/Rules/Models/Actions/MediumactionDto.cs

@ -0,0 +1,67 @@
// ==========================================================================
// 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 author name.
/// </summary>
public string Author { get; set; }
/// <summary>
/// The author name.
/// </summary>
public string Publication { 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());
}
}
}

5
src/Squidex/Areas/Api/Controllers/Rules/Models/Converters/RuleActionDtoFactory.cs

@ -45,6 +45,11 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models.Converters
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());

3
src/Squidex/Config/Domain/RuleServices.cs

@ -36,6 +36,9 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<FastlyActionHandler>()
.As<IRuleActionHandler>();
services.AddSingletonAs<MediumActionHandler>()
.As<IRuleActionHandler>();
services.AddSingletonAs<SlackActionHandler>()
.As<IRuleActionHandler>();

1
src/Squidex/Program.cs

@ -6,7 +6,6 @@
// ==========================================================================
using System.IO;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

2
src/Squidex/WebStartup.cs

@ -5,9 +5,7 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Areas.Api;

1
src/Squidex/app/features/rules/declarations.ts

@ -9,6 +9,7 @@ export * from './pages/rules/actions/algolia-action.component';
export * from './pages/rules/actions/azure-queue-action.component';
export * from './pages/rules/actions/elastic-search-action.component';
export * from './pages/rules/actions/fastly-action.component';
export * from './pages/rules/actions/medium-action.component';
export * from './pages/rules/actions/slack-action.component';
export * from './pages/rules/actions/webhook-action.component';
export * from './pages/rules/triggers/asset-changed-trigger.component';

2
src/Squidex/app/features/rules/module.ts

@ -21,6 +21,7 @@ import {
ContentChangedTriggerComponent,
ElasticSearchActionComponent,
FastlyActionComponent,
MediumActionComponent,
RuleEventBadgeClassPipe,
RuleEventsPageComponent,
RulesPageComponent,
@ -62,6 +63,7 @@ const routes: Routes = [
ContentChangedTriggerComponent,
ElasticSearchActionComponent,
FastlyActionComponent,
MediumActionComponent,
RuleEventBadgeClassPipe,
RuleEventsPageComponent,
RulesPageComponent,

112
src/Squidex/app/features/rules/pages/rules/actions/medium-action.component.html

@ -0,0 +1,112 @@
<h3 class="wizard-title">Post to Medium</h3>
<div [formGroup]="actionForm" class="form-horizontal">
<div class="form-group row">
<label class="col col-3 col-form-label" for="accessToken">Access Token</label>
<div class="col col-9">
<sqx-control-errors for="accessToken" [submitted]="actionFormSubmitted"></sqx-control-errors>
<input type="text" class="form-control" id="accessToken" formControlName="accessToken" />
<small class="form-text text-muted">
The self issued access token. Can be created under <a target="_blank" href="https://medium.com/me/settings">https://medium.com/me/settings</a>.
</small>
</div>
</div>
<div class="form-group row">
<label class="col col-3 col-form-label" for="author">Author</label>
<div class="col col-9">
<sqx-control-errors for="author" [submitted]="actionFormSubmitted"></sqx-control-errors>
<input type="text" class="form-control" id="author" formControlName="author" />
<small class="form-text text-muted">
The name of the author. You can also define the publication.
</small>
</div>
</div>
<div class="form-group row">
<label class="col col-3 col-form-label" for="publication">Publication</label>
<div class="col col-9">
<sqx-control-errors for="publication" [submitted]="actionFormSubmitted"></sqx-control-errors>
<input type="text" class="form-control" id="publication" formControlName="publication" />
<small class="form-text text-muted">
The name of the publication. You can also define the author.
</small>
</div>
</div>
<div class="form-group row">
<label class="col col-3 col-form-label" for="title">Title</label>
<div class="col col-9">
<sqx-control-errors for="title" [submitted]="actionFormSubmitted"></sqx-control-errors>
<input type="text" class="form-control" id="title" formControlName="title" />
<small class="form-text text-muted">
The title of the post. Note that this title is used for SEO and when rendering the post as a listing.
</small>
</div>
</div>
<div class="form-group row">
<label class="col col-3 col-form-label" for="content">Content</label>
<div class="col col-9">
<sqx-control-errors for="content" [submitted]="actionFormSubmitted"></sqx-control-errors>
<textarea class="form-control" id="content" formControlName="content"></textarea>
<small class="form-text text-muted">
The body of the post, in a valid, semantic, HTML fragment, or Markdown.
</small>
</div>
</div>
<div class="form-group row">
<div class="col col-9 offset-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="isHtml" formControlName="isHtml" />
<label class="form-check-label" for="isHtml">
Is Html content
</label>
</div>
</div>
</div>
<div class="form-group row">
<label class="col col-3 col-form-label" for="canonicalUrl">Canonical URL</label>
<div class="col col-9">
<sqx-control-errors for="canonicalUrl" [submitted]="actionFormSubmitted"></sqx-control-errors>
<input type="text" class="form-control" id="canonicalUrl" formControlName="canonicalUrl" />
<small class="form-text text-muted">
The original home of this content, if it was originally published elsewhere.
</small>
</div>
</div>
<div class="form-group row">
<label class="col col-3 col-form-label" for="tags">Tags</label>
<div class="col col-9">
<sqx-control-errors for="tags" [submitted]="actionFormSubmitted"></sqx-control-errors>
<input type="text" class="form-control" id="tags" formControlName="tags" />
<small class="form-text text-muted">
Comma-separated list of tags.
</small>
</div>
</div>
</div>

6
src/Squidex/app/features/rules/pages/rules/actions/medium-action.component.scss

@ -0,0 +1,6 @@
@import '_vars';
@import '_mixins';
textarea {
height: 150px;
}

57
src/Squidex/app/features/rules/pages/rules/actions/medium-action.component.ts

@ -0,0 +1,57 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, Input, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'sqx-medium-action',
styleUrls: ['./medium-action.component.scss'],
templateUrl: './medium-action.component.html'
})
export class MediumActionComponent implements OnInit {
@Input()
public action: any;
@Input()
public actionForm: FormGroup;
@Input()
public actionFormSubmitted = false;
public ngOnInit() {
this.actionForm.setControl('accessToken',
new FormControl(this.action.accessToken || '', [
Validators.required
]));
this.actionForm.setControl('title',
new FormControl(this.action.title || '', [
Validators.required
]));
this.actionForm.setControl('content',
new FormControl(this.action.content || '', [
Validators.required
]));
this.actionForm.setControl('author',
new FormControl(this.action.author || ''));
this.actionForm.setControl('publication',
new FormControl(this.action.publication || ''));
this.actionForm.setControl('canonicalUrl',
new FormControl(this.action.canonicalUrl || ''));
this.actionForm.setControl('tags',
new FormControl(this.action.tags || ''));
this.actionForm.setControl('isHtml',
new FormControl(this.action.isHtml || false));
}
}

7
src/Squidex/app/features/rules/pages/rules/rule-wizard.component.html

@ -96,6 +96,13 @@
[actionFormSubmitted]="actionForm.submitted | async">
</sqx-fastly-action>
</ng-container>
<ng-container *ngSwitchCase="'Medium'">
<sqx-medium-action
[action]="action"
[actionForm]="actionForm.form"
[actionFormSubmitted]="actionForm.submitted | async">
</sqx-medium-action>
</ng-container>
<ng-container *ngSwitchCase="'Slack'">
<sqx-slack-action
[action]="action"

3
src/Squidex/app/shared/services/rules.service.ts

@ -43,6 +43,9 @@ export const ruleActions: any = {
'Fastly': {
name: 'Purge fastly Cache'
},
'Medium': {
name: 'Post to Medium'
},
'Slack': {
name: 'Send to Slack'
},

5
src/Squidex/app/theme/_rules.scss

@ -10,6 +10,7 @@ $action-algolia: #0d9bf9;
$action-slack: #5c3a58;
$action-azure: #55b3ff;
$action-fastly: #e23335;
$action-medium: #00ab6c;
// sass-lint:disable class-name-format
@ -81,6 +82,10 @@ $action-fastly: #e23335;
@include build-element($action-fastly);
}
.rule-element-Medium {
@include build-element($action-medium);
}
.rule-element-Slack {
@include build-element($action-slack);
}

4
src/Squidex/app/theme/icomoon/demo-files/demo.css

@ -147,10 +147,10 @@ p {
font-size: 16px;
}
.fs1 {
font-size: 28px;
font-size: 32px;
}
.fs2 {
font-size: 32px;
font-size: 28px;
}
.fs3 {
font-size: 32px;

1116
src/Squidex/app/theme/icomoon/demo.html

File diff suppressed because it is too large

BIN
src/Squidex/app/theme/icomoon/fonts/icomoon.eot

Binary file not shown.

1
src/Squidex/app/theme/icomoon/fonts/icomoon.svg

@ -96,6 +96,7 @@
<glyph unicode="&#xe956;" glyph-name="type-Array" d="M832 682.057h-657.92c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h657.92c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6zM832 497.737h-409.6c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h409.6c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6zM832 308.297h-409.6c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h409.6c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6zM832 118.857h-409.6c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h409.6c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6z" />
<glyph unicode="&#xe957;" glyph-name="multiple-content" horiz-adv-x="1029" d="M777.143 4.571h-525.714c-89.143 0-160 70.857-160 160v297.143c0 89.143 70.857 160 160 160h525.714c89.143 0 160-70.857 160-160v-297.143c0-89.143-70.857-160-160-160zM251.429 576c-64 0-114.286-50.286-114.286-114.286v-297.143c0-64 50.286-114.286 114.286-114.286h525.714c64 0 114.286 50.286 114.286 114.286v297.143c0 64-50.286 114.286-114.286 114.286h-525.714zM731.429 370.286h-457.143c-13.714 0-22.857 9.143-22.857 22.857s9.143 22.857 22.857 22.857h457.143c13.714 0 22.857-9.143 22.857-22.857s-9.143-22.857-22.857-22.857zM502.857 210.286h-228.571c-13.714 0-22.857 9.143-22.857 22.857s9.143 22.857 22.857 22.857h228.571c13.714 0 22.857-9.143 22.857-22.857s-9.143-22.857-22.857-22.857zM777.143 690.286h-525.714c-13.714 0-22.857 9.143-22.857 22.857s9.143 22.857 22.857 22.857h525.714c13.714 0 22.857-9.143 22.857-22.857s-9.143-22.857-22.857-22.857zM685.714 804.571h-342.857c-13.714 0-22.857 9.143-22.857 22.857s9.143 22.857 22.857 22.857h342.857c13.714 0 22.857-9.143 22.857-22.857s-9.143-22.857-22.857-22.857z" />
<glyph unicode="&#xe958;" glyph-name="single-content" horiz-adv-x="1029" d="M251.429 850.277c-87.896 0-160-72.104-160-160v-525.714c0-87.896 72.104-160 160-160h525.714c87.896 0 160 72.104 160 160v525.714c0 87.896-72.104 160-160 160zM251.429 804.562h525.714c62.961 0 114.286-51.325 114.286-114.286v-525.714c0-62.961-51.325-114.286-114.286-114.286h-525.714c-62.961 0-114.286 51.325-114.286 114.286v525.714c0 62.961 51.325 114.286 114.286 114.286zM251.429 644.562c-0.096 0.001-0.21 0.002-0.323 0.002-12.625 0-22.859-10.235-22.859-22.859s10.235-22.859 22.859-22.859c0.114 0 0.227 0.001 0.34 0.002h525.697c0.096-0.001 0.21-0.002 0.323-0.002 12.625 0 22.859 10.235 22.859 22.859s-10.235 22.859-22.859 22.859c-0.114 0-0.227-0.001-0.34-0.002h0.017zM251.429 507.419c-0.096 0.001-0.21 0.002-0.323 0.002-12.625 0-22.859-10.235-22.859-22.859s10.235-22.859 22.859-22.859c0.114 0 0.227 0.001 0.34 0.002h297.126c0.096-0.001 0.21-0.002 0.323-0.002 12.625 0 22.859 10.235 22.859 22.859s-10.235 22.859-22.859 22.859c-0.114 0-0.227-0.001-0.34-0.002h0.017zM251.429 370.277c-0.096 0.001-0.21 0.002-0.323 0.002-12.625 0-22.859-10.235-22.859-22.859s10.235-22.859 22.859-22.859c0.114 0 0.227 0.001 0.34 0.002h297.126c0.096-0.001 0.21-0.002 0.323-0.002 12.625 0 22.859 10.235 22.859 22.859s-10.235 22.859-22.859 22.859c-0.114 0-0.227-0.001-0.34-0.002h0.017z" />
<glyph unicode="&#xe959;" glyph-name="action-Medium" d="M121.429 688.64c1.28 12.587-3.541 25.003-12.928 33.451l-95.573 115.2v17.195h296.832l229.461-503.253 201.728 503.253h283.051v-17.195l-81.792-78.379c-7.040-5.376-10.539-14.208-9.088-22.955v-576c-1.451-8.704 2.048-17.493 9.088-22.912l79.787-78.379v-17.195h-401.493v17.195l82.645 80.299c8.107 8.107 8.107 10.496 8.107 22.955v465.536l-229.973-584.021h-31.019l-267.733 584.021v-391.424c-2.219-16.469 3.243-33.024 14.805-44.928l107.52-130.56v-17.152h-304.853v17.195l107.52 130.56c11.52 11.861 16.64 28.587 13.909 44.885v452.608z" />
<glyph unicode="&#xe9ca;" glyph-name="earth" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512-0.002c-62.958 0-122.872 13.012-177.23 36.452l233.148 262.29c5.206 5.858 8.082 13.422 8.082 21.26v96c0 17.674-14.326 32-32 32-112.99 0-232.204 117.462-233.374 118.626-6 6.002-14.14 9.374-22.626 9.374h-128c-17.672 0-32-14.328-32-32v-192c0-12.122 6.848-23.202 17.69-28.622l110.31-55.156v-187.886c-116.052 80.956-192 215.432-192 367.664 0 68.714 15.49 133.806 43.138 192h116.862c8.488 0 16.626 3.372 22.628 9.372l128 128c6 6.002 9.372 14.14 9.372 22.628v77.412c40.562 12.074 83.518 18.588 128 18.588 70.406 0 137.004-16.26 196.282-45.2-4.144-3.502-8.176-7.164-12.046-11.036-36.266-36.264-56.236-84.478-56.236-135.764s19.97-99.5 56.236-135.764c36.434-36.432 85.218-56.264 135.634-56.26 3.166 0 6.342 0.080 9.518 0.236 13.814-51.802 38.752-186.656-8.404-372.334-0.444-1.744-0.696-3.488-0.842-5.224-81.324-83.080-194.7-134.656-320.142-134.656z" />
<glyph unicode="&#xf00a;" glyph-name="grid" d="M292.571 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM292.571 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM292.571 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857z" />
<glyph unicode="&#xf0c9;" glyph-name="list" horiz-adv-x="878" d="M877.714 182.857v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571zM877.714 475.428v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571zM877.714 768v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571z" />

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

BIN
src/Squidex/app/theme/icomoon/fonts/icomoon.ttf

Binary file not shown.

BIN
src/Squidex/app/theme/icomoon/fonts/icomoon.woff

Binary file not shown.

2215
src/Squidex/app/theme/icomoon/selection.json

File diff suppressed because it is too large

289
src/Squidex/app/theme/icomoon/style.css

@ -1,10 +1,10 @@
@font-face {
font-family: 'icomoon';
src: url('fonts/icomoon.eot?vrpp1i');
src: url('fonts/icomoon.eot?vrpp1i#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?vrpp1i') format('truetype'),
url('fonts/icomoon.woff?vrpp1i') format('woff'),
url('fonts/icomoon.svg?vrpp1i#icomoon') format('svg');
src: url('fonts/icomoon.eot?o6u2w7');
src: url('fonts/icomoon.eot?o6u2w7#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?o6u2w7') format('truetype'),
url('fonts/icomoon.woff?o6u2w7') format('woff'),
url('fonts/icomoon.svg?o6u2w7#icomoon') format('svg');
font-weight: normal;
font-style: normal;
}
@ -24,6 +24,168 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-action-Medium:before {
content: "\e959";
}
.icon-circle:before {
content: "\e951";
}
.icon-action-Fastly:before {
content: "\e94e";
}
.icon-control-Slug:before {
content: "\e94f";
}
.icon-action-Algolia:before {
content: "\e94c";
}
.icon-type-Tags:before {
content: "\e94a";
}
.icon-activity:before {
content: "\e904";
}
.icon-history:before {
content: "\e904";
}
.icon-time:before {
content: "\e904";
}
.icon-add:before {
content: "\e905";
}
.icon-plus:before {
content: "\e905";
}
.icon-check-circle:before {
content: "\e906";
}
.icon-check-circle-filled:before {
content: "\e907";
}
.icon-close:before {
content: "\e908";
}
.icon-type-References:before {
content: "\e909";
}
.icon-control-Checkbox:before {
content: "\e90a";
}
.icon-control-Dropdown:before {
content: "\e90b";
}
.icon-control-Input:before {
content: "\e90c";
}
.icon-control-Radio:before {
content: "\e90d";
}
.icon-control-TextArea:before {
content: "\e90e";
}
.icon-control-Toggle:before {
content: "\e90f";
}
.icon-copy:before {
content: "\e910";
}
.icon-dashboard:before {
content: "\e911";
}
.icon-delete:before {
content: "\e912";
}
.icon-bin:before {
content: "\e912";
}
.icon-delete-filled:before {
content: "\e913";
}
.icon-document-delete:before {
content: "\e914";
}
.icon-document-disable:before {
content: "\e915";
}
.icon-document-publish:before {
content: "\e916";
}
.icon-drag:before {
content: "\e917";
}
.icon-filter:before {
content: "\e918";
}
.icon-github:before {
content: "\e941";
}
.icon-help:before {
content: "\e919";
}
.icon-location:before {
content: "\e91b";
}
.icon-control-Map:before {
content: "\e91b";
}
.icon-type-Geolocation:before {
content: "\e91b";
}
.icon-logo:before {
content: "\e91c";
}
.icon-media:before {
content: "\e91d";
}
.icon-type-Assets:before {
content: "\e91d";
}
.icon-trigger-AssetChanged:before {
content: "\e91d";
}
.icon-more:before {
content: "\e91e";
}
.icon-dots:before {
content: "\e91e";
}
.icon-pencil:before {
content: "\e91f";
}
.icon-reference:before {
content: "\e920";
}
.icon-schemas:before {
content: "\e921";
}
.icon-search:before {
content: "\e922";
}
.icon-settings:before {
content: "\e923";
}
.icon-type-Boolean:before {
content: "\e924";
}
.icon-type-DateTime:before {
content: "\e925";
}
.icon-type-Json:before {
content: "\e91a";
}
.icon-json:before {
content: "\e91a";
}
.icon-type-Number:before {
content: "\e926";
}
.icon-type-String:before {
content: "\e927";
}
.icon-user:before {
content: "\e928";
}
.icon-single-content:before {
content: "\e958";
}
@ -162,60 +324,6 @@
.icon-unlocked:before {
content: "\e933";
}
.icon-circle:before {
content: "\e951";
}
.icon-action-Fastly:before {
content: "\e94e";
}
.icon-control-Slug:before {
content: "\e94f";
}
.icon-action-Algolia:before {
content: "\e94c";
}
.icon-type-Tags:before {
content: "\e94a";
}
.icon-activity:before {
content: "\e904";
}
.icon-history:before {
content: "\e904";
}
.icon-time:before {
content: "\e904";
}
.icon-add:before {
content: "\e905";
}
.icon-plus:before {
content: "\e905";
}
.icon-check-circle:before {
content: "\e906";
}
.icon-check-circle-filled:before {
content: "\e907";
}
.icon-close:before {
content: "\e908";
}
.icon-type-References:before {
content: "\e909";
}
.icon-control-Checkbox:before {
content: "\e90a";
}
.icon-control-Dropdown:before {
content: "\e90b";
}
.icon-control-Input:before {
content: "\e90c";
}
.icon-control-Radio:before {
content: "\e90d";
}
.icon-control-TextArea:before {
content: "\e90e";
}
@ -258,69 +366,6 @@
.icon-help:before {
content: "\e919";
}
.icon-location:before {
content: "\e91b";
}
.icon-control-Map:before {
content: "\e91b";
}
.icon-type-Geolocation:before {
content: "\e91b";
}
.icon-logo:before {
content: "\e91c";
}
.icon-media:before {
content: "\e91d";
}
.icon-type-Assets:before {
content: "\e91d";
}
.icon-trigger-AssetChanged:before {
content: "\e91d";
}
.icon-more:before {
content: "\e91e";
}
.icon-dots:before {
content: "\e91e";
}
.icon-pencil:before {
content: "\e91f";
}
.icon-reference:before {
content: "\e920";
}
.icon-schemas:before {
content: "\e921";
}
.icon-search:before {
content: "\e922";
}
.icon-settings:before {
content: "\e923";
}
.icon-type-Boolean:before {
content: "\e924";
}
.icon-type-DateTime:before {
content: "\e925";
}
.icon-type-Json:before {
content: "\e91a";
}
.icon-json:before {
content: "\e91a";
}
.icon-type-Number:before {
content: "\e926";
}
.icon-type-String:before {
content: "\e927";
}
.icon-user:before {
content: "\e928";
}
.icon-browser:before {
content: "\e935";
}

Loading…
Cancel
Save