Browse Source

fix: fix case in reference project paths

pull/547/head
cKey 4 years ago
parent
commit
711b9e0edf
  1. 16
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks.ClientProxies/LINGYUN.Abp.WebHooks.ClientProxies.csproj
  2. 10
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks.ClientProxies/LINGYUN/Abp/WebHooks/ClientProxies/AbpWebHooksClientProxiesModule.cs
  3. 91
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks.ClientProxies/LINGYUN/Abp/WebHooks/ClientProxies/ClientProxiesWebhookPublisher.cs
  4. 3
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/FodyWeavers.xml
  5. 30
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/FodyWeavers.xsd
  6. 18
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN.Abp.WebHooks.csproj
  7. 54
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/AbpWebhooksModule.cs
  8. 35
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/AbpWebhooksOptions.cs
  9. 131
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/BackgroundWorker/WebhookSenderJob.cs
  10. 140
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/DefaultWebhookPublisher.cs
  11. 129
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/DefaultWebhookSender.cs
  12. 21
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/Extensions/WebhookSubscriptionExtensions.cs
  13. 16
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookDefinitionContext.cs
  14. 37
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookDefinitionManager.cs
  15. 18
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookEventStore.cs
  16. 22
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookManager.cs
  17. 56
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookPublisher.cs
  18. 25
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookSendAttemptStore.cs
  19. 16
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookSender.cs
  20. 74
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookSubscriptionManager.cs
  21. 83
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookSubscriptionsStore.cs
  22. 24
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/NullWebhookEventStore.cs
  23. 47
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/NullWebhookSendAttemptStore.cs
  24. 65
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/NullWebhookSubscriptionsStore.cs
  25. 67
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookDefinition.cs
  26. 55
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookDefinitionContext.cs
  27. 139
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookDefinitionManager.cs
  28. 13
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookDefinitionProvider.cs
  29. 30
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookEvent.cs
  30. 101
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookGroupDefinition.cs
  31. 18
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookHeader.cs
  32. 80
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookManager.cs
  33. 35
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookPayload.cs
  34. 39
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookSendAttempt.cs
  35. 62
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookSenderArgs.cs
  36. 60
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookSubscriptionInfo.cs
  37. 172
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookSubscriptionManager.cs
  38. 13
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/System/AbpStringCryptographyExtensions.cs

16
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks.ClientProxies/LINGYUN.Abp.WebHooks.ClientProxies.csproj

@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.WebhooksManagement.HttpApi.Client\LINGYUN.Abp.WebhooksManagement.HttpApi.Client.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.Webhooks\LINGYUN.Abp.Webhooks.csproj" />
</ItemGroup>
</Project>

10
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks.ClientProxies/LINGYUN/Abp/WebHooks/ClientProxies/AbpWebHooksClientProxiesModule.cs

@ -1,10 +0,0 @@
using LINGYUN.Abp.WebhooksManagement;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Webhooks.ClientProxies;
[DependsOn(typeof(AbpWebhooksModule))]
[DependsOn(typeof(WebhooksManagementHttpApiClientModule))]
public class AbpWebHooksClientProxiesModule : AbpModule
{
}

91
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks.ClientProxies/LINGYUN/Abp/WebHooks/ClientProxies/ClientProxiesWebhookPublisher.cs

@ -1,91 +0,0 @@
using LINGYUN.Abp.WebhooksManagement;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.Webhooks.ClientProxies;
[Dependency(ReplaceServices = true)]
public class ClientProxiesWebhookPublisher : IWebhookPublisher, ITransientDependency
{
protected IWebhookPublishAppService PublishAppService { get; }
public ClientProxiesWebhookPublisher(
IWebhookPublishAppService publishAppService)
{
PublishAppService = publishAppService;
}
public async virtual Task PublishAsync(string webhookName, object data, bool sendExactSameData = false, WebhookHeader headers = null)
{
var input = new WebhookPublishInput
{
WebhookName = webhookName,
Data = JsonConvert.SerializeObject(data),
SendExactSameData = sendExactSameData,
};
if (headers != null)
{
input.Header = new WebhooksHeaderInput
{
UseOnlyGivenHeaders = headers.UseOnlyGivenHeaders,
Headers = headers.Headers
};
}
await PublishAsync(input);
}
public async virtual Task PublishAsync(string webhookName, object data, Guid? tenantId, bool sendExactSameData = false, WebhookHeader headers = null)
{
var input = new WebhookPublishInput
{
WebhookName = webhookName,
Data = JsonConvert.SerializeObject(data),
SendExactSameData = sendExactSameData,
TenantIds = new List<Guid?>
{
tenantId
},
};
if (headers != null)
{
input.Header = new WebhooksHeaderInput
{
UseOnlyGivenHeaders = headers.UseOnlyGivenHeaders,
Headers = headers.Headers
};
}
await PublishAsync(input);
}
public async virtual Task PublishAsync(Guid?[] tenantIds, string webhookName, object data, bool sendExactSameData = false, WebhookHeader headers = null)
{
var input = new WebhookPublishInput
{
WebhookName = webhookName,
Data = JsonConvert.SerializeObject(data),
SendExactSameData = sendExactSameData,
TenantIds = tenantIds.ToList(),
};
if (headers != null)
{
input.Header = new WebhooksHeaderInput
{
UseOnlyGivenHeaders = headers.UseOnlyGivenHeaders,
Headers = headers.Headers
};
}
await PublishAsync(input);
}
protected virtual async Task PublishAsync(WebhookPublishInput input)
{
await PublishAppService.PublishAsync(input);
}
}

3
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/FodyWeavers.xml

@ -1,3 +0,0 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/FodyWeavers.xsd

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

18
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN.Abp.WebHooks.csproj

@ -1,18 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.BackgroundJobs" Version="$(VoloAbpPackageVersion)" />
<PackageReference Include="Volo.Abp.Features" Version="$(VoloAbpPackageVersion)" />
<PackageReference Include="Volo.Abp.Guids" Version="$(VoloAbpPackageVersion)" />
<PackageReference Include="Volo.Abp.Http.Client" Version="$(VoloAbpPackageVersion)" />
</ItemGroup>
</Project>

54
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/AbpWebhooksModule.cs

@ -1,54 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.Features;
using Volo.Abp.Guids;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Webhooks;
//[DependsOn(typeof(AbpBackgroundJobsAbstractionsModule))]
// 防止未引用实现无法发布到后台作业
[DependsOn(typeof(AbpBackgroundJobsModule))]
[DependsOn(typeof(AbpFeaturesModule))]
[DependsOn(typeof(AbpGuidsModule))]
[DependsOn(typeof(AbpHttpClientModule))]
public class AbpWebhooksModule : AbpModule
{
internal const string WebhooksClient = "__Abp_Webhooks_HttpClient";
public override void PreConfigureServices(ServiceConfigurationContext context)
{
AutoAddDefinitionProviders(context.Services);
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var options = context.Services.ExecutePreConfiguredActions<AbpWebhooksOptions>();
context.Services.AddHttpClient(WebhooksClient, client =>
{
client.Timeout = options.TimeoutDuration;
});
}
private static void AutoAddDefinitionProviders(IServiceCollection services)
{
var definitionProviders = new List<Type>();
services.OnRegistred(context =>
{
if (typeof(WebhookDefinitionProvider).IsAssignableFrom(context.ImplementationType))
{
definitionProviders.Add(context.ImplementationType);
}
});
services.Configure<AbpWebhooksOptions>(options =>
{
options.DefinitionProviders.AddIfNotContains(definitionProviders);
});
}
}

