< Summary

Information
Class: Chronicis.Api.Services.ImageAccessService
Assembly: Chronicis.Api
File(s): /home/runner/work/chronicis/chronicis/src/Chronicis.Api/Services/ImageAccessService.cs
Line coverage
100%
Covered lines: 4
Uncovered lines: 0
Coverable lines: 4
Total lines: 53
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%

File(s)

/home/runner/work/chronicis/chronicis/src/Chronicis.Api/Services/ImageAccessService.cs

#LineLine coverage
 1using Chronicis.Api.Data;
 2using Chronicis.Api.Models;
 3using Microsoft.EntityFrameworkCore;
 4
 5namespace Chronicis.Api.Services;
 6
 7public sealed class ImageAccessService : IImageAccessService
 8{
 9    private readonly ChronicisDbContext _context;
 10    private readonly IBlobStorageService _blobStorage;
 11    private readonly ILogger<ImageAccessService> _logger;
 12
 13    public ImageAccessService(
 14        ChronicisDbContext context,
 15        IBlobStorageService blobStorage,
 16        ILogger<ImageAccessService> logger)
 17    {
 418        _context = context;
 419        _blobStorage = blobStorage;
 420        _logger = logger;
 421    }
 22
 23    public async Task<ServiceResult<string>> GetImageDownloadUrlAsync(Guid documentId, Guid userId)
 24    {
 25        var document = await _context.WorldDocuments
 26            .AsNoTracking()
 27            .Include(d => d.World)
 28            .FirstOrDefaultAsync(d => d.Id == documentId);
 29
 30        if (document == null)
 31        {
 32            return ServiceResult<string>.NotFound();
 33        }
 34
 35        var hasAccess = document.World.OwnerId == userId
 36            || await _context.WorldMembers.AnyAsync(m => m.WorldId == document.WorldId && m.UserId == userId);
 37
 38        if (!hasAccess)
 39        {
 40            return ServiceResult<string>.Forbidden();
 41        }
 42
 43        if (!document.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
 44        {
 45            _logger.LogWarningSanitized("Non-image document {DocumentId} requested via image proxy", documentId);
 46            return ServiceResult<string>.ValidationError("Document is not an image");
 47        }
 48
 49        var downloadUrl = await _blobStorage.GenerateDownloadSasUrlAsync(document.BlobPath);
 50        return ServiceResult<string>.Success(downloadUrl);
 51    }
 52}
 53