Files
MilkyShots/Lactose/Repositories/IAssetRepository.cs
T
REDCODE b6386aad98 refactor(asset): rename fs-browse to directory and remove the DB-path browse endpoint
- Rename the filesystem browse route from /api/asset/fs-browse to /api/asset/directory
  (controller route, client URL, REST tests, and service log label).
- Remove the old /api/asset/browse endpoint and its BrowseAssets/GetDirectoryNames
  repository code, plus the client BrowseAsync method. Repoint AlbumAssetPicker's
  admin/curator folder browse to the /directory endpoint.
- Drop the now-unused pg_catalog.split_part DbFunction mapping.
- Refresh .env GIT_VERSION.
2026-08-21 01:00:38 +02:00

266 lines
13 KiB
C#

using Butter.Dtos.Asset;
using Butter.Types;
using Lactose.Models;
namespace Lactose.Repositories;
/// <summary>
/// Interface for asset repository operations.
/// </summary>
public interface IAssetRepository : IDisposable {
/// <summary>
/// Finds an asset by its ID.
/// </summary>
/// <param name="id">The ID of the asset.</param>
/// <returns>Null if not found, otherwise the requested asset.</returns>
public Asset? Find(Guid id);
/// <summary>
/// Finds an asset by its ID, respecting the requesting user's access level.
/// Returns null if the asset does not exist or is not visible to the user.
/// </summary>
/// <param name="id">The ID of the asset.</param>
/// <param name="userId">The requesting user's ID.</param>
/// <param name="accessLevel">The requesting user's access level.</param>
/// <returns>The asset if found and visible; otherwise null.</returns>
public Asset? FindVisible(Guid id, Guid? userId, EAccessLevel accessLevel);
/// <summary>
/// Finds an asset by its ID with its album navigation properties loaded.
/// </summary>
/// <param name="id">The ID of the asset.</param>
/// <returns>Null if not found, otherwise the requested asset with albums.</returns>
public Asset? FindWithAlbums(Guid id);
/// <summary>
/// Finds a set of assets by their IDs.
/// </summary>
/// <param name="ids">The IDs of the assets.</param>
/// <returns>A collection of assets with the specified IDs.</returns>
public IEnumerable<Asset> FindBulk(IEnumerable<Guid> ids);
/// <summary>
/// Finds all assets uploaded by the user.
/// </summary>
/// <param name="uploaderId">The ID of the uploader.</param>
/// <returns>A collection of assets uploaded by the specified user.</returns>
public IEnumerable<Asset> FindByUploader(Guid uploaderId);
/// <summary>
/// Bulk-updates the visibility of non-deleted assets in the specified albums via a single SQL UPDATE,
/// respecting the requesting user's access level.
/// </summary>
/// <param name="albumIds">The IDs of the albums.</param>
/// <param name="visibility">The target visibility level.</param>
/// <param name="userId">The requesting user's ID.</param>
/// <param name="accessLevel">The requesting user's access level.</param>
/// <returns>The number of assets updated.</returns>
public int BulkSetVisibilityByAlbumIds(IEnumerable<Guid> albumIds, EVisibility visibility, Guid? userId, EAccessLevel accessLevel);
/// <summary>
/// Bulk-updates the visibility of non-deleted assets in any album owned by the specified people
/// via a single SQL UPDATE.
/// </summary>
/// <param name="personIds">The IDs of the people whose album assets to update.</param>
/// <param name="visibility">The target visibility level.</param>
/// <returns>The number of assets updated.</returns>
public int BulkSetVisibilityByPersonIds(IEnumerable<Guid> personIds, EVisibility visibility);
/// <summary>
/// Finds all assets created or updated between the given dates.
/// </summary>
/// <param name="from">The start date of the range.</param>
/// <param name="to">The end date of the range.</param>
/// <returns>A collection of assets created or updated within the specified date range.</returns>
public IEnumerable<Asset> FindByDateRange(DateTime from, DateTime to);
/// <summary>
/// Finds all assets created or updated between the given dates with pagination.
/// </summary>
/// <param name="from">The start date of the range.</param>
/// <param name="to">The end date of the range.</param>
/// <param name="pageNumber">The page number for pagination.</param>
/// <param name="pageSize">The number of items per page.</param>
/// <returns>A collection of assets created or updated within the specified date range.</returns>
public IEnumerable<Asset> FindByDateRange(DateTime from, DateTime to, int pageNumber, int pageSize);
/// <summary>
/// Saves all the changes to the model.
/// </summary>
void Save();
/// <summary>
/// Inserts a new asset.
/// </summary>
/// <param name="asset">The asset to insert.</param>
public void Insert(Asset asset);
/// <summary>
/// Updates a given asset.
/// </summary>
/// <param name="asset">The asset to update.</param>
public void Update(Asset asset);
/// <summary>
/// Updates a list of assets.
/// </summary>
/// <param name="assets">The list of assets to update.</param>
public void UpdateBulk(IEnumerable<Asset> assets);
/// <summary>
/// Gets an asset by its file path.
/// </summary>
/// <param name="filePath">The file path of the asset.</param>
/// <returns>Null if not found, otherwise the requested asset.</returns>
Asset? FindByPath(string filePath);
/// <summary>
/// Counts all assets that are missing a perceptual hash (pHash).
/// </summary>
int CountAssetsMissingPHash();
/// <summary>
/// Finds a page of assets that are missing a perceptual hash (pHash).
/// </summary>
/// <param name="limit">Maximum number of assets to return.</param>
/// <param name="offset">Number of assets to skip.</param>
IEnumerable<Asset> GetAssetsMissingPHash(int limit, int offset);
/// <summary>
/// Finds assets within a normalized Hamming distance (0 to 1).
/// </summary>
/// <param name="phash">The perceptual hash to compare against.</param>
/// <param name="distance">The maximum distance as a fraction (0 to 1).</param>
/// <returns>Assets whose hash is within the specified distance.</returns>
public IEnumerable<Asset> GetWithinHammingDistance(ulong phash, float distance);
/// <summary>
/// Finds all assets that are missing a thumbnail.
/// </summary>
/// <param name="totalAssets">The total number of assets missing thumbnails.</param>
/// <returns>Assets that do not have a thumbnail path set.</returns>
IEnumerable<Asset> GetAssetsMissingThumbnail(out int totalAssets);
/// <summary>
/// Counts all assets that need thumbnails — either missing entirely, with wrong dimensions, or wrong format.
/// </summary>
/// <param name="thumbnailSize">The expected longest-side size in pixels.</param>
/// <param name="expectedFormat">The expected thumbnail format (e.g. "webp").</param>
/// <returns>The total count of assets needing thumbnails.</returns>
int CountAssetsMissingOrWrongThumbnail(int thumbnailSize, string expectedFormat);
/// <summary>
/// Finds a page of assets that need thumbnails — either missing entirely, with wrong dimensions, or wrong format.
/// </summary>
/// <param name="thumbnailSize">The expected longest-side size in pixels.</param>
/// <param name="expectedFormat">The expected thumbnail format (e.g. "webp").</param>
/// <param name="limit">Maximum number of assets to return.</param>
/// <param name="offset">Number of assets to skip.</param>
/// <returns>A page of assets that need thumbnails regenerated.</returns>
IEnumerable<Asset> GetAssetsMissingOrWrongThumbnail(int thumbnailSize, string expectedFormat, int limit, int offset);
/// <summary>
/// Counts all assets that need previews — either missing entirely, with wrong dimensions, or wrong format.
/// </summary>
/// <param name="previewSize">The expected longest-side size in pixels.</param>
/// <param name="expectedFormat">The expected preview format (e.g. "webp").</param>
/// <returns>The total count of assets needing previews.</returns>
int CountAssetsMissingOrWrongPreview(int previewSize, string expectedFormat);
/// <summary>
/// Finds a page of assets that need previews — either missing entirely, with wrong dimensions, or wrong format.
/// </summary>
/// <param name="previewSize">The expected longest-side size in pixels.</param>
/// <param name="expectedFormat">The expected preview format (e.g. "webp").</param>
/// <param name="limit">Maximum number of assets to return.</param>
/// <param name="offset">Number of assets to skip.</param>
/// <returns>A page of assets that need previews regenerated.</returns>
IEnumerable<Asset> GetAssetsMissingOrWrongPreview(int previewSize, string expectedFormat, int limit, int offset);
/// <summary>
/// Counts image assets that are missing resolution metadata.
/// </summary>
int CountAssetsMissingMetadata();
/// <summary>
/// Finds a page of image assets missing resolution metadata.
/// </summary>
/// <param name="limit">Maximum number of assets to return.</param>
/// <param name="offset">Number of assets to skip.</param>
IEnumerable<Asset> GetAssetsMissingMetadata(int limit, int offset);
/// <summary>
/// Counts animated assets (GIF) that need a converted video and/or first-frame thumbnail.
/// Excludes deleted and broken assets.
/// </summary>
int CountAssetsNeedingConversion();
/// <summary>
/// Finds a page of animated assets (GIF) that need a converted video and/or first-frame thumbnail.
/// </summary>
/// <param name="limit">Maximum number of assets to return.</param>
/// <param name="offset">Number of assets to skip.</param>
IEnumerable<Asset> GetAssetsNeedingConversion(int limit, int offset);
/// <summary>
/// Counts assets currently marked broken (processing failed, not deleted).
/// </summary>
int CountBrokenAssets();
/// <summary>
/// Finds a page of assets marked broken (processing failed, not deleted), most recently broken first.
/// </summary>
/// <param name="page">The zero-based page number.</param>
/// <param name="pageSize">The number of assets per page.</param>
/// <param name="total">The total count of broken assets.</param>
/// <returns>A page of broken assets as preview DTOs.</returns>
IEnumerable<AssetPreviewDto> GetBrokenAssets(int page, int pageSize, out int total);
/// <summary>
/// Clears the broken (processing failed) state for the given assets so they are picked up for
/// re-processing on the next job run. Caller must invoke <see cref="Save"/> afterwards.
/// </summary>
/// <param name="ids">The IDs of the assets to retry.</param>
void ClearProcessError(IEnumerable<Guid> ids);
/// <summary>
/// Gets a random sample of asset paths from the specified folder.
/// </summary>
/// <param name="folderId">The folder ID.</param>
/// <param name="count">The number of random paths to return.</param>
/// <returns>A list of asset original paths.</returns>
List<string> GetRandomPathsByFolder(Guid folderId, int count);
/// <summary>
/// Queries assets with optional type filter, date range, random ordering, and visibility scoping.
/// </summary>
/// <param name="type">Optional asset type to filter by.</param>
/// <param name="from">Optional start date for the date range filter.</param>
/// <param name="to">Optional end date for the date range filter.</param>
/// <param name="orderRandomly">If true, orders randomly instead of by date.</param>
/// <param name="seed">An optional seed for deterministic random ordering across paginated requests.</param>
/// <param name="pageNumber">The zero-based page number.</param>
/// <param name="pageSize">The number of items per page.</param>
/// <param name="total">The total count of matching assets (after visibility filtering).</param>
/// <param name="userId">The requesting user's ID for visibility filtering.</param>
/// <param name="accessLevel">The requesting user's access level for visibility filtering.</param>
/// <param name="unlinked">If true, filters for assets not assigned to any album.</param>
/// <param name="folderId">Optional folder ID to filter assets by their scan folder.</param>
/// <param name="uploadedBy">Optional uploader user ID to filter assets by their uploader.</param>
/// <param name="search">Optional search term for ILike matching against OriginalFilename.</param>
/// <param name="includeCount">If true (default), computes the total matching count. When false, <paramref name="total"/> is set to zero and the count query is skipped.</param>
/// <returns>A paginated collection of asset previews matching the filters.</returns>
IEnumerable<AssetPreviewDto> GetAssets(EAssetType? type, DateTime? from, DateTime? to, bool orderRandomly, Guid? seed, int pageNumber, int pageSize, out int total, Guid? userId = null, EAccessLevel accessLevel = EAccessLevel.User, bool unlinked = false, Guid? folderId = null, Guid? uploadedBy = null, string? search = null, bool includeCount = true);
/// <summary>
/// Returns groups of unlinked assets (not assigned to any album), grouped by folder for drill-down browsing.
/// Admins and curators receive all folders with their unlinked asset counts. Maintainers receive a single
/// "My Uploads" group with their own unlinked upload count.
/// </summary>
/// <param name="userId">The requesting user's ID.</param>
/// <param name="accessLevel">The requesting user's access level.</param>
/// <param name="unlinkedOnly">If true (default), only counts assets not assigned to any album.</param>
/// <returns>A list of unlinked asset groups with folder ID, name, and asset count.</returns>
List<Butter.Dtos.Asset.AssetGroupDto> GetFolderGroups(Guid? userId, EAccessLevel accessLevel, bool unlinkedOnly = true);
}