35
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/AbpWebhooksOptions.cs

@ -1,35 +0,0 @@
using System;
using Volo.Abp.Collections;
namespace LINGYUN.Abp.Webhooks;
public class AbpWebhooksOptions
{
/// <summary>
/// 默认超时时间
/// </summary>
public TimeSpan TimeoutDuration { get; set; }
/// <summary>
/// 默认最大发送次数
/// </summary>
public int MaxSendAttemptCount { get; set; }
/// <summary>
/// 是否达到最大连续失败次数时自动取消订阅
/// </summary>
public bool IsAutomaticSubscriptionDeactivationEnabled { get; set; }
/// <summary>
/// 取消订阅前最大连续失败次数
/// </summary>
public int MaxConsecutiveFailCountBeforeDeactivateSubscription { get; set; }
public ITypeList<WebhookDefinitionProvider> DefinitionProviders { get; }
public AbpWebhooksOptions()
{
TimeoutDuration = TimeSpan.FromSeconds(60);
MaxSendAttemptCount = 5;
MaxConsecutiveFailCountBeforeDeactivateSubscription = MaxSendAttemptCount * 3;
DefinitionProviders = new TypeList<WebhookDefinitionProvider>();
}
}

131
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/BackgroundWorker/WebhookSenderJob.cs

@ -1,131 +0,0 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace LINGYUN.Abp.Webhooks.BackgroundWorker
{
public class WebhookSenderJob : AsyncBackgroundJob<WebhookSenderArgs>, ITransientDependency
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IWebhookDefinitionManager _webhookDefinitionManager;
private readonly IWebhookSubscriptionManager _webhookSubscriptionManager;
private readonly IWebhookSendAttemptStore _webhookSendAttemptStore;
private readonly IWebhookSender _webhookSender;
private readonly AbpWebhooksOptions _options;
public WebhookSenderJob(
IUnitOfWorkManager unitOfWorkManager,
IWebhookDefinitionManager webhookDefinitionManager,
IWebhookSubscriptionManager webhookSubscriptionManager,
IWebhookSendAttemptStore webhookSendAttemptStore,
IWebhookSender webhookSender,
IOptions<AbpWebhooksOptions> options)
{
_unitOfWorkManager = unitOfWorkManager;
_webhookDefinitionManager = webhookDefinitionManager;
_webhookSubscriptionManager = webhookSubscriptionManager;
_webhookSendAttemptStore = webhookSendAttemptStore;
_webhookSender = webhookSender;
_options = options.Value;
}
public override async Task ExecuteAsync(WebhookSenderArgs args)
{
var webhookDefinition = _webhookDefinitionManager.Get(args.WebhookName);
if (webhookDefinition.TryOnce)
{
try
{
await SendWebhook(args, webhookDefinition);
}
catch (Exception e)
{
Logger.LogWarning("An error occured while sending webhook with try once.", e);
// ignored
}
}
else
{
await SendWebhook(args, webhookDefinition);
}
}
private async Task SendWebhook(WebhookSenderArgs args, WebhookDefinition webhookDefinition)
{
if (args.WebhookEventId == default)
{
return;
}
if (args.WebhookSubscriptionId == default)
{
return;
}
if (!webhookDefinition.TryOnce)
{
var sendAttemptCount = await _webhookSendAttemptStore.GetSendAttemptCountAsync(
args.TenantId,
args.WebhookEventId,
args.WebhookSubscriptionId
);
if ((webhookDefinition.MaxSendAttemptCount > 0 && sendAttemptCount > webhookDefinition.MaxSendAttemptCount) ||
sendAttemptCount > _options.MaxSendAttemptCount)
{
return;
}
}
try
{
await _webhookSender.SendWebhookAsync(args);
}
catch (Exception)
{
// no need to retry to send webhook since subscription disabled
if (!await TryDeactivateSubscriptionIfReachedMaxConsecutiveFailCount(
args.TenantId,
args.WebhookSubscriptionId))
{
throw; //Throw exception to re-try sending webhook
}
}
}
private async Task<bool> TryDeactivateSubscriptionIfReachedMaxConsecutiveFailCount(
Guid? tenantId,
Guid subscriptionId)
{
if (!_options.IsAutomaticSubscriptionDeactivationEnabled)
{
return false;
}
var hasXConsecutiveFail = await _webhookSendAttemptStore
.HasXConsecutiveFailAsync(
tenantId,
subscriptionId,
_options.MaxConsecutiveFailCountBeforeDeactivateSubscription
);
if (!hasXConsecutiveFail)
{
return false;
}
using (var uow = _unitOfWorkManager.Begin())
{
await _webhookSubscriptionManager.ActivateWebhookSubscriptionAsync(subscriptionId, false);
await uow.CompleteAsync();
return true;
}
}
}
}

140
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/DefaultWebhookPublisher.cs

@ -1,140 +0,0 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.Webhooks
{
public class DefaultWebhookPublisher : IWebhookPublisher, ITransientDependency
{
public IWebhookEventStore WebhookEventStore { get; set; }
private readonly ICurrentTenant _currentTenant;
private readonly IBackgroundJobManager _backgroundJobManager;
private readonly IWebhookSubscriptionManager _webhookSubscriptionManager;
public DefaultWebhookPublisher(
IWebhookSubscriptionManager webhookSubscriptionManager,
ICurrentTenant currentTenant,
IBackgroundJobManager backgroundJobManager)
{
_currentTenant = currentTenant;
_backgroundJobManager = backgroundJobManager;
_webhookSubscriptionManager = webhookSubscriptionManager;
WebhookEventStore = NullWebhookEventStore.Instance;
}
#region Async Publish Methods
public virtual async Task PublishAsync(
string webhookName,
object data,
bool sendExactSameData = false,
WebhookHeader headers = null)
{
var subscriptions = await _webhookSubscriptionManager.GetAllSubscriptionsIfFeaturesGrantedAsync(_currentTenant.Id, webhookName);
await PublishAsync(webhookName, data, subscriptions, sendExactSameData, headers);
}
public virtual async Task PublishAsync(
string webhookName,
object data,
Guid? tenantId,
bool sendExactSameData = false,
WebhookHeader headers = null)
{
var subscriptions = await _webhookSubscriptionManager.GetAllSubscriptionsIfFeaturesGrantedAsync(tenantId, webhookName);
await PublishAsync(webhookName, data, subscriptions, sendExactSameData, headers);
}
public virtual async Task PublishAsync(
Guid?[] tenantIds,
string webhookName,
object data,
bool sendExactSameData = false,
WebhookHeader headers = null)
{
var subscriptions = await _webhookSubscriptionManager.GetAllSubscriptionsOfTenantsIfFeaturesGrantedAsync(tenantIds, webhookName);
await PublishAsync(webhookName, data, subscriptions, sendExactSameData, headers);
}
protected virtual async Task PublishAsync(
string webhookName,
object data,
List<WebhookSubscriptionInfo> webhookSubscriptions,
bool sendExactSameData = false,
WebhookHeader headers = null)
{
if (webhookSubscriptions.IsNullOrEmpty())
{
return;
}
var subscriptionsGroupedByTenant = webhookSubscriptions.GroupBy(x => x.TenantId);
foreach (var subscriptionGroupedByTenant in subscriptionsGroupedByTenant)
{
var webhookInfo = await SaveAndGetWebhookAsync(subscriptionGroupedByTenant.Key, webhookName, data);
foreach (var webhookSubscription in subscriptionGroupedByTenant)
{
var headersToSend = webhookSubscription.Headers;
if (headers != null)
{
if (headers.UseOnlyGivenHeaders)//do not use the headers defined in subscription
{
headersToSend = headers.Headers;
}
else
{
//use the headers defined in subscription. If additional headers has same header, use additional headers value.
foreach (var additionalHeader in headers.Headers)
{
headersToSend[additionalHeader.Key] = additionalHeader.Value;
}
}
}
await _backgroundJobManager.EnqueueAsync(new WebhookSenderArgs
{
TenantId = webhookSubscription.TenantId,
WebhookEventId = webhookInfo.Id,
Data = webhookInfo.Data,
WebhookName = webhookInfo.WebhookName,
WebhookSubscriptionId = webhookSubscription.Id,
Headers = headersToSend,
Secret = webhookSubscription.Secret,
WebhookUri = webhookSubscription.WebhookUri,
SendExactSameData = sendExactSameData
});
}
}
}
#endregion
protected virtual async Task<WebhookEvent> SaveAndGetWebhookAsync(
Guid? tenantId,
string webhookName,
object data)
{
var webhookInfo = new WebhookEvent
{
WebhookName = webhookName,
Data = JsonConvert.SerializeObject(data),
TenantId = tenantId
};
var webhookId = await WebhookEventStore.InsertAndGetIdAsync(webhookInfo);
webhookInfo.Id = webhookId;
return webhookInfo;
}
}
}

