using Htmx.ApiDemo.Data; using Immediate.Apis.Shared; using Immediate.Handlers.Shared; using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace Htmx.ApiDemo.Templates; public sealed class Register : RegisterBase { private readonly byte[] _errorData; private readonly byte[] _afTokenData; public Register(string? errorMessage = null, string? afToken = null) { _errorData = string.IsNullOrEmpty(errorMessage) ? [] : $"""
{System.Web.HttpUtility.HtmlEncode(errorMessage)}
""".ToUtf8Bytes(); _afTokenData = string.IsNullOrEmpty(afToken) ? [] : $"""""".ToUtf8Bytes(); } protected override void RenderErrorMessage(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_errorData); protected override void RenderAntiforgeryToken(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_afTokenData); } [Handler] [MapGet("/register")] public static partial class GetRegisterHandler { public class Query; private static ValueTask HandleAsync( Query _, IHttpContextAccessor httpContextAccessor, IAntiforgery antiforgery, CancellationToken token) { var ctx = httpContextAccessor.HttpContext ?? throw new InvalidOperationException("HttpContext is not available."); if (ctx.User.Identity?.IsAuthenticated == true) return ValueTask.FromResult(new HtmxResult("/")); var afTokens = antiforgery.GetAndStoreTokens(ctx); return ValueTask.FromResult(ctx.WriteHtmxPage(new Register(afToken: afTokens.RequestToken), title: "Register", appName: "HtmxApp", pageTitle: "Create account")); } } [Handler] [MapPost("/register")] public static partial class PostRegisterHandler { public class Command { [FromForm] public string Email { get; set; } = default!; [FromForm] public string Password { get; set; } = default!; [FromForm] public string ConfirmPassword { get; set; } = default!; [FromForm] public string? DisplayName { get; set; } } private static async ValueTask HandleAsync( [AsParameters] Command command, IHttpContextAccessor httpContextAccessor, IAntiforgery antiforgery, AuthService authService, CancellationToken token) { var ctx = httpContextAccessor.HttpContext ?? throw new InvalidOperationException("HttpContext is not available."); if (command.Password != command.ConfirmPassword) { var afTokens1 = antiforgery.GetAndStoreTokens(ctx); return ctx.WriteHtmxPage(new Register("Passwords do not match.", afToken: afTokens1.RequestToken), title: "Register", appName: "HtmxApp", pageTitle: "Create account"); } var (success, error) = await authService.RegisterAsync(command.Email, command.Password, command.DisplayName); if (success) return new HtmxResult("/"); var afTokens2 = antiforgery.GetAndStoreTokens(ctx); return ctx.WriteHtmxPage(new Register(error, afToken: afTokens2.RequestToken), title: "Register", appName: "HtmxApp", pageTitle: "Create account"); } }