Userverwaltung improved

This commit is contained in:
Wieland, Marc
2026-06-08 15:24:20 +02:00
parent 9030b332a1
commit ee4d6cb5b1
4 changed files with 114 additions and 34 deletions
+9 -5
View File
@@ -1,5 +1,5 @@
<MudNavMenu> <div style="display:flex; flex-direction:column; height:100%;">
<MudText Typo="Typo.h6" Class="px-4 mt-4 mb-2">Navigation</MudText> <MudNavMenu Style="flex:1">
<MudDivider Class="mb-2" /> <MudDivider Class="mb-2" />
<MudNavLink Href="" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.CalendarMonth">Wochenübersicht</MudNavLink> <MudNavLink Href="" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.CalendarMonth">Wochenübersicht</MudNavLink>
<MudNavLink Href="month" Icon="@Icons.Material.Filled.CalendarViewMonth">Monatsübersicht</MudNavLink> <MudNavLink Href="month" Icon="@Icons.Material.Filled.CalendarViewMonth">Monatsübersicht</MudNavLink>
@@ -12,14 +12,18 @@
Benutzerverwaltung Benutzerverwaltung
</MudNavLink> </MudNavLink>
</AuthorizeView> </AuthorizeView>
</MudNavMenu>
<AuthorizeView> <AuthorizeView>
<Authorized> <Authorized>
<MudStack Row="true" AlignItems="AlignItems.Center" Class="px-4 py-1" Spacing="1"> <MudDivider />
<MudStack Row="true" AlignItems="AlignItems.Center" Class="px-4 py-2" Spacing="1">
<MudIcon Icon="@Icons.Material.Filled.AccountCircle" Color="Color.Primary" Size="Size.Small" /> <MudIcon Icon="@Icons.Material.Filled.AccountCircle" Color="Color.Primary" Size="Size.Small" />
<MudText Typo="Typo.body2" Style="font-weight:600">@context.User.Identity?.Name</MudText> <MudText Typo="Typo.body2" Style="font-weight:600">@context.User.Identity?.Name</MudText>
</MudStack> </MudStack>
<MudNavMenu>
<MudNavLink Href="/auth/logout" Icon="@Icons.Material.Filled.Logout">Abmelden</MudNavLink> <MudNavLink Href="/auth/logout" Icon="@Icons.Material.Filled.Logout">Abmelden</MudNavLink>
</MudNavMenu>
</Authorized> </Authorized>
</AuthorizeView> </AuthorizeView>
</MudNavMenu> <MudText Typo="Typo.caption" Class="px-4 py-2" Style="color: var(--mud-palette-text-disabled); text-align:center;">Version 1.1</MudText>
</div>
+59
View File
@@ -47,6 +47,17 @@ else
<MudText Typo="Typo.body2" Color="Color.Secondary">@context.Id</MudText> <MudText Typo="Typo.body2" Color="Color.Secondary">@context.Id</MudText>
</MudTd> </MudTd>
<MudTd> <MudTd>
@if (_editUserId == context.Id)
{
<MudTextField @bind-Value="_editUsername"
Variant="Variant.Outlined"
Margin="Margin.Dense"
Immediate="true"
Style="max-width:220px"
OnKeyDown="@(async e => { if (e.Key == "Enter") await SaveRename(context); })" />
}
else
{
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2"> <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudIcon Icon="@Icons.Material.Filled.AccountCircle" <MudIcon Icon="@Icons.Material.Filled.AccountCircle"
Color="@(context.Username == "marc" ? Color.Error : Color.Default)" Color="@(context.Username == "marc" ? Color.Error : Color.Default)"
@@ -59,8 +70,26 @@ else
<MudChip T="string" Size="Size.Small" Color="Color.Error" Variant="Variant.Outlined">Admin</MudChip> <MudChip T="string" Size="Size.Small" Color="Color.Error" Variant="Variant.Outlined">Admin</MudChip>
} }
</MudStack> </MudStack>
}
</MudTd> </MudTd>
<MudTd Style="text-align:right"> <MudTd Style="text-align:right">
@if (_editUserId == context.Id)
{
<MudIconButton Icon="@Icons.Material.Filled.Check"
Color="Color.Success"
Size="Size.Small"
OnClick="@(() => SaveRename(context))" />
<MudIconButton Icon="@Icons.Material.Filled.Close"
Color="Color.Default"
Size="Size.Small"
OnClick="CancelEdit" />
}
else
{
<MudIconButton Icon="@Icons.Material.Filled.Edit"
Color="Color.Primary"
Size="Size.Small"
OnClick="@(() => StartEdit(context))" />
@if (context.Username != "marc") @if (context.Username != "marc")
{ {
<MudIconButton Icon="@Icons.Material.Filled.DeleteOutline" <MudIconButton Icon="@Icons.Material.Filled.DeleteOutline"
@@ -68,6 +97,7 @@ else
Size="Size.Small" Size="Size.Small"
OnClick="@(() => DeleteUser(context))" /> OnClick="@(() => DeleteUser(context))" />
} }
}
</MudTd> </MudTd>
</RowTemplate> </RowTemplate>
<NoRecordsContent> <NoRecordsContent>
@@ -83,6 +113,8 @@ else
@code { @code {
private List<User> _users = []; private List<User> _users = [];
private bool _loading = true; private bool _loading = true;
private int? _editUserId;
private string _editUsername = "";
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
@@ -94,6 +126,33 @@ else
_loading = false; _loading = false;
} }
private void StartEdit(User user)
{
_editUserId = user.Id;
_editUsername = user.Username;
}
private void CancelEdit()
{
_editUserId = null;
_editUsername = "";
}
private async Task SaveRename(User user)
{
var trimmed = _editUsername.Trim();
var error = await AuthService.RenameUserAsync(user.Id, trimmed);
if (error != null)
{
Snackbar.Add(error, Severity.Error);
return;
}
user.Username = trimmed;
_editUserId = null;
_editUsername = "";
Snackbar.Add($"Benutzer umbenannt zu \"{trimmed}\".", Severity.Success);
}
private async Task DeleteUser(User user) private async Task DeleteUser(User user)
{ {
await AuthService.DeleteUserAsync(user.Id); await AuthService.DeleteUserAsync(user.Id);
+17
View File
@@ -34,6 +34,23 @@ public class AuthService(IDbContextFactory<TimetrackerDbContext> factory)
} }
} }
public async Task<string?> RenameUserAsync(int userId, string newUsername)
{
if (string.IsNullOrWhiteSpace(newUsername) || newUsername.Length < 3)
return "Benutzername muss mindestens 3 Zeichen lang sein.";
await using var db = await factory.CreateDbContextAsync();
if (await db.Users.AnyAsync(u => u.Username == newUsername && u.Id != userId))
return "Benutzername bereits vergeben.";
var user = await db.Users.FindAsync(userId);
if (user == null) return "Benutzer nicht gefunden.";
user.Username = newUsername;
await db.SaveChangesAsync();
return null;
}
public async Task<(User? User, string? Error)> RegisterAsync(string username, string password) { public async Task<(User? User, string? Error)> RegisterAsync(string username, string password) {
if (string.IsNullOrWhiteSpace(username) || username.Length < 3) if (string.IsNullOrWhiteSpace(username) || username.Length < 3)
return (null, "Benutzername muss mindestens 3 Zeichen lang sein."); return (null, "Benutzername muss mindestens 3 Zeichen lang sein.");
BIN
View File
Binary file not shown.