Add image management functionality: introduce Image entity and related API endpoints, update database schema to support image storage, and enhance UI with a new gallery feature for image selection and upload. Update translations for gallery-related terms.

This commit is contained in:
Leonid Pershin
2026-07-25 11:27:34 +03:00
parent 72451f89a8
commit 149cd153b9
34 changed files with 1732 additions and 11 deletions
@@ -0,0 +1,48 @@
using TeleWave.Application.Common.Interfaces;
namespace TeleWave.Infrastructure.Media;
/// <summary>Файловое хранилище общего реестра изображений: images/{imageId}{ext}.</summary>
public sealed class ImageStore(MediaPathResolver paths) : IImageStore
{
public async Task SaveAsync(
Guid imageId,
string extension,
Stream content,
CancellationToken cancellationToken
)
{
Directory.CreateDirectory(paths.ImagesDir);
var path = paths.ImagePath(imageId, Normalize(extension));
await using var fs = File.Create(path);
await content.CopyToAsync(fs, cancellationToken);
}
public async Task SaveAsync(
Guid imageId,
string extension,
byte[] content,
CancellationToken cancellationToken
)
{
Directory.CreateDirectory(paths.ImagesDir);
var path = paths.ImagePath(imageId, Normalize(extension));
await File.WriteAllBytesAsync(path, content, cancellationToken);
}
public void Delete(Guid imageId, string extension)
{
var path = paths.ImagePath(imageId, Normalize(extension));
if (File.Exists(path))
File.Delete(path);
}
public string? ResolvePath(Guid imageId, string extension)
{
var path = paths.ImagePath(imageId, Normalize(extension));
return File.Exists(path) ? path : null;
}
private static string Normalize(string extension) =>
extension.StartsWith('.') ? extension : "." + extension;
}
@@ -19,6 +19,7 @@ public sealed class MediaPathResolver
AssetsDir = Path.Combine(_root, "assets");
BumpersDir = Path.Combine(_root, "bumpers");
MetadataDir = Path.Combine(_root, "metadata");
ImagesDir = Path.Combine(_root, "images");
}
public string InboxDir { get; }
@@ -32,6 +33,9 @@ public sealed class MediaPathResolver
/// <summary>Картинки метаданных (постеры/кадры), скачанные локально.</summary>
public string MetadataDir { get; }
/// <summary>Общий реестр изображений (галерея): файлы images/{imageId}{ext}.</summary>
public string ImagesDir { get; }
public void EnsureDirectories()
{
Directory.CreateDirectory(InboxDir);
@@ -40,6 +44,7 @@ public sealed class MediaPathResolver
Directory.CreateDirectory(AssetsDir);
Directory.CreateDirectory(BumpersDir);
Directory.CreateDirectory(MetadataDir);
Directory.CreateDirectory(ImagesDir);
}
public string MetadataShowDir(Guid showId) =>
@@ -86,6 +91,10 @@ public sealed class MediaPathResolver
public string BumperTemplateFilePath(Guid templateId, string kind, string extension) =>
EnsureWithinRoot(Path.Combine(BumpersDir, templateId.ToString("N"), kind + extension));
/// <summary>Путь к файлу изображения общего реестра (extension — с точкой).</summary>
public string ImagePath(Guid imageId, string extension) =>
EnsureWithinRoot(Path.Combine(ImagesDir, imageId.ToString("N") + extension));
public string OriginalPath(Guid assetId, string extension) =>
EnsureWithinRoot(Path.Combine(OriginalsDir, assetId.ToString("N") + extension));