Wave/Wave/Components/Pages/EmailSignup.razor

151 lines
5.2 KiB
Plaintext

@page "/Email/Subscribe"
@page "/Email/Confirm"
@using Microsoft.Extensions.Options
@using Wave.Data
@using System.ComponentModel.DataAnnotations
@using Microsoft.EntityFrameworkCore
@using Wave.Services
@using Wave.Utilities
@inject ILogger<EmailSignup> Logger
@inject IStringLocalizer<EmailSignup> Localizer
@inject IDbContextFactory<ApplicationDbContext> ContextFactory
@inject IOptions<Features> Features
@inject IEmailService EmailService
@inject EmailFactory Email
@inject IMessageDisplay Messages
@inject NavigationManager Navigation
<HeadContent>
<meta name="robots" content="nofollow">
<link rel="canonical" href="@(new UriBuilder(Navigation.BaseUri) { Scheme = "https", Port = -1, Path = "/email/subscribe" }.Uri.AbsoluteUri)" />
</HeadContent>
<PageTitle>@(Localizer["Title"] + TitlePostfix)</PageTitle>
<BoardComponent CenterContent="true">
<BoardCardComponent Heading="@Localizer["Title"]">
<EditForm method="post" FormName="email-signup" Model="Model" OnValidSubmit="OnValidSubmit">
<DataAnnotationsValidator />
<InputLabelComponent LabelText="@Localizer["Name_Label"]" For="() => Model.Name">
<InputText @bind-Value="Model.Name" class="input input-bordered w-full" autocomplete="name"
placeholder="@Localizer["Name_Placeholder"]" />
</InputLabelComponent>
<InputLabelComponent LabelText="@Localizer["Email_Label"]" For="() => Model.Name">
<InputText @bind-Value="Model.Email" class="input input-bordered w-full" autocomplete="email" type="email"
required aria-required="true" placeholder="@Localizer["Email_Placeholder"]" />
</InputLabelComponent>
<button type="submit" class="btn btn-primary w-full">@Localizer["Submit"]</button>
</EditForm>
</BoardCardComponent>
</BoardComponent>
@code {
[CascadingParameter(Name = "TitlePostfix")]
private string TitlePostfix { get; set; } = default!;
[SupplyParameterFromForm(FormName = "email-signup")]
private InputModel Model { get; set; } = new();
[Parameter, SupplyParameterFromQuery(Name = "user")]
public string? Id { get; set; }
[Parameter, SupplyParameterFromQuery(Name = "token")]
public string? Token { get; set; }
protected override async Task OnInitializedAsync() {
if (Features.Value.EmailSubscriptions is not true)
throw new ApplicationException("Email subscriptions not enabled.");
if (Id is null || Token is null) return;
try {
var id = await Email.IsTokenValid(Id, Token);
if (id is null) {
Messages.ShowError(Localizer["Failure_Message"]);
return;
}
await using var context = await ContextFactory.CreateDbContextAsync();
var subscriber = context.Set<EmailSubscriber>().IgnoreQueryFilters().FirstOrDefault(s => s.Id == id);
if (subscriber is null) {
Messages.ShowError(Localizer["Failure_Message"]);
return;
}
subscriber.Unsubscribed = false;
await context.SaveChangesAsync();
Messages.ShowSuccess(Localizer["Success_Message"]);
await Email.ClearToken(Id, Token);
var articles = await context.Set<EmailNewsletter>()
.IgnoreAutoIncludes().IgnoreQueryFilters().Where(n => n.IsSend)
.Include(a => a.Article).ThenInclude(a => a.Author)
.OrderByDescending(a => a.DistributionDateTime)
.Take(3)
.ToListAsync();
var mail = await Email.CreateWelcomeEmail(
subscriber, articles,
Localizer["WelcomeEmailSubject"],
Localizer["WelcomeEmailTitle"],
Localizer["WelcomeEmailBody"],
Localizer["WelcomeEmailBody"]);
await EmailService.ConnectAsync(CancellationToken.None);
await EmailService.SendEmailAsync(mail);
await EmailService.DisconnectAsync(CancellationToken.None);
} catch (Exception ex) {
Logger.LogError(ex, "Error trying to confirm subscriber.");
Messages.ShowError(Localizer["Failure_Message"]);
}
}
private async Task OnValidSubmit() {
if (Features.Value.EmailSubscriptions is not true)
throw new ApplicationException("Email subscriptions not enabled.");
try {
Messages.ShowSuccess(Localizer["Submit_Message"]);
await using var context = await ContextFactory.CreateDbContextAsync();
var subscriber = context.Set<EmailSubscriber>().IgnoreQueryFilters().FirstOrDefault(s => s.Email == Model.Email);
if (subscriber?.Unsubscribed is false) return;
subscriber ??= new EmailSubscriber {
Email = Model.Email.Trim(),
Unsubscribed = true,
Language = "en-US" // TODO
};
subscriber.Name = Model.Name;
subscriber.UnsubscribeReason = "Not Confirmed";
context.Update(subscriber);
await context.SaveChangesAsync();
if (subscriber.Unsubscribed) {
var email = await Email.CreateConfirmationEmail(subscriber,
Localizer["ConfirmEmailSubject"],
Localizer["ConfirmEmailTitle"],
Localizer["ConfirmEmailBody"],
Localizer["ConfirmEmailBody"],
Localizer["Submit"]);
await EmailService.ConnectAsync(CancellationToken.None);
await EmailService.SendEmailAsync(email);
await EmailService.DisconnectAsync(CancellationToken.None);
}
Model = new();
} catch (Exception ex) {
Logger.LogError(ex, "Failed to create subscriber/send confirmation mail.");
}
}
private sealed class InputModel {
[MaxLength(128)]
public string? Name { get; set; }
[EmailAddress, Required(AllowEmptyStrings = false), MaxLength(256)]
public string Email { get; set; } = string.Empty;
}
}