diff --git a/Wave/Components/Pages/EmailSignup.razor b/Wave/Components/Pages/EmailSignup.razor new file mode 100644 index 0000000..66b2976 --- /dev/null +++ b/Wave/Components/Pages/EmailSignup.razor @@ -0,0 +1,83 @@ +@page "/Email/Subscribe" + +@using Microsoft.Extensions.Options +@using Wave.Data +@using System.ComponentModel.DataAnnotations +@using Microsoft.AspNetCore.Identity.UI.Services +@using Microsoft.EntityFrameworkCore + +@inject IOptions Features +@inject IStringLocalizer Localizer +@inject IDbContextFactory ContextFactory +@inject IEmailSender EmailSender + +@(TitlePrefix + Localizer["Title"]) + +@if (!string.IsNullOrWhiteSpace(Message)) { +
+ @Message +
+} + + + + + + + + + + + + + + + + + + +@code { + [CascadingParameter(Name = "TitlePrefix")] + private string TitlePrefix { get; set; } = default!; + [SupplyParameterFromForm(FormName = "email-signup")] + private InputModel Model { get; set; } = new(); + + private string Message { get; set; } = string.Empty; + + protected override void OnInitialized() { + if (Features.Value.EmailSubscriptions is not true) + throw new ApplicationException("Email subscriptions not enabled."); + } + + private async Task OnValidSubmit() { + if (Features.Value.EmailSubscriptions is not true) + throw new ApplicationException("Email subscriptions not enabled."); + + Message = Localizer["Submit_Message"]; + await using var context = await ContextFactory.CreateDbContextAsync(); + + var subscriber = context.Set().IgnoreQueryFilters().FirstOrDefault(s => s.Email == Model.Email); + if (subscriber?.Unsubscribed is false) return; + + subscriber ??= new EmailSubscriber { + Email = Model.Email.Trim(), + Unsubscribed = true + }; + subscriber.Name = Model.Name; + context.Update(subscriber); + await context.SaveChangesAsync(); + + if (subscriber.Unsubscribed) { + await EmailSender.SendEmailAsync(subscriber.Email, Localizer["ConfirmEmailSubject"], Localizer["ConfirmEmailBody"]); + } + } + + private sealed class InputModel { + [MaxLength(128)] + public string? Name { get; set; } + [EmailAddress, Required(AllowEmptyStrings = false), MaxLength(256)] + public string Email { get; set; } = string.Empty; + } +} diff --git a/Wave/Program.cs b/Wave/Program.cs index e320cda..cce534a 100644 --- a/Wave/Program.cs +++ b/Wave/Program.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel; using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.UI.Services; using Microsoft.AspNetCore.StaticFiles; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; @@ -120,6 +121,7 @@ var smtpConfig = builder.Configuration.GetSection("Email:Smtp"); if (smtpConfig.Exists()) { builder.Services.Configure(smtpConfig); + builder.Services.AddScoped(); builder.Services.AddScoped, SmtpEmailSender>(); } else { builder.Services.AddSingleton, IdentityNoOpEmailSender>();