Implemented add subscribers on Subscribers Page (CSV)

This commit is contained in:
Mia Rose Winter 2024-04-22 14:17:11 +02:00
parent 4a4110b7ae
commit bb2f1f5c92
Signed by: miawinter
GPG key ID: 4B6F6A83178F595E
4 changed files with 115 additions and 1 deletions

View file

@ -3,6 +3,9 @@
@using Microsoft.Extensions.Options @using Microsoft.Extensions.Options
@using Wave.Data @using Wave.Data
@using Wave.Utilities @using Wave.Utilities
@using CsvHelper.Configuration
@using System.Globalization
@using CsvHelper
@attribute [Authorize(Roles = "Admin")] @attribute [Authorize(Roles = "Admin")]
@ -12,12 +15,40 @@
@inject IMessageDisplay Message @inject IMessageDisplay Message
@inject IOptions<Features> Features @inject IOptions<Features> Features
<ModalComponent Id="@ModalId">
<ChildContent>
<form id="AddSubscribers" method="post" @formname="AddSubscribers" @onsubmit="AddSubscribers">
<AntiforgeryToken/>
<h2 class="text-xl">@Localizer["AddSubscribers_Label"]</h2>
<span class="my-3"><small>Format: Email;[Name];[Exclusion Reason];</small></span>
<InputLabelComponent LabelText="@Localizer["AddSubscribers_Input_Label"]">
<InputTextArea class="textarea textarea-bordered" rows="12"
@bind-Value="@SubscribersInput"
placeholder="@Localizer["AddSubscribers_Input_Placeholder"]"
required aria-required max="8096"
autocomplete="off"/>
</InputLabelComponent>
</form>
</ChildContent>
<Actions>
<button type="submit" form="AddSubscribers" class="btn btn-primary">
@Localizer["Submit"]
</button>
</Actions>
</ModalComponent>
<PageTitle>@(Localizer["Title"] + TitlePostfix)</PageTitle> <PageTitle>@(Localizer["Title"] + TitlePostfix)</PageTitle>
<h1 class="text-3xl lg:text-5xl font-light mb-6 text-primary">@Localizer["Title"]</h1> <h1 class="text-3xl lg:text-5xl font-light mb-6 text-primary">@Localizer["Title"]</h1>
<div class="flex gap-2 mb-3">
<button class="btn btn-sm btn-primary" onclick="@(ModalId).showModal()">
@Localizer["AddSubscribers_Label"]
</button>
</div>
<section> <section>
<div class="overflow-x-auto"> <div class="overflow-x-auto">
<table class="table table-zebra"> <table class="table table-zebra">
<thead> <thead>
@ -92,6 +123,10 @@
private const int ItemsPerPage = 10; private const int ItemsPerPage = 10;
private int TotalPages { get; set; } private int TotalPages { get; set; }
[SupplyParameterFromForm(FormName = "AddSubscribers")]
private string SubscribersInput { get; set; } = string.Empty;
private static string ModalId => "AddSubscribersDialog";
protected override async Task OnInitializedAsync() { protected override async Task OnInitializedAsync() {
await using var context = await ContextFactory.CreateDbContextAsync(); await using var context = await ContextFactory.CreateDbContextAsync();
var query = context.Set<EmailSubscriber>(); var query = context.Set<EmailSubscriber>();
@ -111,4 +146,50 @@
return []; return [];
} }
} }
private async Task AddSubscribers() {
var config = new CsvConfiguration(CultureInfo.CurrentCulture) {
NewLine = Environment.NewLine,
HasHeaderRecord = false
};
List<SubscriberModel> list;
try {
using var reader = new CsvReader(new StringReader(SubscribersInput), config);
list = reader.GetRecords<SubscriberModel>().ToList();
} catch (Exception ex) {
Message.ShowError(string.Format(Localizer["AddSubscribers_Parse_Error"], ex.Message));
return;
}
if (list.Count < 1) return;
try {
var emailSubscribers = new List<EmailSubscriber>();
foreach (var input in list) {
emailSubscribers.Add(new EmailSubscriber {
Email = input.Email,
Name = input.Name,
Unsubscribed = !string.IsNullOrWhiteSpace(input.UnsubscribeReason),
UnsubscribeReason = input.UnsubscribeReason,
Language = "en-US"
});
}
await using var context = await ContextFactory.CreateDbContextAsync();
context.AddRange(emailSubscribers);
await context.SaveChangesAsync();
SubscribersInput = string.Empty;
} catch (Exception ex) {
Message.ShowError(string.Format(Localizer["AddSubscribers_Save_Error"], ex.InnerException?.Message ?? ex.Message));
}
}
internal sealed class SubscriberModel {
[CsvHelper.Configuration.Attributes.Index(0)]
public string Email { get; set; } = string.Empty;
[CsvHelper.Configuration.Attributes.Index(1)]
public string? Name { get; set; }
[CsvHelper.Configuration.Attributes.Index(2)]
public string? UnsubscribeReason { get; set; }
}
} }

