248 lines
10 KiB
Plaintext
248 lines
10 KiB
Plaintext
@using System.Text.Json
|
|
@using TaikoWebUI.Pages.Dialogs;
|
|
@inject Utilities.StringUtil StringUtil;
|
|
@inject IDialogService DialogService;
|
|
@inject AuthService AuthService;
|
|
@inject HttpClient Client
|
|
@inject NavigationManager NavigationManager
|
|
|
|
|
|
@if (User is not null)
|
|
{
|
|
<MudCard Outlined="true">
|
|
<MudCardHeader>
|
|
<CardHeaderContent>
|
|
<div style="display:flex;flex-wrap:wrap;align-items:center;gap:5px;">
|
|
@if (UserSetting is not null)
|
|
{
|
|
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@UserSetting?.MyDonName</MudText>
|
|
} else
|
|
{
|
|
<MudSkeleton Width="35%" Height="32px" />
|
|
}
|
|
|
|
@if (AuthService.LoginRequired && User?.IsAdmin == true)
|
|
{
|
|
<MudChip Variant="Variant.Outlined" Color="Color.Info" Size="Size.Small" Icon="@Icons.Material.TwoTone.AdminPanelSettings">@Localizer["Admin"]</MudChip>
|
|
}
|
|
</div>
|
|
<MudText Typo="Typo.caption">@Localizer["User ID"]: @User?.Baid</MudText>
|
|
</CardHeaderContent>
|
|
<CardHeaderActions>
|
|
<MudMenu Icon="@Icons.Material.Filled.MoreVert" Dense="true" AnchorOrigin="Origin.BottomLeft"
|
|
TransformOrigin="Origin.TopLeft" Size="Size.Small">
|
|
<MudMenuItem Icon="@Icons.Material.Filled.QrCode"
|
|
OnClick="@(_ => ShowQrCode(User))"
|
|
OnTouch="@(_ => ShowQrCode(User))"
|
|
IconColor="@Color.Primary">
|
|
@Localizer["Show QR Code"]
|
|
</MudMenuItem>
|
|
<MudDivider />
|
|
<MudMenuItem Icon="@Icons.Material.Filled.FeaturedPlayList"
|
|
Href="@($"Users/{User.Baid}/AccessCode")"
|
|
IconColor="@Color.Primary">
|
|
@Localizer["Access Codes"]
|
|
</MudMenuItem>
|
|
<MudDivider />
|
|
@if (AuthService.OnlyAdmin || AuthService.LoginRequired)
|
|
{
|
|
<MudMenuItem Icon="@Icons.Material.Filled.Lock"
|
|
Href="@($"/ChangePassword")"
|
|
IconColor="@Color.Primary">
|
|
@Localizer["Change Password"]
|
|
</MudMenuItem>
|
|
<MudDivider />
|
|
}
|
|
@if (AuthService.LoginRequired && AuthService.IsAdmin)
|
|
{
|
|
<MudMenuItem Icon="@Icons.Material.Filled.Password"
|
|
OnClick="@(_ => GenerateInviteCode(User.Baid))"
|
|
OnTouch="@(_ => GenerateInviteCode(User.Baid))"
|
|
IconColor="@Color.Primary">
|
|
@Localizer["Generate Invite Code"]
|
|
</MudMenuItem>
|
|
<MudDivider />
|
|
}
|
|
@if (AuthService.LoginRequired && AuthService.IsAdmin)
|
|
{
|
|
<MudMenuItem Icon="@Icons.Material.Filled.LockReset"
|
|
OnClick="@(_ => ResetPassword(User))"
|
|
OnTouch="@(_ => ResetPassword(User))"
|
|
IconColor="@Color.Primary">
|
|
@Localizer["Unregister"]
|
|
</MudMenuItem>
|
|
<MudDivider />
|
|
}
|
|
@if (AuthService.AllowUserDelete)
|
|
{
|
|
<MudMenuItem Icon="@Icons.Material.Filled.Delete"
|
|
OnClick="@(_ => DeleteUser(User))"
|
|
OnTouch="@(_ => DeleteUser(User))"
|
|
IconColor="@Color.Error">
|
|
@Localizer["Delete User"]
|
|
</MudMenuItem>
|
|
}
|
|
</MudMenu>
|
|
</CardHeaderActions>
|
|
</MudCardHeader>
|
|
<MudCardContent>
|
|
<MudText Typo="Typo.body2" Style="font-weight:bold">@Localizer["Access Code"]</MudText>
|
|
<MudText Style="font-family:monospace;overflow:hidden;overflow-x:scroll">
|
|
@if (User.AccessCodes.Count > 0)
|
|
{
|
|
@foreach (var digitGroup in StringUtil.SplitIntoGroups(User.AccessCodes[0], 4))
|
|
{
|
|
<span class="mr-2">@digitGroup</span>
|
|
}
|
|
} else
|
|
{
|
|
<span class="mr-2">@Localizer["N/A"]</span>
|
|
}
|
|
</MudText>
|
|
@if (User.AccessCodes.Count > 1)
|
|
{
|
|
<MudText Typo="Typo.caption">... @Localizer["And"] @(User.AccessCodes.Count - 1) @Localizer["other access code(s)"]</MudText>
|
|
}
|
|
else
|
|
{
|
|
// Empty line to keep the layout consistent
|
|
<MudText Typo="Typo.caption"> </MudText>
|
|
}
|
|
</MudCardContent>
|
|
<MudCardActions>
|
|
<MudStack Row="true" Style="width:100%" Spacing="4" Justify="Justify.FlexEnd">
|
|
<MudButton Href="@($"Users/{User.Baid}/Profile")"
|
|
Size="Size.Small" Variant="Variant.Text" StartIcon="@Icons.Material.Filled.Edit"
|
|
Color="Color.Primary">
|
|
@Localizer["Edit Profile"]
|
|
</MudButton>
|
|
<MudMenu Size="Size.Small"
|
|
Dense="true"
|
|
Color="Color.Primary"
|
|
Label="@Localizer["View Play Data"]"
|
|
StartIcon="@Icons.Material.Filled.EmojiEvents"
|
|
EndIcon="@Icons.Material.Filled.KeyboardArrowDown"
|
|
FullWidth="true"
|
|
AnchorOrigin="Origin.BottomCenter"
|
|
TransformOrigin="Origin.TopCenter">
|
|
<MudMenuItem Href="@($"Users/{User.Baid}/HighScores")">@Localizer["High Scores"]</MudMenuItem>
|
|
<MudMenuItem Href="@($"Users/{User.Baid}/PlayHistory")">@Localizer["Play History"]</MudMenuItem>
|
|
<MudMenuItem Href="@($"Users/{User.Baid}/Songs")">@Localizer["Song List"]</MudMenuItem>
|
|
<MudMenuItem Href="@($"Users/{User.Baid}/DaniDojo")">@Localizer["Dani Dojo"]</MudMenuItem>
|
|
</MudMenu>
|
|
</MudStack>
|
|
</MudCardActions>
|
|
</MudCard>
|
|
}
|
|
|
|
@code {
|
|
[Parameter] public User? User { get; set; }
|
|
[Parameter] public UserSetting? UserSetting { get; set; }
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
await base.OnInitializedAsync();
|
|
}
|
|
|
|
private Task ShowQrCode(User user)
|
|
{
|
|
var parameters = new DialogParameters
|
|
{
|
|
["user"] = user
|
|
};
|
|
|
|
var options = new DialogOptions { DisableBackdropClick = true };
|
|
DialogService.Show<UserQrCodeDialog>(Localizer["QR Code"], parameters, options);
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private async Task ResetPassword(User user)
|
|
{
|
|
var options = new DialogOptions { DisableBackdropClick = true };
|
|
if (AuthService.LoginRequired && !AuthService.IsAdmin)
|
|
{
|
|
await DialogService.ShowMessageBox(
|
|
Localizer["Error"],
|
|
"Only admin can reset password.",
|
|
Localizer["Dialog OK"], null, null, options);
|
|
return;
|
|
}
|
|
var parameters = new DialogParameters
|
|
{
|
|
["user"] = user
|
|
};
|
|
|
|
var dialog = await DialogService.ShowAsync<ResetPasswordConfirmDialog>(Localizer["Reset Password"], parameters, options);
|
|
await dialog.Result;
|
|
}
|
|
|
|
private async Task DeleteUser(User user)
|
|
{
|
|
var options = new DialogOptions { DisableBackdropClick = true };
|
|
if (!AuthService.AllowUserDelete)
|
|
{
|
|
await DialogService.ShowMessageBox(
|
|
Localizer["Error"],
|
|
"User deletion is disabled by admin.",
|
|
Localizer["Dialog OK"], null, null, options);
|
|
return;
|
|
}
|
|
var parameters = new DialogParameters
|
|
{
|
|
["user"] = user
|
|
};
|
|
|
|
var dialog = await DialogService.ShowAsync<UserDeleteConfirmDialog>(Localizer["Delete User"], parameters, options);
|
|
var result = await dialog.Result;
|
|
|
|
if (result.Canceled) return;
|
|
|
|
if (user.Baid == AuthService.GetLoggedInBaid())
|
|
{
|
|
await AuthService.Logout();
|
|
}
|
|
|
|
NavigationManager.NavigateTo("/Users");
|
|
}
|
|
|
|
private async Task GenerateInviteCode(uint baid)
|
|
{
|
|
var request = new GenerateOtpRequest
|
|
{
|
|
Baid = baid
|
|
};
|
|
|
|
var responseMessage = await Client.PostAsJsonAsync("api/Auth/GenerateOtp", request);
|
|
|
|
if (!responseMessage.IsSuccessStatusCode)
|
|
{
|
|
await DialogService.ShowMessageBox(
|
|
Localizer["Error"],
|
|
Localizer["Unknown Error"],
|
|
Localizer["Dialog OK"], null, null, new DialogOptions { DisableBackdropClick = true });
|
|
return;
|
|
}
|
|
|
|
var responseContent = await responseMessage.Content.ReadAsStringAsync();
|
|
var responseJson = JsonSerializer.Deserialize<Dictionary<string, string>>(responseContent);
|
|
if (responseJson == null)
|
|
{
|
|
await DialogService.ShowMessageBox(
|
|
Localizer["Error"],
|
|
Localizer["Unknown Error"],
|
|
Localizer["Dialog OK"], null, null, new DialogOptions { DisableBackdropClick = true });
|
|
return;
|
|
}
|
|
|
|
var otp = responseJson["otp"];
|
|
|
|
var parameters = new DialogParameters
|
|
{
|
|
["otp"] = otp
|
|
};
|
|
|
|
var options = new DialogOptions { DisableBackdropClick = true };
|
|
await DialogService.ShowAsync<OTPDialog>(Localizer["Invite Code"], parameters, options);
|
|
}
|
|
} |