mirror of https://github.com/abpframework/eventhub
Browse Source
Send email for new event creation, event reminder, and event registrationpull/21/head
committed by
GitHub
21 changed files with 5935 additions and 12 deletions
@ -0,0 +1,37 @@ |
|||||
|
using Volo.Abp.TextTemplating; |
||||
|
|
||||
|
namespace EventHub.Emailing |
||||
|
{ |
||||
|
public class EmailTemplateDefinitionProvider : TemplateDefinitionProvider |
||||
|
{ |
||||
|
public override void Define(ITemplateDefinitionContext context) |
||||
|
{ |
||||
|
context.Add( |
||||
|
new TemplateDefinition( |
||||
|
EmailTemplates.EventRegistration |
||||
|
).WithVirtualFilePath( |
||||
|
"/Emailing/Templates/EventRegistration.tpl", |
||||
|
isInlineLocalized: true |
||||
|
) |
||||
|
); |
||||
|
|
||||
|
context.Add( |
||||
|
new TemplateDefinition( |
||||
|
EmailTemplates.EventReminder |
||||
|
).WithVirtualFilePath( |
||||
|
"/Emailing/Templates/EventReminder.tpl", |
||||
|
isInlineLocalized: true |
||||
|
) |
||||
|
); |
||||
|
|
||||
|
context.Add( |
||||
|
new TemplateDefinition( |
||||
|
EmailTemplates.NewEventCreated |
||||
|
).WithVirtualFilePath( |
||||
|
"/Emailing/Templates/NewEventCreated.tpl", |
||||
|
isInlineLocalized: true |
||||
|
) |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
namespace EventHub.Emailing |
||||
|
{ |
||||
|
public static class EmailTemplates |
||||
|
{ |
||||
|
public const string EventRegistration = "EventHub.Event.Registration"; |
||||
|
|
||||
|
public const string EventReminder = "EventHub.Event.Reminder"; |
||||
|
|
||||
|
public const string NewEventCreated = "EventHub.Event.NewEventCreated"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,157 @@ |
|||||
|
<html> |
||||
|
|
||||
|
<head> |
||||
|
<meta name="viewport" content="width=device-width"> |
||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
||||
|
<title>Eventhub</title> |
||||
|
<style> |
||||
|
@media only screen and (max-width: 620px) { |
||||
|
table[class=mail-body] h1{ |
||||
|
font-size: 36px !important; |
||||
|
margin-bottom: 10px !important; |
||||
|
} |
||||
|
table[class=mail-body] .content { |
||||
|
padding: 0 !important; |
||||
|
} |
||||
|
table[class=mail-body] .container { |
||||
|
padding: 0 !important; |
||||
|
width: 100% !important; |
||||
|
} |
||||
|
table[class=mail-body] .main { |
||||
|
border-left-width: 0 !important; |
||||
|
border-radius: 0 !important; |
||||
|
border-right-width: 0 !important; |
||||
|
} |
||||
|
table[class=mail-body] td { |
||||
|
width: 100% !important; |
||||
|
float: left!important; |
||||
|
} |
||||
|
table[class=mail-body] td a.btn { |
||||
|
display: block !important; |
||||
|
text-align: center; |
||||
|
} |
||||
|
table[class=mail-body] td h2 { |
||||
|
margin: 10px 0 !important; |
||||
|
} |
||||
|
table[class=mail-body] td .cont { |
||||
|
padding: 30px !important; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
<table border="0" cellpadding="0" cellspacing="0" class="mail-body" style="background-color: #ffffff;width: 100%; font-size: 16px;line-height: 1.4;font-family: Arial, sans-serif;"> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td class="container" width="800" style="display: block;margin: 0 auto !important; max-width: 800px;padding: 10px;width: 800px;"> |
||||
|
<div class="content" style="box-sizing: border-box;display: block;margin: 0 auto;max-width: 800px;padding: 0px;"> |
||||
|
<div style="display: flex; padding-top: 1.5rem"> |
||||
|
|
||||
|
<h1 style="justify-content: center;margin-left: auto;margin-right: auto;align-content: center;">EventHub</h1> |
||||
|
|
||||
|
</div> |
||||
|
<!-- START CENTERED WHITE CONTAINER --> |
||||
|
<div style="display: flex;"> |
||||
|
|
||||
|
<h1 style="justify-content: center;margin-left: auto;margin-right: auto;align-content: center;">{{model.title}}</h1> |
||||
|
|
||||
|
</div> |
||||
|
<table class="main" style="background: #ffffff;border-radius: 3px; width: 100%;"> |
||||
|
<!-- START MAIN CONTENT AREA --> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td class="wrapper" width="800"> |
||||
|
<table class="main" style="background: #ffffff;border-radius: 3px;width: 100%;"> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td class="wrapper" width="800"> |
||||
|
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; vertical-align: top;mso-table-lspace: 0pt;mso-table-rspace: 0pt;width: 100%; "> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td style="vertical-align: top;" width="100%"> |
||||
|
<div class="cont" style="background: #eeeeee; border-radius: 10px; padding: 40px; margin-top: 20px;"> |
||||
|
<table style="border-collapse: separate; vertical-align: top;mso-table-lspace: 0pt;mso-table-rspace: 0pt;width: 100%; "> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td width="100%" style="vertical-align: top; font-size: 16px; font-family: Arial, sans-serif; color: #444; margin-top: 20px; margin-bottom: 20px; line-height: 1.75"> |
||||
|
<p> |
||||
|
Hi, |
||||
|
</p> |
||||
|
<p> |
||||
|
Great news! You attended the "{{model.title}}" event. |
||||
|
</p> |
||||
|
<div> |
||||
|
<table border="0" cellpadding="0" cellspacing="0" style=" border-collapse: separate; vertical-align: top; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;"> |
||||
|
<tbody> |
||||
|
<tr style="text-align: center"> |
||||
|
<td style="vertical-align: top;"> |
||||
|
|
||||
|
<p style="font-size: 13px; font-family: Arial, sans-serif; color: #777777; margin: 0; margin-top: 30px;">Start Time</p> |
||||
|
<p style="font-size: 21px; font-family: Arial, sans-serif; color: #444444; margin-bottom: 30px; margin-top: 6px;">{{model.start_time}}</p> |
||||
|
</td> |
||||
|
<td style="vertical-align: top;"> |
||||
|
|
||||
|
<p style="font-size: 13px; font-family: Arial, sans-serif; color: #777777; margin: 0; margin-top: 30px;">End Time</p> |
||||
|
<p style="font-size: 21px; font-family: Arial, sans-serif; color: #444444; margin-bottom: 30px; margin-top: 6px;">{{model.end_time}}</p> |
||||
|
</td> |
||||
|
|
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
<p style="margin-bottom: 20px; margin-top: 20px; text-align: center;"> |
||||
|
<a href="/events/{{model.url}}" class="btn" target="_blank" style="padding: 15px; background: #e90052; border-radius: 40px; text-align: center; color: white; font-weight: bold; text-decoration: none; font-size: 18px; padding-left: 45px; padding-right: 45px;">Event Details</a> |
||||
|
</p> |
||||
|
</div> |
||||
|
|
||||
|
<p style="font-size: 16px; font-family: Arial, sans-serif; color: #444; margin-top: 20px; margin-bottom: 0px;"> |
||||
|
Thank you,<br> EventHub |
||||
|
</p> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
|
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
<!-- START FOOTER --> |
||||
|
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; vertical-align: top;mso-table-lspace: 0pt;mso-table-rspace: 0pt;width: 100%;"> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td class="content-block" style="vertical-align: top;" width="800"> |
||||
|
<div class="cont" style="background: #ffffff;border-top: 2px solid #eee; padding: 35px 40px 5px; margin-top: 0px; text-align: center;"> |
||||
|
<a href="https://eventhub.abp.io/" style="font-size: 16px; font-family: Arial, sans-serif; color: #777; font-weight: bold; margin-right: 30px; text-decoration: none;">Home</a> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td class="content-block powered-by" style="vertical-align: top;" width="100%"> |
||||
|
<div class="cont" style="background: #ffffff; border-radius: 10px; padding: 5px 40px; margin-top: 10px; margin-bottom: 50px; text-align: center;"> |
||||
|
<a href="mailto:info@eventhub.abp.io" style="font-size: 16px; font-family: Arial, sans-serif; color: #777; font-weight: bold; margin-right: 30px; text-decoration: none;"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAARCAYAAADHeGwwAAABMElEQVQ4je3TvyvFYRQG8M+9LEwWiV0xyeAi2ZTUFQuZDAqTxUCJzY9BFotS/gAySAZFEgYlySzFLosfs169w6XL/V6uzbO973vO85z3OeekstlsGRYxrrTYw1g56jGNO6yivAQyS5hFdRpHGMQauvDwC+IXDGAGnTgJApXYxAJO0YLrH5Dfog3bmMAhatI5AUF1B4/oiIFJcYAMbrCRa3X6E0EvzlEbbZtLILCMHlQESzCS+/hZIKARF7Ef8+jDc564VwxhCq24jL/4gHwCAVXYxyR2o7e3Oe/30cbQuzEcB7/zEX03kkF8BU2RJFS3hVS07wnrGP2GI9HMD6MB/eiOd9Wx6vZCyUmXKhM9Hojn8JO6JInFbG2YrLMi4t/xVZNLhn+BgghNvkLzn7Bz9QbIADMmEt9imAAAAABJRU5ErkJggg==" width="16"> info@eventhub.abp.io</a> |
||||
|
<span style="font-size: 16px; font-family: Arial, sans-serif; color: #777; margin-right: 0px; text-decoration: none;"><strong>EventHub</strong> - Powered by Volosoft</span> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
<!-- END FOOTER --> |
||||
|
<!-- END CENTERED WHITE CONTAINER --> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</body> |
||||
|
|
||||
|
</html> |
||||
@ -0,0 +1,157 @@ |
|||||
|
<html> |
||||
|
|
||||
|
<head> |
||||
|
<meta name="viewport" content="width=device-width"> |
||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
||||
|
<title>Eventhub</title> |
||||
|
<style> |
||||
|
@media only screen and (max-width: 620px) { |
||||
|
table[class=mail-body] h1{ |
||||
|
font-size: 36px !important; |
||||
|
margin-bottom: 10px !important; |
||||
|
} |
||||
|
table[class=mail-body] .content { |
||||
|
padding: 0 !important; |
||||
|
} |
||||
|
table[class=mail-body] .container { |
||||
|
padding: 0 !important; |
||||
|
width: 100% !important; |
||||
|
} |
||||
|
table[class=mail-body] .main { |
||||
|
border-left-width: 0 !important; |
||||
|
border-radius: 0 !important; |
||||
|
border-right-width: 0 !important; |
||||
|
} |
||||
|
table[class=mail-body] td { |
||||
|
width: 100% !important; |
||||
|
float: left!important; |
||||
|
} |
||||
|
table[class=mail-body] td a.btn { |
||||
|
display: block !important; |
||||
|
text-align: center; |
||||
|
} |
||||
|
table[class=mail-body] td h2 { |
||||
|
margin: 10px 0 !important; |
||||
|
} |
||||
|
table[class=mail-body] td .cont { |
||||
|
padding: 30px !important; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
<table border="0" cellpadding="0" cellspacing="0" class="mail-body" style="background-color: #ffffff;width: 100%; font-size: 16px;line-height: 1.4;font-family: Arial, sans-serif;"> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td class="container" width="800" style="display: block;margin: 0 auto !important; max-width: 800px;padding: 10px;width: 800px;"> |
||||
|
<div class="content" style="box-sizing: border-box;display: block;margin: 0 auto;max-width: 800px;padding: 0px;"> |
||||
|
<div style="display: flex; padding-top: 1.5rem"> |
||||
|
|
||||
|
<h1 style="justify-content: center;margin-left: auto;margin-right: auto;align-content: center;">EventHub</h1> |
||||
|
|
||||
|
</div> |
||||
|
<!-- START CENTERED WHITE CONTAINER --> |
||||
|
<div style="display: flex;"> |
||||
|
|
||||
|
<h1 style="justify-content: center;margin-left: auto;margin-right: auto;align-content: center;">{{model.title}} event will start soon</h1> |
||||
|
|
||||
|
</div> |
||||
|
<table class="main" style="background: #ffffff;border-radius: 3px; width: 100%;"> |
||||
|
<!-- START MAIN CONTENT AREA --> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td class="wrapper" width="800"> |
||||
|
<table class="main" style="background: #ffffff;border-radius: 3px;width: 100%;"> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td class="wrapper" width="800"> |
||||
|
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; vertical-align: top;mso-table-lspace: 0pt;mso-table-rspace: 0pt;width: 100%; "> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td style="vertical-align: top;" width="100%"> |
||||
|
<div class="cont" style="background: #eeeeee; border-radius: 10px; padding: 40px; margin-top: 20px;"> |
||||
|
<table style="border-collapse: separate; vertical-align: top;mso-table-lspace: 0pt;mso-table-rspace: 0pt;width: 100%; "> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td width="100%" style="vertical-align: top; font-size: 16px; font-family: Arial, sans-serif; color: #444; margin-top: 20px; margin-bottom: 20px; line-height: 1.75"> |
||||
|
<p> |
||||
|
Hi {{model.user_name}}, |
||||
|
</p> |
||||
|
<p> |
||||
|
The "{{model.title}}" event will start very soon. |
||||
|
</p> |
||||
|
<div> |
||||
|
<table border="0" cellpadding="0" cellspacing="0" style=" border-collapse: separate; vertical-align: top; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;"> |
||||
|
<tbody> |
||||
|
<tr style="text-align: center"> |
||||
|
<td style="vertical-align: top;"> |
||||
|
|
||||
|
<p style="font-size: 13px; font-family: Arial, sans-serif; color: #777777; margin: 0; margin-top: 30px;">Start Time</p> |
||||
|
<p style="font-size: 21px; font-family: Arial, sans-serif; color: #444444; margin-bottom: 30px; margin-top: 6px;">{{model.start_time}}</p> |
||||
|
</td> |
||||
|
<td style="vertical-align: top;"> |
||||
|
|
||||
|
<p style="font-size: 13px; font-family: Arial, sans-serif; color: #777777; margin: 0; margin-top: 30px;">End Time</p> |
||||
|
<p style="font-size: 21px; font-family: Arial, sans-serif; color: #444444; margin-bottom: 30px; margin-top: 6px;">{{model.end_time}}</p> |
||||
|
</td> |
||||
|
|
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
<p style="margin-bottom: 20px; margin-top: 20px; text-align: center;"> |
||||
|
<a href="/events/{{model.url}}" class="btn" target="_blank" style="padding: 15px; background: #e90052; border-radius: 40px; text-align: center; color: white; font-weight: bold; text-decoration: none; font-size: 18px; padding-left: 45px; padding-right: 45px;">Event Details</a> |
||||
|
</p> |
||||
|
</div> |
||||
|
|
||||
|
<p style="font-size: 16px; font-family: Arial, sans-serif; color: #444; margin-top: 20px; margin-bottom: 0px;"> |
||||
|
Thank you,<br> EventHub |
||||
|
</p> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
|
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
<!-- START FOOTER --> |
||||
|
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; vertical-align: top;mso-table-lspace: 0pt;mso-table-rspace: 0pt;width: 100%;"> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td class="content-block" style="vertical-align: top;" width="800"> |
||||
|
<div class="cont" style="background: #ffffff;border-top: 2px solid #eee; padding: 35px 40px 5px; margin-top: 0px; text-align: center;"> |
||||
|
<a href="https://eventhub.abp.io/" style="font-size: 16px; font-family: Arial, sans-serif; color: #777; font-weight: bold; margin-right: 30px; text-decoration: none;">Home</a> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td class="content-block powered-by" style="vertical-align: top;" width="100%"> |
||||
|
<div class="cont" style="background: #ffffff; border-radius: 10px; padding: 5px 40px; margin-top: 10px; margin-bottom: 50px; text-align: center;"> |
||||
|
<a href="mailto:info@eventhub.abp.io" style="font-size: 16px; font-family: Arial, sans-serif; color: #777; font-weight: bold; margin-right: 30px; text-decoration: none;"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAARCAYAAADHeGwwAAABMElEQVQ4je3TvyvFYRQG8M+9LEwWiV0xyeAi2ZTUFQuZDAqTxUCJzY9BFotS/gAySAZFEgYlySzFLosfs169w6XL/V6uzbO973vO85z3OeekstlsGRYxrrTYw1g56jGNO6yivAQyS5hFdRpHGMQauvDwC+IXDGAGnTgJApXYxAJO0YLrH5Dfog3bmMAhatI5AUF1B4/oiIFJcYAMbrCRa3X6E0EvzlEbbZtLILCMHlQESzCS+/hZIKARF7Ef8+jDc564VwxhCq24jL/4gHwCAVXYxyR2o7e3Oe/30cbQuzEcB7/zEX03kkF8BU2RJFS3hVS07wnrGP2GI9HMD6MB/eiOd9Wx6vZCyUmXKhM9Hojn8JO6JInFbG2YrLMi4t/xVZNLhn+BgghNvkLzn7Bz9QbIADMmEt9imAAAAABJRU5ErkJggg==" width="16"> info@eventhub.abp.io</a> |
||||
|
<span style="font-size: 16px; font-family: Arial, sans-serif; color: #777; margin-right: 0px; text-decoration: none;"><strong>EventHub</strong> - Powered by Volosoft</span> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
<!-- END FOOTER --> |
||||
|
<!-- END CENTERED WHITE CONTAINER --> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</body> |
||||
|
|
||||
|
</html> |
||||
@ -0,0 +1,157 @@ |
|||||
|
<html> |
||||
|
|
||||
|
<head> |
||||
|
<meta name="viewport" content="width=device-width"> |
||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
||||
|
<title>Eventhub</title> |
||||
|
<style> |
||||
|
@media only screen and (max-width: 620px) { |
||||
|
table[class=mail-body] h1{ |
||||
|
font-size: 36px !important; |
||||
|
margin-bottom: 10px !important; |
||||
|
} |
||||
|
table[class=mail-body] .content { |
||||
|
padding: 0 !important; |
||||
|
} |
||||
|
table[class=mail-body] .container { |
||||
|
padding: 0 !important; |
||||
|
width: 100% !important; |
||||
|
} |
||||
|
table[class=mail-body] .main { |
||||
|
border-left-width: 0 !important; |
||||
|
border-radius: 0 !important; |
||||
|
border-right-width: 0 !important; |
||||
|
} |
||||
|
table[class=mail-body] td { |
||||
|
width: 100% !important; |
||||
|
float: left!important; |
||||
|
} |
||||
|
table[class=mail-body] td a.btn { |
||||
|
display: block !important; |
||||
|
text-align: center; |
||||
|
} |
||||
|
table[class=mail-body] td h2 { |
||||
|
margin: 10px 0 !important; |
||||
|
} |
||||
|
table[class=mail-body] td .cont { |
||||
|
padding: 30px !important; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
<table border="0" cellpadding="0" cellspacing="0" class="mail-body" style="background-color: #ffffff;width: 100%; font-size: 16px;line-height: 1.4;font-family: Arial, sans-serif;"> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td class="container" width="800" style="display: block;margin: 0 auto !important; max-width: 800px;padding: 10px;width: 800px;"> |
||||
|
<div class="content" style="box-sizing: border-box;display: block;margin: 0 auto;max-width: 800px;padding: 0px;"> |
||||
|
<div style="display: flex; padding-top: 1.5rem"> |
||||
|
|
||||
|
<h1 style="justify-content: center;margin-left: auto;margin-right: auto;align-content: center;">EventHub</h1> |
||||
|
|
||||
|
</div> |
||||
|
<!-- START CENTERED WHITE CONTAINER --> |
||||
|
<div style="display: flex;"> |
||||
|
|
||||
|
<h1 style="justify-content: center;margin-left: auto;margin-right: auto;align-content: center;">There is a new event that may interest you</h1> |
||||
|
|
||||
|
</div> |
||||
|
<table class="main" style="background: #ffffff;border-radius: 3px; width: 100%;"> |
||||
|
<!-- START MAIN CONTENT AREA --> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td class="wrapper" width="800"> |
||||
|
<table class="main" style="background: #ffffff;border-radius: 3px;width: 100%;"> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td class="wrapper" width="800"> |
||||
|
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; vertical-align: top;mso-table-lspace: 0pt;mso-table-rspace: 0pt;width: 100%; "> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td style="vertical-align: top;" width="100%"> |
||||
|
<div class="cont" style="background: #eeeeee; border-radius: 10px; padding: 40px; margin-top: 20px;"> |
||||
|
<table style="border-collapse: separate; vertical-align: top;mso-table-lspace: 0pt;mso-table-rspace: 0pt;width: 100%; "> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td width="100%" style="vertical-align: top; font-size: 16px; font-family: Arial, sans-serif; color: #444; margin-top: 20px; margin-bottom: 20px; line-height: 1.75"> |
||||
|
<p> |
||||
|
Hi {{model.user_name}}, |
||||
|
</p> |
||||
|
<p> |
||||
|
A new event called "{{model.title}}" has been created. |
||||
|
</p> |
||||
|
<div> |
||||
|
<table border="0" cellpadding="0" cellspacing="0" style=" border-collapse: separate; vertical-align: top; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;"> |
||||
|
<tbody> |
||||
|
<tr style="text-align: center"> |
||||
|
<td style="vertical-align: top;"> |
||||
|
|
||||
|
<p style="font-size: 13px; font-family: Arial, sans-serif; color: #777777; margin: 0; margin-top: 30px;">Start Time</p> |
||||
|
<p style="font-size: 21px; font-family: Arial, sans-serif; color: #444444; margin-bottom: 30px; margin-top: 6px;">{{model.start_time}}</p> |
||||
|
</td> |
||||
|
<td style="vertical-align: top;"> |
||||
|
|
||||
|
<p style="font-size: 13px; font-family: Arial, sans-serif; color: #777777; margin: 0; margin-top: 30px;">End Time</p> |
||||
|
<p style="font-size: 21px; font-family: Arial, sans-serif; color: #444444; margin-bottom: 30px; margin-top: 6px;">{{model.end_time}}</p> |
||||
|
</td> |
||||
|
|
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
<p style="margin-bottom: 20px; margin-top: 20px; text-align: center;"> |
||||
|
<a href="/events/{{model.url}}" class="btn" target="_blank" style="padding: 15px; background: #e90052; border-radius: 40px; text-align: center; color: white; font-weight: bold; text-decoration: none; font-size: 18px; padding-left: 45px; padding-right: 45px;">Event Details</a> |
||||
|
</p> |
||||
|
</div> |
||||
|
|
||||
|
<p style="font-size: 16px; font-family: Arial, sans-serif; color: #444; margin-top: 20px; margin-bottom: 0px;"> |
||||
|
Thank you,<br> EventHub |
||||
|
</p> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
|
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
<!-- START FOOTER --> |
||||
|
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; vertical-align: top;mso-table-lspace: 0pt;mso-table-rspace: 0pt;width: 100%;"> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td class="content-block" style="vertical-align: top;" width="800"> |
||||
|
<div class="cont" style="background: #ffffff;border-top: 2px solid #eee; padding: 35px 40px 5px; margin-top: 0px; text-align: center;"> |
||||
|
<a href="https://eventhub.abp.io/" style="font-size: 16px; font-family: Arial, sans-serif; color: #777; font-weight: bold; margin-right: 30px; text-decoration: none;">Home</a> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td class="content-block powered-by" style="vertical-align: top;" width="100%"> |
||||
|
<div class="cont" style="background: #ffffff; border-radius: 10px; padding: 5px 40px; margin-top: 10px; margin-bottom: 50px; text-align: center;"> |
||||
|
<a href="mailto:info@eventhub.abp.io" style="font-size: 16px; font-family: Arial, sans-serif; color: #777; font-weight: bold; margin-right: 30px; text-decoration: none;"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAARCAYAAADHeGwwAAABMElEQVQ4je3TvyvFYRQG8M+9LEwWiV0xyeAi2ZTUFQuZDAqTxUCJzY9BFotS/gAySAZFEgYlySzFLosfs169w6XL/V6uzbO973vO85z3OeekstlsGRYxrrTYw1g56jGNO6yivAQyS5hFdRpHGMQauvDwC+IXDGAGnTgJApXYxAJO0YLrH5Dfog3bmMAhatI5AUF1B4/oiIFJcYAMbrCRa3X6E0EvzlEbbZtLILCMHlQESzCS+/hZIKARF7Ef8+jDc564VwxhCq24jL/4gHwCAVXYxyR2o7e3Oe/30cbQuzEcB7/zEX03kkF8BU2RJFS3hVS07wnrGP2GI9HMD6MB/eiOd9Wx6vZCyUmXKhM9Hojn8JO6JInFbG2YrLMi4t/xVZNLhn+BgghNvkLzn7Bz9QbIADMmEt9imAAAAABJRU5ErkJggg==" width="16"> info@eventhub.abp.io</a> |
||||
|
<span style="font-size: 16px; font-family: Arial, sans-serif; color: #777; margin-right: 0px; text-decoration: none;"><strong>EventHub</strong> - Powered by Volosoft</span> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
<!-- END FOOTER --> |
||||
|
<!-- END CENTERED WHITE CONTAINER --> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</body> |
||||
|
|
||||
|
</html> |
||||
@ -0,0 +1,73 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using EventHub.Emailing; |
||||
|
using EventHub.Events.Registrations; |
||||
|
using EventHub.Users; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
using Volo.Abp.Emailing; |
||||
|
using Volo.Abp.Linq; |
||||
|
using Volo.Abp.TextTemplating; |
||||
|
|
||||
|
namespace EventHub.Events |
||||
|
{ |
||||
|
public class EventReminderNotifier : ITransientDependency |
||||
|
{ |
||||
|
private readonly IEmailSender _emailSender; |
||||
|
private readonly ITemplateRenderer _templateRenderer; |
||||
|
private readonly IRepository<AppUser, Guid> _userRepository; |
||||
|
private readonly IRepository<EventRegistration, Guid> _eventRegistrationRepository; |
||||
|
private readonly IAsyncQueryableExecuter _asyncExecuter; |
||||
|
|
||||
|
public EventReminderNotifier( |
||||
|
IEmailSender emailSender, |
||||
|
ITemplateRenderer templateRenderer, |
||||
|
IRepository<AppUser, Guid> userRepository, |
||||
|
IRepository<EventRegistration, Guid> eventRegistrationRepository, |
||||
|
IAsyncQueryableExecuter asyncExecuter) |
||||
|
{ |
||||
|
_emailSender = emailSender; |
||||
|
_templateRenderer = templateRenderer; |
||||
|
_userRepository = userRepository; |
||||
|
_eventRegistrationRepository = eventRegistrationRepository; |
||||
|
_asyncExecuter = asyncExecuter; |
||||
|
} |
||||
|
|
||||
|
public async Task NotifyAsync(Event @event) |
||||
|
{ |
||||
|
if (@event is null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var userQueryable = await _userRepository.GetQueryableAsync(); |
||||
|
var eventRegistrationQueryable = await _eventRegistrationRepository.GetQueryableAsync(); |
||||
|
|
||||
|
var userQuery = from eventRegistration in eventRegistrationQueryable |
||||
|
join user in userQueryable on eventRegistration.UserId equals user.Id |
||||
|
where eventRegistration.EventId == @event.Id |
||||
|
select user; |
||||
|
|
||||
|
var usersToBeNotified = await _asyncExecuter.ToListAsync(userQuery); |
||||
|
|
||||
|
foreach (var user in usersToBeNotified) |
||||
|
{ |
||||
|
var model = new |
||||
|
{ |
||||
|
UserName = user.GetFullNameOrUsername(), |
||||
|
Title = @event.Title, |
||||
|
StartTime = @event.StartTime, |
||||
|
EndTime = @event.EndTime, |
||||
|
Url = @event.Url |
||||
|
}; |
||||
|
|
||||
|
await _emailSender.QueueAsync( |
||||
|
user.Email, |
||||
|
"The event has last thirty minutes to start!", |
||||
|
await _templateRenderer.RenderAsync(EmailTemplates.EventReminder, model) |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,57 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Volo.Abp.BackgroundWorkers; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
using Volo.Abp.Linq; |
||||
|
using Volo.Abp.Threading; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace EventHub.Events |
||||
|
{ |
||||
|
public class EventReminderWorker : AsyncPeriodicBackgroundWorkerBase |
||||
|
{ |
||||
|
public EventReminderWorker(AbpAsyncTimer timer, IServiceScopeFactory serviceScopeFactory) |
||||
|
: base(timer, serviceScopeFactory) |
||||
|
{ |
||||
|
Timer.Period = 60_000; |
||||
|
} |
||||
|
|
||||
|
[UnitOfWork] |
||||
|
protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext) |
||||
|
{ |
||||
|
var eventReminderNotifier = workerContext.ServiceProvider.GetRequiredService<EventReminderNotifier>(); |
||||
|
var eventRepository = workerContext.ServiceProvider.GetRequiredService<IRepository<Event, Guid>>(); |
||||
|
var asyncExecuter = workerContext.ServiceProvider.GetRequiredService<IAsyncQueryableExecuter>(); |
||||
|
|
||||
|
var eventQueryable = await eventRepository.GetQueryableAsync(); |
||||
|
|
||||
|
var thirtyMinutesAfter = DateTime.Now.AddMinutes(30); |
||||
|
var oneMinutesAfter = DateTime.Now.AddMinutes(1); |
||||
|
|
||||
|
var eventQuery = eventQueryable.Where(x => |
||||
|
x.IsRemindingEmailSent == false && |
||||
|
x.StartTime <= thirtyMinutesAfter && |
||||
|
x.StartTime >= oneMinutesAfter); |
||||
|
|
||||
|
var events = await asyncExecuter.ToListAsync(eventQuery); |
||||
|
|
||||
|
foreach (var @event in events) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
await eventReminderNotifier.NotifyAsync(@event); |
||||
|
@event.IsRemindingEmailSent = true; |
||||
|
} |
||||
|
catch (Exception e) |
||||
|
{ |
||||
|
@event.IsRemindingEmailSent = false; |
||||
|
Logger.LogError( |
||||
|
$"An error occurred while sending reminder mail for {@event.Id} event. Error message: {e.Message}"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Volo.Abp.BackgroundWorkers; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
using Volo.Abp.Linq; |
||||
|
using Volo.Abp.Threading; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace EventHub.Events |
||||
|
{ |
||||
|
public class NewEventDetectorWorker : AsyncPeriodicBackgroundWorkerBase |
||||
|
{ |
||||
|
public NewEventDetectorWorker(AbpAsyncTimer timer, IServiceScopeFactory serviceScopeFactory) |
||||
|
: base(timer, serviceScopeFactory) |
||||
|
{ |
||||
|
Timer.Period = 60_000; |
||||
|
} |
||||
|
|
||||
|
[UnitOfWork] |
||||
|
protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext) |
||||
|
{ |
||||
|
var newEventNotifier = workerContext.ServiceProvider.GetRequiredService<NewEventNotifier>(); |
||||
|
var eventRepository = workerContext.ServiceProvider.GetRequiredService<IRepository<Event, Guid>>(); |
||||
|
var asyncExecuter = workerContext.ServiceProvider.GetRequiredService<IAsyncQueryableExecuter>(); |
||||
|
|
||||
|
var eventQueryable = await eventRepository.GetQueryableAsync(); |
||||
|
|
||||
|
var eventQuery = eventQueryable.Where(x => x.IsEmailSentToMembers == false); |
||||
|
|
||||
|
var newEvents = await asyncExecuter.ToListAsync(eventQuery); |
||||
|
|
||||
|
foreach (var @event in newEvents) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
await newEventNotifier.NotifyAsync(@event); |
||||
|
@event.IsEmailSentToMembers = true; |
||||
|
} |
||||
|
catch (Exception e) |
||||
|
{ |
||||
|
@event.IsEmailSentToMembers = false; |
||||
|
Logger.LogError($"An error occurred while sending an email to the members of the organization after the new event was created. Error message: {e.Message}"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,77 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using EventHub.Emailing; |
||||
|
using EventHub.Organizations.Memberships; |
||||
|
using EventHub.Users; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
using Volo.Abp.Emailing; |
||||
|
using Volo.Abp.Linq; |
||||
|
using Volo.Abp.TextTemplating; |
||||
|
|
||||
|
namespace EventHub.Events |
||||
|
{ |
||||
|
public class NewEventNotifier : ITransientDependency |
||||
|
{ |
||||
|
private readonly IEmailSender _emailSender; |
||||
|
private readonly ITemplateRenderer _templateRenderer; |
||||
|
private readonly IRepository<OrganizationMembership, Guid> _organizationMembershipsRepository; |
||||
|
private readonly IRepository<AppUser, Guid> _userRepository; |
||||
|
private readonly IAsyncQueryableExecuter _asyncExecuter; |
||||
|
|
||||
|
public NewEventNotifier( |
||||
|
IEmailSender emailSender, |
||||
|
ITemplateRenderer templateRenderer, |
||||
|
IRepository<OrganizationMembership, Guid> organizationMembershipsRepository, |
||||
|
IRepository<AppUser, Guid> userRepository, |
||||
|
IAsyncQueryableExecuter asyncExecuter) |
||||
|
{ |
||||
|
_emailSender = emailSender; |
||||
|
_templateRenderer = templateRenderer; |
||||
|
_organizationMembershipsRepository = organizationMembershipsRepository; |
||||
|
_userRepository = userRepository; |
||||
|
_asyncExecuter = asyncExecuter; |
||||
|
} |
||||
|
|
||||
|
public async Task NotifyAsync(Event @event) |
||||
|
{ |
||||
|
if (@event is null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var organizationMembershipsQueryable = await _organizationMembershipsRepository.GetQueryableAsync(); |
||||
|
|
||||
|
var membershipQuery = organizationMembershipsQueryable |
||||
|
.Where(x => x.OrganizationId == @event.OrganizationId); |
||||
|
|
||||
|
var organizationMembers = await _asyncExecuter.ToListAsync(membershipQuery); |
||||
|
|
||||
|
foreach (var member in organizationMembers) |
||||
|
{ |
||||
|
var user = await _userRepository.FindAsync(member.UserId); |
||||
|
|
||||
|
if (user is null) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
var model = new |
||||
|
{ |
||||
|
UserName = user.GetFullNameOrUsername(), |
||||
|
Title = @event.Title, |
||||
|
StartTime = @event.StartTime, |
||||
|
EndTime = @event.EndTime, |
||||
|
Url = @event.Url |
||||
|
}; |
||||
|
|
||||
|
await _emailSender.QueueAsync( |
||||
|
user.Email, |
||||
|
$"Do you attend the {@event.Title} event?", |
||||
|
await _templateRenderer.RenderAsync(EmailTemplates.NewEventCreated, model) |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using EventHub.Emailing; |
||||
|
using EventHub.Users; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Emailing; |
||||
|
using Volo.Abp.TextTemplating; |
||||
|
|
||||
|
namespace EventHub.Events.Registrations |
||||
|
{ |
||||
|
public class EventRegistrationNotifier : ITransientDependency |
||||
|
{ |
||||
|
private readonly IEmailSender _emailSender; |
||||
|
private readonly ITemplateRenderer _templateRenderer; |
||||
|
|
||||
|
public EventRegistrationNotifier( |
||||
|
IEmailSender emailSender, |
||||
|
ITemplateRenderer templateRenderer) |
||||
|
{ |
||||
|
_emailSender = emailSender; |
||||
|
_templateRenderer = templateRenderer; |
||||
|
} |
||||
|
|
||||
|
public async Task NotifyAsync( |
||||
|
Event @event, |
||||
|
AppUser user) |
||||
|
{ |
||||
|
if (user is null || @event is null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var model = new |
||||
|
{ |
||||
|
Title = @event.Title, |
||||
|
StartTime = @event.StartTime, |
||||
|
EndTime = @event.EndTime, |
||||
|
Url = @event.Url |
||||
|
}; |
||||
|
|
||||
|
await _emailSender.QueueAsync( |
||||
|
user.Email, |
||||
|
"Your event registration has been received!", |
||||
|
await _templateRenderer.RenderAsync(EmailTemplates.EventRegistration, model) |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,24 @@ |
|||||
|
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
|
||||
|
namespace EventHub.Migrations |
||||
|
{ |
||||
|
public partial class Added_IsRemindingEmailSent_To_Event : Migration |
||||
|
{ |
||||
|
protected override void Up(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.AddColumn<bool>( |
||||
|
name: "IsRemindingEmailSent", |
||||
|
table: "AppEvents", |
||||
|
type: "bit", |
||||
|
nullable: false, |
||||
|
defaultValue: false); |
||||
|
} |
||||
|
|
||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.DropColumn( |
||||
|
name: "IsRemindingEmailSent", |
||||
|
table: "AppEvents"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,24 @@ |
|||||
|
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
|
||||
|
namespace EventHub.Migrations |
||||
|
{ |
||||
|
public partial class Added_IsEmailSentToMembers_To_Event : Migration |
||||
|
{ |
||||
|
protected override void Up(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.AddColumn<bool>( |
||||
|
name: "IsEmailSentToMembers", |
||||
|
table: "AppEvents", |
||||
|
type: "bit", |
||||
|
nullable: false, |
||||
|
defaultValue: false); |
||||
|
} |
||||
|
|
||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.DropColumn( |
||||
|
name: "IsEmailSentToMembers", |
||||
|
table: "AppEvents"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue