feat(media): content-hash dedup for uploads + media-library endpoint
Uploads previously wrote every file to disk with a fresh GUID name, so the
same image uploaded twice produced two identical files. Now:
- New MediaAsset table records each stored upload (SHA-256 hash, size, type,
url, kind, scope) + migration. Indexed on (CafeId, ContentHash).
- MediaStorageService computes the content hash on upload; if an identical file
already exists for that café it returns the existing URL instead of writing a
duplicate (covers images, videos, 3D models). Dedup lookup/record run via a
scoped DbContext (the service is a singleton) and never block an upload on
failure.
- GET /api/cafes/{cafeId}/media lists the café's library (newest first, optional
?kind=) so the UI can let users pick an existing file instead of re-uploading.
86 API tests pass.
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
namespace Meezi.Core.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// A stored upload, recorded so identical files can be de-duplicated and reused
|
||||
/// instead of written to disk again. Files with the same content hash within a
|
||||
/// scope (café, or platform when <see cref="CafeId"/> is null) share one stored file.
|
||||
/// </summary>
|
||||
public class MediaAsset : BaseEntity
|
||||
{
|
||||
/// <summary>Owning café, or null for platform-level (admin) uploads.</summary>
|
||||
public string? CafeId { get; set; }
|
||||
|
||||
/// <summary>SHA-256 of the file content, lowercase hex.</summary>
|
||||
public string ContentHash { get; set; } = string.Empty;
|
||||
|
||||
public long SizeBytes { get; set; }
|
||||
|
||||
public string ContentType { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Public URL/path the file is served from (e.g. /uploads/{cafeId}/{name}).</summary>
|
||||
public string Url { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Logical kind/prefix: menu_img, logo, cover, gallery, review, menu_3d, blog, ...</summary>
|
||||
public string Kind { get; set; } = string.Empty;
|
||||
|
||||
public string? OriginalFileName { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user