Userverwaltung improved
This commit is contained in:
@@ -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>
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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.");
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user