using System.Security.Claims; using System.Text.Json; using FastEndpoints; using Microsoft.EntityFrameworkCore; using TrackQrApi.Data; using TrackQrApi.Features.Auth.Common; using TrackQrApi.Features.QRCodes.Common; namespace TrackQrApi.Features.QRCodes.Endpoints; public class UpdateQRCodeRequest { public Guid WorkspaceId { get; set; } public Guid Id { get; set; } public string? Name { get; set; } public Guid? ProjectId { get; set; } public bool? RemoveProject { get; set; } public Guid? LogoAssetId { get; set; } public bool? RemoveLogo { get; set; } public QRCodeStyle? Style { get; set; } } public class UpdateQRCodeEndpoint(AppDbContext db) : Endpoint { public override void Configure() { Put("/workspaces/{WorkspaceId}/qrcodes/{Id}"); } public override async Task HandleAsync(UpdateQRCodeRequest req, CancellationToken ct) { var userId = Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!); var qrCode = await db.QrCodeDesigns .Include(q => q.Workspace) .Include(q => q.ShortLink) .Include(q => q.LogoAsset) .FirstOrDefaultAsync( q => q.Id == req.Id && q.WorkspaceId == req.WorkspaceId && q.Workspace.OwnerUserId == userId, ct); if (qrCode is null) { await HttpContext.Response.SendAsync(new MessageResponse("QR code not found"), 404, cancellation: ct); return; } // Verify project belongs to workspace if specified if (req.ProjectId.HasValue) { var projectExists = await db.Projects .AnyAsync(p => p.Id == req.ProjectId.Value && p.WorkspaceId == req.WorkspaceId, ct); if (!projectExists) { await HttpContext.Response.SendAsync(new MessageResponse("Project not found"), 404, cancellation: ct); return; } qrCode.ProjectId = req.ProjectId.Value; } else if (req.RemoveProject == true) { qrCode.ProjectId = null; } // Update name if provided if (!string.IsNullOrWhiteSpace(req.Name)) qrCode.Name = req.Name; // Handle logo asset update if (req.LogoAssetId.HasValue) { var assetExists = await db.Assets .AnyAsync(a => a.Id == req.LogoAssetId.Value && a.WorkspaceId == req.WorkspaceId, ct); if (!assetExists) { await HttpContext.Response.SendAsync(new MessageResponse("Logo asset not found"), 404, cancellation: ct); return; } qrCode.LogoAssetId = req.LogoAssetId.Value; // Reload the asset for the response qrCode.LogoAsset = await db.Assets.FindAsync([req.LogoAssetId.Value], ct); } else if (req.RemoveLogo == true) { qrCode.LogoAssetId = null; qrCode.LogoAsset = null; } if (req.Style != null) qrCode.StyleJson = JsonSerializer.Serialize(req.Style); qrCode.UpdatedAt = DateTime.UtcNow; await db.SaveChangesAsync(ct); var style = JsonSerializer.Deserialize(qrCode.StyleJson) ?? new QRCodeStyle(); var baseUrl = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}"; var response = new QRCodeResponse( qrCode.Id, qrCode.WorkspaceId, qrCode.ProjectId, qrCode.ShortLinkId, qrCode.ShortLink?.Slug, qrCode.Name, style, qrCode.LogoAssetId, qrCode.LogoAsset != null ? $"{baseUrl}/assets/{qrCode.LogoAsset.StorageKey}" : null, qrCode.CreatedAt, qrCode.UpdatedAt ); await HttpContext.Response.SendAsync(response, cancellation: ct); } }