129
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/DefaultWebhookSender.cs

@ -1,129 +0,0 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.Webhooks
{
public class DefaultWebhookSender : IWebhookSender, ITransientDependency
{
public ILogger<DefaultWebhookSender> Logger { protected get; set; }
private readonly IWebhookManager _webhookManager;
private readonly IHttpClientFactory _httpClientFactory;
private const string FailedRequestDefaultContent = "Webhook Send Request Failed";
public DefaultWebhookSender(
IWebhookManager webhookManager,
IHttpClientFactory httpClientFactory)
{
_webhookManager = webhookManager;
_httpClientFactory = httpClientFactory;
Logger = NullLogger<DefaultWebhookSender>.Instance;
}
public async Task<Guid> SendWebhookAsync(WebhookSenderArgs webhookSenderArgs)
{
if (webhookSenderArgs.WebhookEventId == default)
{
throw new ArgumentNullException(nameof(webhookSenderArgs.WebhookEventId));
}
if (webhookSenderArgs.WebhookSubscriptionId == default)
{
throw new ArgumentNullException(nameof(webhookSenderArgs.WebhookSubscriptionId));
}
var webhookSendAttemptId = await _webhookManager.InsertAndGetIdWebhookSendAttemptAsync(webhookSenderArgs);
var request = CreateWebhookRequestMessage(webhookSenderArgs);
var serializedBody = await _webhookManager.GetSerializedBodyAsync(webhookSenderArgs);
_webhookManager.SignWebhookRequest(request, serializedBody, webhookSenderArgs.Secret);
AddAdditionalHeaders(request, webhookSenderArgs);
var isSucceed = false;
HttpStatusCode? statusCode = null;
var content = FailedRequestDefaultContent;
try
{
var response = await SendHttpRequest(request);
isSucceed = response.isSucceed;
statusCode = response.statusCode;
content = response.content;
}
catch (TaskCanceledException)
{
statusCode = HttpStatusCode.RequestTimeout;
content = "Request Timeout";
}
catch (HttpRequestException e)
{
content = e.Message;
}
catch (Exception e)
{
Logger.LogError("An error occured while sending a webhook request", e);
}
finally
{
await _webhookManager.StoreResponseOnWebhookSendAttemptAsync(webhookSendAttemptId, webhookSenderArgs.TenantId, statusCode, content);
}
if (!isSucceed)
{
throw new Exception($"Webhook sending attempt failed. WebhookSendAttempt id: {webhookSendAttemptId}");
}
return webhookSendAttemptId;
}
/// <summary>
/// You can override this to change request message
/// </summary>
/// <returns></returns>
protected virtual HttpRequestMessage CreateWebhookRequestMessage(WebhookSenderArgs webhookSenderArgs)
{
return new HttpRequestMessage(HttpMethod.Post, webhookSenderArgs.WebhookUri);
}
protected virtual void AddAdditionalHeaders(HttpRequestMessage request, WebhookSenderArgs webhookSenderArgs)
{
foreach (var header in webhookSenderArgs.Headers)
{
if (request.Headers.TryAddWithoutValidation(header.Key, header.Value))
{
continue;
}
if (request.Content.Headers.TryAddWithoutValidation(header.Key, header.Value))
{
continue;
}
throw new Exception($"Invalid Header. SubscriptionId:{webhookSenderArgs.WebhookSubscriptionId},Header: {header.Key}:{header.Value}");
}
}
protected virtual async Task<(bool isSucceed, HttpStatusCode statusCode, string content)> SendHttpRequest(HttpRequestMessage request)
{
var client = _httpClientFactory.CreateClient(AbpWebhooksModule.WebhooksClient);
var response = await client.SendAsync(request);
var isSucceed = response.IsSuccessStatusCode;
var statusCode = response.StatusCode;
var content = await response.Content.ReadAsStringAsync();
return (isSucceed, statusCode, content);
}
}
}

21
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/Extensions/WebhookSubscriptionExtensions.cs

@ -1,21 +0,0 @@
using System.Collections.Generic;
namespace LINGYUN.Abp.Webhooks.Extensions
{
public static class WebhookSubscriptionExtensions
{
/// <summary>
/// checks if subscribed to given webhook
/// </summary>
/// <returns></returns>
public static bool IsSubscribed(this WebhookSubscriptionInfo webhookSubscription, string webhookName)
{
if (webhookSubscription.Webhooks.IsNullOrEmpty())
{
return false;
}
return webhookSubscription.Webhooks.Contains(webhookName);
}
}
}

16
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookDefinitionContext.cs

@ -1,16 +0,0 @@
using JetBrains.Annotations;
using Volo.Abp.Localization;
namespace LINGYUN.Abp.Webhooks
{
public interface IWebhookDefinitionContext
{
WebhookGroupDefinition AddGroup(
[NotNull] string name,
ILocalizableString displayName = null);
WebhookGroupDefinition GetGroupOrNull(string name);
void RemoveGroup(string name);
}
}

37
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookDefinitionManager.cs

@ -1,37 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Webhooks
{
public interface IWebhookDefinitionManager
{
/// <summary>
/// Gets a webhook definition by name.
/// Returns null if there is no webhook definition with given name.
/// </summary>
WebhookDefinition GetOrNull(string name);
/// <summary>
/// Gets a webhook definition by name.
/// Throws exception if there is no webhook definition with given name.
/// </summary>
WebhookDefinition Get(string name);
/// <summary>
/// Gets all webhook definitions.
/// </summary>
IReadOnlyList<WebhookDefinition> GetAll();
/// <summary>
/// Gets all webhook group definitions.
/// </summary>
/// <returns></returns>
IReadOnlyList<WebhookGroupDefinition> GetGroups();
/// <summary>
/// Checks if given webhook name is available for given tenant.
/// </summary>
Task<bool> IsAvailableAsync(Guid? tenantId, string name);
}
}

18
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookEventStore.cs

@ -1,18 +0,0 @@
using System;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Webhooks
{
public interface IWebhookEventStore
{
/// <summary>
/// Inserts to persistent store
/// </summary>
Task<Guid> InsertAndGetIdAsync(WebhookEvent webhookEvent);
/// <summary>
/// Gets Webhook info by id
/// </summary>
Task<WebhookEvent> GetAsync(Guid? tenantId, Guid id);
}
}

22
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookManager.cs

