diff --git a/Moonlight/Core/Models/Forms/ChangeCookiesForm.cs b/Moonlight/Core/Models/Forms/ChangeCookiesForm.cs deleted file mode 100644 index 0090240e..00000000 --- a/Moonlight/Core/Models/Forms/ChangeCookiesForm.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.ComponentModel; - -namespace Moonlight.Core.Models.Forms; - -public class ChangeCookiesForm -{ - [Description("This specifies if you would like to personalize your experience with optional cookies.")] - public bool UseOptionalCookies { get; set; } = false; -} \ No newline at end of file diff --git a/Moonlight/Core/UI/Components/Auth/TwoFactorWizard.razor b/Moonlight/Core/UI/Components/Auth/TwoFactorWizard.razor index bbaeca55..4d4dc37a 100644 --- a/Moonlight/Core/UI/Components/Auth/TwoFactorWizard.razor +++ b/Moonlight/Core/UI/Components/Auth/TwoFactorWizard.razor @@ -6,6 +6,7 @@ @using MoonCore.Exceptions @inject IdentityService IdentityService +@inject AlertService AlertService @inject IAuthenticationProvider AuthenticationProvider @if (IdentityService.CurrentUser.Totp) @@ -61,15 +62,15 @@ else - +
- +
- +
} else @@ -170,7 +171,10 @@ else var correctCode = totp.ComputeTotp(); if (CodeForm.Code != correctCode) - throw new DisplayException("Invalid code entered. Please try again"); + { + await AlertService.Danger("Invalid code entered. Please try again"); + return; + } // Enable two factor auth for user await AuthenticationProvider.SetTwoFactorSecret(IdentityService.CurrentUser, Key); diff --git a/Moonlight/Core/UI/Views/Account/Index.razor b/Moonlight/Core/UI/Views/Account/Index.razor index 23591e26..ed218f6c 100644 --- a/Moonlight/Core/UI/Views/Account/Index.razor +++ b/Moonlight/Core/UI/Views/Account/Index.razor @@ -1,8 +1,10 @@ @page "/account" +@using System.ComponentModel.DataAnnotations @using Moonlight.Core.Services @using Moonlight.Core.Models.Forms @using Mappy.Net +@using Moonlight.Core.Database.Entities @using Moonlight.Core.Models.Abstractions @using Moonlight.Core.UI.Components.Navigations @@ -22,53 +24,73 @@ - - -
-
-
-
-
-
- image -
-
-
- To change your profile picture go to Gravatar and - register with the same email address you are using here +
+
+
+
+
+
+ image
+
+ To change your profile picture go to Gravatar and + register with the same email address you are using here +
-
-
- -
- -
- -
+
+
+
+
+ +
+
- +
@code { - private UpdateAccountForm Form = new(); + private User User; + private FastForm Form; - private Task Load(LazyLoader _) + protected override void OnInitialized() { - Form = Mapper.Map(IdentityService.CurrentUser); - - return Task.CompletedTask; + // Create a copy of the user + User = Mapper.Map(IdentityService.CurrentUser); } - private async Task Update() + private void OnConfigure(FastFormConfiguration configuration) { - await AuthenticationProvider.ChangeDetails(IdentityService.CurrentUser, Form.Email, Form.Username); + configuration.AddProperty(x => x.Username) + .WithComponent(component => + { + component.ColumnsMd = 12; + }) + .WithValidation(FastFormValidators.Required) + .WithValidation(RegexValidator.Create("^[a-z][a-z0-9]*$", "Usernames can only contain lowercase characters and numbers and should not start with a number")) + .WithValidation(x => x.Length >= 6 ? ValidationResult.Success : new("The username is too short")) + .WithValidation(x => x.Length <= 20 ? ValidationResult.Success : new("The username cannot be longer than 20 characters")); + + configuration.AddProperty(x => x.Email) + .WithComponent(component => + { + component.ColumnsMd = 12; + component.Type = "email"; + }) + .WithValidation(FastFormValidators.Required) + .WithValidation(RegexValidator.Create("^.+@.+$", "You need to provide a valid email address")); + } + + private async Task SaveChanges() + { + if(!await Form.Submit()) + return; + + await AuthenticationProvider.ChangeDetails(IdentityService.CurrentUser, User.Email, User.Username); await ToastService.Success("Successfully updated details"); // This will trigger a re-render as well as an update of the model diff --git a/Moonlight/Core/UI/Views/Account/Security.razor b/Moonlight/Core/UI/Views/Account/Security.razor index d6dd5845..529fd190 100644 --- a/Moonlight/Core/UI/Views/Account/Security.razor +++ b/Moonlight/Core/UI/Views/Account/Security.razor @@ -1,5 +1,6 @@ @page "/account/security" +@using System.ComponentModel.DataAnnotations @using Moonlight.Core.Services @using Moonlight.Core.UI.Components.Navigations @using Moonlight.Core.Models.Forms @@ -23,74 +24,97 @@ - -
-
-
- -
-
- -
-
- -
+
+
+
+
+
-
-
-
-
- -
-
-
-
-
- -
-

Cookies

-
- - -
-
- -
+
- +
+
+
+ +
+
+
+
+
+
+

Cookies

+

+ This specifies if you would like to personalize your experience with optional cookies. +

+
+ @if (CookieConsent) + { + + } + else + { + + } +
+
+
+
+
@code { - private readonly ChangePasswordForm PasswordForm = new(); - - private ChangeCookiesForm CookiesForm = new(); + private ChangePasswordForm PasswordModel = new(); + private FastForm PasswordForm; - private async Task Load(LazyLoader lazyLoader) + private bool CookieConsent; + + protected override async Task OnInitializedAsync() { - CookiesForm.UseOptionalCookies = await IdentityService.HasFlag("CookieConsent"); + CookieConsent = await IdentityService.HasFlag("CookieConsent"); } - private async Task OnValidSubmitPassword() + private async Task SetCookieConsent(bool flag) { - if (PasswordForm.Password != PasswordForm.RepeatedPassword) + await IdentityService.SetFlag("CookieConsent", flag); + + await ToastService.Success("Successfully changed cookie preferences"); + await InvokeAsync(StateHasChanged); + } + + private void OnConfigurePasswordForm(FastFormConfiguration configuration) + { + configuration.AddProperty(x => x.Password) + .WithComponent(component => + { + component.ColumnsMd = 6; + component.Type = "password"; + }) + .WithValidation(FastFormValidators.Required) + .WithValidation(x => x.Length >= 8 ? ValidationResult.Success : new("The password must be at least 8 characters long")) + .WithValidation(x => x.Length <= 256 ? ValidationResult.Success : new("The password must not be longer than 256 characters")); + + configuration.AddProperty(x => x.RepeatedPassword) + .WithComponent(component => + { + component.ColumnsMd = 6; + component.Type = "password"; + }); + } + + private async Task ChangePassword() + { + if(!await PasswordForm.Submit()) + return; + + if (PasswordModel.Password != PasswordModel.RepeatedPassword) throw new DisplayException("The passwords do not match"); - await AuthenticationProvider.ChangePassword(IdentityService.CurrentUser, PasswordForm.Password); + await AuthenticationProvider.ChangePassword(IdentityService.CurrentUser, PasswordModel.Password); await ToastService.Success("Successfully changed password"); await IdentityService.Authenticate(true); } - - private async Task OnValidSubmitCookie() - { - await IdentityService.SetFlag("CookieConsent", CookiesForm.UseOptionalCookies); - - await InvokeAsync(StateHasChanged); - } } \ No newline at end of file diff --git a/Moonlight/Features/Servers/UI/Views/Admin/Index.razor b/Moonlight/Features/Servers/UI/Views/Admin/Index.razor index f6f1f1f0..cdca0ee5 100644 --- a/Moonlight/Features/Servers/UI/Views/Admin/Index.razor +++ b/Moonlight/Features/Servers/UI/Views/Admin/Index.razor @@ -217,6 +217,7 @@ component.SearchFunc = x => $"{x.IpAddress}:{x.Port}"; component.DisplayFunc = x => $"{x.IpAddress}:{x.Port}"; component.ItemsCallback = () =>GetAllocation(server); + component.ColumnsMd = 6; }) .WithPage("Network"); }