using Application.Abstractions.Messaging; using Application.Abstractions.Data; using Application.Abstractions.Cache; using Domain.Entities.Crypto; using SharedKernel.Storage; using Microsoft.EntityFrameworkCore; namespace Application.Features.Admin.Crypto.List.Create { public sealed class Handler(IAppDbContext db, IFileStorage fileStorage, ICacheService cache) : ICommandHandler { public async Task Handle(Command request, CancellationToken ct) { if (await db.Coin.AnyAsync(c => c.Symbol == request.Symbol.ToUpper(), ct)) { throw new InvalidOperationException($"`{request.Symbol.ToUpper()}`는 이미 등록된 심볼입니다."); } var coin = Coin.Create( request.Symbol, request.KorName, request.EngName, request.Description, request.ContractAddress, request.WebsiteUrl, request.WhitepaperUrl, request.TwitterUrl, request.TelegramUrl, request.IsActive, request.IsWarning, request.IsNew, request.IsDelisted ); await db.Coin.AddAsync(coin, ct); await db.SaveChangesAsync(ct); FileStoragePath uploadPath = new FileStoragePath(UploadTarget.Upload, UploadFolder.Crypto, coin.ID); string[] allowedFileExtensions = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg"]; if (request.LogoImageFile is not null) { coin.SetLogoImage( (await fileStorage.SaveFileAsync(request.LogoImageFile, uploadPath, allowedFileExtensions, ct))?.Url ); } foreach (var categoryID in request.CategoryIDs) { db.CoinCategoryMap.Add(new CoinCategoryMap { CoinID = coin.ID, CategoryID = categoryID }); } await db.SaveChangesAsync(ct); await cache.RemoveByPrefixAsync("crypto:", ct); } } }