@ -1,22 +0,0 @@
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Webhooks
{
public interface IWebhookManager
{
Task<WebhookPayload> GetWebhookPayloadAsync(WebhookSenderArgs webhookSenderArgs);
void SignWebhookRequest(HttpRequestMessage request, string serializedBody, string secret);
Task<string> GetSerializedBodyAsync(WebhookSenderArgs webhookSenderArgs);
Task<Guid> InsertAndGetIdWebhookSendAttemptAsync(WebhookSenderArgs webhookSenderArgs);
Task StoreResponseOnWebhookSendAttemptAsync(
Guid webhookSendAttemptId, Guid? tenantId,
HttpStatusCode? statusCode, string content);
}
}

56
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookPublisher.cs

@ -1,56 +0,0 @@
using System;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Webhooks
{
public interface IWebhookPublisher
{
/// <summary>
/// Sends webhooks to current tenant subscriptions (<see cref="IAbpSession.TenantId"/>). with given data, (Checks permissions)
/// </summary>
/// <param name="webhookName"><see cref="WebhookDefinition.Name"/></param>
/// <param name="data">data to send</param>
/// <param name="sendExactSameData">
/// True: It sends the exact same data as the parameter to clients.
/// <para>
/// False: It sends data in <see cref="WebhookPayload"/>. It is recommended way.
/// </para>
/// </param>
/// <param name="headers">Headers to send. Publisher uses subscription defined webhook by default. You can add additional headers from here. If subscription already has given header, publisher uses the one you give here.</param>
Task PublishAsync(string webhookName, object data, bool sendExactSameData = false, WebhookHeader headers = null);
/// <summary>
/// Sends webhooks to given tenant's subscriptions
/// </summary>
/// <param name="webhookName"><see cref="WebhookDefinition.Name"/></param>
/// <param name="data">data to send</param>
/// <param name="tenantId">
/// Target tenant id
/// </param>
/// <param name="sendExactSameData">
/// True: It sends the exact same data as the parameter to clients.
/// <para>
/// False: It sends data in <see cref="WebhookPayload"/>. It is recommended way.
/// </para>
/// </param>
/// <param name="headers">Headers to send. Publisher uses subscription defined webhook by default. You can add additional headers from here. If subscription already has given header, publisher uses the one you give here.</param>
Task PublishAsync(string webhookName, object data, Guid? tenantId, bool sendExactSameData = false, WebhookHeader headers = null);
/// <summary>
/// Sends webhooks to given tenant's subscriptions
/// </summary>
/// <param name="webhookName"><see cref="WebhookDefinition.Name"/></param>
/// <param name="data">data to send</param>
/// <param name="tenantIds">
/// Target tenant id(s)
/// </param>
/// <param name="sendExactSameData">
/// True: It sends the exact same data as the parameter to clients.
/// <para>
/// False: It sends data in <see cref="WebhookPayload"/>. It is recommended way.
/// </para>
/// </param>
/// <param name="headers">Headers to send. Publisher uses subscription defined webhook by default. You can add additional headers from here. If subscription already has given header, publisher uses the one you give here.</param>
Task PublishAsync(Guid?[] tenantIds, string webhookName, object data, bool sendExactSameData = false, WebhookHeader headers = null);
}
}

25
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookSendAttemptStore.cs

@ -1,25 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Webhooks
{
public interface IWebhookSendAttemptStore
{
Task<WebhookSendAttempt> GetAsync(Guid? tenantId, Guid id);
/// <summary>
/// Returns work item count by given web hook id and subscription id, (How many times publisher tried to send web hook)
/// </summary>
Task<int> GetSendAttemptCountAsync(Guid? tenantId, Guid webhookId, Guid webhookSubscriptionId);
/// <summary>
/// Checks is there any successful webhook attempt in last <paramref name="searchCount"/> items. Should return true if there are not X number items
/// </summary>
Task<bool> HasXConsecutiveFailAsync(Guid? tenantId, Guid subscriptionId, int searchCount);
Task<(int TotalCount, IReadOnlyCollection<WebhookSendAttempt> Webhooks)> GetAllSendAttemptsBySubscriptionAsPagedListAsync(Guid? tenantId, Guid subscriptionId, int maxResultCount, int skipCount);
Task<List<WebhookSendAttempt>> GetAllSendAttemptsByWebhookEventIdAsync(Guid? tenantId, Guid webhookEventId);
}
}

16
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookSender.cs

@ -1,16 +0,0 @@
using System;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Webhooks
{
public interface IWebhookSender
{
/// <summary>
/// Tries to send webhook with given transactionId and stores process in <see cref="WebhookSendAttempt"/>
/// Should throw exception if fails or response status not succeed
/// </summary>
/// <param name="webhookSenderArgs">arguments</param>
/// <returns>Webhook send attempt id</returns>
Task<Guid> SendWebhookAsync(WebhookSenderArgs webhookSenderArgs);
}
}

74
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookSubscriptionManager.cs

@ -1,74 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Webhooks
{
public interface IWebhookSubscriptionManager
{
/// <summary>
/// Returns subscription for given id.
/// </summary>
/// <param name="id">Unique identifier of <see cref="WebhookSubscriptionInfo"/></param>
Task<WebhookSubscriptionInfo> GetAsync(Guid id);
/// <summary>
/// Returns all subscriptions of tenant
/// </summary>
/// <param name="tenantId">
/// Target tenant id.
/// </param>
Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsAsync(Guid? tenantId);
/// <summary>
/// Returns all subscriptions for given webhook.
/// </summary>
/// <param name="webhookName"><see cref="WebhookDefinition.Name"/></param>
/// <param name="tenantId">
/// Target tenant id.
/// </param>
Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsIfFeaturesGrantedAsync(Guid? tenantId, string webhookName);
/// <summary>
/// Returns all subscriptions of tenant
/// </summary>
/// <returns></returns>
Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsOfTenantsAsync(Guid?[] tenantIds);
/// <summary>
/// Returns all subscriptions for given webhook.
/// </summary>
/// <param name="webhookName"><see cref="WebhookDefinition.Name"/></param>
/// <param name="tenantIds">
/// Target tenant id(s).
/// </param>
Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsOfTenantsIfFeaturesGrantedAsync(Guid?[] tenantIds, string webhookName);
/// <summary>
/// Checks if tenant subscribed for a webhook. (Checks if webhook features are granted)
/// </summary>
/// <param name="tenantId">
/// Target tenant id(s).
/// </param>
/// <param name="webhookName"><see cref="WebhookDefinition.Name"/></param>
Task<bool> IsSubscribedAsync(Guid? tenantId, string webhookName);
/// <summary>
/// If id is the default(Guid) adds new subscription, else updates current one. (Checks if webhook features are granted)
/// </summary>
Task AddOrUpdateSubscriptionAsync(WebhookSubscriptionInfo webhookSubscription);
/// <summary>
/// Activates/Deactivates given webhook subscription
/// </summary>
/// <param name="id">unique identifier of <see cref="WebhookSubscriptionInfo"/></param>
/// <param name="active">IsActive</param>
Task ActivateWebhookSubscriptionAsync(Guid id, bool active);
/// <summary>
/// Delete given webhook subscription.
/// </summary>
/// <param name="id">unique identifier of <see cref="WebhookSubscriptionInfo"/></param>
Task DeleteSubscriptionAsync(Guid id);
}
}

83
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/IWebhookSubscriptionsStore.cs