View file

@ -131,4 +131,20 @@
<data name="Newsletter_Footer_Timezone" xml:space="preserve"> <data name="Newsletter_Footer_Timezone" xml:space="preserve">
<value>Alle Uhrzeiten sind in der folgenden Zeitzone:</value> <value>Alle Uhrzeiten sind in der folgenden Zeitzone:</value>
</data> </data>
<data name="AddSubscribers_Parse_Error" xml:space="preserve">
<value>Fehler beim einlesen von Abonennent(en): {0}</value>
</data>
<data name="AddSubscribers_Save_Error" xml:space="preserve">
<value>Fehler beim speichern von Abonennent(en): {0}</value>
</data>
<data name="AddSubscribers_Label" xml:space="preserve">
<value>Abonnent(en) Hinzufügen</value>
</data>
<data name="AddSubscribers_Input_Label" xml:space="preserve">
<value>Abonnent(en) [CSV]</value>
</data>
<data name="AddSubscribers_Input_Placeholder" xml:space="preserve">
<value>anna.muster@example.de; Anna Muster; Spam;
peter.muster@example.de;;;</value>
</data>
</root> </root>

View file

@ -134,4 +134,20 @@
<data name="Newsletter_Footer_Timezone" xml:space="preserve"> <data name="Newsletter_Footer_Timezone" xml:space="preserve">
<value>All times are using this timezone:</value> <value>All times are using this timezone:</value>
</data> </data>
<data name="AddSubscribers_Parse_Error" xml:space="preserve">
<value>Failed to parse subscriber(s): {0}</value>
</data>
<data name="AddSubscribers_Save_Error" xml:space="preserve">
<value>Failed to save subscriber(s): {0}</value>
</data>
<data name="AddSubscribers_Label" xml:space="preserve">
<value>Add Subscriber(s)</value>
</data>
<data name="AddSubscribers_Input_Label" xml:space="preserve">
<value>Subscriber(s) [CSV]</value>
</data>
<data name="AddSubscribers_Input_Placeholder" xml:space="preserve">
<value>john.smith@example.com; John Smith; Spam;
jay.smith@example.com;;;</value>
</data>
</root> </root>

View file

@ -11,6 +11,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AspNetCore.Authentication.ApiKey" Version="8.0.1" /> <PackageReference Include="AspNetCore.Authentication.ApiKey" Version="8.0.1" />
<PackageReference Include="CsvHelper" Version="31.0.4" />
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Humanizer.Core.de" Version="2.14.1" /> <PackageReference Include="Humanizer.Core.de" Version="2.14.1" />
<PackageReference Include="Humanizer.Core.uk" Version="2.14.1" /> <PackageReference Include="Humanizer.Core.uk" Version="2.14.1" />