From be385713c2cd7ed18391fa811b46948fa92072ac Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 3 May 2024 03:24:40 +0100 Subject: [PATCH] Reformat new server project. --- Aaru.Server.New/Aaru.Server.New.csproj | 30 ++-- ...omponentsEndpointRouteBuilderExtensions.cs | 63 ++++---- .../Account/IdentityNoOpEmailSender.cs | 6 +- .../Account/IdentityRedirectManager.cs | 19 ++- ...RevalidatingAuthenticationStateProvider.cs | 36 ++--- .../Account/IdentityUserAccessor.cs | 7 +- .../Account/Pages/ConfirmEmail.razor | 9 +- .../Account/Pages/ConfirmEmailChange.razor | 11 +- .../Account/Pages/ExternalLogin.razor | 33 +++-- .../Account/Pages/ForgotPassword.razor | 19 ++- .../Components/Account/Pages/Login.razor | 7 +- .../Account/Pages/LoginWith2fa.razor | 9 +- .../Account/Pages/LoginWithRecoveryCode.razor | 9 +- .../Account/Pages/Manage/ChangePassword.razor | 5 +- .../Pages/Manage/DeletePersonalData.razor | 9 +- .../Account/Pages/Manage/Disable2fa.razor | 7 +- .../Account/Pages/Manage/Email.razor | 37 +++-- .../Pages/Manage/EnableAuthenticator.razor | 21 ++- .../Account/Pages/Manage/ExternalLogins.razor | 15 +- .../Pages/Manage/GenerateRecoveryCodes.razor | 7 +- .../Account/Pages/Manage/Index.razor | 5 +- .../Pages/Manage/ResetAuthenticator.razor | 7 +- .../Account/Pages/Manage/SetPassword.razor | 7 +- .../Manage/TwoFactorAuthentication.razor | 5 +- .../Account/Pages/Manage/_Imports.razor | 5 +- .../Components/Account/Pages/Register.razor | 31 ++-- .../Account/Pages/RegisterConfirmation.razor | 9 +- .../Pages/ResendEmailConfirmation.razor | 21 ++- .../Account/Pages/ResetPassword.razor | 7 +- .../Account/Shared/AccountLayout.razor | 7 +- .../Account/Shared/ExternalLoginPicker.razor | 7 +- .../Account/Shared/ManageNavMenu.razor | 5 +- .../Account/Shared/RedirectToLogin.razor | 2 +- .../Account/Shared/ShowRecoveryCodes.razor | 2 +- .../Account/Shared/StatusMessage.razor | 2 +- .../Components/Layout/MainLayout.razor.css | 134 +++++++++--------- .../Components/Layout/NavMenu.razor.css | 128 ++++++++--------- Aaru.Server.New/Components/Pages/Auth.razor | 1 - .../Components/Pages/Counter.razor | 2 +- .../Components/Pages/Weather.razor | 4 +- Aaru.Server.New/Components/Routes.razor | 3 +- Aaru.Server.New/Program.cs | 18 ++- .../Properties/launchSettings.json | 64 ++++----- Aaru.Server.New/appsettings.Development.json | 2 +- Aaru.Server.New/appsettings.json | 6 +- Aaru.Server.New/wwwroot/app.css | 34 ++--- 46 files changed, 419 insertions(+), 458 deletions(-) diff --git a/Aaru.Server.New/Aaru.Server.New.csproj b/Aaru.Server.New/Aaru.Server.New.csproj index 9bb731a4..8a6d916b 100644 --- a/Aaru.Server.New/Aaru.Server.New.csproj +++ b/Aaru.Server.New/Aaru.Server.New.csproj @@ -1,21 +1,21 @@ - - net8.0 - enable - enable - aspnet-Aaru.Server.New-79282495-4F67-4766-871D-448D1338E8BC - + + net8.0 + enable + enable + aspnet-Aaru.Server.New-79282495-4F67-4766-871D-448D1338E8BC + - - - + + + - - - - - - + + + + + + diff --git a/Aaru.Server.New/Components/Account/IdentityComponentsEndpointRouteBuilderExtensions.cs b/Aaru.Server.New/Components/Account/IdentityComponentsEndpointRouteBuilderExtensions.cs index 806414a3..5f908740 100644 --- a/Aaru.Server.New/Components/Account/IdentityComponentsEndpointRouteBuilderExtensions.cs +++ b/Aaru.Server.New/Components/Account/IdentityComponentsEndpointRouteBuilderExtensions.cs @@ -1,25 +1,26 @@ +using System.Reflection; using System.Security.Claims; using System.Text.Json; +using Aaru.Server.New.Components.Account.Pages; +using Aaru.Server.New.Components.Account.Pages.Manage; +using Aaru.Server.New.Data; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Primitives; -using Aaru.Server.New.Components.Account.Pages; -using Aaru.Server.New.Components.Account.Pages.Manage; -using Aaru.Server.New.Data; namespace Microsoft.AspNetCore.Routing; -internal static class IdentityComponentsEndpointRouteBuilderExtensions +static class IdentityComponentsEndpointRouteBuilderExtensions { // These endpoints are required by the Identity Razor components defined in the /Components/Account/Pages directory of this project. public static IEndpointConventionBuilder MapAdditionalIdentityEndpoints(this IEndpointRouteBuilder endpoints) { ArgumentNullException.ThrowIfNull(endpoints); - var accountGroup = endpoints.MapGroup("/Account"); + RouteGroupBuilder accountGroup = endpoints.MapGroup("/Account"); accountGroup.MapPost("/PerformExternalLogin", (HttpContext context, [FromServices] SignInManager signInManager, @@ -27,14 +28,16 @@ internal static class IdentityComponentsEndpointRouteBuilderExtensions { IEnumerable> query = [ - new("ReturnUrl", returnUrl), new("Action", ExternalLogin.LoginCallbackAction) + new KeyValuePair("ReturnUrl", returnUrl), + new KeyValuePair("Action", + ExternalLogin.LoginCallbackAction) ]; - var redirectUrl = UriHelper.BuildRelative(context.Request.PathBase, - "/Account/ExternalLogin", - QueryString.Create(query)); + string redirectUrl = UriHelper.BuildRelative(context.Request.PathBase, + "/Account/ExternalLogin", + QueryString.Create(query)); - var properties = + AuthenticationProperties properties = signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl); return TypedResults.Challenge(properties, [provider]); @@ -49,7 +52,7 @@ internal static class IdentityComponentsEndpointRouteBuilderExtensions return TypedResults.LocalRedirect($"~/{returnUrl}"); }); - var manageGroup = accountGroup.MapGroup("/Manage").RequireAuthorization(); + RouteGroupBuilder manageGroup = accountGroup.MapGroup("/Manage").RequireAuthorization(); manageGroup.MapPost("/LinkExternalLogin", async (HttpContext context, [FromServices] SignInManager signInManager, @@ -58,13 +61,13 @@ internal static class IdentityComponentsEndpointRouteBuilderExtensions // Clear the existing external cookie to ensure a clean login process await context.SignOutAsync(IdentityConstants.ExternalScheme); - var redirectUrl = UriHelper.BuildRelative(context.Request.PathBase, - "/Account/Manage/ExternalLogins", - QueryString.Create("Action", - ExternalLogins - .LinkLoginCallbackAction)); + string redirectUrl = UriHelper.BuildRelative(context.Request.PathBase, + "/Account/Manage/ExternalLogins", + QueryString.Create("Action", + ExternalLogins + .LinkLoginCallbackAction)); - var properties = + AuthenticationProperties properties = signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, signInManager.UserManager.GetUserId(context.User)); @@ -72,14 +75,14 @@ internal static class IdentityComponentsEndpointRouteBuilderExtensions return TypedResults.Challenge(properties, [provider]); }); - var loggerFactory = endpoints.ServiceProvider.GetRequiredService(); - var downloadLogger = loggerFactory.CreateLogger("DownloadPersonalData"); + ILoggerFactory loggerFactory = endpoints.ServiceProvider.GetRequiredService(); + ILogger downloadLogger = loggerFactory.CreateLogger("DownloadPersonalData"); manageGroup.MapPost("/DownloadPersonalData", async (HttpContext context, [FromServices] UserManager userManager, [FromServices] AuthenticationStateProvider authenticationStateProvider) => { - var user = await userManager.GetUserAsync(context.User); + ApplicationUser? user = await userManager.GetUserAsync(context.User); if(user is null) { @@ -88,7 +91,7 @@ internal static class IdentityComponentsEndpointRouteBuilderExtensions .NotFound($"Unable to load user with ID '{userManager.GetUserId(context.User)}'."); } - var userId = await userManager.GetUserIdAsync(user); + string userId = await userManager.GetUserIdAsync(user); downloadLogger.LogInformation("User with ID '{UserId}' asked for their personal data.", userId); @@ -96,32 +99,26 @@ internal static class IdentityComponentsEndpointRouteBuilderExtensions // Only include personal data for download var personalData = new Dictionary(); - var personalDataProps = typeof(ApplicationUser).GetProperties() + IEnumerable personalDataProps = typeof(ApplicationUser).GetProperties() .Where(prop => Attribute.IsDefined(prop, typeof(PersonalDataAttribute))); - foreach(var p in personalDataProps) - { + foreach(PropertyInfo p in personalDataProps) personalData.Add(p.Name, p.GetValue(user)?.ToString() ?? "null"); - } - var logins = await userManager.GetLoginsAsync(user); + IList logins = await userManager.GetLoginsAsync(user); - foreach(var l in logins) - { + foreach(UserLoginInfo l in logins) personalData.Add($"{l.LoginProvider} external login provider key", l.ProviderKey); - } personalData.Add("Authenticator Key", (await userManager.GetAuthenticatorKeyAsync(user))!); - var fileBytes = JsonSerializer.SerializeToUtf8Bytes(personalData); + byte[] fileBytes = JsonSerializer.SerializeToUtf8Bytes(personalData); context.Response.Headers.TryAdd("Content-Disposition", "attachment; filename=PersonalData.json"); - return TypedResults.File(fileBytes, - contentType: "application/json", - fileDownloadName: "PersonalData.json"); + return TypedResults.File(fileBytes, "application/json", "PersonalData.json"); }); return accountGroup; diff --git a/Aaru.Server.New/Components/Account/IdentityNoOpEmailSender.cs b/Aaru.Server.New/Components/Account/IdentityNoOpEmailSender.cs index 2ff69ae5..3d06f70d 100644 --- a/Aaru.Server.New/Components/Account/IdentityNoOpEmailSender.cs +++ b/Aaru.Server.New/Components/Account/IdentityNoOpEmailSender.cs @@ -1,13 +1,13 @@ +using Aaru.Server.New.Data; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.UI.Services; -using Aaru.Server.New.Data; namespace Aaru.Server.New.Components.Account; // Remove the "else if (EmailSender is IdentityNoOpEmailSender)" block from RegisterConfirmation.razor after updating with a real implementation. -internal sealed class IdentityNoOpEmailSender : IEmailSender +sealed class IdentityNoOpEmailSender : IEmailSender { - private readonly IEmailSender emailSender = new NoOpEmailSender(); + readonly IEmailSender emailSender = new NoOpEmailSender(); public Task SendConfirmationLinkAsync(ApplicationUser user, string email, string confirmationLink) => emailSender.SendEmailAsync(email, diff --git a/Aaru.Server.New/Components/Account/IdentityRedirectManager.cs b/Aaru.Server.New/Components/Account/IdentityRedirectManager.cs index a6f0e007..cb02143d 100644 --- a/Aaru.Server.New/Components/Account/IdentityRedirectManager.cs +++ b/Aaru.Server.New/Components/Account/IdentityRedirectManager.cs @@ -3,28 +3,27 @@ using Microsoft.AspNetCore.Components; namespace Aaru.Server.New.Components.Account; -internal sealed class IdentityRedirectManager(NavigationManager navigationManager) +sealed class IdentityRedirectManager(NavigationManager navigationManager) { public const string StatusCookieName = "Identity.StatusMessage"; - private static readonly CookieBuilder StatusCookieBuilder = new() + static readonly CookieBuilder StatusCookieBuilder = new() { SameSite = SameSiteMode.Strict, HttpOnly = true, IsEssential = true, - MaxAge = TimeSpan.FromSeconds(5), + MaxAge = TimeSpan.FromSeconds(5) }; + string CurrentPath => navigationManager.ToAbsoluteUri(navigationManager.Uri).GetLeftPart(UriPartial.Path); + [DoesNotReturn] public void RedirectTo(string? uri) { uri ??= ""; // Prevent open redirects. - if(!Uri.IsWellFormedUriString(uri, UriKind.Relative)) - { - uri = navigationManager.ToBaseRelativePath(uri); - } + if(!Uri.IsWellFormedUriString(uri, UriKind.Relative)) uri = navigationManager.ToBaseRelativePath(uri); // During static rendering, NavigateTo throws a NavigationException which is handled by the framework as a redirect. // So as long as this is called from a statically rendered Identity component, the InvalidOperationException is never thrown. @@ -37,8 +36,8 @@ internal sealed class IdentityRedirectManager(NavigationManager navigationManage [DoesNotReturn] public void RedirectTo(string uri, Dictionary queryParameters) { - var uriWithoutQuery = navigationManager.ToAbsoluteUri(uri).GetLeftPart(UriPartial.Path); - var newUri = navigationManager.GetUriWithQueryParameters(uriWithoutQuery, queryParameters); + string uriWithoutQuery = navigationManager.ToAbsoluteUri(uri).GetLeftPart(UriPartial.Path); + string newUri = navigationManager.GetUriWithQueryParameters(uriWithoutQuery, queryParameters); RedirectTo(newUri); } @@ -49,8 +48,6 @@ internal sealed class IdentityRedirectManager(NavigationManager navigationManage RedirectTo(uri); } - private string CurrentPath => navigationManager.ToAbsoluteUri(navigationManager.Uri).GetLeftPart(UriPartial.Path); - [DoesNotReturn] public void RedirectToCurrentPage() => RedirectTo(CurrentPath); diff --git a/Aaru.Server.New/Components/Account/IdentityRevalidatingAuthenticationStateProvider.cs b/Aaru.Server.New/Components/Account/IdentityRevalidatingAuthenticationStateProvider.cs index 6df9cf58..e0665172 100644 --- a/Aaru.Server.New/Components/Account/IdentityRevalidatingAuthenticationStateProvider.cs +++ b/Aaru.Server.New/Components/Account/IdentityRevalidatingAuthenticationStateProvider.cs @@ -1,15 +1,15 @@ using System.Security.Claims; +using Aaru.Server.New.Data; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Server; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; -using Aaru.Server.New.Data; namespace Aaru.Server.New.Components.Account; // This is a server-side AuthenticationStateProvider that revalidates the security stamp for the connected user // every 30 minutes an interactive circuit is connected. -internal sealed class IdentityRevalidatingAuthenticationStateProvider +sealed class IdentityRevalidatingAuthenticationStateProvider (ILoggerFactory loggerFactory, IServiceScopeFactory scopeFactory, IOptions options) : RevalidatingServerAuthenticationStateProvider(loggerFactory) { @@ -19,31 +19,25 @@ internal sealed class IdentityRevalidatingAuthenticationStateProvider AuthenticationState authenticationState, CancellationToken cancellationToken) { // Get the user manager from a new scope to ensure it fetches fresh data - await using var scope = scopeFactory.CreateAsyncScope(); - var userManager = scope.ServiceProvider.GetRequiredService>(); + await using AsyncServiceScope scope = scopeFactory.CreateAsyncScope(); + + UserManager userManager = + scope.ServiceProvider.GetRequiredService>(); return await ValidateSecurityStampAsync(userManager, authenticationState.User); } - private async Task ValidateSecurityStampAsync(UserManager userManager, - ClaimsPrincipal principal) + async Task ValidateSecurityStampAsync(UserManager userManager, ClaimsPrincipal principal) { - var user = await userManager.GetUserAsync(principal); + ApplicationUser? user = await userManager.GetUserAsync(principal); - if(user is null) - { - return false; - } - else if(!userManager.SupportsUserSecurityStamp) - { - return true; - } - else - { - var principalStamp = principal.FindFirstValue(options.Value.ClaimsIdentity.SecurityStampClaimType); - var userStamp = await userManager.GetSecurityStampAsync(user); + if(user is null) return false; - return principalStamp == userStamp; - } + if(!userManager.SupportsUserSecurityStamp) return true; + + string? principalStamp = principal.FindFirstValue(options.Value.ClaimsIdentity.SecurityStampClaimType); + string userStamp = await userManager.GetSecurityStampAsync(user); + + return principalStamp == userStamp; } } \ No newline at end of file diff --git a/Aaru.Server.New/Components/Account/IdentityUserAccessor.cs b/Aaru.Server.New/Components/Account/IdentityUserAccessor.cs index 9604636d..51fd12c5 100644 --- a/Aaru.Server.New/Components/Account/IdentityUserAccessor.cs +++ b/Aaru.Server.New/Components/Account/IdentityUserAccessor.cs @@ -1,14 +1,13 @@ -using Microsoft.AspNetCore.Identity; using Aaru.Server.New.Data; +using Microsoft.AspNetCore.Identity; namespace Aaru.Server.New.Components.Account; -internal sealed class IdentityUserAccessor - (UserManager userManager, IdentityRedirectManager redirectManager) +sealed class IdentityUserAccessor(UserManager userManager, IdentityRedirectManager redirectManager) { public async Task GetRequiredUserAsync(HttpContext context) { - var user = await userManager.GetUserAsync(context.User); + ApplicationUser? user = await userManager.GetUserAsync(context.User); if(user is null) { diff --git a/Aaru.Server.New/Components/Account/Pages/ConfirmEmail.razor b/Aaru.Server.New/Components/Account/Pages/ConfirmEmail.razor index 0969ea11..31cc5ae1 100644 --- a/Aaru.Server.New/Components/Account/Pages/ConfirmEmail.razor +++ b/Aaru.Server.New/Components/Account/Pages/ConfirmEmail.razor @@ -1,9 +1,8 @@ @page "/Account/ConfirmEmail" - @using System.Text +@using Aaru.Server.New.Data @using Microsoft.AspNetCore.Identity @using Microsoft.AspNetCore.WebUtilities -@using Aaru.Server.New.Data @inject UserManager UserManager @inject IdentityRedirectManager RedirectManager @@ -32,7 +31,7 @@ RedirectManager.RedirectTo(""); } - var user = await UserManager.FindByIdAsync(UserId); + ApplicationUser? user = await UserManager.FindByIdAsync(UserId); if(user is null) { @@ -41,8 +40,8 @@ } else { - var code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(Code)); - var result = await UserManager.ConfirmEmailAsync(user, code); + string code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(Code)); + IdentityResult result = await UserManager.ConfirmEmailAsync(user, code); statusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email."; } } diff --git a/Aaru.Server.New/Components/Account/Pages/ConfirmEmailChange.razor b/Aaru.Server.New/Components/Account/Pages/ConfirmEmailChange.razor index f8e4c4a7..9a44919d 100644 --- a/Aaru.Server.New/Components/Account/Pages/ConfirmEmailChange.razor +++ b/Aaru.Server.New/Components/Account/Pages/ConfirmEmailChange.razor @@ -1,9 +1,8 @@ @page "/Account/ConfirmEmailChange" - @using System.Text +@using Aaru.Server.New.Data @using Microsoft.AspNetCore.Identity @using Microsoft.AspNetCore.WebUtilities -@using Aaru.Server.New.Data @inject UserManager UserManager @inject SignInManager SignInManager @@ -37,7 +36,7 @@ RedirectManager.RedirectToWithStatus("Account/Login", "Error: Invalid email change confirmation link.", HttpContext); } - var user = await UserManager.FindByIdAsync(UserId); + ApplicationUser? user = await UserManager.FindByIdAsync(UserId); if(user is null) { @@ -46,8 +45,8 @@ return; } - var code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(Code)); - var result = await UserManager.ChangeEmailAsync(user, Email, code); + string code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(Code)); + IdentityResult result = await UserManager.ChangeEmailAsync(user, Email, code); if(!result.Succeeded) { @@ -58,7 +57,7 @@ // In our UI email and user name are one and the same, so when we update the email // we need to update the user name. - var setUserNameResult = await UserManager.SetUserNameAsync(user, Email); + IdentityResult setUserNameResult = await UserManager.SetUserNameAsync(user, Email); if(!setUserNameResult.Succeeded) { diff --git a/Aaru.Server.New/Components/Account/Pages/ExternalLogin.razor b/Aaru.Server.New/Components/Account/Pages/ExternalLogin.razor index 2cc8ccbc..2d0813a3 100644 --- a/Aaru.Server.New/Components/Account/Pages/ExternalLogin.razor +++ b/Aaru.Server.New/Components/Account/Pages/ExternalLogin.razor @@ -1,12 +1,11 @@ @page "/Account/ExternalLogin" - @using System.ComponentModel.DataAnnotations @using System.Security.Claims @using System.Text @using System.Text.Encodings.Web +@using Aaru.Server.New.Data @using Microsoft.AspNetCore.Identity @using Microsoft.AspNetCore.WebUtilities -@using Aaru.Server.New.Data @inject SignInManager SignInManager @inject UserManager UserManager @@ -74,7 +73,7 @@ RedirectManager.RedirectToWithStatus("Account/Login", $"Error from external provider: {RemoteError}", HttpContext); } - var info = await SignInManager.GetExternalLoginInfoAsync(); + ExternalLoginInfo? info = await SignInManager.GetExternalLoginInfoAsync(); if(info is null) { @@ -101,7 +100,7 @@ private async Task OnLoginCallbackAsync() { // Sign in the user with this external login provider if the user already has a login. - var result = await SignInManager.ExternalLoginSignInAsync(externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey, isPersistent: false, bypassTwoFactor: true); + SignInResult result = await SignInManager.ExternalLoginSignInAsync(externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey, false, true); if(result.Succeeded) { @@ -122,13 +121,13 @@ private async Task OnValidSubmitAsync() { - var emailStore = GetEmailStore(); - var user = CreateUser(); + IUserEmailStore emailStore = GetEmailStore(); + ApplicationUser user = CreateUser(); await UserStore.SetUserNameAsync(user, Input.Email, CancellationToken.None); await emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None); - var result = await UserManager.CreateAsync(user); + IdentityResult result = await UserManager.CreateAsync(user); if(result.Succeeded) { @@ -138,16 +137,16 @@ { Logger.LogInformation("User created an account using {Name} provider.", externalLoginInfo.LoginProvider); - var userId = await UserManager.GetUserIdAsync(user); - var code = await UserManager.GenerateEmailConfirmationTokenAsync(user); + string userId = await UserManager.GetUserIdAsync(user); + string code = await UserManager.GenerateEmailConfirmationTokenAsync(user); code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); - var callbackUrl = NavigationManager.GetUriWithQueryParameters(NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri, - new Dictionary - { - ["userId"] = userId, - ["code"] = code - }); + string callbackUrl = NavigationManager.GetUriWithQueryParameters(NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri, + new Dictionary + { + ["userId"] = userId, + ["code"] = code + }); await EmailSender.SendConfirmationLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl)); @@ -155,13 +154,13 @@ if(UserManager.Options.SignIn.RequireConfirmedAccount) { RedirectManager.RedirectTo("Account/RegisterConfirmation", - new() + new Dictionary { ["email"] = Input.Email }); } - await SignInManager.SignInAsync(user, isPersistent: false, externalLoginInfo.LoginProvider); + await SignInManager.SignInAsync(user, false, externalLoginInfo.LoginProvider); RedirectManager.RedirectTo(ReturnUrl); } } diff --git a/Aaru.Server.New/Components/Account/Pages/ForgotPassword.razor b/Aaru.Server.New/Components/Account/Pages/ForgotPassword.razor index e33a0fb7..e8d8afe8 100644 --- a/Aaru.Server.New/Components/Account/Pages/ForgotPassword.razor +++ b/Aaru.Server.New/Components/Account/Pages/ForgotPassword.razor @@ -1,11 +1,10 @@ @page "/Account/ForgotPassword" - @using System.ComponentModel.DataAnnotations @using System.Text @using System.Text.Encodings.Web +@using Aaru.Server.New.Data @using Microsoft.AspNetCore.Identity @using Microsoft.AspNetCore.WebUtilities -@using Aaru.Server.New.Data @inject UserManager UserManager @inject IEmailSender EmailSender @@ -39,9 +38,9 @@ private async Task OnValidSubmitAsync() { - var user = await UserManager.FindByEmailAsync(Input.Email); + ApplicationUser? user = await UserManager.FindByEmailAsync(Input.Email); - if(user is null || !(await UserManager.IsEmailConfirmedAsync(user))) + if(user is null || !await UserManager.IsEmailConfirmedAsync(user)) { // Don't reveal that the user does not exist or is not confirmed RedirectManager.RedirectTo("Account/ForgotPasswordConfirmation"); @@ -49,14 +48,14 @@ // For more information on how to enable account confirmation and password reset please // visit https://go.microsoft.com/fwlink/?LinkID=532713 - var code = await UserManager.GeneratePasswordResetTokenAsync(user); + string code = await UserManager.GeneratePasswordResetTokenAsync(user); code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); - var callbackUrl = NavigationManager.GetUriWithQueryParameters(NavigationManager.ToAbsoluteUri("Account/ResetPassword").AbsoluteUri, - new Dictionary - { - ["code"] = code - }); + string callbackUrl = NavigationManager.GetUriWithQueryParameters(NavigationManager.ToAbsoluteUri("Account/ResetPassword").AbsoluteUri, + new Dictionary + { + ["code"] = code + }); await EmailSender.SendPasswordResetLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl)); diff --git a/Aaru.Server.New/Components/Account/Pages/Login.razor b/Aaru.Server.New/Components/Account/Pages/Login.razor index c2cb756b..2b112692 100644 --- a/Aaru.Server.New/Components/Account/Pages/Login.razor +++ b/Aaru.Server.New/Components/Account/Pages/Login.razor @@ -1,9 +1,8 @@ @page "/Account/Login" - @using System.ComponentModel.DataAnnotations +@using Aaru.Server.New.Data @using Microsoft.AspNetCore.Authentication @using Microsoft.AspNetCore.Identity -@using Aaru.Server.New.Data @inject SignInManager SignInManager @inject ILogger Logger @@ -89,7 +88,7 @@ { // This doesn't count login failures towards account lockout // To enable password failures to trigger account lockout, set lockoutOnFailure: true - var result = await SignInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false); + SignInResult result = await SignInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, false); if(result.Succeeded) { @@ -99,7 +98,7 @@ else if(result.RequiresTwoFactor) { RedirectManager.RedirectTo("Account/LoginWith2fa", - new() + new Dictionary { ["returnUrl"] = ReturnUrl, ["rememberMe"] = Input.RememberMe diff --git a/Aaru.Server.New/Components/Account/Pages/LoginWith2fa.razor b/Aaru.Server.New/Components/Account/Pages/LoginWith2fa.razor index b7b11418..782ddc58 100644 --- a/Aaru.Server.New/Components/Account/Pages/LoginWith2fa.razor +++ b/Aaru.Server.New/Components/Account/Pages/LoginWith2fa.razor @@ -1,8 +1,7 @@ @page "/Account/LoginWith2fa" - @using System.ComponentModel.DataAnnotations -@using Microsoft.AspNetCore.Identity @using Aaru.Server.New.Data +@using Microsoft.AspNetCore.Identity @inject SignInManager SignInManager @inject UserManager UserManager @@ -65,9 +64,9 @@ private async Task OnValidSubmitAsync() { - var authenticatorCode = Input.TwoFactorCode!.Replace(" ", string.Empty).Replace("-", string.Empty); - var result = await SignInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, RememberMe, Input.RememberMachine); - var userId = await UserManager.GetUserIdAsync(user); + string authenticatorCode = Input.TwoFactorCode!.Replace(" ", string.Empty).Replace("-", string.Empty); + SignInResult result = await SignInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, RememberMe, Input.RememberMachine); + string userId = await UserManager.GetUserIdAsync(user); if(result.Succeeded) { diff --git a/Aaru.Server.New/Components/Account/Pages/LoginWithRecoveryCode.razor b/Aaru.Server.New/Components/Account/Pages/LoginWithRecoveryCode.razor index f4ff0bed..6081e7bf 100644 --- a/Aaru.Server.New/Components/Account/Pages/LoginWithRecoveryCode.razor +++ b/Aaru.Server.New/Components/Account/Pages/LoginWithRecoveryCode.razor @@ -1,8 +1,7 @@ @page "/Account/LoginWithRecoveryCode" - @using System.ComponentModel.DataAnnotations -@using Microsoft.AspNetCore.Identity @using Aaru.Server.New.Data +@using Microsoft.AspNetCore.Identity @inject SignInManager SignInManager @inject UserManager UserManager @@ -51,11 +50,11 @@ private async Task OnValidSubmitAsync() { - var recoveryCode = Input.RecoveryCode.Replace(" ", string.Empty); + string recoveryCode = Input.RecoveryCode.Replace(" ", string.Empty); - var result = await SignInManager.TwoFactorRecoveryCodeSignInAsync(recoveryCode); + SignInResult result = await SignInManager.TwoFactorRecoveryCodeSignInAsync(recoveryCode); - var userId = await UserManager.GetUserIdAsync(user); + string userId = await UserManager.GetUserIdAsync(user); if(result.Succeeded) { diff --git a/Aaru.Server.New/Components/Account/Pages/Manage/ChangePassword.razor b/Aaru.Server.New/Components/Account/Pages/Manage/ChangePassword.razor index 41cf0766..1dd32433 100644 --- a/Aaru.Server.New/Components/Account/Pages/Manage/ChangePassword.razor +++ b/Aaru.Server.New/Components/Account/Pages/Manage/ChangePassword.razor @@ -1,8 +1,7 @@ @page "/Account/Manage/ChangePassword" - @using System.ComponentModel.DataAnnotations -@using Microsoft.AspNetCore.Identity @using Aaru.Server.New.Data +@using Microsoft.AspNetCore.Identity @inject UserManager UserManager @inject SignInManager SignInManager @@ -63,7 +62,7 @@ private async Task OnValidSubmitAsync() { - var changePasswordResult = await UserManager.ChangePasswordAsync(user, Input.OldPassword, Input.NewPassword); + IdentityResult changePasswordResult = await UserManager.ChangePasswordAsync(user, Input.OldPassword, Input.NewPassword); if(!changePasswordResult.Succeeded) { diff --git a/Aaru.Server.New/Components/Account/Pages/Manage/DeletePersonalData.razor b/Aaru.Server.New/Components/Account/Pages/Manage/DeletePersonalData.razor index b7397d1a..05d4b088 100644 --- a/Aaru.Server.New/Components/Account/Pages/Manage/DeletePersonalData.razor +++ b/Aaru.Server.New/Components/Account/Pages/Manage/DeletePersonalData.razor @@ -1,8 +1,7 @@ @page "/Account/Manage/DeletePersonalData" - @using System.ComponentModel.DataAnnotations -@using Microsoft.AspNetCore.Identity @using Aaru.Server.New.Data +@using Microsoft.AspNetCore.Identity @inject UserManager UserManager @inject SignInManager SignInManager @@ -51,7 +50,7 @@ protected override async Task OnInitializedAsync() { - Input ??= new(); + Input ??= new InputModel(); user = await UserAccessor.GetRequiredUserAsync(HttpContext); requirePassword = await UserManager.HasPasswordAsync(user); } @@ -65,7 +64,7 @@ return; } - var result = await UserManager.DeleteAsync(user); + IdentityResult result = await UserManager.DeleteAsync(user); if(!result.Succeeded) { @@ -74,7 +73,7 @@ await SignInManager.SignOutAsync(); - var userId = await UserManager.GetUserIdAsync(user); + string userId = await UserManager.GetUserIdAsync(user); Logger.LogInformation("User with ID '{UserId}' deleted themselves.", userId); RedirectManager.RedirectToCurrentPage(); diff --git a/Aaru.Server.New/Components/Account/Pages/Manage/Disable2fa.razor b/Aaru.Server.New/Components/Account/Pages/Manage/Disable2fa.razor index eb9bc26a..68933aae 100644 --- a/Aaru.Server.New/Components/Account/Pages/Manage/Disable2fa.razor +++ b/Aaru.Server.New/Components/Account/Pages/Manage/Disable2fa.razor @@ -1,7 +1,6 @@ @page "/Account/Manage/Disable2fa" - -@using Microsoft.AspNetCore.Identity @using Aaru.Server.New.Data +@using Microsoft.AspNetCore.Identity @inject UserManager UserManager @inject IdentityUserAccessor UserAccessor @@ -48,14 +47,14 @@ private async Task OnSubmitAsync() { - var disable2faResult = await UserManager.SetTwoFactorEnabledAsync(user, false); + IdentityResult disable2faResult = await UserManager.SetTwoFactorEnabledAsync(user, false); if(!disable2faResult.Succeeded) { throw new InvalidOperationException("Unexpected error occurred disabling 2FA."); } - var userId = await UserManager.GetUserIdAsync(user); + string userId = await UserManager.GetUserIdAsync(user); Logger.LogInformation("User with ID '{UserId}' has disabled 2fa.", userId); RedirectManager.RedirectToWithStatus("Account/Manage/TwoFactorAuthentication", "2fa has been disabled. You can reenable 2fa when you setup an authenticator app", HttpContext); } diff --git a/Aaru.Server.New/Components/Account/Pages/Manage/Email.razor b/Aaru.Server.New/Components/Account/Pages/Manage/Email.razor index 1b64673d..780e38c3 100644 --- a/Aaru.Server.New/Components/Account/Pages/Manage/Email.razor +++ b/Aaru.Server.New/Components/Account/Pages/Manage/Email.razor @@ -1,11 +1,10 @@ @page "/Account/Manage/Email" - @using System.ComponentModel.DataAnnotations @using System.Text @using System.Text.Encodings.Web +@using Aaru.Server.New.Data @using Microsoft.AspNetCore.Identity @using Microsoft.AspNetCore.WebUtilities -@using Aaru.Server.New.Data @inject UserManager UserManager @inject IEmailSender EmailSender @@ -83,17 +82,17 @@ return; } - var userId = await UserManager.GetUserIdAsync(user); - var code = await UserManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail); + string userId = await UserManager.GetUserIdAsync(user); + string code = await UserManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail); code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); - var callbackUrl = NavigationManager.GetUriWithQueryParameters(NavigationManager.ToAbsoluteUri("Account/ConfirmEmailChange").AbsoluteUri, - new Dictionary - { - ["userId"] = userId, - ["email"] = Input.NewEmail, - ["code"] = code - }); + string callbackUrl = NavigationManager.GetUriWithQueryParameters(NavigationManager.ToAbsoluteUri("Account/ConfirmEmailChange").AbsoluteUri, + new Dictionary + { + ["userId"] = userId, + ["email"] = Input.NewEmail, + ["code"] = code + }); await EmailSender.SendConfirmationLinkAsync(user, Input.NewEmail, HtmlEncoder.Default.Encode(callbackUrl)); @@ -107,16 +106,16 @@ return; } - var userId = await UserManager.GetUserIdAsync(user); - var code = await UserManager.GenerateEmailConfirmationTokenAsync(user); + string userId = await UserManager.GetUserIdAsync(user); + string code = await UserManager.GenerateEmailConfirmationTokenAsync(user); code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); - var callbackUrl = NavigationManager.GetUriWithQueryParameters(NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri, - new Dictionary - { - ["userId"] = userId, - ["code"] = code - }); + string callbackUrl = NavigationManager.GetUriWithQueryParameters(NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri, + new Dictionary + { + ["userId"] = userId, + ["code"] = code + }); await EmailSender.SendConfirmationLinkAsync(user, email, HtmlEncoder.Default.Encode(callbackUrl)); diff --git a/Aaru.Server.New/Components/Account/Pages/Manage/EnableAuthenticator.razor b/Aaru.Server.New/Components/Account/Pages/Manage/EnableAuthenticator.razor index 3c8dd96a..aa79c691 100644 --- a/Aaru.Server.New/Components/Account/Pages/Manage/EnableAuthenticator.razor +++ b/Aaru.Server.New/Components/Account/Pages/Manage/EnableAuthenticator.razor @@ -1,11 +1,10 @@ @page "/Account/Manage/EnableAuthenticator" - @using System.ComponentModel.DataAnnotations @using System.Globalization @using System.Text @using System.Text.Encodings.Web -@using Microsoft.AspNetCore.Identity @using Aaru.Server.New.Data +@using Microsoft.AspNetCore.Identity @inject UserManager UserManager @inject IdentityUserAccessor UserAccessor @@ -22,6 +21,7 @@ else { +

Configure authenticator app

To use an authenticator app go through the following steps:

@@ -91,9 +91,9 @@ else private async Task OnValidSubmitAsync() { // Strip spaces and hyphens - var verificationCode = Input.Code.Replace(" ", string.Empty).Replace("-", string.Empty); + string verificationCode = Input.Code.Replace(" ", string.Empty).Replace("-", string.Empty); - var is2faTokenValid = await UserManager.VerifyTwoFactorTokenAsync(user, UserManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode); + bool is2faTokenValid = await UserManager.VerifyTwoFactorTokenAsync(user, UserManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode); if(!is2faTokenValid) { @@ -103,7 +103,7 @@ else } await UserManager.SetTwoFactorEnabledAsync(user, true); - var userId = await UserManager.GetUserIdAsync(user); + string userId = await UserManager.GetUserIdAsync(user); Logger.LogInformation("User with ID '{UserId}' has enabled 2FA with an authenticator app.", userId); message = "Your authenticator app has been verified."; @@ -121,7 +121,7 @@ else private async ValueTask LoadSharedKeyAndQrCodeUriAsync(ApplicationUser user) { // Load the authenticator key & QR code URI to display on the form - var unformattedKey = await UserManager.GetAuthenticatorKeyAsync(user); + string? unformattedKey = await UserManager.GetAuthenticatorKeyAsync(user); if(string.IsNullOrEmpty(unformattedKey)) { @@ -131,14 +131,14 @@ else sharedKey = FormatKey(unformattedKey!); - var email = await UserManager.GetEmailAsync(user); + string? email = await UserManager.GetEmailAsync(user); authenticatorUri = GenerateQrCodeUri(email!, unformattedKey!); } private string FormatKey(string unformattedKey) { var result = new StringBuilder(); - int currentPosition = 0; + var currentPosition = 0; while(currentPosition + 4 < unformattedKey.Length) { @@ -154,10 +154,7 @@ else return result.ToString().ToLowerInvariant(); } - private string GenerateQrCodeUri(string email, string unformattedKey) - { - return string.Format(CultureInfo.InvariantCulture, AuthenticatorUriFormat, UrlEncoder.Encode("Microsoft.AspNetCore.Identity.UI"), UrlEncoder.Encode(email), unformattedKey); - } + private string GenerateQrCodeUri(string email, string unformattedKey) => string.Format(CultureInfo.InvariantCulture, AuthenticatorUriFormat, UrlEncoder.Encode("Microsoft.AspNetCore.Identity.UI"), UrlEncoder.Encode(email), unformattedKey); private sealed class InputModel { diff --git a/Aaru.Server.New/Components/Account/Pages/Manage/ExternalLogins.razor b/Aaru.Server.New/Components/Account/Pages/Manage/ExternalLogins.razor index e4612c13..7e1e15ac 100644 --- a/Aaru.Server.New/Components/Account/Pages/Manage/ExternalLogins.razor +++ b/Aaru.Server.New/Components/Account/Pages/Manage/ExternalLogins.razor @@ -1,8 +1,7 @@ @page "/Account/Manage/ExternalLogins" - +@using Aaru.Server.New.Data @using Microsoft.AspNetCore.Authentication @using Microsoft.AspNetCore.Identity -@using Aaru.Server.New.Data @inject UserManager UserManager @inject SignInManager SignInManager @@ -18,7 +17,7 @@

Registered Logins

- @foreach(var login in currentLogins) + @foreach(UserLoginInfo login in currentLogins) { @@ -52,7 +51,7 @@

- @foreach(var provider in otherLogins) + @foreach(AuthenticationScheme provider in otherLogins) { } diff --git a/Aaru.Server.New/Components/Account/Shared/ManageNavMenu.razor b/Aaru.Server.New/Components/Account/Shared/ManageNavMenu.razor index b42ba0c4..867c06f0 100644 --- a/Aaru.Server.New/Components/Account/Shared/ManageNavMenu.razor +++ b/Aaru.Server.New/Components/Account/Shared/ManageNavMenu.razor @@ -1,6 +1,5 @@ -@using Microsoft.AspNetCore.Identity -@using Aaru.Server.New.Data - +@using Aaru.Server.New.Data +@using Microsoft.AspNetCore.Identity @inject SignInManager SignInManager

- @foreach(var recoveryCode in RecoveryCodes) + @foreach(string recoveryCode in RecoveryCodes) {
@recoveryCode diff --git a/Aaru.Server.New/Components/Account/Shared/StatusMessage.razor b/Aaru.Server.New/Components/Account/Shared/StatusMessage.razor index 256f665d..9f4d74eb 100644 --- a/Aaru.Server.New/Components/Account/Shared/StatusMessage.razor +++ b/Aaru.Server.New/Components/Account/Shared/StatusMessage.razor @@ -1,6 +1,6 @@ @if(!string.IsNullOrEmpty(DisplayMessage)) { - var statusMessageClass = DisplayMessage.StartsWith("Error") ? "danger" : "success"; + string statusMessageClass = DisplayMessage.StartsWith("Error") ? "danger" : "success"; diff --git a/Aaru.Server.New/Components/Layout/MainLayout.razor.css b/Aaru.Server.New/Components/Layout/MainLayout.razor.css index 038baf17..205a60d9 100644 --- a/Aaru.Server.New/Components/Layout/MainLayout.razor.css +++ b/Aaru.Server.New/Components/Layout/MainLayout.razor.css @@ -1,96 +1,96 @@ .page { - position: relative; - display: flex; - flex-direction: column; + position: relative; + display: flex; + flex-direction: column; } main { - flex: 1; + flex: 1; } .sidebar { - background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); + background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); } .top-row { - background-color: #f7f7f7; - border-bottom: 1px solid #d6d5d5; - justify-content: flex-end; - height: 3.5rem; - display: flex; - align-items: center; + background-color: #f7f7f7; + border-bottom: 1px solid #d6d5d5; + justify-content: flex-end; + height: 3.5rem; + display: flex; + align-items: center; } - .top-row ::deep a, .top-row ::deep .btn-link { - white-space: nowrap; - margin-left: 1.5rem; - text-decoration: none; - } +.top-row ::deep a, .top-row ::deep .btn-link { + white-space: nowrap; + margin-left: 1.5rem; + text-decoration: none; +} - .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { - text-decoration: underline; - } +.top-row ::deep a:hover, .top-row ::deep .btn-link:hover { + text-decoration: underline; +} - .top-row ::deep a:first-child { - overflow: hidden; - text-overflow: ellipsis; - } +.top-row ::deep a:first-child { + overflow: hidden; + text-overflow: ellipsis; +} @media (max-width: 640.98px) { - .top-row { - justify-content: space-between; - } + .top-row { + justify-content: space-between; + } - .top-row ::deep a, .top-row ::deep .btn-link { - margin-left: 0; - } + .top-row ::deep a, .top-row ::deep .btn-link { + margin-left: 0; + } } @media (min-width: 641px) { - .page { - flex-direction: row; - } + .page { + flex-direction: row; + } - .sidebar { - width: 250px; - height: 100vh; - position: sticky; - top: 0; - } + .sidebar { + width: 250px; + height: 100vh; + position: sticky; + top: 0; + } - .top-row { - position: sticky; - top: 0; - z-index: 1; - } + .top-row { + position: sticky; + top: 0; + z-index: 1; + } - .top-row.auth ::deep a:first-child { - flex: 1; - text-align: right; - width: 0; - } + .top-row.auth ::deep a:first-child { + flex: 1; + text-align: right; + width: 0; + } - .top-row, article { - padding-left: 2rem !important; - padding-right: 1.5rem !important; - } + .top-row, article { + padding-left: 2rem !important; + padding-right: 1.5rem !important; + } } #blazor-error-ui { - background: lightyellow; - bottom: 0; - box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); - display: none; - left: 0; - padding: 0.6rem 1.25rem 0.7rem 1.25rem; - position: fixed; - width: 100%; - z-index: 1000; + background: lightyellow; + bottom: 0; + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); + display: none; + left: 0; + padding: 0.6rem 1.25rem 0.7rem 1.25rem; + position: fixed; + width: 100%; + z-index: 1000; } - #blazor-error-ui .dismiss { - cursor: pointer; - position: absolute; - right: 0.75rem; - top: 0.5rem; - } +#blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; +} diff --git a/Aaru.Server.New/Components/Layout/NavMenu.razor.css b/Aaru.Server.New/Components/Layout/NavMenu.razor.css index 16700eba..b9e7935d 100644 --- a/Aaru.Server.New/Components/Layout/NavMenu.razor.css +++ b/Aaru.Server.New/Components/Layout/NavMenu.razor.css @@ -1,125 +1,125 @@ .navbar-toggler { - appearance: none; - cursor: pointer; - width: 3.5rem; - height: 2.5rem; - color: white; - position: absolute; - top: 0.5rem; - right: 1rem; - border: 1px solid rgba(255, 255, 255, 0.1); - background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1); + appearance: none; + cursor: pointer; + width: 3.5rem; + height: 2.5rem; + color: white; + position: absolute; + top: 0.5rem; + right: 1rem; + border: 1px solid rgba(255, 255, 255, 0.1); + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1); } .navbar-toggler:checked { - background-color: rgba(255, 255, 255, 0.5); + background-color: rgba(255, 255, 255, 0.5); } .top-row { - height: 3.5rem; - background-color: rgba(0,0,0,0.4); + height: 3.5rem; + background-color: rgba(0, 0, 0, 0.4); } .navbar-brand { - font-size: 1.1rem; + font-size: 1.1rem; } .bi { - display: inline-block; - position: relative; - width: 1.25rem; - height: 1.25rem; - margin-right: 0.75rem; - top: -1px; - background-size: cover; + display: inline-block; + position: relative; + width: 1.25rem; + height: 1.25rem; + margin-right: 0.75rem; + top: -1px; + background-size: cover; } .bi-house-door-fill-nav-menu { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E"); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E"); } .bi-plus-square-fill-nav-menu { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E"); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E"); } .bi-list-nested-nav-menu { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E"); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E"); } .bi-lock-nav-menu { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath d='M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2zm3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2zM5 8h6a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1z'/%3E%3C/svg%3E"); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath d='M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2zm3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2zM5 8h6a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1z'/%3E%3C/svg%3E"); } .bi-person-nav-menu { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person' viewBox='0 0 16 16'%3E%3Cpath d='M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0Zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4Zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10Z'/%3E%3C/svg%3E"); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person' viewBox='0 0 16 16'%3E%3Cpath d='M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0Zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4Zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10Z'/%3E%3C/svg%3E"); } .bi-person-badge-nav-menu { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person-badge' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3zM11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0z'/%3E%3Cpath d='M4.5 0A2.5 2.5 0 0 0 2 2.5V14a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2.5A2.5 2.5 0 0 0 11.5 0h-7zM3 2.5A1.5 1.5 0 0 1 4.5 1h7A1.5 1.5 0 0 1 13 2.5v10.795a4.2 4.2 0 0 0-.776-.492C11.392 12.387 10.063 12 8 12s-3.392.387-4.224.803a4.2 4.2 0 0 0-.776.492V2.5z'/%3E%3C/svg%3E"); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person-badge' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3zM11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0z'/%3E%3Cpath d='M4.5 0A2.5 2.5 0 0 0 2 2.5V14a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2.5A2.5 2.5 0 0 0 11.5 0h-7zM3 2.5A1.5 1.5 0 0 1 4.5 1h7A1.5 1.5 0 0 1 13 2.5v10.795a4.2 4.2 0 0 0-.776-.492C11.392 12.387 10.063 12 8 12s-3.392.387-4.224.803a4.2 4.2 0 0 0-.776.492V2.5z'/%3E%3C/svg%3E"); } .bi-person-fill-nav-menu { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person-fill' viewBox='0 0 16 16'%3E%3Cpath d='M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3Zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z'/%3E%3C/svg%3E"); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person-fill' viewBox='0 0 16 16'%3E%3Cpath d='M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3Zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z'/%3E%3C/svg%3E"); } .bi-arrow-bar-left-nav-menu { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-arrow-bar-left' viewBox='0 0 16 16'%3E%3Cpath d='M12.5 15a.5.5 0 0 1-.5-.5v-13a.5.5 0 0 1 1 0v13a.5.5 0 0 1-.5.5ZM10 8a.5.5 0 0 1-.5.5H3.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L3.707 7.5H9.5a.5.5 0 0 1 .5.5Z'/%3E%3C/svg%3E"); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-arrow-bar-left' viewBox='0 0 16 16'%3E%3Cpath d='M12.5 15a.5.5 0 0 1-.5-.5v-13a.5.5 0 0 1 1 0v13a.5.5 0 0 1-.5.5ZM10 8a.5.5 0 0 1-.5.5H3.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L3.707 7.5H9.5a.5.5 0 0 1 .5.5Z'/%3E%3C/svg%3E"); } .nav-item { - font-size: 0.9rem; - padding-bottom: 0.5rem; + font-size: 0.9rem; + padding-bottom: 0.5rem; } - .nav-item:first-of-type { - padding-top: 1rem; - } +.nav-item:first-of-type { + padding-top: 1rem; +} - .nav-item:last-of-type { - padding-bottom: 1rem; - } +.nav-item:last-of-type { + padding-bottom: 1rem; +} - .nav-item ::deep .nav-link { - color: #d7d7d7; - background: none; - border: none; - border-radius: 4px; - height: 3rem; - display: flex; - align-items: center; - line-height: 3rem; - width: 100%; - } +.nav-item ::deep .nav-link { + color: #d7d7d7; + background: none; + border: none; + border-radius: 4px; + height: 3rem; + display: flex; + align-items: center; + line-height: 3rem; + width: 100%; +} .nav-item ::deep a.active { - background-color: rgba(255,255,255,0.37); - color: white; + background-color: rgba(255, 255, 255, 0.37); + color: white; } .nav-item ::deep .nav-link:hover { - background-color: rgba(255,255,255,0.1); - color: white; + background-color: rgba(255, 255, 255, 0.1); + color: white; } .nav-scrollable { - display: none; + display: none; } .navbar-toggler:checked ~ .nav-scrollable { - display: block; + display: block; } @media (min-width: 641px) { - .navbar-toggler { - display: none; - } + .navbar-toggler { + display: none; + } - .nav-scrollable { - /* Never collapse the sidebar for wide screens */ - display: block; + .nav-scrollable { + /* Never collapse the sidebar for wide screens */ + display: block; - /* Allow sidebar to scroll for tall menus */ - height: calc(100vh - 3.5rem); - overflow-y: auto; - } + /* Allow sidebar to scroll for tall menus */ + height: calc(100vh - 3.5rem); + overflow-y: auto; + } } diff --git a/Aaru.Server.New/Components/Pages/Auth.razor b/Aaru.Server.New/Components/Pages/Auth.razor index d43f4636..8d04a523 100644 --- a/Aaru.Server.New/Components/Pages/Auth.razor +++ b/Aaru.Server.New/Components/Pages/Auth.razor @@ -1,5 +1,4 @@ @page "/auth" - @using Microsoft.AspNetCore.Authorization @attribute [Authorize] diff --git a/Aaru.Server.New/Components/Pages/Counter.razor b/Aaru.Server.New/Components/Pages/Counter.razor index 818def9c..4f4fa2fb 100644 --- a/Aaru.Server.New/Components/Pages/Counter.razor +++ b/Aaru.Server.New/Components/Pages/Counter.razor @@ -10,7 +10,7 @@ @code { - private int currentCount = 0; + private int currentCount; private void IncrementCount() { diff --git a/Aaru.Server.New/Components/Pages/Weather.razor b/Aaru.Server.New/Components/Pages/Weather.razor index 827ce88f..6c91671e 100644 --- a/Aaru.Server.New/Components/Pages/Weather.razor +++ b/Aaru.Server.New/Components/Pages/Weather.razor @@ -25,7 +25,7 @@ else
- @foreach(var forecast in forecasts) + @foreach(WeatherForecast forecast in forecasts) { @@ -48,7 +48,7 @@ else var startDate = DateOnly.FromDateTime(DateTime.Now); - var summaries = new[] + string[] summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; diff --git a/Aaru.Server.New/Components/Routes.razor b/Aaru.Server.New/Components/Routes.razor index d8e1939d..08b47c9f 100644 --- a/Aaru.Server.New/Components/Routes.razor +++ b/Aaru.Server.New/Components/Routes.razor @@ -1,7 +1,8 @@ @using Aaru.Server.New.Components.Account.Shared +@using Aaru.Server.New.Components.Layout - + diff --git a/Aaru.Server.New/Program.cs b/Aaru.Server.New/Program.cs index 0eb7f5fb..e4e1ea34 100644 --- a/Aaru.Server.New/Program.cs +++ b/Aaru.Server.New/Program.cs @@ -1,11 +1,11 @@ -using Microsoft.AspNetCore.Components.Authorization; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; using Aaru.Server.New.Components; using Aaru.Server.New.Components.Account; using Aaru.Server.New.Data; +using Microsoft.AspNetCore.Components.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; -var builder = WebApplication.CreateBuilder(args); +WebApplicationBuilder builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorComponents().AddInteractiveServerComponents(); @@ -22,8 +22,8 @@ builder.Services.AddAuthentication(options => }) .AddIdentityCookies(); -var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? - throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); +string connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? + throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); builder.Services.AddDbContext(options => options.UseSqlite(connectionString)); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); @@ -35,16 +35,14 @@ builder.Services.AddIdentityCore(options => options.SignIn.Requ builder.Services.AddSingleton, IdentityNoOpEmailSender>(); -var app = builder.Build(); +WebApplication app = builder.Build(); // Configure the HTTP request pipeline. if(app.Environment.IsDevelopment()) -{ app.UseMigrationsEndPoint(); -} else { - app.UseExceptionHandler("/Error", createScopeForErrors: true); + app.UseExceptionHandler("/Error", true); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); diff --git a/Aaru.Server.New/Properties/launchSettings.json b/Aaru.Server.New/Properties/launchSettings.json index 2fdf30ec..c8d66cad 100644 --- a/Aaru.Server.New/Properties/launchSettings.json +++ b/Aaru.Server.New/Properties/launchSettings.json @@ -1,38 +1,38 @@ { - "$schema": "http://json.schemastore.org/launchsettings.json", - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:24383", - "sslPort": 44391 + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:24383", + "sslPort": 44391 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:5279", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" } }, - "profiles": { - "http": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "applicationUrl": "http://localhost:5279", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "https": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "applicationUrl": "https://localhost:7089;http://localhost:5279", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7089;http://localhost:5279", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" } } } +} diff --git a/Aaru.Server.New/appsettings.Development.json b/Aaru.Server.New/appsettings.Development.json index 0c208ae9..0df00402 100644 --- a/Aaru.Server.New/appsettings.Development.json +++ b/Aaru.Server.New/appsettings.Development.json @@ -1,7 +1,7 @@ { "Logging": { "LogLevel": { - "Default": "Information", + "Default": "Information", "Microsoft.AspNetCore": "Warning" } } diff --git a/Aaru.Server.New/appsettings.json b/Aaru.Server.New/appsettings.json index c818a934..5127de6c 100644 --- a/Aaru.Server.New/appsettings.json +++ b/Aaru.Server.New/appsettings.json @@ -2,11 +2,11 @@ "ConnectionStrings": { "DefaultConnection": "DataSource=Data\\app.db;Cache=Shared" }, - "Logging": { + "Logging": { "LogLevel": { - "Default": "Information", + "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" + "AllowedHosts": "*" } diff --git a/Aaru.Server.New/wwwroot/app.css b/Aaru.Server.New/wwwroot/app.css index 2bd9b789..56ad2153 100644 --- a/Aaru.Server.New/wwwroot/app.css +++ b/Aaru.Server.New/wwwroot/app.css @@ -1,15 +1,15 @@ html, body { - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; } a, .btn-link { - color: #006bb7; + color: #006bb7; } .btn-primary { - color: #fff; - background-color: #1b6ec2; - border-color: #1861ac; + color: #fff; + background-color: #1b6ec2; + border-color: #1861ac; } .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { @@ -17,35 +17,35 @@ a, .btn-link { } .content { - padding-top: 1.1rem; + padding-top: 1.1rem; } h1:focus { - outline: none; + outline: none; } .valid.modified:not([type=checkbox]) { - outline: 1px solid #26b050; + outline: 1px solid #26b050; } .invalid { - outline: 1px solid #e50000; + outline: 1px solid #e50000; } .validation-message { - color: #e50000; + color: #e50000; } .blazor-error-boundary { - background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; - padding: 1rem 1rem 1rem 3.7rem; - color: white; + background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; + padding: 1rem 1rem 1rem 3.7rem; + color: white; } - .blazor-error-boundary::after { - content: "An error has occurred." - } +.blazor-error-boundary::after { + content: "An error has occurred." +} .darker-border-checkbox.form-check-input { - border-color: #929292; + border-color: #929292; }
@login.ProviderDisplayName
@forecast.Date.ToShortDateString()