@ -1,83 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Webhooks
{
/// <summary>
/// This interface should be implemented by vendors to make webhooks working.
/// </summary>
public interface IWebhookSubscriptionsStore
{
/// <summary>
/// returns subscription
/// </summary>
/// <param name="id">webhook subscription id</param>
/// <returns></returns>
Task<WebhookSubscriptionInfo> GetAsync(Guid id);
/// <summary>
/// Saves webhook subscription to a persistent store.
/// </summary>
/// <param name="webhookSubscription">webhook subscription information</param>
Task InsertAsync(WebhookSubscriptionInfo webhookSubscription);
/// <summary>
/// Updates webhook subscription to a persistent store.
/// </summary>
/// <param name="webhookSubscription">webhook subscription information</param>
Task UpdateAsync(WebhookSubscriptionInfo webhookSubscription);
/// <summary>
/// Deletes subscription if exists
/// </summary>
/// <param name="id"><see cref="WebhookSubscriptionInfo"/> primary key</param>
/// <returns></returns>
Task DeleteAsync(Guid id);
/// <summary>
/// Returns all subscriptions of given tenant including deactivated
/// </summary>
/// <param name="tenantId">
/// Target tenant id.
/// </param>
Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsAsync(Guid? tenantId);
/// <summary>
/// Returns webhook subscriptions which subscribe to given webhook on tenant(s)
/// </summary>
/// <param name="tenantId">
/// Target tenant id.
/// </param>
/// <param name="webhookName"><see cref="WebhookDefinition.Name"/></param>
/// <returns></returns>
Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsAsync(Guid? tenantId, string webhookName);
/// <summary>
/// Returns all subscriptions of given tenant including deactivated
/// </summary>
/// <param name="tenantIds">
/// Target tenant id(s).
/// </param>
Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsOfTenantsAsync(Guid?[] tenantIds);
/// <summary>
/// Returns webhook subscriptions which subscribe to given webhook on tenant(s)
/// </summary>
/// <param name="tenantIds">
/// Target tenant id(s).
/// </param>
/// <param name="webhookName"><see cref="WebhookDefinition.Name"/></param>
/// <returns></returns>
Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsOfTenantsAsync(Guid?[] tenantIds, string webhookName);
/// <summary>
/// Checks if tenant subscribed for a webhook
/// </summary>
/// <param name="tenantId">
/// Target tenant id(s).
/// </param>
/// <param name="webhookName">Name of the webhook</param>
Task<bool> IsSubscribedAsync(Guid? tenantId, string webhookName);
}
}

24
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/NullWebhookEventStore.cs

@ -1,24 +0,0 @@
using System;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Webhooks
{
/// <summary>
/// Null pattern implementation of <see cref="IWebhookSubscriptionsStore"/>.
/// It's used if <see cref="IWebhookSubscriptionsStore"/> is not implemented by actual persistent store
/// </summary>
public class NullWebhookEventStore : IWebhookEventStore
{
public static NullWebhookEventStore Instance { get; } = new NullWebhookEventStore();
public Task<Guid> InsertAndGetIdAsync(WebhookEvent webhookEvent)
{
return Task.FromResult<Guid>(default);
}
public Task<WebhookEvent> GetAsync(Guid? tenantId, Guid id)
{
return Task.FromResult<WebhookEvent>(default);
}
}
}

47
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/NullWebhookSendAttemptStore.cs

@ -1,47 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Webhooks
{
public class NullWebhookSendAttemptStore : IWebhookSendAttemptStore
{
public static NullWebhookSendAttemptStore Instance = new NullWebhookSendAttemptStore();
public Task InsertAsync(WebhookSendAttempt webhookSendAttempt)
{
return Task.CompletedTask;
}
public Task UpdateAsync(WebhookSendAttempt webhookSendAttempt)
{
return Task.CompletedTask;
}
public Task<WebhookSendAttempt> GetAsync(Guid? tenantId, Guid id)
{
return Task.FromResult<WebhookSendAttempt>(default);
}
public Task<int> GetSendAttemptCountAsync(Guid? tenantId, Guid webhookId, Guid webhookSubscriptionId)
{
return Task.FromResult(int.MaxValue);
}
public Task<bool> HasXConsecutiveFailAsync(Guid? tenantId, Guid subscriptionId, int searchCount)
{
return default;
}
public Task<(int TotalCount, IReadOnlyCollection<WebhookSendAttempt> Webhooks)> GetAllSendAttemptsBySubscriptionAsPagedListAsync(Guid? tenantId, Guid subscriptionId, int maxResultCount,
int skipCount)
{
return Task.FromResult(ValueTuple.Create(0, new List<WebhookSendAttempt>() as IReadOnlyCollection<WebhookSendAttempt>));
}
public Task<List<WebhookSendAttempt>> GetAllSendAttemptsByWebhookEventIdAsync(Guid? tenantId, Guid webhookEventId)
{
return Task.FromResult(new List<WebhookSendAttempt>());
}
}
}

65
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/NullWebhookSubscriptionsStore.cs

@ -1,65 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Webhooks
{
/// <summary>
/// Null pattern implementation of <see cref="IWebhookSubscriptionsStore"/>.
/// It's used if <see cref="IWebhookSubscriptionsStore"/> is not implemented by actual persistent store
/// </summary>
public class NullWebhookSubscriptionsStore : IWebhookSubscriptionsStore
{
public static NullWebhookSubscriptionsStore Instance { get; } = new NullWebhookSubscriptionsStore();
public Task<WebhookSubscriptionInfo> GetAsync(Guid id)
{
return Task.FromResult<WebhookSubscriptionInfo>(default);
}
public WebhookSubscriptionInfo Get(Guid id)
{
return default;
}
public Task InsertAsync(WebhookSubscriptionInfo webhookSubscription)
{
return Task.CompletedTask;
}
public Task UpdateAsync(WebhookSubscriptionInfo webhookSubscription)
{
return Task.CompletedTask;
}
public Task DeleteAsync(Guid id)
{
return Task.CompletedTask;
}
public Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsAsync(Guid? tenantId)
{
return Task.FromResult(new List<WebhookSubscriptionInfo>());
}
public Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsAsync(Guid? tenantId, string webhookName)
{
return Task.FromResult(new List<WebhookSubscriptionInfo>());
}
public Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsOfTenantsAsync(Guid?[] tenantIds)
{
return Task.FromResult(new List<WebhookSubscriptionInfo>());
}
public Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsOfTenantsAsync(Guid?[] tenantIds, string webhookName)
{
return Task.FromResult(new List<WebhookSubscriptionInfo>());
}
public Task<bool> IsSubscribedAsync(Guid? tenantId, string webhookName)
{
return Task.FromResult(false);
}
}
}

67
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookDefinition.cs

@ -1,67 +0,0 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Localization;
namespace LINGYUN.Abp.Webhooks
{
public class WebhookDefinition
{
/// <summary>
/// Unique name of the webhook.
/// </summary>
public string Name { get; }
/// <summary>
/// Tries to send webhook only one time without checking to send attempt count
/// </summary>
public bool TryOnce { get; set; }
/// <summary>
/// Defined maximum number of sending times
/// </summary>
public int MaxSendAttemptCount { get; set; }
/// <summary>
/// Display name of the webhook.
/// Optional.
/// </summary>
public ILocalizableString DisplayName { get; set; }
/// <summary>
/// Description for the webhook.
/// Optional.
/// </summary>
public ILocalizableString Description { get; set; }
public List<string> RequiredFeatures { get; set; }
public WebhookDefinition(string name, ILocalizableString displayName = null, ILocalizableString description = null)
{
if (name.IsNullOrWhiteSpace())
{
throw new ArgumentNullException(nameof(name), $"{nameof(name)} can not be null, empty or whitespace!");
}
Name = name.Trim();
DisplayName = displayName;
Description = description;
RequiredFeatures = new List<string>();
}
public WebhookDefinition WithFeature(params string[] features)
{
if (!features.IsNullOrEmpty())
{
RequiredFeatures.AddRange(features);
}
return this;
}
public override string ToString()
{
return $"[{nameof(WebhookDefinition)} {Name}]";
}
}
}

