62 changed files with 1517 additions and 11 deletions
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?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> |
|||
@ -0,0 +1,16 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\common\LINGYUN.Abp.Notifications\LINGYUN.Abp.Notifications.csproj" /> |
|||
<ProjectReference Include="..\LINGYUN.Abp.TuiJuhe\LINGYUN.Abp.TuiJuhe.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,57 @@ |
|||
using LINGYUN.Abp.TuiJuhe.Messages; |
|||
|
|||
namespace LINGYUN.Abp.Notifications; |
|||
|
|||
public static class NotificationDefinitionExtensions |
|||
{ |
|||
private const string Prefix = "tui-juhe:"; |
|||
private const string ServiceIdKey = Prefix + "serviceId"; |
|||
|
|||
/// <summary>
|
|||
/// 获取消息内容类型
|
|||
/// </summary>
|
|||
/// <param name="notification"></param>
|
|||
/// <param name="defaultContentType"></param>
|
|||
/// <returns></returns>
|
|||
public static MessageContentType GetContentTypeOrDefault( |
|||
this NotificationDefinition notification, |
|||
MessageContentType defaultContentType = MessageContentType.Text) |
|||
{ |
|||
return notification.ContentType switch |
|||
{ |
|||
NotificationContentType.Text => MessageContentType.Text, |
|||
NotificationContentType.Html => MessageContentType.Html, |
|||
NotificationContentType.Markdown => MessageContentType.Markdown, |
|||
NotificationContentType.Json => MessageContentType.Text, |
|||
_ => defaultContentType, |
|||
}; |
|||
} |
|||
/// <summary>
|
|||
/// 指定服务编号
|
|||
/// </summary>
|
|||
/// <param name="notification">群组编码</param>
|
|||
/// <param name="serviceId">服务编号,在服务创建后自动生成ServiceID,是服务的唯一标识,可在每个服务的详情页中查看</param>
|
|||
/// <returns>
|
|||
/// <see cref="NotificationDefinition"/>
|
|||
/// </returns>
|
|||
public static NotificationDefinition WithServiceId( |
|||
this NotificationDefinition notification, |
|||
string serviceId) |
|||
{ |
|||
return notification.WithProperty(ServiceIdKey, serviceId); |
|||
} |
|||
/// <summary>
|
|||
/// 获取服务编号
|
|||
/// </summary>
|
|||
/// <param name="notification"></param>
|
|||
public static string GetServiceIdOrNull( |
|||
this NotificationDefinition notification) |
|||
{ |
|||
if (notification.Properties.TryGetValue(ServiceIdKey, out var serviceIdDefine)) |
|||
{ |
|||
return serviceIdDefine.ToString(); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
using LINGYUN.Abp.TuiJuhe; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.Notifications.TuiJuhe; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpNotificationsModule), |
|||
typeof(AbpTuiJuheModule))] |
|||
public class AbpNotificationsTuiJuheModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpNotificationsPublishOptions>(options => |
|||
{ |
|||
options.PublishProviders.Add<TuiJuheNotificationPublishProvider>(); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,115 @@ |
|||
using LINGYUN.Abp.RealTime.Localization; |
|||
using LINGYUN.Abp.TuiJuhe.Features; |
|||
using LINGYUN.Abp.TuiJuhe.Messages; |
|||
using Microsoft.Extensions.Localization; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Features; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.Notifications.TuiJuhe; |
|||
|
|||
public class TuiJuheNotificationPublishProvider : NotificationPublishProvider |
|||
{ |
|||
public const string ProviderName = "TuiJuhe"; |
|||
|
|||
public override string Name => ProviderName; |
|||
|
|||
protected IFeatureChecker FeatureChecker { get; } |
|||
|
|||
protected ITuiJuheMessageSender TuiJuheMessageSender { get; } |
|||
|
|||
protected IStringLocalizerFactory LocalizerFactory { get; } |
|||
|
|||
protected AbpLocalizationOptions LocalizationOptions { get; } |
|||
|
|||
protected INotificationDefinitionManager NotificationDefinitionManager { get; } |
|||
|
|||
public TuiJuheNotificationPublishProvider( |
|||
IFeatureChecker featureChecker, |
|||
ITuiJuheMessageSender tuiJuheMessageSender, |
|||
IStringLocalizerFactory localizerFactory, |
|||
IOptions<AbpLocalizationOptions> localizationOptions, |
|||
INotificationDefinitionManager notificationDefinitionManager) |
|||
{ |
|||
FeatureChecker = featureChecker; |
|||
TuiJuheMessageSender = tuiJuheMessageSender; |
|||
LocalizerFactory = localizerFactory; |
|||
LocalizationOptions = localizationOptions.Value; |
|||
NotificationDefinitionManager = notificationDefinitionManager; |
|||
} |
|||
|
|||
protected async override Task<bool> CanPublishAsync(NotificationInfo notification, CancellationToken cancellationToken = default) |
|||
{ |
|||
if (!await FeatureChecker.IsEnabledAsync(TuiJuheFeatureNames.Message.Enable)) |
|||
{ |
|||
Logger.LogWarning( |
|||
"{0} cannot push messages because the feature {1} is not enabled", |
|||
Name, |
|||
TuiJuheFeatureNames.Message.Enable); |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
protected async override Task PublishAsync( |
|||
NotificationInfo notification, |
|||
IEnumerable<UserIdentifier> identifiers, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
var notificationDefine = await NotificationDefinitionManager.GetOrNullAsync(notification.Name); |
|||
var contentType = notificationDefine?.GetContentTypeOrDefault(MessageContentType.Text) |
|||
?? MessageContentType.Text; |
|||
var serviceId = notificationDefine?.GetServiceIdOrNull(); |
|||
|
|||
if (serviceId.IsNullOrWhiteSpace()) |
|||
{ |
|||
Logger.LogWarning( |
|||
"{0} cannot push messages because the notification {1} service id is not specified", |
|||
Name, |
|||
notification.Name); |
|||
return; |
|||
} |
|||
|
|||
if (!notification.Data.NeedLocalizer()) |
|||
{ |
|||
var title = notification.Data.TryGetData("title").ToString(); |
|||
var message = notification.Data.TryGetData("message").ToString(); |
|||
|
|||
await TuiJuheMessageSender.SendAsync( |
|||
title: title, |
|||
content: message, |
|||
serviceId: serviceId, |
|||
contentType: contentType, |
|||
cancellationToken: cancellationToken); |
|||
} |
|||
else |
|||
{ |
|||
var titleInfo = notification.Data.TryGetData("title").As<LocalizableStringInfo>(); |
|||
var titleResource = GetResource(titleInfo.ResourceName); |
|||
var title = LocalizerFactory.Create(titleResource.ResourceType)[titleInfo.Name, titleInfo.Values].Value; |
|||
|
|||
var messageInfo = notification.Data.TryGetData("message").As<LocalizableStringInfo>(); |
|||
var messageResource = GetResource(messageInfo.ResourceName); |
|||
var message = LocalizerFactory.Create(messageResource.ResourceType)[messageInfo.Name, messageInfo.Values].Value; |
|||
|
|||
await TuiJuheMessageSender.SendAsync( |
|||
title: title, |
|||
content: message, |
|||
serviceId: serviceId, |
|||
contentType: contentType, |
|||
cancellationToken: cancellationToken); |
|||
} |
|||
} |
|||
|
|||
private LocalizationResource GetResource(string resourceName) |
|||
{ |
|||
return LocalizationOptions.Resources.Values |
|||
.First(x => x.ResourceName.Equals(resourceName)); |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
# LINGYUN.Abp.Notifications.TuiJuhe |
|||
|
|||
通知模块的TuiJuhe实现 |
|||
|
|||
使应用可通过TuiJuhe发布实时通知 |
|||
|
|||
## 模块引用 |
|||
|
|||
```csharp |
|||
[DependsOn(typeof(AbpNotificationsTuiJuheModule))] |
|||
public class YouProjectModule : AbpModule |
|||
{ |
|||
// other |
|||
} |
|||
``` |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?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> |
|||
@ -0,0 +1,30 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<EmbeddedResource Include="LINGYUN\Abp\TuiJuhe\SettingManagement\Localization\Resources\*.json" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<None Remove="LINGYUN\Abp\TuiJuhe\SettingManagement\Localization\Resources\en.json" /> |
|||
<None Remove="LINGYUN\Abp\TuiJuhe\SettingManagement\Localization\Resources\zh-Hans.json" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.SettingManagement.Domain" Version="$(VoloAbpPackageVersion)" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\settings\LINGYUN.Abp.SettingManagement.Application.Contracts\LINGYUN.Abp.SettingManagement.Application.Contracts.csproj" /> |
|||
<ProjectReference Include="..\LINGYUN.Abp.TuiJuhe\LINGYUN.Abp.TuiJuhe.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,48 @@ |
|||
using LINGYUN.Abp.TuiJuhe.Localization; |
|||
using Localization.Resources.AbpUi; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe.SettingManagement |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpTuiJuheModule), |
|||
typeof(AbpAspNetCoreMvcModule))] |
|||
public class AbpWxPusherSettingManagementModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
PreConfigure<IMvcBuilder>(mvcBuilder => |
|||
{ |
|||
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpWxPusherSettingManagementModule).Assembly); |
|||
}); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AbpWxPusherSettingManagementModule>(); |
|||
}); |
|||
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Resources |
|||
.Get<TuiJuheResource>() |
|||
.AddVirtualJson("/LINGYUN/Abp/TuiJuhe/SettingManagement/Localization/Resources"); |
|||
}); |
|||
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Resources |
|||
.Get<TuiJuheResource>() |
|||
.AddBaseTypes( |
|||
typeof(AbpUiResource) |
|||
); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
using LINGYUN.Abp.SettingManagement; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe.SettingManagement |
|||
{ |
|||
public interface ITuiJuheSettingAppService : IReadonlySettingAppService |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
{ |
|||
"culture": "en", |
|||
"texts": { |
|||
"Permission:TuiJuhe": "TuiJuhe", |
|||
"Permission:ManageSetting": "Manage Setting" |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
{ |
|||
"culture": "zh-Hans", |
|||
"texts": { |
|||
"Permission:TuiJuhe": "聚合云推", |
|||
"Permission:ManageSetting": "管理设置" |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
using LINGYUN.Abp.SettingManagement; |
|||
using LINGYUN.Abp.TuiJuhe.Localization; |
|||
using LINGYUN.Abp.TuiJuhe.Settings; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Services; |
|||
using Volo.Abp.Authorization.Permissions; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.SettingManagement; |
|||
using Volo.Abp.Settings; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe.SettingManagement |
|||
{ |
|||
public class TuiJuheSettingAppService : ApplicationService, ITuiJuheSettingAppService |
|||
{ |
|||
protected ISettingManager SettingManager { get; } |
|||
protected IPermissionChecker PermissionChecker { get; } |
|||
protected ISettingDefinitionManager SettingDefinitionManager { get; } |
|||
|
|||
public TuiJuheSettingAppService( |
|||
ISettingManager settingManager, |
|||
IPermissionChecker permissionChecker, |
|||
ISettingDefinitionManager settingDefinitionManager) |
|||
{ |
|||
SettingManager = settingManager; |
|||
PermissionChecker = permissionChecker; |
|||
SettingDefinitionManager = settingDefinitionManager; |
|||
LocalizationResource = typeof(TuiJuheResource); |
|||
} |
|||
|
|||
public async virtual Task<SettingGroupResult> GetAllForCurrentTenantAsync() |
|||
{ |
|||
return await GetAllForProviderAsync(TenantSettingValueProvider.ProviderName, CurrentTenant.GetId().ToString()); |
|||
} |
|||
|
|||
public async virtual Task<SettingGroupResult> GetAllForGlobalAsync() |
|||
{ |
|||
return await GetAllForProviderAsync(GlobalSettingValueProvider.ProviderName, null); |
|||
} |
|||
|
|||
protected async virtual Task<SettingGroupResult> GetAllForProviderAsync(string providerName, string providerKey) |
|||
{ |
|||
var settingGroups = new SettingGroupResult(); |
|||
var wxPusherSettingGroup = new SettingGroupDto(L["DisplayName:TuiJuhe"], L["Description:TuiJuhe"]); |
|||
|
|||
if (await PermissionChecker.IsGrantedAsync(TuiJuheSettingPermissionNames.ManageSetting)) |
|||
{ |
|||
var securitySetting = wxPusherSettingGroup.AddSetting(L["Security"], L["Security"]); |
|||
securitySetting.AddDetail( |
|||
SettingDefinitionManager.Get(TuiJuheSettingNames.Security.Token), |
|||
StringLocalizerFactory, |
|||
await SettingManager.GetOrNullAsync(TuiJuheSettingNames.Security.Token, providerName, providerKey), |
|||
ValueType.String, |
|||
providerName); |
|||
} |
|||
|
|||
settingGroups.AddGroup(wxPusherSettingGroup); |
|||
|
|||
return settingGroups; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
using LINGYUN.Abp.SettingManagement; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe.SettingManagement |
|||
{ |
|||
[RemoteService(Name = AbpSettingManagementRemoteServiceConsts.RemoteServiceName)] |
|||
[Area(AbpSettingManagementRemoteServiceConsts.ModuleName)] |
|||
[Route($"api/{AbpSettingManagementRemoteServiceConsts.ModuleName}/tui-juhe")] |
|||
public class TuiJuheSettingController : AbpController, ITuiJuheSettingAppService |
|||
{ |
|||
protected ITuiJuheSettingAppService Service { get; } |
|||
|
|||
public TuiJuheSettingController( |
|||
ITuiJuheSettingAppService service) |
|||
{ |
|||
Service = service; |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("by-current-tenant")] |
|||
public async virtual Task<SettingGroupResult> GetAllForCurrentTenantAsync() |
|||
{ |
|||
return await Service.GetAllForCurrentTenantAsync(); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("by-global")] |
|||
public async virtual Task<SettingGroupResult> GetAllForGlobalAsync() |
|||
{ |
|||
return await Service.GetAllForGlobalAsync(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using LINGYUN.Abp.TuiJuhe.Localization; |
|||
using Volo.Abp.Authorization.Permissions; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe.SettingManagement |
|||
{ |
|||
public class WxPusherSettingPermissionDefinitionProvider : PermissionDefinitionProvider |
|||
{ |
|||
public override void Define(IPermissionDefinitionContext context) |
|||
{ |
|||
var tuiJuheGroup = context.AddGroup( |
|||
TuiJuheSettingPermissionNames.GroupName, |
|||
L("Permission:TuiJuhe")); |
|||
|
|||
tuiJuheGroup.AddPermission( |
|||
TuiJuheSettingPermissionNames.ManageSetting, L("Permission:ManageSetting")); |
|||
} |
|||
|
|||
private static LocalizableString L(string name) |
|||
{ |
|||
return LocalizableString.Create<TuiJuheResource>(name); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
namespace LINGYUN.Abp.TuiJuhe.SettingManagement |
|||
{ |
|||
public class TuiJuheSettingPermissionNames |
|||
{ |
|||
public const string GroupName = "Abp.TuiJuhe"; |
|||
|
|||
public const string ManageSetting = GroupName + ".ManageSetting"; |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?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> |
|||
@ -0,0 +1,29 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<EmbeddedResource Include="LINGYUN\Abp\TuiJuhe\Localization\Resources\*.json" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<None Remove="LINGYUN\Abp\TuiJuhe\Localization\Resources\*.json" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Caching" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.Json" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Microsoft.Extensions.Http" Version="$(MicrosoftPackageVersion)" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\common\LINGYUN.Abp.Features.LimitValidation\LINGYUN.Abp.Features.LimitValidation.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,42 @@ |
|||
using LINGYUN.Abp.Features.LimitValidation; |
|||
using LINGYUN.Abp.TuiJuhe.Localization; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Caching; |
|||
using Volo.Abp.Json; |
|||
using Volo.Abp.Json.SystemTextJson; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Settings; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpJsonModule), |
|||
typeof(AbpSettingsModule), |
|||
typeof(AbpCachingModule), |
|||
typeof(AbpFeaturesLimitValidationModule))] |
|||
public class AbpTuiJuheModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddTuiJuheClient(); |
|||
|
|||
Configure<AbpSystemTextJsonSerializerOptions>(options => |
|||
{ |
|||
|
|||
}); |
|||
|
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AbpTuiJuheModule>(); |
|||
}); |
|||
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Resources |
|||
.Add<TuiJuheResource>() |
|||
.AddVirtualJson("/LINGYUN/Abp/TuiJuhe/Localization/Resources"); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
using LINGYUN.Abp.TuiJuhe.Localization; |
|||
using Volo.Abp.Features; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Validation.StringValues; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe.Features; |
|||
|
|||
public class TuiJuheFeatureDefinitionProvider : FeatureDefinitionProvider |
|||
{ |
|||
public override void Define(IFeatureDefinitionContext context) |
|||
{ |
|||
var group = context.AddGroup( |
|||
name: TuiJuheFeatureNames.GroupName, |
|||
displayName: L("Features:TuiJuhe")); |
|||
group.AddFeature( |
|||
name: TuiJuheFeatureNames.Enable, |
|||
defaultValue: "false", |
|||
displayName: L("Features:TuiJuheEnable"), |
|||
description: L("Features:TuiJuheEnableDesc"), |
|||
valueType: new ToggleStringValueType(new BooleanValueValidator())); |
|||
|
|||
var message = group.AddFeature( |
|||
name: TuiJuheFeatureNames.Message.GroupName, |
|||
displayName: L("Features:Message"), |
|||
description: L("Features:Message")); |
|||
|
|||
message.CreateChild( |
|||
name: TuiJuheFeatureNames.Message.Enable, |
|||
defaultValue: "false", |
|||
displayName: L("Features:MessageEnable"), |
|||
description: L("Features:MessageEnableDesc"), |
|||
valueType: new ToggleStringValueType(new BooleanValueValidator())); |
|||
message.CreateChild( |
|||
name: TuiJuheFeatureNames.Message.SendLimit, |
|||
defaultValue: "50", |
|||
displayName: L("Features:Message.SendLimit"), |
|||
description: L("Features:Message.SendLimitDesc"), |
|||
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 50))); |
|||
message.CreateChild( |
|||
name: TuiJuheFeatureNames.Message.SendLimitInterval, |
|||
defaultValue: "1", |
|||
displayName: L("Features:Message.SendLimitInterval"), |
|||
description: L("Features:Message.SendLimitIntervalDesc"), |
|||
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 1))); |
|||
} |
|||
|
|||
private static LocalizableString L(string name) |
|||
{ |
|||
return LocalizableString.Create<TuiJuheResource>(name); |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
namespace LINGYUN.Abp.TuiJuhe.Features; |
|||
|
|||
public static class TuiJuheFeatureNames |
|||
{ |
|||
public const string GroupName = "TuiJuhe"; |
|||
|
|||
/// <summary>
|
|||
/// 启用TuiJuhe
|
|||
/// </summary>
|
|||
public const string Enable = GroupName + ".Enable"; |
|||
|
|||
public static class Message |
|||
{ |
|||
public const string GroupName = TuiJuheFeatureNames.GroupName + ".Message"; |
|||
/// <summary>
|
|||
/// 启用消息推送
|
|||
/// </summary>
|
|||
public const string Enable = GroupName + ".Enable"; |
|||
/// <summary>
|
|||
/// 发送次数上限
|
|||
/// </summary>
|
|||
public const string SendLimit = GroupName + ".SendLimit"; |
|||
/// <summary>
|
|||
/// 发送次数上限时长
|
|||
/// </summary>
|
|||
public const string SendLimitInterval = GroupName + ".SendLimitInterval"; |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
{ |
|||
"culture": "en", |
|||
"texts": { |
|||
"DisplayName:TuiJuhe": "TuiJuhe", |
|||
"Description:TuiJuhe": "TuiJuhe", |
|||
"Settings:Security.Token": "Token", |
|||
"Settings:Security.TokenDesc": "The user token, (https://tui.juhe.cn/setup) in the center of the personal page views.", |
|||
"Features:TuiJuhe": "TuiJuhe push service", |
|||
"Features:TuiJuheEnable": "Enable TuiJuhe", |
|||
"Features:TuiJuheEnableDesc": "Enable to enable the application to have TuiJuhe capabilities.", |
|||
"Features:Message": "TuiJuhe message push", |
|||
"Features:MessageEnable": "Enable TuiJuhe Message Push", |
|||
"Features:MessageEnableDesc": "Enable so that apps will have the ability to be pushed notification via TuiJuhe.", |
|||
"Features:Message.SendLimit": "Amount of TuiJuhe push", |
|||
"Features:Message.SendLimitDesc": "Set to limit the amount of TuiJuhe message push.", |
|||
"Features:Message.SendLimitInterval": "TuiJuhe message limit interval", |
|||
"Features:Message.SendLimitIntervalDesc": "Set the TuiJuhe message limit period (time scale: hours). Message sending frequency (request limit) : The rate does not exceed 50 times per unit hour.", |
|||
"Security": "Security" |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
{ |
|||
"culture": "zh-Hans", |
|||
"texts": { |
|||
"DisplayName:TuiJuhe": "聚合云推", |
|||
"Description:TuiJuhe": "聚合云推(TuiJuhe)", |
|||
"Settings:Security.Token": "用户令牌", |
|||
"Settings:Security.TokenDesc": "用户令牌,在个人中心(https://tui.juhe.cn/setup)页面查看获取.", |
|||
"Features:TuiJuhe": "聚合云推服务", |
|||
"Features:TuiJuheEnable": "启用聚合云推", |
|||
"Features:TuiJuheEnableDesc": "启用以使应用拥有聚合云推的能力.", |
|||
"Features:Message": "聚合云推消息推送", |
|||
"Features:MessageEnable": "启用聚合云推消息推送", |
|||
"Features:MessageEnableDesc": "启用以使应用将拥有通过聚合云推推送到实时消息的能力.", |
|||
"Features:Message.SendLimit": "聚合云推推送量", |
|||
"Features:Message.SendLimitDesc": "设置以限制聚合云推推送量.", |
|||
"Features:Message.SendLimitInterval": "聚合云推消息限制周期", |
|||
"Features:Message.SendLimitIntervalDesc": "设置聚合云推消息限制周期(时间刻度: 时).消息发送频率(请求限制): 单位小时内不超过50次率.", |
|||
"Security": "安全选项" |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe.Localization; |
|||
|
|||
[LocalizationResourceName("TuiJuhe")] |
|||
public class TuiJuheResource |
|||
{ |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe.Messages; |
|||
|
|||
public interface ITuiJuheMessageSender |
|||
{ |
|||
Task<TuiJuheResult<object, object>> SendAsync( |
|||
[NotNull] string title, |
|||
[NotNull] string content, |
|||
[NotNull] string serviceId, |
|||
MessageContentType contentType = MessageContentType.Text, |
|||
CancellationToken cancellationToken = default); |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
namespace LINGYUN.Abp.TuiJuhe.Messages; |
|||
|
|||
public enum MessageContentType |
|||
{ |
|||
Text = 0, |
|||
Html = 1, |
|||
Markdown = 2, |
|||
Json = 3 |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
using System.Collections.Generic; |
|||
using System.Net.Http; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe.Messages; |
|||
|
|||
internal static class MessageHttpClientExtensions |
|||
{ |
|||
public async static Task<string> SendMessageAsync( |
|||
this HttpClient httpClient, |
|||
string token, |
|||
string title, |
|||
string content, |
|||
string serviceId, |
|||
string docType = "txt", |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
var requestMessage = new HttpRequestMessage( |
|||
HttpMethod.Post, |
|||
"/api/plus/pushApi"); |
|||
|
|||
var requestData = new Dictionary<string, string> |
|||
{ |
|||
{ "token", token }, |
|||
{ "title", title }, |
|||
{ "content", content }, |
|||
{ "service_id", serviceId }, |
|||
{ "doc_type", docType ?? "txt" }, |
|||
}; |
|||
var formData = new FormUrlEncodedContent(requestData); |
|||
requestMessage.Content = formData; |
|||
|
|||
var httpResponse = await httpClient.SendAsync(requestMessage, cancellationToken); |
|||
|
|||
return await httpResponse.Content.ReadAsStringAsync(); |
|||
} |
|||
} |
|||
@ -0,0 +1,76 @@ |
|||
using JetBrains.Annotations; |
|||
using LINGYUN.Abp.Features.LimitValidation; |
|||
using LINGYUN.Abp.TuiJuhe.Features; |
|||
using LINGYUN.Abp.TuiJuhe.Token; |
|||
using System.Net.Http; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Features; |
|||
using Volo.Abp.Json; |
|||
using Volo.Abp.Settings; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe.Messages; |
|||
|
|||
[RequiresFeature(TuiJuheFeatureNames.Enable)] |
|||
public class TuiJuheMessageSender : ITuiJuheMessageSender, ITransientDependency |
|||
{ |
|||
protected IJsonSerializer JsonSerializer { get; } |
|||
protected ISettingProvider SettingProvider { get; } |
|||
protected IHttpClientFactory HttpClientFactory { get; } |
|||
protected ITuiJuheTokenProvider TokenProvider { get; } |
|||
|
|||
public TuiJuheMessageSender( |
|||
IJsonSerializer jsonSerializer, |
|||
ISettingProvider settingProvider, |
|||
IHttpClientFactory httpClientFactory, |
|||
ITuiJuheTokenProvider tokenProvider) |
|||
{ |
|||
JsonSerializer = jsonSerializer; |
|||
SettingProvider = settingProvider; |
|||
HttpClientFactory = httpClientFactory; |
|||
TokenProvider = tokenProvider; |
|||
} |
|||
|
|||
// 消息发送频率(请求限制):单位小时内不超过50次
|
|||
[RequiresFeature(TuiJuheFeatureNames.Message.Enable)] |
|||
[RequiresLimitFeature( |
|||
TuiJuheFeatureNames.Message.SendLimit, |
|||
TuiJuheFeatureNames.Message.SendLimitInterval, |
|||
LimitPolicy.Hours)] |
|||
public async virtual Task<TuiJuheResult<object, object>> SendAsync( |
|||
[NotNull] string title, |
|||
[NotNull] string content, |
|||
[NotNull] string serviceId, |
|||
MessageContentType contentType = MessageContentType.Text, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
var token = await TokenProvider.GetTokenAsync(cancellationToken); |
|||
var client = HttpClientFactory.GetTuiJuheClient(); |
|||
|
|||
var resultContent = await client.SendMessageAsync( |
|||
token, |
|||
title, |
|||
content, |
|||
serviceId, |
|||
GetDocType(contentType), |
|||
cancellationToken); |
|||
|
|||
var response = JsonSerializer |
|||
.Deserialize<TuiJuheResult<object, object>>(resultContent); |
|||
|
|||
return response; |
|||
} |
|||
|
|||
private static string GetDocType(MessageContentType contentType) |
|||
{ |
|||
return contentType switch |
|||
{ |
|||
MessageContentType.Html => "html", |
|||
MessageContentType.Text => "txt", |
|||
MessageContentType.Json => "json", |
|||
MessageContentType.Markdown => "markdown", |
|||
_ => "html", |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
using LINGYUN.Abp.TuiJuhe.Localization; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Settings; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe.Settings; |
|||
|
|||
public class TuiJuheSettingDefinitionProvider : SettingDefinitionProvider |
|||
{ |
|||
public override void Define(ISettingDefinitionContext context) |
|||
{ |
|||
context.Add(new[] |
|||
{ |
|||
new SettingDefinition( |
|||
name: TuiJuheSettingNames.Security.Token, |
|||
displayName: L("Settings:Security.Token"), |
|||
description: L("Settings:Security.TokenDesc"), |
|||
isEncrypted: true) |
|||
.WithProviders( |
|||
DefaultValueSettingValueProvider.ProviderName, |
|||
ConfigurationSettingValueProvider.ProviderName, |
|||
GlobalSettingValueProvider.ProviderName, |
|||
TenantSettingValueProvider.ProviderName), |
|||
}); |
|||
} |
|||
|
|||
public static ILocalizableString L(string name) |
|||
{ |
|||
return LocalizableString.Create<TuiJuheResource>(name); |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
namespace LINGYUN.Abp.TuiJuhe.Settings; |
|||
|
|||
public static class TuiJuheSettingNames |
|||
{ |
|||
public const string Prefix = "TuiJuhe"; |
|||
|
|||
public static class Security |
|||
{ |
|||
public const string Prefix = TuiJuheSettingNames.Prefix + ".Security"; |
|||
|
|||
public const string Token = Prefix + ".Token"; |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe.Token; |
|||
|
|||
public interface ITuiJuheTokenProvider |
|||
{ |
|||
Task<string> GetTokenAsync(CancellationToken cancellationToken = default); |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
using LINGYUN.Abp.TuiJuhe.Settings; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Settings; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe.Token; |
|||
|
|||
public class TuiJuheTokenProvider : ITuiJuheTokenProvider, ITransientDependency |
|||
{ |
|||
protected ISettingProvider SettingProvider { get; } |
|||
|
|||
public TuiJuheTokenProvider(ISettingProvider settingProvider) |
|||
{ |
|||
SettingProvider = settingProvider; |
|||
} |
|||
|
|||
public async virtual Task<string> GetTokenAsync(CancellationToken cancellationToken = default) |
|||
{ |
|||
return await SettingProvider.GetOrNullAsync( |
|||
TuiJuheSettingNames.Security.Token); |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using Volo.Abp; |
|||
using Volo.Abp.ExceptionHandling; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe; |
|||
|
|||
public class TuiJuheRemoteCallException : AbpException, IHasErrorCode |
|||
{ |
|||
public string Code { get; } |
|||
|
|||
public TuiJuheRemoteCallException(string code, string message) |
|||
: base($"The TuiJuhe api returns an error: {code} - {message}") |
|||
{ |
|||
Code = code; |
|||
} |
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe; |
|||
|
|||
[Serializable] |
|||
public class TuiJuheResult<TParam, TResult> |
|||
{ |
|||
/// <summary>
|
|||
/// 状态码
|
|||
/// </summary>
|
|||
[JsonProperty("code")] |
|||
public int Code { get; set; } |
|||
/// <summary>
|
|||
/// 错误消息
|
|||
/// </summary>
|
|||
[JsonProperty("reason")] |
|||
public string Reason { get; set; } |
|||
/// <summary>
|
|||
/// 响应数据
|
|||
/// </summary>
|
|||
[JsonProperty("result")] |
|||
public TResult Result { get; set; } |
|||
/// <summary>
|
|||
/// 响应参数
|
|||
/// </summary>
|
|||
[JsonProperty("params")] |
|||
public TParam Params { get; set; } |
|||
|
|||
[JsonIgnore] |
|||
public bool Success => 200 == Code; |
|||
|
|||
public TuiJuheResult() |
|||
{ |
|||
} |
|||
|
|||
public TuiJuheResult(int code, string reason) |
|||
{ |
|||
Code = code; |
|||
Reason = reason; |
|||
} |
|||
|
|||
public TuiJuheResult(int code, string reason, TResult result) |
|||
{ |
|||
Code = code; |
|||
Reason = reason; |
|||
Result = result; |
|||
} |
|||
|
|||
public TResult GetData() |
|||
{ |
|||
ThrowOfFailed(); |
|||
|
|||
return Result; |
|||
} |
|||
|
|||
public void ThrowOfFailed() |
|||
{ |
|||
if (!Success) |
|||
{ |
|||
throw new TuiJuheRemoteCallException(Code.ToString(), Reason); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using System; |
|||
|
|||
namespace Microsoft.Extensions.DependencyInjection; |
|||
|
|||
internal static class IServiceCollectionExtensions |
|||
{ |
|||
public static IServiceCollection AddTuiJuheClient( |
|||
this IServiceCollection services) |
|||
{ |
|||
services.AddHttpClient( |
|||
"_Abp_TuiJuhe_Client", |
|||
(httpClient) => |
|||
{ |
|||
httpClient.BaseAddress = new Uri("https://tui.juhe.cn"); |
|||
}); |
|||
|
|||
return services; |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
# LINGYUN.Abp.TuiJuhe |
|||
|
|||
集成TuiJuhe(仅适用于特定消息与人员通知, 不支持群发) |
|||
|
|||
实现TuiJuhe相关Api文档,拥有TuiJuhe开放能力 |
|||
|
|||
详情见TuiJuhe文档: https://tui.juhe.cn/docs |
|||
|
|||
## 模块引用 |
|||
|
|||
```csharp |
|||
[DependsOn(typeof(AbpTuiJuheModule))] |
|||
public class YouProjectModule : AbpModule |
|||
{ |
|||
// other |
|||
} |
|||
``` |
|||
|
|||
## Features |
|||
|
|||
* TuiJuhe TuiJuhe特性分组 |
|||
* TuiJuhe.Enable 全局启用TuiJuhe |
|||
* TuiJuhe.Message.Enable 全局启用TuiJuhe消息通道 |
|||
* TuiJuhe.Message TuiJuhe消息推送 |
|||
* TuiJuhe.Message.Enable 启用TuiJuhe消息推送 |
|||
* TuiJuhe.Message.SendLimit TuiJuhe消息推送限制次数 |
|||
* TuiJuhe.Message.SendLimitInterval TuiJuhe消息推送限制周期(时) |
|||
|
|||
## Settings |
|||
|
|||
* TuiJuhe.Security.Token 用户令牌. |
|||
@ -0,0 +1,10 @@ |
|||
namespace System.Net.Http; |
|||
|
|||
internal static class IHttpClientFactoryExtensions |
|||
{ |
|||
public static HttpClient GetTuiJuheClient( |
|||
this IHttpClientFactory httpClientFactory) |
|||
{ |
|||
return httpClientFactory.CreateClient("_Abp_TuiJuhe_Client"); |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
using LINGYUN.Abp.Tests; |
|||
|
|||
namespace LINGYUN.Abp.Notifications.TuiJuhe; |
|||
|
|||
public abstract class AbpNotificationsTuiJuheTestBase : AbpTestsBase<AbpNotificationsTuiJuheTestModule> |
|||
{ |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.Notifications.TuiJuhe; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpNotificationsTuiJuheModule), |
|||
typeof(AbpTuiJuheTestModule), |
|||
typeof(AbpNotificationsTestsModule))] |
|||
public class AbpNotificationsTuiJuheTestModule : AbpModule |
|||
{ |
|||
} |
|||
@ -0,0 +1,94 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.Notifications.TuiJuhe; |
|||
|
|||
public class NotificationSenderTests : AbpNotificationsTuiJuheTestBase |
|||
{ |
|||
protected INotificationSender NotificationSender { get; } |
|||
|
|||
public NotificationSenderTests() |
|||
{ |
|||
NotificationSender = GetRequiredService<INotificationSender>(); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData( |
|||
"Form nTest Text", |
|||
"Text content from the Xunit unit test. \r\n Click the link https://www.baidu.com/ at the top to redirect baidu site.")] |
|||
public async Task Send_Text_Test( |
|||
string title, |
|||
string message) |
|||
{ |
|||
var notificationData = new NotificationData(); |
|||
notificationData.WriteStandardData( |
|||
title, |
|||
message, |
|||
DateTime.Now, |
|||
"xUnit Test"); |
|||
|
|||
await NotificationSender.SendNofiterAsync( |
|||
NotificationsTestsNames.Test1, |
|||
notificationData); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData( |
|||
"Form nTest Html", |
|||
"<h>Html content from the Xunit unit test.</h> <br /> <a href=\"https://www.baidu.com/\">Click to redirect baidu site.</a>")] |
|||
public async Task Send_Html_Test( |
|||
string title, |
|||
string message) |
|||
{ |
|||
var notificationData = new NotificationData(); |
|||
notificationData.WriteStandardData( |
|||
title, |
|||
message, |
|||
DateTime.Now, |
|||
"xUnit Test"); |
|||
|
|||
await NotificationSender.SendNofiterAsync( |
|||
NotificationsTestsNames.Test2, |
|||
notificationData); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData( |
|||
"Form nTest Markdown", |
|||
"**Markdown content from the Xunit unit test.** <br /> <a href=\"https://www.baidu.com/\">Click to redirect baidu site.</a>")] |
|||
public async Task Send_Markdown_Test( |
|||
string title, |
|||
string message) |
|||
{ |
|||
var notificationData = new NotificationData(); |
|||
notificationData.WriteStandardData( |
|||
title, |
|||
message, |
|||
DateTime.Now, |
|||
"xUnit Test"); |
|||
|
|||
await NotificationSender.SendNofiterAsync( |
|||
NotificationsTestsNames.Test3, |
|||
notificationData); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData( |
|||
"Form nTest Json", |
|||
"{\"content\":\"Content from the Xunit unit test.\",\"url\":{\"component\":{\"name\":\"a\",\"value\":\"Click to redirect baidu site.\",\"options\":{\"href\":\"https://www.baidu.com/\"}}}}")] |
|||
public async Task Send_Json_Test( |
|||
string title, |
|||
string message) |
|||
{ |
|||
var notificationData = new NotificationData(); |
|||
notificationData.WriteStandardData( |
|||
title, |
|||
message, |
|||
DateTime.Now, |
|||
"xUnit Test"); |
|||
|
|||
await NotificationSender.SendNofiterAsync( |
|||
NotificationsTestsNames.Test4, |
|||
notificationData); |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using System.Linq; |
|||
|
|||
namespace LINGYUN.Abp.Notifications.TuiJuhe; |
|||
|
|||
public class NotificationsWxPusherTestsDefinitionProvider : NotificationDefinitionProvider |
|||
{ |
|||
public override void Define(INotificationDefinitionContext context) |
|||
{ |
|||
var group = context.GetGroupOrNull(NotificationsTestsNames.GroupName); |
|||
|
|||
var nt1 = group.Notifications.FirstOrDefault(n => n.Name.Equals(NotificationsTestsNames.Test1)); |
|||
nt1.WithProviders(TuiJuheNotificationPublishProvider.ProviderName) |
|||
.WithServiceId("1d5v5GuH"); |
|||
|
|||
var nt2 = group.Notifications.FirstOrDefault(n => n.Name.Equals(NotificationsTestsNames.Test2)); |
|||
nt2.WithProviders(TuiJuheNotificationPublishProvider.ProviderName) |
|||
.WithServiceId("1d5v5GuH"); |
|||
|
|||
var nt3 = group.Notifications.FirstOrDefault(n => n.Name.Equals(NotificationsTestsNames.Test3)); |
|||
nt3.WithProviders(TuiJuheNotificationPublishProvider.ProviderName) |
|||
.WithServiceId("1d5v5GuH"); |
|||
|
|||
var nt4 = group.Notifications.FirstOrDefault(n => n.Name.Equals(NotificationsTestsNames.Test4)); |
|||
nt4.WithProviders(TuiJuheNotificationPublishProvider.ProviderName) |
|||
.WithServiceId("1d5v5GuH"); |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<RootNamespace /> |
|||
<IsPackable>false</IsPackable> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\modules\tui-juhe\LINGYUN.Abp.Notifications.TuiJuhe\LINGYUN.Abp.Notifications.TuiJuhe.csproj" /> |
|||
<ProjectReference Include="..\LINGYUN.Abp.TestBase\LINGYUN.Abp.TestsBase.csproj" /> |
|||
<ProjectReference Include="..\LINGYUN.Abp.TuiJuhe.Tests\LINGYUN.Abp.TuiJuhe.Tests.csproj" /> |
|||
<ProjectReference Include="..\LINGYUN.Abp.Notifications.Tests\LINGYUN.Abp.Notifications.Tests.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,4 @@ |
|||
global using Xunit; |
|||
global using Shouldly; |
|||
global using LINGYUN.Abp.TuiJuhe; |
|||
global using LINGYUN.Abp.Notifications.TuiJuhe; |
|||
@ -0,0 +1,18 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<RootNamespace /> |
|||
<IsPackable>false</IsPackable> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\modules\tui-juhe\LINGYUN.Abp.TuiJuhe\LINGYUN.Abp.TuiJuhe.csproj" /> |
|||
<ProjectReference Include="..\LINGYUN.Abp.TestBase\LINGYUN.Abp.TestsBase.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,7 @@ |
|||
using LINGYUN.Abp.Tests; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe; |
|||
|
|||
public class AbpTuiJuheTestBase : AbpTestsBase<AbpTuiJuheTestModule> |
|||
{ |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
using LINGYUN.Abp.Tests; |
|||
using LINGYUN.Abp.Tests.Features; |
|||
using LINGYUN.Abp.TuiJuhe.Features; |
|||
using Microsoft.Extensions.Configuration; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpTuiJuheModule), |
|||
typeof(AbpTestsBaseModule))] |
|||
public class AbpTuiJuheTestModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var configurationOptions = new AbpConfigurationBuilderOptions |
|||
{ |
|||
BasePath = @"D:\Projects\Development\Abp\TuiJuhe", |
|||
EnvironmentName = "Test" |
|||
}; |
|||
var configuration = ConfigurationHelper.BuildConfiguration(configurationOptions); |
|||
|
|||
context.Services.ReplaceConfiguration(configuration); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<FakeFeatureOptions>(options => |
|||
{ |
|||
options.Map(TuiJuheFeatureNames.Enable, (_) => "true"); |
|||
options.Map(TuiJuheFeatureNames.Message.Enable, (_) => "true"); |
|||
options.Map(TuiJuheFeatureNames.Message.SendLimit, (_) => "50"); |
|||
options.Map(TuiJuheFeatureNames.Message.SendLimitInterval, (_) => "1"); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,100 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.TuiJuhe.Messages; |
|||
|
|||
public class TuiJuheMessageSenderTests : AbpTuiJuheTestBase |
|||
{ |
|||
protected ITuiJuheMessageSender MessageSender { get; } |
|||
public TuiJuheMessageSenderTests() |
|||
{ |
|||
MessageSender = GetRequiredService<ITuiJuheMessageSender>(); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData( |
|||
"Form Test Text", |
|||
"Content from the xUnit unit test. \r\n Click the link https://www.baidu.com/ at the top to redirect baidu site.", |
|||
"1d5v5GuH")] |
|||
public async virtual Task Send_Text_Test(string title, string content, string serviceId) |
|||
{ |
|||
var result = await MessageSender |
|||
.SendAsync( |
|||
title, |
|||
content, |
|||
serviceId, |
|||
MessageContentType.Text); |
|||
|
|||
result.ShouldNotBeNull(); |
|||
result.Code.ShouldBe(200); |
|||
result.Reason.ShouldBe("success"); |
|||
result.Success.ShouldBeTrue(); |
|||
result.Params.ShouldBeNull(); |
|||
result.Result.ShouldBeNull(); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData( |
|||
"Form Test Html", |
|||
"<h>Content from the xUnit unit test.</h> <br /> <a href=\"https://www.baidu.com/\">Click to redirect baidu site.</a>", |
|||
"1d5v5GuH")] |
|||
public async virtual Task Send_Html_Test(string title, string content, string serviceId) |
|||
{ |
|||
var result = await MessageSender |
|||
.SendAsync( |
|||
title, |
|||
content, |
|||
serviceId, |
|||
MessageContentType.Html); |
|||
|
|||
result.ShouldNotBeNull(); |
|||
result.Code.ShouldBe(200); |
|||
result.Reason.ShouldBe("success"); |
|||
result.Success.ShouldBeTrue(); |
|||
result.Params.ShouldBeNull(); |
|||
result.Result.ShouldBeNull(); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData( |
|||
"Form Test Markdown", |
|||
"**Content from the Xunit unit test.** <br /> <a href=\"https://www.baidu.com/\">Click to redirect baidu site.</a>", |
|||
"1d5v5GuH")] |
|||
public async virtual Task Send_Markdown_Test(string title, string content, string serviceId) |
|||
{ |
|||
var result = await MessageSender |
|||
.SendAsync( |
|||
title, |
|||
content, |
|||
serviceId, |
|||
MessageContentType.Markdown); |
|||
|
|||
result.ShouldNotBeNull(); |
|||
result.Code.ShouldBe(200); |
|||
result.Reason.ShouldBe("success"); |
|||
result.Success.ShouldBeTrue(); |
|||
result.Params.ShouldBeNull(); |
|||
result.Result.ShouldBeNull(); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData( |
|||
"Form Test Json", |
|||
"{\"content\":\"Content from the Xunit unit test.\",\"url\":{\"component\":{\"name\":\"a\",\"value\":\"Click to redirect baidu site.\",\"options\":{\"href\":\"https://www.baidu.com/\"}}}}", |
|||
"1d5v5GuH")] |
|||
public async virtual Task Send_Json_Test(string title, string content, string serviceId) |
|||
{ |
|||
var result = await MessageSender |
|||
.SendAsync( |
|||
title, |
|||
content, |
|||
serviceId, |
|||
MessageContentType.Json); |
|||
|
|||
result.ShouldNotBeNull(); |
|||
result.Code.ShouldBe(200); |
|||
result.Reason.ShouldBe("success"); |
|||
result.Success.ShouldBeTrue(); |
|||
result.Params.ShouldBeNull(); |
|||
result.Result.ShouldBeNull(); |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
global using Xunit; |
|||
global using Shouldly; |
|||
global using LINGYUN.Abp.TuiJuhe; |
|||
Loading…
Reference in new issue