using System.IO; using FastEndpoints; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Framework.ResponseStandard; using GB5Shared.FastEndPoint; using WiBLL.WiScanCode; using WiDAL.DTOs; using static GB5Shared.GB5Constant.Constant; namespace WiSL.EndPoints.WiScanCode { // Tenant-scoped — mirrors TMSSL's DownloadCertificate.cs pattern (BaseEndpoint + // HttpContext.Response.SendStreamAsync + return null!) rather than an anonymous // byte-stream endpoint, since generating a code requires login.ClientId to check // the target entity actually belongs to this tenant before handing out a scannable code. public class GenerateScanCode : BaseEndpoint> { private readonly IWiScanCodeBLL _bll; public GenerateScanCode(IWiScanCodeBLL bll) { _bll = bll; } public override void Configure() { Get("/Wi/GenerateScanCode"); AllowAnonymous(); } public record Parameters( [property: FromHeader] string Login, [property: QueryParam] ScanCodeType CodeType, [property: QueryParam] int EntityId, [property: QueryParam] int? PixelsPerModule ); protected override string? GetCacheKey(Parameters req, LoginDTO login) => null; protected override async Task> ExecuteAsync( Parameters req, LoginDTO login, CancellationToken ct) { try { var png = await _bll.GenerateScanCode(req.CodeType, req.EntityId, req.PixelsPerModule ?? 20, login, ct) .ConfigureAwait(false); using var ms = new MemoryStream(png); await HttpContext.Response.SendStreamAsync(ms, $"{req.CodeType}_{req.EntityId}.png", ms.Length, "image/png", cancellation: ct); return null!; } catch (InvalidOperationException ex) { return await GB5Shared.ResponseStandard.Response.CreateExceptionError(ex, CacheKeyLevel.NOT_REQUIRED, login, ex.Message, 404); } catch (Exception ex) { return await GB5Shared.ResponseStandard.Response.CreateExceptionError(ex, CacheKeyLevel.NOT_REQUIRED, login, ex.Message, 500); } } } }