Compare commits

...

2 Commits

Author SHA1 Message Date
troogs
c0c18f2ddd Refactor FsBase component: remove unused private fields and streamline OnInitializedAsync method
All checks were successful
Build And Push Dev Docker Image / docker (push) Successful in 1m52s
2026-04-26 11:07:02 +02:00
troogs
b0866754e0 Add initial password setup functionality: implement email sending for new account password setup and update user interface to include password setup button
Co-authored-by: Copilot <copilot@github.com>
2026-04-26 11:00:43 +02:00
4 changed files with 48 additions and 28 deletions

View File

@@ -212,6 +212,34 @@ namespace FoodsharingSiegen.Server.Auth
#region Password Recovery
public async Task InitiateInitialPasswordSetup(string email, string baseUri)
{
if (string.IsNullOrWhiteSpace(email)) return;
var user = await Context.Users!.FirstOrDefaultAsync(x => x.Mail.ToLower() == email.ToLower());
if (user == null) return; // Do not leak existence
var resetToken = Guid.NewGuid().ToString("N");
user.ResetToken = resetToken;
user.ResetTokenExpiry = DateTime.UtcNow.AddDays(7);
await Context.SaveChangesAsync();
var resetLink = $"{baseUri.TrimEnd('/')}/reset-password/{resetToken}";
var mailBody = $"""
Hallo {user.Name},<br>
<br>
für dich wurde ein neues Konto bei {_appSettings.Terms.Title} erstellt. <br>
<br>
Um dein Passwort festzulegen, klicke bitte auf den folgenden Link (dieser ist 7 Tage gültig):<br>
<a href='{resetLink}'>{resetLink}</a><br>
<br>
Viele Grüße<br>Dein Team {_appSettings.Terms.Title}
""";
await _mailService.SendEmailAsync(user.Mail, "Passwort festlegen", mailBody);
}
public async Task InitiatePasswordReset(string email, string baseUri)
{
if (string.IsNullOrWhiteSpace(email)) return;

View File

@@ -71,12 +71,6 @@ namespace FoodsharingSiegen.Server.BaseClasses
#endregion
#region Private Fields
private bool _dataInitialized;
#endregion
#region Override OnInitializedAsync
/// <summary>
@@ -85,26 +79,8 @@ namespace FoodsharingSiegen.Server.BaseClasses
protected override async Task OnInitializedAsync()
{
await AuthService.Initialize();
await base.OnInitializedAsync();
}
#endregion
#region Override SetParametersAsync
/// <inheritdoc />
public override async Task SetParametersAsync(ParameterView parameters)
{
parameters.SetParameterProperties(this);
if (!_dataInitialized)
{
_dataInitialized = true;
await InitializeDataAsync();
}
// Da die Parameter bereits gesetzt wurden, kann die Basisklasse am Ende aufgerufen werden.
await base.SetParametersAsync(ParameterView.Empty);
await base.OnInitializedAsync();
}
#endregion

View File

@@ -56,9 +56,11 @@
</CardBody>
<CardFooter Class="d-flex justify-content-between">
<div>
<Button Color="Color.Primary" Size="Size.Small" Class="me-2" Clicked="() => EditUser(user)"><Icon Name="IconName.Edit" /></Button>
<Button Color="Color.Info" Size="Size.Small" Clicked="() => SetPassword(user)"><i class="fa-solid fa-key"></i></Button>
</div>
<Button Color="Color.Primary" Size="Size.Small" Clicked="() => EditUser(user)"><Icon Name="IconName.Edit" /></Button>
<Button Color="Color.Info" Size="Size.Small" Clicked="() => SetPassword(user)"><i class="fa-solid fa-key"></i></Button>
<Button Color="Color.Secondary" Size="Size.Small" Clicked="() => SendPasswordSetupMail(user)"><Icon Name="IconName.Mail" /></Button>
<Button Color="Color.Danger" Size="Size.Small" Clicked="() => RemoveUserAsync(user)"><Icon Name="IconName.Delete" /></Button>
</CardFooter>
</Card>
@@ -77,7 +79,7 @@
grid-template-columns: repeat(2, 1fr);
}
}
@@media (min-width: 1070px) {
@@media (min-width: 1250px) {
.user-grid {
grid-template-columns: repeat(3, 1fr);
}

View File

@@ -22,6 +22,12 @@ namespace FoodsharingSiegen.Server.Pages
[Inject]
public UserService UserService { get; set; } = null!;
[Inject]
public new FoodsharingSiegen.Server.Auth.AuthService AuthService { get; set; } = null!;
[Inject]
public new NavigationManager NavigationManager { get; set; } = null!;
#endregion
#region Private Properties
@@ -115,6 +121,14 @@ namespace FoodsharingSiegen.Server.Pages
PasswordModal?.Show(user);
}
private async Task SendPasswordSetupMail(User user)
{
await ConfirmDialog.ShowAsync(ModalService, "Bestätigen", $"Soll eine E-Mail zum Festlegen des Passworts an {user.Mail} gesendet werden?", async () =>
{
await AuthService.InitiateInitialPasswordSetup(user.Mail, NavigationManager.BaseUri);
});
}
private async Task SaveUser()
{
if (EditModel == null) return;