using FastEndpoints; using Microsoft.EntityFrameworkCore; using Socialize.Api.Data; using Socialize.Api.Infrastructure.BlobStorage.Contracts; using Socialize.Api.Infrastructure.Security; using Socialize.Api.Modules.Feedback.Data; using Socialize.Api.Modules.Feedback.Services; using Socialize.Api.Modules.Identity.Contracts; namespace Socialize.Api.Modules.Feedback.Handlers; public class GetFeedbackScreenshotHandler( AppDbContext dbContext, IBlobStorage blobStorage) : EndpointWithoutRequest { public override void Configure() { Get("/api/feedback/{id}/screenshot"); Options(o => o.WithTags("Feedback")); } public override async Task HandleAsync(CancellationToken ct) { Guid id = Route("id"); Guid userId = User.GetUserId(); FeedbackReport? report = await dbContext.FeedbackReports .Include(candidate => candidate.Screenshot) .SingleOrDefaultAsync(candidate => candidate.Id == id, ct); if (report is null || report.Screenshot is null) { await SendNotFoundAsync(ct); return; } if (!FeedbackAccessRules.CanAccessScreenshot(report, userId, User.IsInRole(KnownRoles.Developer))) { await SendForbiddenAsync(ct); return; } MemoryStream stream; try { stream = await blobStorage.DownloadFileAsync( report.Screenshot.BlobContainerName, report.Screenshot.BlobName, ct); } catch (FileNotFoundException) { await SendNotFoundAsync(ct); return; } await SendStreamAsync( stream, fileName: report.Screenshot.FileName, fileLengthBytes: report.Screenshot.SizeBytes, contentType: report.Screenshot.ContentType, cancellation: ct); } }