55
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookDefinitionContext.cs

@ -1,55 +0,0 @@
using JetBrains.Annotations;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Localization;
namespace LINGYUN.Abp.Webhooks
{
public class WebhookDefinitionContext : IWebhookDefinitionContext
{
protected Dictionary<string, WebhookGroupDefinition> Groups { get; }
public WebhookDefinitionContext(Dictionary<string, WebhookGroupDefinition> webhooks)
{
Groups = webhooks;
}
public WebhookGroupDefinition AddGroup(
[NotNull] string name,
ILocalizableString displayName = null)
{
Check.NotNull(name, nameof(name));
if (Groups.ContainsKey(name))
{
throw new AbpException($"There is already an existing webhook group with name: {name}");
}
return Groups[name] = new WebhookGroupDefinition(name, displayName);
}
public WebhookGroupDefinition GetGroupOrNull([NotNull] string name)
{
Check.NotNull(name, nameof(name));
if (!Groups.ContainsKey(name))
{
return null;
}
return Groups[name];
}
public void RemoveGroup(string name)
{
Check.NotNull(name, nameof(name));
if (!Groups.ContainsKey(name))
{
throw new AbpException($"Undefined notification webhook group: '{name}'.");
}
Groups.Remove(name);
}
}
}

139
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookDefinitionManager.cs

@ -1,139 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.Webhooks
{
internal class WebhookDefinitionManager : IWebhookDefinitionManager, ISingletonDependency
{
protected IDictionary<string, WebhookGroupDefinition> WebhookGroupDefinitions => _lazyWebhookGroupDefinitions.Value;
private readonly Lazy<Dictionary<string, WebhookGroupDefinition>> _lazyWebhookGroupDefinitions;
protected IDictionary<string, WebhookDefinition> WebhookDefinitions => _lazyWebhookDefinitions.Value;
private readonly Lazy<Dictionary<string, WebhookDefinition>> _lazyWebhookDefinitions;
private readonly IServiceProvider _serviceProvider;
private readonly AbpWebhooksOptions _options;
public WebhookDefinitionManager(
IServiceProvider serviceProvider,
IOptions<AbpWebhooksOptions> options)
{
_serviceProvider = serviceProvider;
_options = options.Value;
_lazyWebhookGroupDefinitions = new Lazy<Dictionary<string, WebhookGroupDefinition>>(CreateWebhookGroupDefinitions);
_lazyWebhookDefinitions = new Lazy<Dictionary<string, WebhookDefinition>>(CreateWebhookDefinitions);
}
public WebhookDefinition GetOrNull(string name)
{
if (!WebhookDefinitions.ContainsKey(name))
{
return null;
}
return WebhookDefinitions[name];
}
public WebhookDefinition Get(string name)
{
if (!WebhookDefinitions.ContainsKey(name))
{
throw new KeyNotFoundException($"Webhook definitions does not contain a definition with the key \"{name}\".");
}
return WebhookDefinitions[name];
}
public IReadOnlyList<WebhookDefinition> GetAll()
{
return WebhookDefinitions.Values.ToImmutableList();
}
public IReadOnlyList<WebhookGroupDefinition> GetGroups()
{
return WebhookGroupDefinitions.Values.ToImmutableList();
}
public async Task<bool> IsAvailableAsync(Guid? tenantId, string name)
{
if (tenantId == null) // host allowed to subscribe all webhooks
{
return true;
}
var webhookDefinition = GetOrNull(name);
if (webhookDefinition == null)
{
return false;
}
if (webhookDefinition.RequiredFeatures?.Any() == false)
{
return true;
}
var currentTenant = _serviceProvider.GetRequiredService<ICurrentTenant>();
var featureChecker = _serviceProvider.GetRequiredService<IFeatureChecker>();
using (currentTenant.Change(tenantId))
{
if (!await featureChecker.IsEnabledAsync(true, webhookDefinition.RequiredFeatures.ToArray()))
{
return false;
}
}
return true;
}
protected virtual Dictionary<string, WebhookDefinition> CreateWebhookDefinitions()
{
var definitions = new Dictionary<string, WebhookDefinition>();
foreach (var groupDefinition in WebhookGroupDefinitions.Values)
{
foreach (var webhook in groupDefinition.Webhooks)
{
if (definitions.ContainsKey(webhook.Name))
{
throw new AbpException("Duplicate webhook name: " + webhook.Name);
}
definitions[webhook.Name] = webhook;
}
}
return definitions;
}
protected virtual Dictionary<string, WebhookGroupDefinition> CreateWebhookGroupDefinitions()
{
var definitions = new Dictionary<string, WebhookGroupDefinition>();
using (var scope = _serviceProvider.CreateScope())
{
var providers = _options
.DefinitionProviders
.Select(p => scope.ServiceProvider.GetRequiredService(p) as WebhookDefinitionProvider)
.ToList();
foreach (var provider in providers)
{
provider.Define(new WebhookDefinitionContext(definitions));
}
}
return definitions;
}
}
}

13
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookDefinitionProvider.cs

@ -1,13 +0,0 @@
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.Webhooks
{
public abstract class WebhookDefinitionProvider : ITransientDependency
{
/// <summary>
/// Used to add/manipulate webhook definitions.
/// </summary>
/// <param name="context">Context</param>,
public abstract void Define(IWebhookDefinitionContext context);
}
}

30
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookEvent.cs

@ -1,30 +0,0 @@
using System;
namespace LINGYUN.Abp.Webhooks
{
/// <summary>
/// Store created web hooks. To see who get that webhook check with <see cref="WebhookSendAttempt.WebhookEventId"/> and you can get <see cref="WebhookSendAttempt.WebhookSubscriptionId"/>
/// </summary>
public class WebhookEvent
{
public Guid Id { get; set; }
/// <summary>
/// Webhook unique name <see cref="WebhookDefinition.Name"/>
/// </summary>
public string WebhookName { get; set; }
/// <summary>
/// Webhook data as JSON string.
/// </summary>
public string Data { get; set; }
public DateTime CreationTime { get; set; }
public Guid? TenantId { get; set; }
public bool IsDeleted { get; set; }
public DateTime? DeletionTime { get; set; }
}
}

101
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookGroupDefinition.cs

@ -1,101 +0,0 @@
using JetBrains.Annotations;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Volo.Abp;
using Volo.Abp.Localization;
namespace LINGYUN.Abp.Webhooks;
public class WebhookGroupDefinition
{
[NotNull]
public string Name { get; set; }
public Dictionary<string, object> Properties { get; }
private ILocalizableString _displayName;
public ILocalizableString DisplayName
{
get {
return _displayName;
}
set {
_displayName = value;
}
}
public IReadOnlyList<WebhookDefinition> Webhooks => _webhooks.ToImmutableList();
private readonly List<WebhookDefinition> _webhooks;
public object this[string name] {
get => Properties.GetOrDefault(name);
set => Properties[name] = value;
}
protected internal WebhookGroupDefinition(
string name,
ILocalizableString displayName = null)
{
Name = name;
DisplayName = displayName ?? new FixedLocalizableString(Name);
Properties = new Dictionary<string, object>();
_webhooks = new List<WebhookDefinition>();
}
public virtual WebhookDefinition AddWebhook(
string name,
ILocalizableString displayName = null,
ILocalizableString description = null)
{
if (Webhooks.Any(hook => hook.Name.Equals(name)))
{
throw new AbpException($"There is already an existing webhook with name: {name} in group {Name}");
}
var webhook = new WebhookDefinition(
name,
displayName,
description
);
_webhooks.Add(webhook);
return webhook;
}
public virtual void AddWebhooks(params WebhookDefinition[] webhooks)
{
foreach (var webhook in webhooks)
{
if (Webhooks.Any(hook => hook.Name.Equals(webhook.Name)))
{
throw new AbpException($"There is already an existing webhook with name: {webhook.Name} in group {Name}");
}
}
_webhooks.AddRange(webhooks);
}
[CanBeNull]
public WebhookDefinition GetWebhookOrNull([NotNull] string name)
{
Check.NotNull(name, nameof(name));
foreach (var webhook in Webhooks)
{
if (webhook.Name == name)
{
return webhook;
}
}
return null;
}
public override string ToString()
{
return $"[{nameof(WebhookGroupDefinition)} {Name}]";
}
}

