Browse Source

Merge pull request #18 from volosoft/berkan/emailings

Send email for new event creation, event reminder, and event registration
pull/21/head
Halil İbrahim Kalkan 6 years ago
committed by GitHub
parent
commit
3b1fb5bfec
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 37
      src/EventHub.Application/Emailing/EmailTemplateDefinitionProvider.cs
  2. 11
      src/EventHub.Application/Emailing/EmailTemplates.cs
  3. 157
      src/EventHub.Application/Emailing/Templates/EventRegistration.tpl
  4. 157
      src/EventHub.Application/Emailing/Templates/EventReminder.tpl
  5. 157
      src/EventHub.Application/Emailing/Templates/NewEventCreated.tpl
  6. 5
      src/EventHub.Application/EventHub.Application.csproj
  7. 20
      src/EventHub.Application/EventHubApplicationModule.cs
  8. 10
      src/EventHub.Application/Events/EventAppService.cs
  9. 73
      src/EventHub.Application/Events/EventReminderNotifier.cs
  10. 57
      src/EventHub.Application/Events/EventReminderWorker.cs
  11. 50
      src/EventHub.Application/Events/NewEventDetectorWorker.cs
  12. 77
      src/EventHub.Application/Events/NewEventNotifier.cs
  13. 15
      src/EventHub.Application/Events/Registrations/EventRegistrationAppService.cs
  14. 47
      src/EventHub.Application/Events/Registrations/EventRegistrationNotifier.cs
  15. 4
      src/EventHub.Domain/Events/Event.cs
  16. 15
      src/EventHub.Domain/Users/AppUser.cs
  17. 2499
      src/EventHub.EntityFrameworkCore.DbMigrations/Migrations/20210203084538_Added_IsRemindingEmailSent_To_Event.Designer.cs
  18. 24
      src/EventHub.EntityFrameworkCore.DbMigrations/Migrations/20210203084538_Added_IsRemindingEmailSent_To_Event.cs
  19. 2502
      src/EventHub.EntityFrameworkCore.DbMigrations/Migrations/20210203124302_Added_IsEmailSentToMembers_To_Event.Designer.cs
  20. 24
      src/EventHub.EntityFrameworkCore.DbMigrations/Migrations/20210203124302_Added_IsEmailSentToMembers_To_Event.cs
  21. 6
      src/EventHub.EntityFrameworkCore.DbMigrations/Migrations/EventHubMigrationsDbContextModelSnapshot.cs

37
src/EventHub.Application/Emailing/EmailTemplateDefinitionProvider.cs

@ -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
)
);
}
}
}

11
src/EventHub.Application/Emailing/EmailTemplates.cs

@ -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";
}
}

157
src/EventHub.Application/Emailing/Templates/EventRegistration.tpl

@ -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>

157
src/EventHub.Application/Emailing/Templates/EventReminder.tpl

@ -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>

157
src/EventHub.Application/Emailing/Templates/NewEventCreated.tpl

@ -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>

5
src/EventHub.Application/EventHub.Application.csproj

@ -18,4 +18,9 @@
<PackageReference Include="Volo.Abp.PermissionManagement.Application" Version="4.2.0-rc.1" />
</ItemGroup>
<ItemGroup>
<None Remove="Emailing\Templates\*.tpl" />
<EmbeddedResource Include="Emailing\Templates\*.tpl" />
</ItemGroup>
</Project>

20
src/EventHub.Application/EventHubApplicationModule.cs

@ -1,8 +1,12 @@
using Volo.Abp.Account;
using EventHub.Events;
using Volo.Abp;
using Volo.Abp.Account;
using Volo.Abp.AutoMapper;
using Volo.Abp.BackgroundWorkers;
using Volo.Abp.Identity;
using Volo.Abp.Modularity;
using Volo.Abp.PermissionManagement;
using Volo.Abp.VirtualFileSystem;
namespace EventHub
{
@ -11,16 +15,28 @@ namespace EventHub
typeof(AbpAccountApplicationModule),
typeof(EventHubApplicationContractsModule),
typeof(AbpIdentityApplicationModule),
typeof(AbpPermissionManagementApplicationModule)
typeof(AbpPermissionManagementApplicationModule),
typeof(AbpBackgroundWorkersModule)
)]
public class EventHubApplicationModule : AbpModule
{
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
context.AddBackgroundWorker<EventReminderWorker>();
context.AddBackgroundWorker<NewEventDetectorWorker>();
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<EventHubApplicationModule>();
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<EventHubApplicationModule>("EventHub");
});
}
}
}

10
src/EventHub.Application/Events/EventAppService.cs

@ -13,17 +13,17 @@ namespace EventHub.Events
public class EventAppService : EventHubAppService, IEventAppService
{
private readonly EventManager _eventManager;
private readonly IRepository<Organization, Guid> _organizationRepository;
private readonly IRepository<Event, Guid> _eventRepository;
private readonly IRepository<Organization, Guid> _organizationRepository;
public EventAppService(
EventManager eventManager,
IRepository<Organization, Guid> organizationRepository,
IRepository<Event, Guid> eventRepository)
IRepository<Event, Guid> eventRepository,
IRepository<Organization, Guid> organizationRepository)
{
_eventManager = eventManager;
_organizationRepository = organizationRepository;
_eventRepository = eventRepository;
_organizationRepository = organizationRepository;
}
[Authorize]
@ -120,4 +120,4 @@ namespace EventHub.Events
return dto;
}
}
}
}

73
src/EventHub.Application/Events/EventReminderNotifier.cs

@ -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)
);
}
}
}
}

57
src/EventHub.Application/Events/EventReminderWorker.cs

@ -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}");
}
}
}
}
}

50
src/EventHub.Application/Events/NewEventDetectorWorker.cs

@ -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}");
}
}
}
}
}

77
src/EventHub.Application/Events/NewEventNotifier.cs

@ -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)
);
}
}
}
}

15
src/EventHub.Application/Events/Registrations/EventRegistrationAppService.cs

@ -16,26 +16,31 @@ namespace EventHub.Events.Registrations
private readonly IRepository<AppUser, Guid> _userRepository;
private readonly IRepository<Event, Guid> _eventRepository;
private readonly IRepository<EventRegistration, Guid> _eventRegistrationRepository;
private readonly EventRegistrationNotifier _eventRegistrationNotifier;
public EventRegistrationAppService(
EventRegistrationManager eventRegistrationManager,
IRepository<AppUser, Guid> userRepository,
IRepository<Event, Guid> eventRepository,
IRepository<EventRegistration, Guid> eventRegistrationRepository)
IRepository<EventRegistration, Guid> eventRegistrationRepository,
EventRegistrationNotifier eventRegistrationNotifier)
{
_eventRegistrationManager = eventRegistrationManager;
_userRepository = userRepository;
_eventRepository = eventRepository;
_eventRegistrationRepository = eventRegistrationRepository;
_eventRegistrationNotifier = eventRegistrationNotifier;
}
[Authorize]
public async Task RegisterAsync(Guid eventId)
{
await _eventRegistrationManager.RegisterAsync(
await _eventRepository.GetAsync(eventId),
await _userRepository.GetAsync(CurrentUser.GetId())
);
var @event = await _eventRepository.GetAsync(eventId);
var user = await _userRepository.GetAsync(CurrentUser.GetId());
await _eventRegistrationManager.RegisterAsync(@event, user);
await _eventRegistrationNotifier.NotifyAsync(@event, user);
}
[Authorize]

47
src/EventHub.Application/Events/Registrations/EventRegistrationNotifier.cs

@ -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)
);
}
}
}

4
src/EventHub.Domain/Events/Event.cs

@ -24,6 +24,10 @@ namespace EventHub.Events
public int? Capacity { get; set; }
public bool IsRemindingEmailSent { get; set; }
public bool IsEmailSentToMembers { get; set; }
private Event()
{

15
src/EventHub.Domain/Users/AppUser.cs

@ -59,5 +59,20 @@ namespace EventHub.Users
{
}
public string GetFullNameOrUsername()
{
if (!string.IsNullOrWhiteSpace(Name) && !string.IsNullOrWhiteSpace(Surname))
{
return Name + " " + Surname;
}
if (!string.IsNullOrWhiteSpace(Name))
{
return Name;
}
return UserName;
}
}
}

2499
src/EventHub.EntityFrameworkCore.DbMigrations/Migrations/20210203084538_Added_IsRemindingEmailSent_To_Event.Designer.cs

File diff suppressed because it is too large

24
src/EventHub.EntityFrameworkCore.DbMigrations/Migrations/20210203084538_Added_IsRemindingEmailSent_To_Event.cs

@ -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");
}
}
}

2502
src/EventHub.EntityFrameworkCore.DbMigrations/Migrations/20210203124302_Added_IsEmailSentToMembers_To_Event.Designer.cs

File diff suppressed because it is too large

24
src/EventHub.EntityFrameworkCore.DbMigrations/Migrations/20210203124302_Added_IsEmailSentToMembers_To_Event.cs

@ -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");
}
}
}

6
src/EventHub.EntityFrameworkCore.DbMigrations/Migrations/EventHubMigrationsDbContextModelSnapshot.cs

@ -70,9 +70,15 @@ namespace EventHub.Migrations
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<bool>("IsEmailSentToMembers")
.HasColumnType("bit");
b.Property<bool>("IsOnline")
.HasColumnType("bit");
b.Property<bool>("IsRemindingEmailSent")
.HasColumnType("bit");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");

Loading…
Cancel
Save