using Htmx.ApiDemo.Data; using Immediate.Apis.Shared; using Immediate.Handlers.Shared; using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Mvc; namespace Htmx.ApiDemo.Templates; public sealed class Login : LoginBase { private readonly byte[] _errorData; private readonly byte[] _afTokenData; public Login(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("/login")] public static partial class GetLoginHandler { public record 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) { ctx.Response.Redirect("/"); return ValueTask.CompletedTask; } var afTokens = antiforgery.GetAndStoreTokens(ctx); ctx.WriteHtmxPage(new Login(afToken: afTokens.RequestToken), title: "Sign in", appName: "HtmxApp", pageTitle: "Sign in"); return ValueTask.CompletedTask; } } [Handler] [MapPost("/login")] public static partial class PostLoginHandler { public record Command( [property: FromForm] string Email, [property: FromForm] string Password ); 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."); var (success, error) = await authService.LoginAsync(command.Email, command.Password); if (success) { ctx.Response.Redirect("/"); return; } var afTokens = antiforgery.GetAndStoreTokens(ctx); ctx.WriteHtmxPage(new Login(error, afToken: afTokens.RequestToken), title: "Sign in", appName: "HtmxApp", pageTitle: "Sign in"); } }