using Butter.Dtos; using Butter.Types; using Lactose.Context; using Lactose.Models; using Microsoft.EntityFrameworkCore; namespace Lactose.Repositories; /// public class MediaRepository(LactoseDbContext context, IPersonRepository personRepository) : IMediaRepository { /// /// Trys to get the asset with the given ID, and checks visibility for the requesting user. /// Public assets are accessible to all; Protected assets require authentication; /// Private assets require the user to be the uploader, a curator+, or a maintainer /// of the cosplayer whose album contains the asset. /// /// Asset ID /// UserID we are trying to get this as /// The requesting user's access level /// Token to cancel the operation. /// async Task GetVisibleAsset(Guid id, Guid? userId, EAccessLevel accessLevel, CancellationToken cancellationToken) { var query = context.Assets.Where(asset => asset.Id == id); if (accessLevel >= EAccessLevel.Admin) return await query.FirstOrDefaultAsync(cancellationToken); if (accessLevel >= EAccessLevel.Curator) return await query.FirstOrDefaultAsync(asset => asset.DeletedAt == null || asset.UploadedBy == userId, cancellationToken); if (accessLevel == EAccessLevel.Maintainer && userId.HasValue) { var asset = await query .AsSplitQuery() .Include(a => a.Albums) .FirstOrDefaultAsync(cancellationToken); if (asset == null || asset.DeletedAt != null) return null; if (asset.Visibility == EVisibility.Public) return asset; if (asset.Visibility == EVisibility.Protected) return asset; if (asset.UploadedBy == userId) return asset; if (asset.Albums != null) { foreach (var album in asset.Albums) { if (album.PersonOwnerId.HasValue && await personRepository.IsMaintainerOfAsync(userId.Value, album.PersonOwnerId.Value, cancellationToken)) return asset; } } return null; } return await query.FirstOrDefaultAsync(asset => asset.DeletedAt == null && ( asset.Visibility == EVisibility.Public || (asset.Visibility == EVisibility.Protected && userId.HasValue) || (asset.Visibility == EVisibility.Private && userId.HasValue && asset.UploadedBy == userId) ), cancellationToken); } /// public async Task GetOriginalDataAsync(Guid id, Guid? userId, EAccessLevel accessLevel, CancellationToken cancellationToken) { var media = await GetVisibleAsset(id, userId, accessLevel, cancellationToken); if (media == null) return null; return new MediaDto { MimeType = media.MimeType, Path = media.OriginalPath }; } //TODO: for Thumbnails the MimeType should be the correct one (depending on which format is used for thumbnails) /// public async Task GetThumbDataAsync(Guid id, Guid? userId, EAccessLevel accessLevel, CancellationToken cancellationToken) { var media = await GetVisibleAsset(id, userId, accessLevel, cancellationToken); if(media == null) return null; if (string.IsNullOrEmpty(media.ThumbnailPath)) return null; return new MediaDto { MimeType = "image/webp", Path = media.ThumbnailPath }; } //TODO: for Previews the MimeType should be the correct one (depending on which format is used for previews and if the asset is a video) /// public async Task GetPreviewDataAsync(Guid id, Guid? userId, EAccessLevel accessLevel, CancellationToken cancellationToken) { var media = await GetVisibleAsset(id, userId, accessLevel, cancellationToken); if(media == null) return null; if (string.IsNullOrEmpty(media.PreviewPath)) return null; return new MediaDto { MimeType = "image/webp", Path = media.PreviewPath }; } /// public async Task GetConvertedDataAsync(Guid id, Guid? userId, EAccessLevel accessLevel, CancellationToken cancellationToken) { var media = await GetVisibleAsset(id, userId, accessLevel, cancellationToken); if (media == null) return null; if (string.IsNullOrEmpty(media.ConvertedPath) || string.IsNullOrEmpty(media.ConvertedMimeType)) return null; return new MediaDto { MimeType = media.ConvertedMimeType, Path = media.ConvertedPath }; } /// public void Dispose() { context.Dispose(); personRepository.Dispose(); } }