18
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookHeader.cs

@ -1,18 +0,0 @@
using System.Collections.Generic;
namespace LINGYUN.Abp.Webhooks
{
public class WebhookHeader
{
/// <summary>
/// If true, webhook will only contain given headers. If false given headers will be added to predefined headers in subscription.
/// Default is false
/// </summary>
public bool UseOnlyGivenHeaders { get; set; }
/// <summary>
/// That headers will be sent with the webhook.
/// </summary>
public IDictionary<string, string> Headers { get; set; }
}
}

80
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookManager.cs

@ -1,80 +0,0 @@
using Newtonsoft.Json;
using System;
using System.Globalization;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Webhooks
{
public abstract class WebhookManager : IWebhookManager
{
private const string SignatureHeaderKey = "sha256";
private const string SignatureHeaderValueTemplate = SignatureHeaderKey + "={0}";
private const string SignatureHeaderName = "abp-webhook-signature";
protected IWebhookSendAttemptStore WebhookSendAttemptStore { get; }
protected WebhookManager(
IWebhookSendAttemptStore webhookSendAttemptStore)
{
WebhookSendAttemptStore = webhookSendAttemptStore;
}
public virtual async Task<WebhookPayload> GetWebhookPayloadAsync(WebhookSenderArgs webhookSenderArgs)
{
var data = JsonConvert.SerializeObject(webhookSenderArgs.Data);
var attemptNumber = await WebhookSendAttemptStore.GetSendAttemptCountAsync(
webhookSenderArgs.TenantId,
webhookSenderArgs.WebhookEventId,
webhookSenderArgs.WebhookSubscriptionId);
return new WebhookPayload(
webhookSenderArgs.WebhookEventId.ToString(),
webhookSenderArgs.WebhookName,
attemptNumber)
{
Data = data
};
}
public virtual void SignWebhookRequest(HttpRequestMessage request, string serializedBody, string secret)
{
if (request == null)
{
throw new ArgumentNullException(nameof(request));
}
if (string.IsNullOrWhiteSpace(serializedBody))
{
throw new ArgumentNullException(nameof(serializedBody));
}
request.Content = new StringContent(serializedBody, Encoding.UTF8, "application/json");
var secretBytes = Encoding.UTF8.GetBytes(secret);
var headerValue = string.Format(CultureInfo.InvariantCulture, SignatureHeaderValueTemplate, serializedBody.Sha256(secretBytes));
request.Headers.Add(SignatureHeaderName, headerValue);
}
public virtual async Task<string> GetSerializedBodyAsync(WebhookSenderArgs webhookSenderArgs)
{
if (webhookSenderArgs.SendExactSameData)
{
return webhookSenderArgs.Data;
}
var payload = await GetWebhookPayloadAsync(webhookSenderArgs);
var serializedBody = JsonConvert.SerializeObject(payload);
return serializedBody;
}
public abstract Task<Guid> InsertAndGetIdWebhookSendAttemptAsync(WebhookSenderArgs webhookSenderArgs);
public abstract Task StoreResponseOnWebhookSendAttemptAsync(Guid webhookSendAttemptId, Guid? tenantId, HttpStatusCode? statusCode, string content);
}
}

35
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookPayload.cs

@ -1,35 +0,0 @@
using System;
namespace LINGYUN.Abp.Webhooks
{
public class WebhookPayload
{
public string Id { get; set; }
public string WebhookEvent { get; set; }
public int Attempt { get; set; }
public dynamic Data { get; set; }
public DateTime CreationTimeUtc { get; set; }
public WebhookPayload(string id, string webhookEvent, int attempt)
{
if (id.IsNullOrWhiteSpace())
{
throw new ArgumentNullException(nameof(id));
}
if (webhookEvent.IsNullOrWhiteSpace())
{
throw new ArgumentNullException(nameof(webhookEvent));
}
Id = id;
WebhookEvent = webhookEvent;
Attempt = attempt;
CreationTimeUtc = DateTime.UtcNow;
}
}
}

39
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookSendAttempt.cs

@ -1,39 +0,0 @@
using System;
using System.Net;
namespace LINGYUN.Abp.Webhooks
{
/// <summary>
/// Table for store webhook work items. Each item stores web hook send attempt of <see cref="WebhookEvent"/> to subscribed tenants
/// </summary>
public class WebhookSendAttempt
{
public Guid Id { get; set; }
/// <summary>
/// <see cref="WebhookEvent"/> foreign id
/// </summary>
public Guid WebhookEventId { get; set; }
/// <summary>
/// <see cref="WebhookSubscription"/> foreign id
/// </summary>
public Guid WebhookSubscriptionId { get; set; }
/// <summary>
/// Webhook response content that webhook endpoint send back
/// </summary>
public string Response { get; set; }
/// <summary>
/// Webhook response status code that webhook endpoint send back
/// </summary>
public HttpStatusCode? ResponseStatusCode { get; set; }
public DateTime CreationTime { get; set; }
public DateTime? LastModificationTime { get; set; }
public Guid? TenantId { get; set; }
}
}

62
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookSenderArgs.cs

@ -1,62 +0,0 @@
using System;
using System.Collections.Generic;
namespace LINGYUN.Abp.Webhooks
{
public class WebhookSenderArgs
{
public Guid? TenantId { get; set; }
//Webhook information
/// <summary>
/// <see cref="WebhookEvent"/> foreign id
/// </summary>
public Guid WebhookEventId { get; set; }
/// <summary>
/// Webhook unique name
/// </summary>
public string WebhookName { get; set; }
/// <summary>
/// Webhook data as JSON string.
/// </summary>
public string Data { get; set; }
//Subscription information
/// <summary>
/// <see cref="WebhookSubscription"/> foreign id
/// </summary>
public Guid WebhookSubscriptionId { get; set; }
/// <summary>
/// Subscription webhook endpoint
/// </summary>
public string WebhookUri { get; set; }
/// <summary>
/// Webhook secret
/// </summary>
public string Secret { get; set; }
/// <summary>
/// Gets a set of additional HTTP headers.That headers will be sent with the webhook.
/// </summary>
public IDictionary<string, string> Headers { get; set; }
/// <summary>
/// True: It sends the exact same data as the parameter to clients.
/// <para>
/// False: It sends data in <see cref="WebhookPayload"/>. It is recommended way.
/// </para>
/// </summary>
public bool SendExactSameData { get; set; }
public WebhookSenderArgs()
{
Headers = new Dictionary<string, string>();
}
}
}

60
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookSubscriptionInfo.cs

