29 changed files with 442 additions and 54 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,20 @@ |
|||
<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.Emailing" Version="$(VoloAbpPackageVersion)" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\identity\LINGYUN.Abp.Identity.Domain\LINGYUN.Abp.Identity.Domain.csproj" /> |
|||
<ProjectReference Include="..\LINGYUN.Abp.Notifications\LINGYUN.Abp.Notifications.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,22 @@ |
|||
using LINGYUN.Abp.Identity; |
|||
using Volo.Abp.Emailing; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.Notifications.Emailing; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpNotificationModule), |
|||
typeof(AbpEmailingModule), |
|||
typeof(AbpIdentityDomainModule))] |
|||
public class AbpNotificationsEmailingModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpNotificationOptions>(options => |
|||
{ |
|||
options.PublishProviders.Add<EmailingNotificationPublishProvider>(); |
|||
options.NotificationDataMappings |
|||
.MappingDefault(EmailingNotificationPublishProvider.ProviderName, data => data); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,77 @@ |
|||
using LINGYUN.Abp.Identity; |
|||
using Microsoft.Extensions.Localization; |
|||
using Microsoft.Extensions.Logging; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Emailing; |
|||
using Volo.Abp.TextTemplating; |
|||
|
|||
namespace LINGYUN.Abp.Notifications.Emailing; |
|||
|
|||
public class EmailingNotificationPublishProvider : NotificationPublishProvider |
|||
{ |
|||
public const string ProviderName = NotificationProviderNames.Emailing; |
|||
|
|||
public override string Name => ProviderName; |
|||
|
|||
protected IEmailSender EmailSender { get; } |
|||
|
|||
protected ITemplateRenderer TemplateRenderer { get; } |
|||
|
|||
protected IStringLocalizerFactory LocalizerFactory { get; } |
|||
|
|||
protected IIdentityUserRepository UserRepository { get; } |
|||
|
|||
protected INotificationDefinitionManager NotificationDefinitionManager { get; } |
|||
|
|||
public EmailingNotificationPublishProvider( |
|||
IServiceProvider serviceProvider, |
|||
IEmailSender emailSender, |
|||
ITemplateRenderer templateRenderer, |
|||
IStringLocalizerFactory localizerFactory, |
|||
IIdentityUserRepository userRepository, |
|||
INotificationDefinitionManager notificationDefinitionManager) |
|||
: base(serviceProvider) |
|||
{ |
|||
EmailSender = emailSender; |
|||
TemplateRenderer = templateRenderer; |
|||
LocalizerFactory = localizerFactory; |
|||
UserRepository = userRepository; |
|||
NotificationDefinitionManager = notificationDefinitionManager; |
|||
} |
|||
|
|||
protected async override Task PublishAsync( |
|||
NotificationInfo notification, |
|||
IEnumerable<UserIdentifier> identifiers, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
var userIds = identifiers.Select(x => x.UserId).ToList(); |
|||
var userList = await UserRepository.GetListByIdListAsync(userIds, cancellationToken: cancellationToken); |
|||
var emailAddress = userList.Where(x => x.EmailConfirmed).Select(x => x.Email).Distinct().JoinAsString(","); |
|||
|
|||
if (emailAddress.IsNullOrWhiteSpace()) |
|||
{ |
|||
Logger.LogWarning("The subscriber did not confirm the email address and could not send email notifications!"); |
|||
return; |
|||
} |
|||
|
|||
var notificationDefinition = NotificationDefinitionManager.Get(notification.Name); |
|||
var notificationDisplayName = notificationDefinition.DisplayName.Localize(LocalizerFactory).Value; |
|||
|
|||
notificationDefinition.Properties.TryGetValue("Template", out var template); |
|||
if (template == null) |
|||
{ |
|||
Logger.LogWarning("The email template is not specified, so the email notification cannot be sent!"); |
|||
return; |
|||
} |
|||
|
|||
var content = await TemplateRenderer.RenderAsync( |
|||
template.ToString(), |
|||
globalContext: notification.Data.ExtraProperties); |
|||
|
|||
await EmailSender.SendAsync(emailAddress, notificationDisplayName, content); |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
namespace LINGYUN.Abp.Notifications; |
|||
|
|||
/// <summary>
|
|||
/// 内置通知提供者
|
|||
/// </summary>
|
|||
public static class NotificationProviderNames |
|||
{ |
|||
/// <summary>
|
|||
/// SignalR 实时通知
|
|||
/// </summary>
|
|||
public const string SignalR = "SignalR"; |
|||
/// <summary>
|
|||
/// 短信通知
|
|||
/// </summary>
|
|||
public const string Sms = "Sms"; |
|||
/// <summary>
|
|||
/// 邮件通知
|
|||
/// </summary>
|
|||
public const string Emailing = "Emailing"; |
|||
/// <summary>
|
|||
/// 微信小程序模板通知
|
|||
/// </summary>
|
|||
public const string WechatMiniProgram = "WeChat.MiniProgram"; |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
using Volo.Abp.TextTemplating; |
|||
using Volo.Abp.TextTemplating.Scriban; |
|||
|
|||
namespace LY.MicroService.RealtimeMessage.Emailing; |
|||
|
|||
public class RealtimeMessageTemplateProvider : TemplateDefinitionProvider |
|||
{ |
|||
public override void Define(ITemplateDefinitionContext context) |
|||
{ |
|||
context.Add(CreateEmailTemplate()); |
|||
} |
|||
|
|||
protected virtual TemplateDefinition[] CreateEmailTemplate() |
|||
{ |
|||
return new TemplateDefinition[] |
|||
{ |
|||
new TemplateDefinition( |
|||
name: "EmailNotifierLayout", |
|||
defaultCultureName: "en", |
|||
isLayout: true) |
|||
.WithScribanEngine() |
|||
.WithVirtualFilePath( |
|||
"/Emailing/Templates/layout.tpl", |
|||
isInlineLocalized: false), |
|||
new TemplateDefinition( |
|||
name: "ExceptionNotifier", |
|||
defaultCultureName: "en", |
|||
layout: "EmailNotifierLayout") |
|||
.WithScribanEngine() |
|||
.WithVirtualFilePath( |
|||
"/Emailing/Templates/ExceptionNotifier", |
|||
isInlineLocalized: false), |
|||
new TemplateDefinition( |
|||
"NewTenantRegisterd", |
|||
defaultCultureName: "en", |
|||
layout: "EmailNotifierLayout") |
|||
.WithScribanEngine() |
|||
.WithVirtualFilePath( |
|||
"/Emailing/Templates/NewTenantRegisterd", |
|||
isInlineLocalized: false), |
|||
new TemplateDefinition( |
|||
"WelcomeToApplication", |
|||
defaultCultureName: "en", |
|||
layout: "EmailNotifierLayout") |
|||
.WithScribanEngine() |
|||
.WithVirtualFilePath( |
|||
"/Emailing/Templates/WelcomeToApplication", |
|||
isInlineLocalized: false), |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif"> |
|||
<tr> |
|||
<td> |
|||
<br /> <b><font color="#0B610B">{{ header }}</font></b> |
|||
<hr size="2" width="100%" align="center" /> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td> |
|||
<ul> |
|||
<li>Type : {{ type }}</li> |
|||
<li>Message : {{ message }}</li> |
|||
<li>Alarm level : {{ loglevel }}</li> |
|||
<li>TriggerTime : {{ createTime }}</li> |
|||
</ul> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td> |
|||
<b><font color="#0B610B">Stack trace</font></b> |
|||
<hr size="2" width="100%" align="center" /> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td> |
|||
<pre style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">{{ stacktrace }}</pre> |
|||
<br /> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td> |
|||
<br /> |
|||
<b style="float: right"><font color="#0B610B">{{ footer }}</font></b> |
|||
<hr size="2" width="100%" align="center" /> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
@ -0,0 +1,37 @@ |
|||
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif"> |
|||
<tr> |
|||
<td> |
|||
<br /> <b><font color="#0B610B">{{ header }}</font></b> |
|||
<hr size="2" width="100%" align="center" /> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td> |
|||
<ul> |
|||
<li>异常类型 : {{ title }}</li> |
|||
<li>异常信息 : {{ message }}</li> |
|||
<li>告警级别 : {{ loglevel }}</li> |
|||
<li>触发时间 : {{ createTime }}</li> |
|||
</ul> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td> |
|||
<b><font color="#0B610B">异常堆栈</font></b> |
|||
<hr size="2" width="100%" align="center" /> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td> |
|||
<pre style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">{{ stacktrace }}</pre> |
|||
<br /> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td> |
|||
<br /> |
|||
<b style="float: right"><font color="#0B610B">{{ footer }}</font></b> |
|||
<hr size="2" width="100%" align="center" /> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
@ -0,0 +1 @@ |
|||
<h3>A new tenant {{name}} has been created.</h3> |
|||
@ -0,0 +1 @@ |
|||
<h3>一个新的租户 {{name}} 已建立,切换租户开始! </h3> |
|||
@ -0,0 +1 @@ |
|||
<h3>{{user}}, Welcome to my application!</h3> |
|||
@ -0,0 +1 @@ |
|||
<h3>{{user}}, Welcome to my application!</h3> |
|||
@ -0,0 +1,10 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<title>{{title}}</title> |
|||
</head> |
|||
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0"> |
|||
{{content}} |
|||
</body> |
|||
</html> |
|||
Loading…
Reference in new issue