From a1309347876efa28325294900ccdaec4c9cebcb0 Mon Sep 17 00:00:00 2001 From: Lilian Date: Sat, 23 Nov 2024 19:31:11 +0100 Subject: [PATCH] [frontend/components] Add registration page and update login page style (ISH-472) --- .../Controllers/Web/InstanceController.cs | 11 +- Iceshrimp.Frontend/Layout/LoginLayout.razor | 5 - .../Layout/LoginLayout.razor.css | 0 Iceshrimp.Frontend/Layout/UnauthLayout.razor | 8 ++ .../Layout/UnauthLayout.razor.css | 10 ++ Iceshrimp.Frontend/Pages/Login.razor | 26 ++-- Iceshrimp.Frontend/Pages/Login.razor.css | 5 + Iceshrimp.Frontend/Pages/Register.razor | 117 ++++++++++++++++++ Iceshrimp.Frontend/Pages/Register.razor.css | 20 +++ .../Schemas/Web/InstanceResponse.cs | 15 ++- 10 files changed, 195 insertions(+), 22 deletions(-) delete mode 100644 Iceshrimp.Frontend/Layout/LoginLayout.razor delete mode 100644 Iceshrimp.Frontend/Layout/LoginLayout.razor.css create mode 100644 Iceshrimp.Frontend/Layout/UnauthLayout.razor create mode 100644 Iceshrimp.Frontend/Layout/UnauthLayout.razor.css create mode 100644 Iceshrimp.Frontend/Pages/Register.razor create mode 100644 Iceshrimp.Frontend/Pages/Register.razor.css diff --git a/Iceshrimp.Backend/Controllers/Web/InstanceController.cs b/Iceshrimp.Backend/Controllers/Web/InstanceController.cs index 9b1a9118..9030b504 100644 --- a/Iceshrimp.Backend/Controllers/Web/InstanceController.cs +++ b/Iceshrimp.Backend/Controllers/Web/InstanceController.cs @@ -6,6 +6,7 @@ using Iceshrimp.Backend.Core.Configuration; using Iceshrimp.Backend.Core.Database; using Iceshrimp.Backend.Core.Extensions; using Iceshrimp.Backend.Core.Middleware; +using Iceshrimp.Backend.Core.Services; using Iceshrimp.Shared.Schemas.Web; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; @@ -17,16 +18,18 @@ namespace Iceshrimp.Backend.Controllers.Web; [EnableRateLimiting("sliding")] [Route("/api/iceshrimp/instance")] [Produces(MediaTypeNames.Application.Json)] -public class InstanceController(DatabaseContext db, UserRenderer userRenderer, IOptions config) : ControllerBase +public class InstanceController(DatabaseContext db, UserRenderer userRenderer, IOptions instanceConfig, IOptions securityConfig, MetaService meta) : ControllerBase { [HttpGet] [ProducesResults(HttpStatusCode.OK)] - public InstanceResponse GetInfo() + public async Task GetInfo() { return new InstanceResponse { - AccountDomain = config.Value.AccountDomain, - WebDomain = config.Value.WebDomain, + AccountDomain = instanceConfig.Value.AccountDomain, + WebDomain = instanceConfig.Value.WebDomain, + Registration = (Registrations)securityConfig.Value.Registrations, + Name = await meta.GetAsync(MetaEntity.InstanceName) }; } diff --git a/Iceshrimp.Frontend/Layout/LoginLayout.razor b/Iceshrimp.Frontend/Layout/LoginLayout.razor deleted file mode 100644 index 939916c7..00000000 --- a/Iceshrimp.Frontend/Layout/LoginLayout.razor +++ /dev/null @@ -1,5 +0,0 @@ -@inherits LayoutComponentBase - -
- @Body -
\ No newline at end of file diff --git a/Iceshrimp.Frontend/Layout/LoginLayout.razor.css b/Iceshrimp.Frontend/Layout/LoginLayout.razor.css deleted file mode 100644 index e69de29b..00000000 diff --git a/Iceshrimp.Frontend/Layout/UnauthLayout.razor b/Iceshrimp.Frontend/Layout/UnauthLayout.razor new file mode 100644 index 00000000..df069f15 --- /dev/null +++ b/Iceshrimp.Frontend/Layout/UnauthLayout.razor @@ -0,0 +1,8 @@ +@inherits LayoutComponentBase + +
+ +
+
+ @Body +
\ No newline at end of file diff --git a/Iceshrimp.Frontend/Layout/UnauthLayout.razor.css b/Iceshrimp.Frontend/Layout/UnauthLayout.razor.css new file mode 100644 index 00000000..78734daa --- /dev/null +++ b/Iceshrimp.Frontend/Layout/UnauthLayout.razor.css @@ -0,0 +1,10 @@ +.header { + display: flex; + width: 100%; + padding: 1rem; +} + +.logo { + object-fit: contain; + height: 2rem +} \ No newline at end of file diff --git a/Iceshrimp.Frontend/Pages/Login.razor b/Iceshrimp.Frontend/Pages/Login.razor index f522151b..e5f031d2 100644 --- a/Iceshrimp.Frontend/Pages/Login.razor +++ b/Iceshrimp.Frontend/Pages/Login.razor @@ -6,13 +6,16 @@ @using Iceshrimp.Frontend.Localization @using Iceshrimp.Shared.Schemas.Web @using Microsoft.Extensions.Localization -@inject ApiService Api -@inject SessionService SessionService -@inject NavigationManager Navigation +@inject ApiService Api +@inject SessionService SessionService +@inject NavigationManager Navigation @inject IStringLocalizer Loc; -@layout LoginLayout +@inject MetadataService Metadata; +@layout UnauthLayout
-

Login

+ + +

@Loc["Login to {0}", Name ?? "this Iceshrimp.NET Instance."]

@code { [SupplyParameterFromQuery(Name = "rd")] @@ -42,6 +43,7 @@ private string? Username { get; set; } private bool Loading { get; set; } private bool Failure { get; set; } + private string? Name { get; set; } private async Task Submit() { @@ -76,7 +78,7 @@ MovedTo = res.User.MovedTo }); SessionService.SetSession(res.User.Id); - Navigation.NavigateTo(Uri.TryCreate(Redirect, UriKind.Relative, out _) ? Redirect : "/"); + Navigation.NavigateTo(Uri.TryCreate(Redirect, UriKind.Relative, out _) ? Redirect : "/", true); break; case AuthStatusEnum.Guest: Failure = true; @@ -94,4 +96,10 @@ StateHasChanged(); // Manually triggering a state update, else component will not re-render. } } + + protected override async Task OnInitializedAsync() + { + var metadata = await Metadata.Instance.Value; + Name = metadata.Name; + } } \ No newline at end of file diff --git a/Iceshrimp.Frontend/Pages/Login.razor.css b/Iceshrimp.Frontend/Pages/Login.razor.css index 4df376b4..b50013f3 100644 --- a/Iceshrimp.Frontend/Pages/Login.razor.css +++ b/Iceshrimp.Frontend/Pages/Login.razor.css @@ -5,7 +5,12 @@ } .login-form { + margin-top: 1rem; display: flex; flex-direction: column; align-items: center; } + +.logo { + height: 3rem; +} \ No newline at end of file diff --git a/Iceshrimp.Frontend/Pages/Register.razor b/Iceshrimp.Frontend/Pages/Register.razor new file mode 100644 index 00000000..28d2a8a4 --- /dev/null +++ b/Iceshrimp.Frontend/Pages/Register.razor @@ -0,0 +1,117 @@ +@page "/register" +@using Iceshrimp.Frontend.Core.Miscellaneous +@using Iceshrimp.Frontend.Core.Schemas +@using Iceshrimp.Frontend.Core.Services +@using Iceshrimp.Shared.Schemas.Web +@using Microsoft.Extensions.Localization +@layout UnauthLayout +@inject IStringLocalizer Loc; +@inject MetadataService Metadata; +@inject ApiService Api; +@inject SessionService SessionService; +@inject NavigationManager Navigation; +@if (State is State.Loaded) +{ +
+ + +

@Loc["Register on {0}", Name ?? "this Iceshrimp.NET Instance."]

+ @if (RegistrationAvailability is not Registrations.Closed) + { +
+ + + @if (RegistrationAvailability is Registrations.Invite) + { + + } + +
+ @if (Result is RegistrationResult.Failure) + { +
@Loc[RegistrationError ?? string.Empty]
+ } + } + @if (RegistrationAvailability is Registrations.Closed) + { +
@Loc["Registrations for this instance are closed."]
+ } +
+} + +@code { + private string? Username { get; set; } + private string? Password { get; set; } + private string? Invite { get; set; } + private bool Loading { get; set; } + private RegistrationResult Result { get; set; } + private Registrations RegistrationAvailability { get; set; } + private State State { get; set; } = State.Loading; + private string? RegistrationError { get; set; } + private string? Name { get; set; } + + private async Task Submit() + { + Loading = true; + StateHasChanged(); + if (Username is null || Password is null) + { + Result = RegistrationResult.Failure; + RegistrationError = "Please fill out all fields"; + Loading = false; + return; + } + + var registration = new RegistrationRequest { Username = Username, Password = Password, Invite = Invite, }; + try + { + var res = await Api.Auth.RegisterAsync(registration); + if (res.Status is AuthStatusEnum.Authenticated) + { + SessionService.AddUser(new StoredUser + { // Token nor user will ever be null on an authenticated response + Id = res.User!.Id, + Username = res.User.Username, + DisplayName = res.User.DisplayName, + AvatarUrl = res.User.AvatarUrl, + BannerUrl = res.User.BannerUrl, + InstanceName = res.User.InstanceName, + InstanceIconUrl = res.User.InstanceIconUrl, + Token = res.Token!, + Host = res.User.Host, + IsAdmin = res.IsAdmin ?? false, + Emojis = res.User.Emojis, + MovedTo = res.User.MovedTo + }); + SessionService.SetSession(res.User.Id); + Navigation.NavigateTo("/"); + } + + Loading = false; + } + catch (ApiException e) + { + RegistrationError = e.Response.Message; + Result = RegistrationResult.Failure; + Loading = false; + StateHasChanged(); + } + } + + private enum RegistrationResult + { + Incomplete, + Success, + Failure + } + + protected override async Task OnInitializedAsync() + { + var metadata = await Metadata.Instance.Value; + RegistrationAvailability = metadata.Registration; + State = State.Loaded; + Name = metadata.Name; + } +} \ No newline at end of file diff --git a/Iceshrimp.Frontend/Pages/Register.razor.css b/Iceshrimp.Frontend/Pages/Register.razor.css new file mode 100644 index 00000000..bf202344 --- /dev/null +++ b/Iceshrimp.Frontend/Pages/Register.razor.css @@ -0,0 +1,20 @@ +.body { + display: flex; + flex-direction: column; + align-items: center; +} + +.register-form { + margin-top: 1rem; + display: flex; + flex-direction: column; + align-items: center; +} + +input:invalid { + border: 0.1rem solid var(--highlight-color); +} + +.logo { + height: 3rem; +} \ No newline at end of file diff --git a/Iceshrimp.Shared/Schemas/Web/InstanceResponse.cs b/Iceshrimp.Shared/Schemas/Web/InstanceResponse.cs index 703dabc0..131ea131 100644 --- a/Iceshrimp.Shared/Schemas/Web/InstanceResponse.cs +++ b/Iceshrimp.Shared/Schemas/Web/InstanceResponse.cs @@ -2,14 +2,21 @@ namespace Iceshrimp.Shared.Schemas.Web; public class InstanceResponse { - public required string AccountDomain { get; set; } - public required string WebDomain { get; set; } - - // TODO: Add more instance metadata + public required string AccountDomain { get; set; } + public required string WebDomain { get; set; } + public required Registrations Registration { get; set; } + public required string? Name { get; set; } } public class StaffResponse { public required List Admins { get; set; } public required List Moderators { get; set; } +} + +public enum Registrations +{ + Closed = 0, + Invite = 1, + Open = 2 } \ No newline at end of file