mirror of https://github.com/Squidex/squidex.git
32 changed files with 1613 additions and 1156 deletions
@ -0,0 +1,52 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Core.Rules.Actions |
|||
{ |
|||
[TypeName(nameof(SlackAction))] |
|||
public sealed class SlackAction : RuleAction |
|||
{ |
|||
private Uri webhookUrl; |
|||
private string text; |
|||
|
|||
public Uri WebhookUrl |
|||
{ |
|||
get |
|||
{ |
|||
return webhookUrl; |
|||
} |
|||
set |
|||
{ |
|||
ThrowIfFrozen(); |
|||
|
|||
webhookUrl = value; |
|||
} |
|||
} |
|||
|
|||
public string Text |
|||
{ |
|||
get |
|||
{ |
|||
return text; |
|||
} |
|||
set |
|||
{ |
|||
ThrowIfFrozen(); |
|||
|
|||
text = value; |
|||
} |
|||
} |
|||
|
|||
public override T Accept<T>(IRuleActionVisitor<T> visitor) |
|||
{ |
|||
return visitor.Visit(this); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,101 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Net.Http; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Newtonsoft.Json; |
|||
using Newtonsoft.Json.Linq; |
|||
using Squidex.Domain.Apps.Core.Rules; |
|||
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 SlackActionHandler : RuleActionHandler<SlackAction> |
|||
{ |
|||
private static readonly HttpClient Client = new HttpClient { Timeout = TimeSpan.FromSeconds(2) }; |
|||
private readonly RuleEventFormatter formatter; |
|||
|
|||
public SlackActionHandler(RuleEventFormatter formatter) |
|||
{ |
|||
Guard.NotNull(formatter, nameof(formatter)); |
|||
|
|||
this.formatter = formatter; |
|||
} |
|||
|
|||
protected override (string Description, RuleJobData Data) CreateJob(Envelope<AppEvent> @event, string eventName, SlackAction action) |
|||
{ |
|||
var body = CreatePayload(@event, action.Text); |
|||
|
|||
var ruleDescription = "Send message to slack"; |
|||
var ruleData = new RuleJobData |
|||
{ |
|||
["RequestUrl"] = action.WebhookUrl, |
|||
["RequestBody"] = body |
|||
}; |
|||
|
|||
return (ruleDescription, ruleData); |
|||
} |
|||
|
|||
private JObject CreatePayload(Envelope<AppEvent> @event, string text) |
|||
{ |
|||
return new JObject( |
|||
new JProperty("text", formatter.FormatString(text, @event))); |
|||
} |
|||
|
|||
public override async Task<(string Dump, Exception Exception)> ExecuteJobAsync(RuleJobData job) |
|||
{ |
|||
var requestBody = job["RequestBody"].ToString(Formatting.Indented); |
|||
var request = BuildRequest(job, requestBody); |
|||
|
|||
HttpResponseMessage response = null; |
|||
|
|||
try |
|||
{ |
|||
response = await Client.SendAsync(request); |
|||
|
|||
var responseString = await response.Content.ReadAsStringAsync(); |
|||
var requestDump = DumpFormatter.BuildDump(request, response, requestBody, responseString, TimeSpan.Zero, false); |
|||
|
|||
return (requestDump, null); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
if (request != null) |
|||
{ |
|||
var requestDump = DumpFormatter.BuildDump(request, response, requestBody, ex.ToString(), TimeSpan.Zero, false); |
|||
|
|||
return (requestDump, ex); |
|||
} |
|||
else |
|||
{ |
|||
var requestDump = ex.ToString(); |
|||
|
|||
return (requestDump, ex); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private static HttpRequestMessage BuildRequest(Dictionary<string, JToken> job, string requestBody) |
|||
{ |
|||
var requestUrl = job["RequestUrl"].Value<string>(); |
|||
|
|||
var request = new HttpRequestMessage(HttpMethod.Post, requestUrl) |
|||
{ |
|||
Content = new StringContent(requestBody, Encoding.UTF8, "application/json") |
|||
}; |
|||
|
|||
return request; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
// ==========================================================================
|
|||
// 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()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
<form [formGroup]="actionForm" class="form-horizontal" (ngSubmit)="save()"> |
|||
<div class="form-group row"> |
|||
<label class="col col-2 col-form-label" for="webhookUrl">Webhook Url</label> |
|||
|
|||
<div class="col col-10"> |
|||
<sqx-control-errors for="webhookUrl" [submitted]="actionFormSubmitted"></sqx-control-errors> |
|||
|
|||
<input type="webhookUrl" class="form-control" id="webhookUrl" formControlName="webhookUrl" /> |
|||
|
|||
<small class="form-text text-muted"> |
|||
The url to the incoming slack webhook. |
|||
</small> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="form-group row"> |
|||
<label class="col col-2 col-form-label" for="text">Text</label> |
|||
|
|||
<div class="col col-10"> |
|||
<sqx-control-errors for="text" [submitted]="actionFormSubmitted"></sqx-control-errors> |
|||
|
|||
<textarea class="form-control" id="text" formControlName="text"></textarea> |
|||
|
|||
<small class="form-text text-muted"> |
|||
The text to send to slack. Read the <a routerLink="help">help</a> section for information about advanced formatting. |
|||
</small> |
|||
</div> |
|||
</div> |
|||
</form> |
|||
@ -0,0 +1,2 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
@ -0,0 +1,55 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; |
|||
import { FormBuilder, Validators } from '@angular/forms'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-slack-action', |
|||
styleUrls: ['./slack-action.component.scss'], |
|||
templateUrl: './slack-action.component.html' |
|||
}) |
|||
export class SlackActionComponent implements OnInit { |
|||
@Input() |
|||
public action: any; |
|||
|
|||
@Output() |
|||
public actionChanged = new EventEmitter<object>(); |
|||
|
|||
public actionFormSubmitted = false; |
|||
public actionForm = |
|||
this.formBuilder.group({ |
|||
webhookUrl: ['', |
|||
[ |
|||
Validators.required |
|||
]], |
|||
text: [''] |
|||
}); |
|||
|
|||
constructor( |
|||
private readonly formBuilder: FormBuilder |
|||
) { |
|||
} |
|||
|
|||
public ngOnInit() { |
|||
this.action = Object.assign({}, { webhookUrl: '', text: '' }, this.action || {}); |
|||
|
|||
this.actionFormSubmitted = false; |
|||
this.actionForm.reset(); |
|||
this.actionForm.setValue(this.action); |
|||
} |
|||
|
|||
public save() { |
|||
this.actionFormSubmitted = true; |
|||
|
|||
if (this.actionForm.valid) { |
|||
const action = this.actionForm.value; |
|||
|
|||
this.actionChanged.emit(action); |
|||
} |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
Binary file not shown.
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 69 KiB |
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
@ -0,0 +1,47 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Domain.Apps.Core.Rules.Actions; |
|||
using Xunit; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Rules.Guards.Actions |
|||
{ |
|||
public sealed class SlackActionTests |
|||
{ |
|||
[Fact] |
|||
public async Task Should_add_error_if_webhook_url_is_null() |
|||
{ |
|||
var action = new SlackAction { WebhookUrl = null }; |
|||
|
|||
var errors = await RuleActionValidator.ValidateAsync(action); |
|||
|
|||
Assert.NotEmpty(errors); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_add_error_if_webhook_url_is_relative() |
|||
{ |
|||
var action = new SlackAction { WebhookUrl = new Uri("/invalid", UriKind.Relative) }; |
|||
|
|||
var errors = await RuleActionValidator.ValidateAsync(action); |
|||
|
|||
Assert.NotEmpty(errors); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_not_add_error_if_webhook_url_is_absolute() |
|||
{ |
|||
var action = new SlackAction { WebhookUrl = new Uri("https://squidex.io", UriKind.Absolute) }; |
|||
|
|||
var errors = await RuleActionValidator.ValidateAsync(action); |
|||
|
|||
Assert.Empty(errors); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue