Email Inferstructure

This commit is contained in:
Stefan
2023-05-10 12:13:31 +02:00
parent 711955dd09
commit 9520fa04b8
8 changed files with 179 additions and 7 deletions
@@ -42,7 +42,9 @@
<PackageReference Include="Blazorise.Icons.Material" Version="1.2.0" />
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="FluentResults" Version="3.15.2" />
<PackageReference Include="Handlebars.Net" Version="2.1.4" />
<PackageReference Include="HiveMQtt" Version="0.1.10" />
<PackageReference Include="MailKit" Version="4.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.4">
@@ -50,6 +52,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" />
<PackageReference Include="Mjml.Net" Version="1.22.0" />
<PackageReference Include="Tmds.MDns" Version="0.7.1" />
</ItemGroup>
@@ -7,17 +7,22 @@ using Elektrifikatsiya.Database;
using Elektrifikatsiya.Models;
using Elektrifikatsiya.Services;
using Elektrifikatsiya.Services.Implementations;
using Elektrifikatsiya.Utilities;
using HiveMQtt.Client;
using HiveMQtt.Client.Options;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
// Read configuration
builder.Services.Configure<EmailSettings>(builder.Configuration.GetRequiredSection("EmailSettings"));
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddOptions();
builder.Services.AddHttpContextAccessor();
builder.Services.AddHostedService<UpdateService>();
builder.Services.AddSingleton<IDeviceStatusService, DeviceStatusService>();
@@ -38,6 +43,7 @@ builder.Services.AddTransient<IDeviceManagmentService, DeviceManagmentService>()
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
builder.Services.AddScoped<IAuthorizationService, AuthorizationService>();
builder.Services.AddScoped<ICookieService, CookieService>();
builder.Services.AddScoped<IEmailService, EmailService>();
builder.Services.AddDbContext<MainDatabaseContext>(options => options.UseSqlite("Data Source=./MainDatabase.sqlite"));
builder.Services.AddBootstrapProviders();
builder.Services.AddHttpClient<IDeviceManagmentService, DeviceManagmentService>();
@@ -46,6 +52,7 @@ builder.Services.AddBlazorise(options =>
options.Immediate = true;
});
AddBlazorise(builder.Services);
WebApplication app = builder.Build();
@@ -67,6 +74,8 @@ app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.MapControllers();
app.Services.GetRequiredService<IOptions<EmailSettings>>().Value.CompileTemplates();
IServiceScope serviceScope = app.Services.GetRequiredService<IServiceScopeFactory>().CreateScope();
MainDatabaseContext mainDatabase = serviceScope.ServiceProvider.GetRequiredService<MainDatabaseContext>();
@@ -0,0 +1,8 @@
namespace Elektrifikatsiya.Services;
public interface IEmailService
{
Task SendAsync(string to, string subject, string html, string? from = null);
Task SendWithTemeplateAsync(string to, string subject, string templateKey, string? from = null, Dictionary<string, string>? templateParameters = null);
}
@@ -0,0 +1,44 @@
using Elektrifikatsiya.Utilities;
using HandlebarsDotNet;
using MailKit.Net.Smtp;
using MailKit.Security;
using Microsoft.Extensions.Options;
using MimeKit;
using MimeKit.Text;
namespace Elektrifikatsiya.Services.Implementations
{
public class EmailService : IEmailService
{
private readonly EmailSettings emailSettings;
public EmailService(IOptions<EmailSettings> emailSettings)
{
this.emailSettings = emailSettings.Value;
}
public async Task SendAsync(string to, string subject, string html, string? from = null)
{
from ??= emailSettings.DefaultEmail;
MimeMessage message = new MimeMessage();
message.From.Add(MailboxAddress.Parse(from));
message.To.Add(MailboxAddress.Parse(to));
message.Subject = subject;
message.Body = new TextPart(TextFormat.Html) { Text = html };
using SmtpClient smtp = new SmtpClient();
await smtp.ConnectAsync(emailSettings.SmtpServer, emailSettings.SmtpPort, SecureSocketOptions.StartTls);
await smtp.AuthenticateAsync(emailSettings.User, emailSettings.Key);
await smtp.SendAsync(message);
await smtp.DisconnectAsync(true);
}
public Task SendWithTemeplateAsync(string to, string subject, string templateKey, string? from = null, Dictionary<string, string>? templateParameters = null)
{
string content = emailSettings.CompiledTemplates[templateKey](templateParameters ?? new());
return SendAsync(to, subject, content, from);
}
}
}
@@ -0,0 +1,23 @@
using HandlebarsDotNet;
namespace Elektrifikatsiya.Utilities;
public class EmailSettings
{
public string User { get; set; }
public string DefaultEmail { get; set; }
public string Key { get; set; }
public Dictionary<string, string> Templates { get; set; }
public string SmtpServer { get; set; }
public int SmtpPort { get; set; }
public Dictionary<string, HandlebarsTemplate<object, object>> CompiledTemplates = new();
public void CompileTemplates()
{
foreach ((string templateName, string templatePath) in Templates)
{
CompiledTemplates.Add(templateName, Handlebars.Compile(File.ReadAllText(templatePath)));
}
}
}
@@ -5,5 +5,15 @@
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"EmailSettings": {
"User": "",
"DefaultEmail": "",
"Key": "",
"Templates": {
},
"SmtpServer": "",
"SmtpPort": 0
}
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,49 @@
<mjml>
<mj-head>
<mj-attributes>
<mj-class name="primary" background-color="#1a237e"/>
</mj-attributes>
<mj-style>
@font-face {
font-family: Nunito;
src: url(https://fonts.gstatic.com/s/nunito/v16/XRXV3I6Li01BKofINeaB.woff2)
format('truetype');
}
</mj-style>
</mj-head>
<mj-body background-color="white">
<mj-wrapper padding-right="20px" padding-left="20px" padding-top="7%" >
<mj-section border-right="2px solid #B0B0B0" border-top="2px solid #B0B0B0" border-left="2px solid #B0B0B0" border-radius="33px">
</mj-section>
<mj-section padding-bottom="0px" padding-top="0px" border-left="2px solid #B0B0B0" border-right="2px solid #B0B0B0">
<mj-column>
<mj-text align="center" font-family="Nunito, Sans-Serif" font-weight="bold" font-size="30px">
Daily Notification
</mj-text>
</mj-column>
</mj-section>
<mj-section padding-bottom="0px" border-left="2px solid #B0B0B0" border-right="2px solid #B0B0B0">
<mj-column padding-left="5%" padding-right="5%">
<mj-text font-family="Nunito, Sans-Serif" align="center" font-size="18px">
Energy Consumption yesterday: {{yesterday}}
</mj-text>
</mj-column>
<mj-column>
<mj-text font-family="Nunito, Sans-Serif" algin="center" font-size="18px">
Energy Consumption since the start of the year: {{yearly}}
</mj-text>
</mj-column>
</mj-section>
<mj-section padding-top="0px" border-right="2px solid #B0B0B0" border-left="2px solid #B0B0B0" border-bottom="2px solid #B0B0B0" border-radius="33px">
<mj-column>
<mj-button font-size="16px" mj-class="primary" font-weight="bold" font-family="Nunito, Sans-Serif">
<mj-text>
<a href="{{link}}" target="_blank" style="color:white; text-decoration:none;">Goto Dashboard</a>
</mj-text>
</mj-button>
</mj-column>
</mj-section>
</mj-wrapper>
</mj-body>
</mjml>