Webhook: async
This commit is contained in:
parent
6ec79e015e
commit
4cdce5b713
@ -24,8 +24,6 @@
|
|||||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||||
|
|
||||||
using JsonSerializer = System.Text.Json.JsonSerializer;
|
|
||||||
|
|
||||||
namespace ASC.Api.Core.Middleware;
|
namespace ASC.Api.Core.Middleware;
|
||||||
|
|
||||||
[Scope]
|
[Scope]
|
||||||
@ -76,7 +74,7 @@ public class WebhooksGlobalFilterAttribute : ResultFilterAttribute, IDisposable
|
|||||||
|
|
||||||
var resultContent = Encoding.UTF8.GetString(_stream.ToArray());
|
var resultContent = Encoding.UTF8.GetString(_stream.ToArray());
|
||||||
|
|
||||||
_webhookPublisher.Publish(method, routePattern, JsonSerializer.Serialize(context.HttpContext.Request.Headers.ToDictionary(r => r.Key, v => v.Value)), resultContent);
|
await _webhookPublisher.Publish(method, routePattern, resultContent);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -31,43 +31,37 @@ public class DbWorker
|
|||||||
{
|
{
|
||||||
private readonly IDbContextFactory<WebhooksDbContext> _dbContextFactory;
|
private readonly IDbContextFactory<WebhooksDbContext> _dbContextFactory;
|
||||||
private readonly TenantManager _tenantManager;
|
private readonly TenantManager _tenantManager;
|
||||||
public DbWorker(IDbContextFactory<WebhooksDbContext> dbContextFactory, TenantManager tenantManager)
|
private readonly AuthContext _authContext;
|
||||||
|
|
||||||
|
private int Tenant
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _tenantManager.GetCurrentTenant().Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbWorker(IDbContextFactory<WebhooksDbContext> dbContextFactory, TenantManager tenantManager, AuthContext authContext)
|
||||||
{
|
{
|
||||||
_dbContextFactory = dbContextFactory;
|
_dbContextFactory = dbContextFactory;
|
||||||
_tenantManager = tenantManager;
|
_tenantManager = tenantManager;
|
||||||
}
|
_authContext = authContext;
|
||||||
public void AddWebhookConfig(WebhooksConfig webhooksConfig)
|
|
||||||
{
|
|
||||||
webhooksConfig.TenantId = _tenantManager.GetCurrentTenant().Id;
|
|
||||||
|
|
||||||
using var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var addObj = webhooksDbContext.WebhooksConfigs.Where(it =>
|
|
||||||
it.SecretKey == webhooksConfig.SecretKey &&
|
|
||||||
it.TenantId == webhooksConfig.TenantId &&
|
|
||||||
it.Uri == webhooksConfig.Uri).FirstOrDefault();
|
|
||||||
|
|
||||||
if (addObj != null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
webhooksDbContext.WebhooksConfigs.Add(webhooksConfig);
|
public async Task AddWebhookConfig(string uri, string secretKey)
|
||||||
webhooksDbContext.SaveChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ConfigsNumber()
|
|
||||||
{
|
{
|
||||||
using var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
using var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
||||||
return webhooksDbContext.WebhooksConfigs.Count();
|
|
||||||
|
await webhooksDbContext.AddOrUpdateAsync(r => r.WebhooksConfigs, new WebhooksConfig { TenantId = Tenant, Uri = uri, SecretKey = secretKey });
|
||||||
|
await webhooksDbContext.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<WebhooksLog> GetTenantWebhooks()
|
public async IAsyncEnumerable<WebhooksLog> GetTenantWebhooks()
|
||||||
{
|
{
|
||||||
var tenant = _tenantManager.GetCurrentTenant().Id;
|
|
||||||
|
|
||||||
using var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
using var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
||||||
return webhooksDbContext.WebhooksLogs.Where(it => it.TenantId == tenant)
|
|
||||||
|
var q = webhooksDbContext.WebhooksLogs
|
||||||
|
.Where(it => it.TenantId == Tenant)
|
||||||
.Select(t => new WebhooksLog
|
.Select(t => new WebhooksLog
|
||||||
{
|
{
|
||||||
Uid = t.Uid,
|
Uid = t.Uid,
|
||||||
@ -77,13 +71,61 @@ public class DbWorker
|
|||||||
ResponsePayload = t.ResponsePayload,
|
ResponsePayload = t.ResponsePayload,
|
||||||
ResponseHeaders = t.ResponseHeaders,
|
ResponseHeaders = t.ResponseHeaders,
|
||||||
Status = t.Status
|
Status = t.Status
|
||||||
}).ToList();
|
})
|
||||||
|
.AsAsyncEnumerable();
|
||||||
|
|
||||||
|
await foreach (var webhook in q)
|
||||||
|
{
|
||||||
|
yield return webhook;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<WebhooksConfig> GetWebhookConfigs(int tenant)
|
public IAsyncEnumerable<WebhooksConfig> GetWebhookConfigs()
|
||||||
|
{
|
||||||
|
var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
||||||
|
|
||||||
|
return webhooksDbContext.WebhooksConfigs
|
||||||
|
.Where(t => t.TenantId == Tenant)
|
||||||
|
.AsAsyncEnumerable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateWebhookConfig(int id, string uri, string key)
|
||||||
{
|
{
|
||||||
using var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
using var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
||||||
return webhooksDbContext.WebhooksConfigs.Where(t => t.TenantId == tenant).ToList();
|
|
||||||
|
var updateObj = await webhooksDbContext.WebhooksConfigs
|
||||||
|
.Where(it => it.TenantId == Tenant && it.ConfigId == id)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
if (updateObj != null)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(uri))
|
||||||
|
{
|
||||||
|
updateObj.Uri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(key))
|
||||||
|
{
|
||||||
|
updateObj.SecretKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
webhooksDbContext.WebhooksConfigs.Update(updateObj);
|
||||||
|
await webhooksDbContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RemoveWebhookConfig(int id)
|
||||||
|
{
|
||||||
|
var tenant = _tenantManager.GetCurrentTenant().Id;
|
||||||
|
|
||||||
|
using var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
||||||
|
|
||||||
|
var removeObj = await webhooksDbContext.WebhooksConfigs
|
||||||
|
.Where(it => it.TenantId == tenant && it.ConfigId == id)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
webhooksDbContext.WebhooksConfigs.Remove(removeObj);
|
||||||
|
await webhooksDbContext.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebhookEntry ReadFromJournal(int id)
|
public WebhookEntry ReadFromJournal(int id)
|
||||||
@ -93,55 +135,34 @@ public class DbWorker
|
|||||||
.Where(it => it.Id == id)
|
.Where(it => it.Id == id)
|
||||||
.Join(webhooksDbContext.WebhooksConfigs, t => t.ConfigId, t => t.ConfigId, (payload, config) => new { payload, config })
|
.Join(webhooksDbContext.WebhooksConfigs, t => t.ConfigId, t => t.ConfigId, (payload, config) => new { payload, config })
|
||||||
.Select(t => new WebhookEntry { Id = t.payload.Id, Payload = t.payload.RequestPayload, SecretKey = t.config.SecretKey, Uri = t.config.Uri })
|
.Select(t => new WebhookEntry { Id = t.payload.Id, Payload = t.payload.RequestPayload, SecretKey = t.config.SecretKey, Uri = t.config.Uri })
|
||||||
.OrderBy(t => t.Id).FirstOrDefault();
|
.OrderBy(t => t.Id)
|
||||||
|
.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveWebhookConfig(WebhooksConfig webhooksConfig)
|
public async Task<int> WriteToJournal(WebhooksLog webhook)
|
||||||
{
|
{
|
||||||
webhooksConfig.TenantId = _tenantManager.GetCurrentTenant().Id;
|
webhook.TenantId = _tenantManager.GetCurrentTenant().Id;
|
||||||
|
webhook.Uid = _authContext.CurrentAccount.ID;
|
||||||
|
|
||||||
using var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
using var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
||||||
var removeObj = webhooksDbContext.WebhooksConfigs.Where(it =>
|
|
||||||
it.SecretKey == webhooksConfig.SecretKey &&
|
|
||||||
it.TenantId == webhooksConfig.TenantId &&
|
|
||||||
it.Uri == webhooksConfig.Uri).FirstOrDefault();
|
|
||||||
|
|
||||||
webhooksDbContext.WebhooksConfigs.Remove(removeObj);
|
var entity = await webhooksDbContext.WebhooksLogs.AddAsync(webhook);
|
||||||
webhooksDbContext.SaveChanges();
|
await webhooksDbContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
return entity.Entity.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateWebhookConfig(WebhooksConfig webhooksConfig)
|
public async Task UpdateWebhookJournal(int id, ProcessStatus status, string requestHeaders, string responsePayload, string responseHeaders)
|
||||||
{
|
|
||||||
webhooksConfig.TenantId = _tenantManager.GetCurrentTenant().Id;
|
|
||||||
|
|
||||||
using var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
|
||||||
var updateObj = webhooksDbContext.WebhooksConfigs.Where(it =>
|
|
||||||
it.SecretKey == webhooksConfig.SecretKey &&
|
|
||||||
it.TenantId == webhooksConfig.TenantId &&
|
|
||||||
it.Uri == webhooksConfig.Uri).FirstOrDefault();
|
|
||||||
|
|
||||||
webhooksDbContext.WebhooksConfigs.Update(updateObj);
|
|
||||||
webhooksDbContext.SaveChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateWebhookJournal(int id, ProcessStatus status, string responsePayload, string responseHeaders)
|
|
||||||
{
|
{
|
||||||
using var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
using var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
||||||
|
|
||||||
var webhook = await webhooksDbContext.WebhooksLogs.Where(t => t.Id == id).FirstOrDefaultAsync();
|
var webhook = await webhooksDbContext.WebhooksLogs.Where(t => t.Id == id).FirstOrDefaultAsync();
|
||||||
webhook.Status = status;
|
webhook.Status = status;
|
||||||
|
webhook.RequestHeaders = requestHeaders;
|
||||||
webhook.ResponsePayload = responsePayload;
|
webhook.ResponsePayload = responsePayload;
|
||||||
webhook.ResponseHeaders = responseHeaders;
|
webhook.ResponseHeaders = responseHeaders;
|
||||||
|
|
||||||
webhooksDbContext.WebhooksLogs.Update(webhook);
|
webhooksDbContext.WebhooksLogs.Update(webhook);
|
||||||
await webhooksDbContext.SaveChangesAsync();
|
await webhooksDbContext.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int WriteToJournal(WebhooksLog webhook)
|
|
||||||
{
|
|
||||||
using var webhooksDbContext = _dbContextFactory.CreateDbContext();
|
|
||||||
var entity = webhooksDbContext.WebhooksLogs.Add(webhook);
|
|
||||||
webhooksDbContext.SaveChanges();
|
|
||||||
return entity.Entity.Id;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -25,12 +25,18 @@
|
|||||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||||
|
|
||||||
namespace ASC.Webhooks.Core.EF.Model;
|
namespace ASC.Webhooks.Core.EF.Model;
|
||||||
public partial class WebhooksConfig
|
|
||||||
|
public class WebhooksConfig : BaseEntity
|
||||||
{
|
{
|
||||||
public int ConfigId { get; set; }
|
public int ConfigId { get; set; }
|
||||||
public string SecretKey { get; set; }
|
public string SecretKey { get; set; }
|
||||||
public int TenantId { get; set; }
|
public int TenantId { get; set; }
|
||||||
public string Uri { get; set; }
|
public string Uri { get; set; }
|
||||||
|
|
||||||
|
public override object[] GetKeys()
|
||||||
|
{
|
||||||
|
return new object[] { ConfigId };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class WebhooksConfigExtension
|
public static class WebhooksConfigExtension
|
||||||
|
@ -39,7 +39,7 @@ public partial class WebhooksLog
|
|||||||
public string ResponsePayload { get; set; }
|
public string ResponsePayload { get; set; }
|
||||||
public ProcessStatus Status { get; set; }
|
public ProcessStatus Status { get; set; }
|
||||||
public int TenantId { get; set; }
|
public int TenantId { get; set; }
|
||||||
public string Uid { get; set; }
|
public Guid Uid { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class WebhooksPayloadExtension
|
public static class WebhooksPayloadExtension
|
||||||
@ -73,9 +73,10 @@ public static class WebhooksPayloadExtension
|
|||||||
.HasColumnName("config_id");
|
.HasColumnName("config_id");
|
||||||
|
|
||||||
entity.Property(e => e.Uid)
|
entity.Property(e => e.Uid)
|
||||||
.HasColumnType("varchar")
|
|
||||||
.HasColumnName("uid")
|
.HasColumnName("uid")
|
||||||
.HasMaxLength(50);
|
.HasColumnType("varchar(38)")
|
||||||
|
.HasCharSet("utf8")
|
||||||
|
.UseCollation("utf8_general_ci");
|
||||||
|
|
||||||
entity.Property(e => e.TenantId)
|
entity.Property(e => e.TenantId)
|
||||||
.HasColumnName("tenant_id")
|
.HasColumnName("tenant_id")
|
||||||
|
@ -29,5 +29,5 @@ namespace ASC.Webhooks.Core;
|
|||||||
[Scope]
|
[Scope]
|
||||||
public interface IWebhookPublisher
|
public interface IWebhookPublisher
|
||||||
{
|
{
|
||||||
public void Publish(string method, string route, string requestHeaders, string requestPayload);
|
public Task Publish(string method, string route, string requestPayload);
|
||||||
}
|
}
|
@ -30,48 +30,38 @@ namespace ASC.Webhooks.Core;
|
|||||||
public class WebhookPublisher : IWebhookPublisher
|
public class WebhookPublisher : IWebhookPublisher
|
||||||
{
|
{
|
||||||
private readonly DbWorker _dbWorker;
|
private readonly DbWorker _dbWorker;
|
||||||
private readonly TenantManager _tenantManager;
|
|
||||||
private readonly ICacheNotify<WebhookRequest> _webhookNotify;
|
private readonly ICacheNotify<WebhookRequest> _webhookNotify;
|
||||||
private readonly AuthContext _authContext;
|
|
||||||
|
|
||||||
public WebhookPublisher(
|
public WebhookPublisher(
|
||||||
DbWorker dbWorker,
|
DbWorker dbWorker,
|
||||||
TenantManager tenantManager,
|
ICacheNotify<WebhookRequest> webhookNotify)
|
||||||
ICacheNotify<WebhookRequest> webhookNotify,
|
|
||||||
AuthContext authContext)
|
|
||||||
{
|
{
|
||||||
_dbWorker = dbWorker;
|
_dbWorker = dbWorker;
|
||||||
_tenantManager = tenantManager;
|
|
||||||
_webhookNotify = webhookNotify;
|
_webhookNotify = webhookNotify;
|
||||||
_authContext = authContext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Publish(string method, string route, string requestHeaders, string requestPayload)
|
public async Task Publish(string method, string route, string requestPayload)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(requestPayload))
|
if (string.IsNullOrEmpty(requestPayload))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var tenantId = _tenantManager.GetCurrentTenant().Id;
|
var webhookConfigs = _dbWorker.GetWebhookConfigs();
|
||||||
var webhookConfigs = _dbWorker.GetWebhookConfigs(tenantId);
|
|
||||||
|
|
||||||
foreach (var config in webhookConfigs)
|
await foreach (var config in webhookConfigs)
|
||||||
{
|
{
|
||||||
var webhooksLog = new WebhooksLog
|
var webhooksLog = new WebhooksLog
|
||||||
{
|
{
|
||||||
Uid = _authContext.CurrentAccount.ID.ToString(),
|
|
||||||
TenantId = tenantId,
|
|
||||||
Method = method,
|
Method = method,
|
||||||
Route = route,
|
Route = route,
|
||||||
CreationTime = DateTime.UtcNow,
|
CreationTime = DateTime.UtcNow,
|
||||||
RequestHeaders = requestHeaders,
|
|
||||||
RequestPayload = requestPayload,
|
RequestPayload = requestPayload,
|
||||||
Status = ProcessStatus.InProcess,
|
Status = ProcessStatus.InProcess,
|
||||||
ConfigId = config.ConfigId
|
ConfigId = config.ConfigId
|
||||||
};
|
};
|
||||||
|
|
||||||
var id = _dbWorker.WriteToJournal(webhooksLog);
|
var id = await _dbWorker.WriteToJournal(webhooksLog);
|
||||||
|
|
||||||
var request = new WebhookRequest
|
var request = new WebhookRequest
|
||||||
{
|
{
|
||||||
|
@ -72,7 +72,7 @@ public class WorkerService : BackgroundService
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var tasks = new List<Task>();
|
var tasks = new List<Task>(queueSize);
|
||||||
var counter = 0;
|
var counter = 0;
|
||||||
|
|
||||||
for (var i = 0; i < queueSize; i++)
|
for (var i = 0; i < queueSize; i++)
|
||||||
|
@ -37,7 +37,7 @@ public class Settings
|
|||||||
{
|
{
|
||||||
var cfg = configuration.GetSetting<Settings>("webhooks");
|
var cfg = configuration.GetSetting<Settings>("webhooks");
|
||||||
RepeatCount = cfg.RepeatCount ?? 5;
|
RepeatCount = cfg.RepeatCount ?? 5;
|
||||||
ThreadCount = cfg.ThreadCount ?? 1;
|
ThreadCount = cfg.ThreadCount ?? 10;
|
||||||
}
|
}
|
||||||
public int? RepeatCount { get; }
|
public int? RepeatCount { get; }
|
||||||
public int? ThreadCount { get; }
|
public int? ThreadCount { get; }
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||||
|
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace ASC.Webhooks.Service;
|
namespace ASC.Webhooks.Service;
|
||||||
|
|
||||||
[Singletone]
|
[Singletone]
|
||||||
@ -32,12 +34,19 @@ public class WebhookSender
|
|||||||
private readonly IHttpClientFactory _clientFactory;
|
private readonly IHttpClientFactory _clientFactory;
|
||||||
private readonly ILogger _log;
|
private readonly ILogger _log;
|
||||||
private readonly IServiceScopeFactory _scopeFactory;
|
private readonly IServiceScopeFactory _scopeFactory;
|
||||||
|
private readonly JsonSerializerOptions _jsonSerializerOptions;
|
||||||
|
|
||||||
public WebhookSender(ILoggerProvider options, IServiceScopeFactory scopeFactory, IHttpClientFactory clientFactory)
|
public WebhookSender(ILoggerProvider options, IServiceScopeFactory scopeFactory, IHttpClientFactory clientFactory)
|
||||||
{
|
{
|
||||||
_log = options.CreateLogger("ASC.Webhooks.Core");
|
_log = options.CreateLogger("ASC.Webhooks.Core");
|
||||||
_scopeFactory = scopeFactory;
|
_scopeFactory = scopeFactory;
|
||||||
_clientFactory = clientFactory;
|
_clientFactory = clientFactory;
|
||||||
|
_jsonSerializerOptions = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||||
|
IgnoreReadOnlyProperties = true,
|
||||||
|
WriteIndented = true
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Send(WebhookRequest webhookRequest, CancellationToken cancellationToken)
|
public async Task Send(WebhookRequest webhookRequest, CancellationToken cancellationToken)
|
||||||
@ -51,6 +60,7 @@ public class WebhookSender
|
|||||||
var status = ProcessStatus.InProcess;
|
var status = ProcessStatus.InProcess;
|
||||||
string responsePayload = null;
|
string responsePayload = null;
|
||||||
string responseHeaders = null;
|
string responseHeaders = null;
|
||||||
|
string requestHeaders = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -62,10 +72,12 @@ public class WebhookSender
|
|||||||
|
|
||||||
request.Headers.Add("Accept", "*/*");
|
request.Headers.Add("Accept", "*/*");
|
||||||
request.Headers.Add("Secret", "SHA256=" + GetSecretHash(entry.SecretKey, data));
|
request.Headers.Add("Secret", "SHA256=" + GetSecretHash(entry.SecretKey, data));
|
||||||
|
requestHeaders = JsonSerializer.Serialize(request.Headers.ToDictionary(r => r.Key, v => v.Value), _jsonSerializerOptions);
|
||||||
|
|
||||||
var response = await httpClient.SendAsync(request, cancellationToken);
|
var response = await httpClient.SendAsync(request, cancellationToken);
|
||||||
|
|
||||||
status = ProcessStatus.Success;
|
status = ProcessStatus.Success;
|
||||||
responseHeaders = JsonSerializer.Serialize(response.Headers.ToDictionary(r => r.Key, v => v.Value));
|
responseHeaders = JsonSerializer.Serialize(response.Headers.ToDictionary(r => r.Key, v => v.Value), _jsonSerializerOptions);
|
||||||
responsePayload = await response.Content.ReadAsStringAsync();
|
responsePayload = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
_log.DebugResponse(response);
|
_log.DebugResponse(response);
|
||||||
@ -82,7 +94,7 @@ public class WebhookSender
|
|||||||
_log.ErrorWithException(e);
|
_log.ErrorWithException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
await dbWorker.UpdateWebhookJournal(entry.Id, status, responsePayload, responseHeaders);
|
await dbWorker.UpdateWebhookJournal(entry.Id, status, requestHeaders, responsePayload, responseHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetSecretHash(string secretKey, string body)
|
private string GetSecretHash(string secretKey, string body)
|
||||||
|
@ -11,7 +11,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|||||||
namespace ASC.Migrations.MySql.Migrations.WebhooksDb
|
namespace ASC.Migrations.MySql.Migrations.WebhooksDb
|
||||||
{
|
{
|
||||||
[DbContext(typeof(WebhooksDbContext))]
|
[DbContext(typeof(WebhooksDbContext))]
|
||||||
[Migration("20220816111541_WebhooksDbContext_Upgrade1")]
|
[Migration("20220816154718_WebhooksDbContext_Upgrade1")]
|
||||||
partial class WebhooksDbContext_Upgrade1
|
partial class WebhooksDbContext_Upgrade1
|
||||||
{
|
{
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
@ -111,9 +111,11 @@ namespace ASC.Migrations.MySql.Migrations.WebhooksDb
|
|||||||
.HasColumnName("tenant_id");
|
.HasColumnName("tenant_id");
|
||||||
|
|
||||||
b.Property<string>("Uid")
|
b.Property<string>("Uid")
|
||||||
.HasMaxLength(50)
|
.IsRequired()
|
||||||
.HasColumnType("varchar(50)")
|
.HasColumnType("varchar(36)")
|
||||||
.HasColumnName("uid");
|
.HasColumnName("uid")
|
||||||
|
.UseCollation("utf8_general_ci")
|
||||||
|
.HasAnnotation("MySql:CharSet", "utf8");
|
||||||
|
|
||||||
b.HasKey("Id")
|
b.HasKey("Id")
|
||||||
.HasName("PRIMARY");
|
.HasName("PRIMARY");
|
@ -13,6 +13,26 @@ namespace ASC.Migrations.MySql.Migrations.WebhooksDb
|
|||||||
table: "webhooks_logs",
|
table: "webhooks_logs",
|
||||||
newName: "route");
|
newName: "route");
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "webhooks_logs",
|
||||||
|
keyColumn: "uid",
|
||||||
|
keyValue: null,
|
||||||
|
column: "uid",
|
||||||
|
value: "");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "uid",
|
||||||
|
table: "webhooks_logs",
|
||||||
|
type: "varchar(36)",
|
||||||
|
nullable: false,
|
||||||
|
collation: "utf8_general_ci",
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "varchar(50)",
|
||||||
|
oldMaxLength: 50,
|
||||||
|
oldNullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8")
|
||||||
|
.OldAnnotation("MySql:CharSet", "utf8");
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
migrationBuilder.AlterColumn<string>(
|
||||||
name: "response_payload",
|
name: "response_payload",
|
||||||
table: "webhooks_logs",
|
table: "webhooks_logs",
|
||||||
@ -56,6 +76,18 @@ namespace ASC.Migrations.MySql.Migrations.WebhooksDb
|
|||||||
table: "webhooks_logs",
|
table: "webhooks_logs",
|
||||||
newName: "event");
|
newName: "event");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "uid",
|
||||||
|
table: "webhooks_logs",
|
||||||
|
type: "varchar(50)",
|
||||||
|
maxLength: 50,
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "varchar(36)",
|
||||||
|
oldCollation: "utf8_general_ci")
|
||||||
|
.Annotation("MySql:CharSet", "utf8")
|
||||||
|
.OldAnnotation("MySql:CharSet", "utf8");
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
migrationBuilder.AlterColumn<string>(
|
||||||
name: "response_payload",
|
name: "response_payload",
|
||||||
table: "webhooks_logs",
|
table: "webhooks_logs",
|
@ -109,9 +109,11 @@ namespace ASC.Migrations.MySql.Migrations
|
|||||||
.HasColumnName("tenant_id");
|
.HasColumnName("tenant_id");
|
||||||
|
|
||||||
b.Property<string>("Uid")
|
b.Property<string>("Uid")
|
||||||
.HasMaxLength(50)
|
.IsRequired()
|
||||||
.HasColumnType("varchar(50)")
|
.HasColumnType("varchar(36)")
|
||||||
.HasColumnName("uid");
|
.HasColumnName("uid")
|
||||||
|
.UseCollation("utf8_general_ci")
|
||||||
|
.HasAnnotation("MySql:CharSet", "utf8");
|
||||||
|
|
||||||
b.HasKey("Id")
|
b.HasKey("Id")
|
||||||
.HasName("PRIMARY");
|
.HasName("PRIMARY");
|
||||||
|
@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace ASC.Migrations.PostgreSql.Migrations.WebhooksDb
|
namespace ASC.Migrations.PostgreSql.Migrations.WebhooksDb
|
||||||
{
|
{
|
||||||
[DbContext(typeof(WebhooksDbContext))]
|
[DbContext(typeof(WebhooksDbContext))]
|
||||||
[Migration("20220816111541_WebhooksDbContext_Upgrade1")]
|
[Migration("20220816154718_WebhooksDbContext_Upgrade1")]
|
||||||
partial class WebhooksDbContext_Upgrade1
|
partial class WebhooksDbContext_Upgrade1
|
||||||
{
|
{
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
@ -109,6 +109,7 @@ namespace ASC.Migrations.PostgreSql.Migrations.WebhooksDb
|
|||||||
.HasColumnName("tenant_id");
|
.HasColumnName("tenant_id");
|
||||||
|
|
||||||
b.Property<string>("Uid")
|
b.Property<string>("Uid")
|
||||||
|
.IsRequired()
|
||||||
.HasMaxLength(50)
|
.HasMaxLength(50)
|
||||||
.HasColumnType("varchar")
|
.HasColumnType("varchar")
|
||||||
.HasColumnName("uid");
|
.HasColumnName("uid");
|
@ -13,6 +13,18 @@ namespace ASC.Migrations.PostgreSql.Migrations.WebhooksDb
|
|||||||
table: "webhooks_logs",
|
table: "webhooks_logs",
|
||||||
newName: "route");
|
newName: "route");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "uid",
|
||||||
|
table: "webhooks_logs",
|
||||||
|
type: "varchar",
|
||||||
|
maxLength: 50,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "",
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "varchar",
|
||||||
|
oldMaxLength: 50,
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
migrationBuilder.AlterColumn<string>(
|
||||||
name: "response_payload",
|
name: "response_payload",
|
||||||
table: "webhooks_logs",
|
table: "webhooks_logs",
|
||||||
@ -49,6 +61,16 @@ namespace ASC.Migrations.PostgreSql.Migrations.WebhooksDb
|
|||||||
table: "webhooks_logs",
|
table: "webhooks_logs",
|
||||||
newName: "event");
|
newName: "event");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "uid",
|
||||||
|
table: "webhooks_logs",
|
||||||
|
type: "varchar",
|
||||||
|
maxLength: 50,
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "varchar",
|
||||||
|
oldMaxLength: 50);
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
migrationBuilder.AlterColumn<string>(
|
||||||
name: "response_payload",
|
name: "response_payload",
|
||||||
table: "webhooks_logs",
|
table: "webhooks_logs",
|
@ -107,6 +107,7 @@ namespace ASC.Migrations.PostgreSql.Migrations
|
|||||||
.HasColumnName("tenant_id");
|
.HasColumnName("tenant_id");
|
||||||
|
|
||||||
b.Property<string>("Uid")
|
b.Property<string>("Uid")
|
||||||
|
.IsRequired()
|
||||||
.HasMaxLength(50)
|
.HasMaxLength(50)
|
||||||
.HasColumnType("varchar")
|
.HasColumnType("varchar")
|
||||||
.HasColumnName("uid");
|
.HasColumnName("uid");
|
||||||
|
@ -28,15 +28,18 @@ namespace ASC.Web.Api.Controllers.Settings;
|
|||||||
|
|
||||||
public class WebhooksController : BaseSettingsController
|
public class WebhooksController : BaseSettingsController
|
||||||
{
|
{
|
||||||
|
private readonly PermissionContext _permissionContext;
|
||||||
private readonly DbWorker _webhookDbWorker;
|
private readonly DbWorker _webhookDbWorker;
|
||||||
|
|
||||||
public WebhooksController(
|
public WebhooksController(
|
||||||
|
PermissionContext permissionContext,
|
||||||
ApiContext apiContext,
|
ApiContext apiContext,
|
||||||
WebItemManager webItemManager,
|
WebItemManager webItemManager,
|
||||||
IMemoryCache memoryCache,
|
IMemoryCache memoryCache,
|
||||||
DbWorker dbWorker,
|
DbWorker dbWorker,
|
||||||
IHttpContextAccessor httpContextAccessor) : base(apiContext, memoryCache, webItemManager, httpContextAccessor)
|
IHttpContextAccessor httpContextAccessor) : base(apiContext, memoryCache, webItemManager, httpContextAccessor)
|
||||||
{
|
{
|
||||||
|
_permissionContext = permissionContext;
|
||||||
_webhookDbWorker = dbWorker;
|
_webhookDbWorker = dbWorker;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,65 +47,59 @@ public class WebhooksController : BaseSettingsController
|
|||||||
/// Add new config for webhooks
|
/// Add new config for webhooks
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpPost("webhook")]
|
[HttpPost("webhook")]
|
||||||
public void CreateWebhook(WebhooksConfig model)
|
public async Task<WebhooksConfigDto> CreateWebhook(WebhooksConfigRequestsDto model)
|
||||||
{
|
{
|
||||||
if (model.Uri == null)
|
_permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
|
||||||
{
|
|
||||||
throw new ArgumentNullException("Uri");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (model.SecretKey == null)
|
ArgumentNullException.ThrowIfNull(model.Uri);
|
||||||
{
|
ArgumentNullException.ThrowIfNull(model.SecretKey);
|
||||||
throw new ArgumentNullException("SecretKey");
|
|
||||||
}
|
|
||||||
|
|
||||||
_webhookDbWorker.AddWebhookConfig(model);
|
await _webhookDbWorker.AddWebhookConfig(model.Uri, model.SecretKey);
|
||||||
|
|
||||||
|
return new WebhooksConfigDto
|
||||||
|
{
|
||||||
|
Uri = model.Uri
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update config for webhooks
|
/// Update config for webhooks
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpPut("webhook")]
|
[HttpPut("webhook")]
|
||||||
public void UpdateWebhook(WebhooksConfig model)
|
public async Task<WebhooksConfigDto> UpdateWebhook(WebhooksConfigRequestsDto model)
|
||||||
{
|
{
|
||||||
if (model.Uri == null)
|
_permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
|
||||||
{
|
|
||||||
throw new ArgumentNullException("Uri");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (model.SecretKey == null)
|
ArgumentNullException.ThrowIfNull(model.Uri);
|
||||||
{
|
ArgumentNullException.ThrowIfNull(model.SecretKey);
|
||||||
throw new ArgumentNullException("SecretKey");
|
|
||||||
}
|
|
||||||
|
|
||||||
_webhookDbWorker.UpdateWebhookConfig(model);
|
await _webhookDbWorker.UpdateWebhookConfig(model.Id, model.Uri, model.SecretKey);
|
||||||
|
|
||||||
|
return new WebhooksConfigDto
|
||||||
|
{
|
||||||
|
Uri = model.Uri
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Remove config for webhooks
|
/// Remove config for webhooks
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpDelete("webhook")]
|
[HttpDelete("webhook")]
|
||||||
public void RemoveWebhook(WebhooksConfig model)
|
public async Task RemoveWebhook(int id)
|
||||||
{
|
{
|
||||||
if (model.Uri == null)
|
_permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
|
||||||
{
|
|
||||||
throw new ArgumentNullException("Uri");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (model.SecretKey == null)
|
await _webhookDbWorker.RemoveWebhookConfig(id);
|
||||||
{
|
|
||||||
throw new ArgumentNullException("SecretKey");
|
|
||||||
}
|
|
||||||
|
|
||||||
_webhookDbWorker.RemoveWebhookConfig(model);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Read Webhooks history for actual tenant
|
/// Read Webhooks history for actual tenant
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpGet("webhooks")]
|
[HttpGet("webhooks")]
|
||||||
public List<WebhooksLog> TenantWebhooks()
|
public IAsyncEnumerable<WebhooksLog> TenantWebhooks()
|
||||||
{
|
{
|
||||||
|
_permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
|
||||||
|
|
||||||
return _webhookDbWorker.GetTenantWebhooks();
|
return _webhookDbWorker.GetTenantWebhooks();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
// (c) Copyright Ascensio System SIA 2010-2022
|
||||||
|
//
|
||||||
|
// This program is a free software product.
|
||||||
|
// You can redistribute it and/or modify it under the terms
|
||||||
|
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||||
|
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||||
|
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||||
|
// any third-party rights.
|
||||||
|
//
|
||||||
|
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||||
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||||
|
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||||
|
//
|
||||||
|
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||||
|
//
|
||||||
|
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||||
|
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||||
|
//
|
||||||
|
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||||
|
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||||
|
// trademark law for use of our trademarks.
|
||||||
|
//
|
||||||
|
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||||
|
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||||
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||||
|
|
||||||
|
namespace ASC.Web.Api.ApiModels.RequestsDto;
|
||||||
|
|
||||||
|
public class WebhooksConfigRequestsDto
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Uri { get; set; }
|
||||||
|
public string SecretKey { get; set; }
|
||||||
|
}
|
32
web/ASC.Web.Api/ApiModels/ResponseDto/WebhooksConfigDto.cs
Normal file
32
web/ASC.Web.Api/ApiModels/ResponseDto/WebhooksConfigDto.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// (c) Copyright Ascensio System SIA 2010-2022
|
||||||
|
//
|
||||||
|
// This program is a free software product.
|
||||||
|
// You can redistribute it and/or modify it under the terms
|
||||||
|
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||||
|
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||||
|
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||||
|
// any third-party rights.
|
||||||
|
//
|
||||||
|
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||||
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||||
|
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||||
|
//
|
||||||
|
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||||
|
//
|
||||||
|
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||||
|
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||||
|
//
|
||||||
|
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||||
|
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||||
|
// trademark law for use of our trademarks.
|
||||||
|
//
|
||||||
|
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||||
|
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||||
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||||
|
|
||||||
|
namespace ASC.Web.Api.ApiModels.ResponseDto;
|
||||||
|
|
||||||
|
public class WebhooksConfigDto
|
||||||
|
{
|
||||||
|
public string Uri { get; set; }
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user