121 lines
5.0 KiB
C#
121 lines
5.0 KiB
C#
using Butter.Dtos;
|
|
using Butter.Types;
|
|
using Lactose.Context;
|
|
using Lactose.Models;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace Lactose.Repositories;
|
|
|
|
/// <inheritdoc />
|
|
public class MediaRepository(LactoseDbContext context, IPersonRepository personRepository) : IMediaRepository {
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="id">Asset ID</param>
|
|
/// <param name="userId">UserID we are trying to get this as</param>
|
|
/// <param name="accessLevel">The requesting user's access level</param>
|
|
/// <param name="cancellationToken">Token to cancel the operation.</param>
|
|
/// <returns></returns>
|
|
async Task<Asset?> 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);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<MediaDto?> 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)
|
|
/// <inheritdoc />
|
|
public async Task<MediaDto?> 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)
|
|
/// <inheritdoc />
|
|
public async Task<MediaDto?> 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
|
|
};
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<MediaDto?> 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
|
|
};
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void Dispose() {
|
|
context.Dispose();
|
|
personRepository.Dispose();
|
|
}
|
|
}
|