@ -1,60 +0,0 @@
using System;
using System.Collections.Generic;
namespace LINGYUN.Abp.Webhooks
{
public class WebhookSubscriptionInfo
{
public Guid Id { get; set; }
/// <summary>
/// Subscribed Tenant's id .
/// </summary>
public Guid? TenantId { get; set; }
/// <summary>
/// Subscription webhook endpoint
/// </summary>
public string WebhookUri { get; set; }
/// <summary>
/// Webhook secret
/// </summary>
public string Secret { get; set; }
/// <summary>
/// Is subscription active
/// </summary>
public bool IsActive { get; set; }
/// <summary>
/// Subscribed webhook definitions unique names.It contains webhook definitions list as json
/// <para>
/// Do not change it manually.
/// Use <see cref=" WebhookSubscriptionInfoExtensions.GetSubscribedWebhooks"/>,
/// <see cref=" WebhookSubscriptionInfoExtensions.SubscribeWebhook"/>,
/// <see cref="WebhookSubscriptionInfoExtensions.UnsubscribeWebhook"/> and
/// <see cref="WebhookSubscriptionInfoExtensions.RemoveAllSubscribedWebhooks"/> to change it.
/// </para>
/// </summary>
public List<string> Webhooks { get; set; }
/// <summary>
/// Gets a set of additional HTTP headers.That headers will be sent with the webhook. It contains webhook header dictionary as json
/// <para>
/// Do not change it manually.
/// Use <see cref=" WebhookSubscriptionInfoExtensions.GetWebhookHeaders"/>,
/// <see cref="WebhookSubscriptionInfoExtensions.AddWebhookHeader"/>,
/// <see cref="WebhookSubscriptionInfoExtensions.RemoveWebhookHeader"/>,
/// <see cref="WebhookSubscriptionInfoExtensions.RemoveAllWebhookHeaders"/> to change it.
/// </para>
/// </summary>
public IDictionary<string, string> Headers { get; set; }
public WebhookSubscriptionInfo()
{
IsActive = true;
Headers = new Dictionary<string, string>();
Webhooks = new List<string>();
}
}
}

172
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookSubscriptionManager.cs

@ -1,172 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Authorization;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.Uow;
namespace LINGYUN.Abp.Webhooks
{
public class WebhookSubscriptionManager : IWebhookSubscriptionManager, ITransientDependency
{
public IWebhookSubscriptionsStore WebhookSubscriptionsStore { get; set; }
private readonly IGuidGenerator _guidGenerator;
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IWebhookDefinitionManager _webhookDefinitionManager;
private const string WebhookSubscriptionSecretPrefix = "whs_";
public WebhookSubscriptionManager(
IGuidGenerator guidGenerator,
IUnitOfWorkManager unitOfWorkManager,
IWebhookDefinitionManager webhookDefinitionManager)
{
_guidGenerator = guidGenerator;
_unitOfWorkManager = unitOfWorkManager;
_webhookDefinitionManager = webhookDefinitionManager;
WebhookSubscriptionsStore = NullWebhookSubscriptionsStore.Instance;
}
public virtual async Task<WebhookSubscriptionInfo> GetAsync(Guid id)
{
return await WebhookSubscriptionsStore.GetAsync(id);
}
public virtual async Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsAsync(Guid? tenantId)
{
return await WebhookSubscriptionsStore.GetAllSubscriptionsAsync(tenantId);
}
public virtual async Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsIfFeaturesGrantedAsync(Guid? tenantId, string webhookName)
{
if (!await _webhookDefinitionManager.IsAvailableAsync(tenantId, webhookName))
{
return new List<WebhookSubscriptionInfo>();
}
return (await WebhookSubscriptionsStore.GetAllSubscriptionsAsync(tenantId, webhookName)).ToList();
}
public virtual async Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsOfTenantsAsync(Guid?[] tenantIds)
{
return (await WebhookSubscriptionsStore.GetAllSubscriptionsOfTenantsAsync(tenantIds)).ToList();
}
public virtual async Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsOfTenantsIfFeaturesGrantedAsync(Guid?[] tenantIds, string webhookName)
{
var featureGrantedTenants = new List<Guid?>();
foreach (var tenantId in tenantIds)
{
if (await _webhookDefinitionManager.IsAvailableAsync(tenantId, webhookName))
{
featureGrantedTenants.Add(tenantId);
}
}
return (await WebhookSubscriptionsStore.GetAllSubscriptionsOfTenantsAsync(featureGrantedTenants.ToArray(), webhookName)).ToList();
}
public virtual async Task<bool> IsSubscribedAsync(Guid? tenantId, string webhookName)
{
if (!await _webhookDefinitionManager.IsAvailableAsync(tenantId, webhookName))
{
return false;
}
return await WebhookSubscriptionsStore.IsSubscribedAsync(tenantId, webhookName);
}
public virtual async Task AddOrUpdateSubscriptionAsync(WebhookSubscriptionInfo webhookSubscription)
{
using (var uow = _unitOfWorkManager.Begin())
{
await CheckIfPermissionsGrantedAsync(webhookSubscription);
if (webhookSubscription.Id == default)
{
webhookSubscription.Id = _guidGenerator.Create();
webhookSubscription.Secret = WebhookSubscriptionSecretPrefix + Guid.NewGuid().ToString("N");
await WebhookSubscriptionsStore.InsertAsync(webhookSubscription);
}
else
{
await WebhookSubscriptionsStore.UpdateAsync(webhookSubscription);
}
await uow.SaveChangesAsync();
}
}
public virtual async Task ActivateWebhookSubscriptionAsync(Guid id, bool active)
{
using (var uow = _unitOfWorkManager.Begin())
{
var webhookSubscription = await WebhookSubscriptionsStore.GetAsync(id);
webhookSubscription.IsActive = active;
await uow.SaveChangesAsync();
}
}
public virtual async Task DeleteSubscriptionAsync(Guid id)
{
using (var uow = _unitOfWorkManager.Begin())
{
await WebhookSubscriptionsStore.DeleteAsync(id);
await uow.SaveChangesAsync();
}
}
public virtual async Task AddWebhookAsync(WebhookSubscriptionInfo subscription, string webhookName)
{
using (var uow = _unitOfWorkManager.Begin())
{
await CheckPermissionsAsync(subscription.TenantId, webhookName);
webhookName = webhookName.Trim();
if (webhookName.IsNullOrWhiteSpace())
{
throw new ArgumentNullException(nameof(webhookName), $"{nameof(webhookName)} can not be null, empty or whitespace!");
}
if (!subscription.Webhooks.Contains(webhookName))
{
subscription.Webhooks.Add(webhookName);
await WebhookSubscriptionsStore.UpdateAsync(subscription);
}
await uow.SaveChangesAsync();
}
}
#region PermissionCheck
protected virtual async Task CheckIfPermissionsGrantedAsync(WebhookSubscriptionInfo webhookSubscription)
{
if (webhookSubscription.Webhooks.IsNullOrEmpty())
{
return;
}
foreach (var webhookDefinition in webhookSubscription.Webhooks)
{
await CheckPermissionsAsync(webhookSubscription.TenantId, webhookDefinition);
}
}
protected virtual async Task CheckPermissionsAsync(Guid? tenantId, string webhookName)
{
if (!await _webhookDefinitionManager.IsAvailableAsync(tenantId, webhookName))
{
throw new AbpAuthorizationException($"Tenant \"{tenantId}\" must have necessary feature(s) to use webhook \"{webhookName}\"");
}
}
#endregion
}
}

13
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/System/AbpStringCryptographyExtensions.cs

@ -1,13 +0,0 @@
using System.Security.Cryptography;
namespace System;
internal static class AbpStringCryptographyExtensions
{
public static string Sha256(this string planText, byte[] salt)
{
var data = planText.GetBytes();
using var hmacsha256 = new HMACSHA256(salt);
return BitConverter.ToString(hmacsha256.ComputeHash(data));
}
}
Loading…
Cancel
Save