120 lines
6.0 KiB
C#
120 lines
6.0 KiB
C#
using System.Text.Json;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Tiku.Application.Assets;
|
|
using Tiku.Application.Catalog;
|
|
using Tiku.Application.Content;
|
|
using Tiku.Domain.Content;
|
|
|
|
namespace Tiku.Infrastructure.Assets;
|
|
|
|
internal sealed class AssetCatalogManagementService(AssetManagementDependencies dependencies)
|
|
: AssetManagementServiceBase(dependencies), IAssetCatalogManagementService
|
|
{
|
|
public async Task<CatalogList<ContentAssetManagementItem>> GetAssetsAsync(
|
|
AssetManagementActor actor,
|
|
AssetManagementFilter filter,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var query = contentAssetPersistence.ContentAssets
|
|
.AsNoTracking()
|
|
.Where(asset => asset.TenantId == actor.TenantId);
|
|
|
|
if (filter.RegionId.HasValue) query = query.Where(asset => asset.RegionId == filter.RegionId.Value);
|
|
|
|
if (filter.SubjectId.HasValue) query = query.Where(asset => asset.SubjectId == filter.SubjectId.Value);
|
|
|
|
if (filter.CategoryId.HasValue) query = query.Where(asset => asset.CategoryId == filter.CategoryId.Value);
|
|
|
|
if (filter.ContentNodeId.HasValue)
|
|
query = query.Where(asset => asset.ContentNodeId == filter.ContentNodeId.Value);
|
|
|
|
if (!string.IsNullOrWhiteSpace(filter.AssetType) &&
|
|
Enum.TryParse<ContentAssetType>(filter.AssetType, true, out var assetType))
|
|
query = query.Where(asset => asset.AssetType == assetType);
|
|
|
|
if (!string.IsNullOrWhiteSpace(filter.UploadStatus) &&
|
|
Enum.TryParse<AssetUploadStatus>(filter.UploadStatus, true, out var uploadStatus))
|
|
query = query.Where(asset => asset.UploadStatus == uploadStatus);
|
|
|
|
if (!string.IsNullOrWhiteSpace(filter.SecurityScanStatus) &&
|
|
Enum.TryParse<AssetSecurityScanStatus>(filter.SecurityScanStatus, true, out var securityScanStatus))
|
|
query = query.Where(asset => asset.SecurityScanStatus == securityScanStatus);
|
|
|
|
if (!string.IsNullOrWhiteSpace(filter.Category))
|
|
{
|
|
var category = filter.Category.Trim();
|
|
query = query.Where(asset => asset.Category == category);
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(filter.Keyword))
|
|
{
|
|
var keyword = filter.Keyword.Trim();
|
|
query = query.Where(asset =>
|
|
(asset.Title != null && asset.Title.Contains(keyword)) ||
|
|
(asset.FileName != null && asset.FileName.Contains(keyword)) ||
|
|
(asset.Description != null && asset.Description.Contains(keyword)) ||
|
|
(asset.AssetKey != null && asset.AssetKey.Contains(keyword)));
|
|
}
|
|
|
|
var items = await query
|
|
.OrderBy(asset => asset.SortOrder)
|
|
.ThenByDescending(asset => asset.CreatedAt)
|
|
.Take(ResolveLimit(filter.Limit))
|
|
.Select(asset => ToItem(asset))
|
|
.ToArrayAsync(cancellationToken);
|
|
|
|
return new CatalogList<ContentAssetManagementItem>(items);
|
|
}
|
|
|
|
public async Task<ContentManagementResult<ContentAssetManagementItem>> UpsertAssetAsync(
|
|
AssetManagementActor actor,
|
|
UpsertAssetCommand command,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var asset = await ResolveManagementAssetAsync(actor, command, cancellationToken);
|
|
var accountedBytesBefore = AccountedStorageBytes(asset);
|
|
asset.RegionId = command.RegionId;
|
|
asset.SubjectId = command.SubjectId;
|
|
asset.CategoryId = command.CategoryId;
|
|
asset.ContentNodeId = command.ContentNodeId;
|
|
asset.LegacyId = NormalizeOptional(command.LegacyId);
|
|
asset.AssetKey = NormalizeOptional(command.AssetKey);
|
|
asset.Title = NormalizeOptional(command.Title) ?? NormalizeOptional(command.FileName) ?? asset.Title ?? "未命名资源";
|
|
asset.Category = NormalizeOptional(command.Category);
|
|
asset.Description = NormalizeOptional(command.Description);
|
|
asset.FileName = NormalizeOptional(command.FileName);
|
|
asset.CdnUrl = NormalizeOptional(command.CdnUrl);
|
|
asset.IsPublic = command.IsPublic ?? asset.IsPublic;
|
|
asset.AssetType = ParseEnum(command.AssetType, asset.AssetType);
|
|
asset.Visibility = ResolveVisibility(command.Visibility, asset.IsPublic);
|
|
asset.Status = ParseEnum(command.Status, asset.Status);
|
|
asset.StorageProvider =
|
|
ToAssetStorageProvider(objectStorageService.NormalizeProvider(command.Provider,
|
|
ToObjectStorageProvider(asset.StorageProvider)));
|
|
asset.Bucket = string.IsNullOrWhiteSpace(command.Bucket) ? asset.Bucket : command.Bucket.Trim();
|
|
asset.ObjectKey = string.IsNullOrWhiteSpace(command.ObjectKey)
|
|
? asset.ObjectKey
|
|
: objectStorageService.ValidateObjectKey(actor.TenantId, command.ObjectKey.Trim());
|
|
asset.MimeType = string.IsNullOrWhiteSpace(command.MimeType)
|
|
? asset.MimeType
|
|
: objectStorageService.ValidateMimeType(command.MimeType.Trim());
|
|
asset.FileSizeBytes = objectStorageService.ValidateFileSize(command.FileSizeBytes ?? asset.FileSizeBytes);
|
|
asset.ChecksumSha256 = NormalizeChecksum(command.ChecksumSha256) ?? asset.ChecksumSha256;
|
|
asset.PreviewUrl = NormalizeOptional(command.PreviewUrl);
|
|
asset.PreviewObjectKey = NormalizeOptional(command.PreviewObjectKey) ?? asset.PreviewObjectKey;
|
|
asset.SortOrder = command.Order ?? asset.SortOrder;
|
|
asset.AccessRules = command.AccessRules.ValueKind == JsonValueKind.Undefined
|
|
? asset.AccessRules
|
|
: command.AccessRules;
|
|
asset.Metadata = command.Metadata.ValueKind == JsonValueKind.Undefined ? asset.Metadata : command.Metadata;
|
|
asset.UpdatedBy = actor.UserId;
|
|
|
|
var accountedBytesAfter = AccountedStorageBytes(asset);
|
|
await SaveWithStorageQuotaAdjustmentAsync(
|
|
actor.TenantId,
|
|
accountedBytesAfter - accountedBytesBefore,
|
|
cancellationToken);
|
|
return new ContentManagementResult<ContentAssetManagementItem>(ToItem(asset));
|
|
}
|
|
}
|