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 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 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 Login(afToken: afTokens.RequestToken), title: "Sign in", appName: "HtmxApp", pageTitle: "Sign in")); } } [Handler] [MapPost("/login")] public static partial class PostLoginHandler { public class Command { [FromForm] public string Email { get; set; } = default!; [FromForm] public string Password { get; set; } = default!; } 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) return new HtmxResult("/"); var afTokens = antiforgery.GetAndStoreTokens(ctx); return ctx.WriteHtmxPage(new Login(error, afToken: afTokens.RequestToken), title: "Sign in", appName: "HtmxApp", pageTitle: "Sign in"); } }