233 lines
8.0 KiB
C#
233 lines
8.0 KiB
C#
using GozareshgirProgramManager.Application.Services.FileManagement;
|
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Entities;
|
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Enums;
|
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Repositories;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace GozareshgirProgramManager.Infrastructure.Services.FileManagement;
|
|
|
|
/// <summary>
|
|
/// پیادهسازی سرویس آپلود کامل فایل
|
|
/// </summary>
|
|
public class FileUploadService : IFileUploadService
|
|
{
|
|
private readonly IUploadedFileRepository _fileRepository;
|
|
private readonly IFileStorageService _fileStorageService;
|
|
private readonly IThumbnailGeneratorService _thumbnailService;
|
|
private readonly ILogger<FileUploadService> _logger;
|
|
|
|
public FileUploadService(
|
|
IUploadedFileRepository fileRepository,
|
|
IFileStorageService fileStorageService,
|
|
IThumbnailGeneratorService thumbnailService,
|
|
ILogger<FileUploadService> logger)
|
|
{
|
|
_fileRepository = fileRepository;
|
|
_fileStorageService = fileStorageService;
|
|
_thumbnailService = thumbnailService;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task<FileUploadResult> UploadFileAsync(
|
|
IFormFile file,
|
|
FileCategory category,
|
|
long uploadedByUserId,
|
|
long maxFileSizeBytes = 100 * 1024 * 1024)
|
|
{
|
|
try
|
|
{
|
|
// اعتبارسنجی ورودی
|
|
if (file.Length == 0)
|
|
{
|
|
return FileUploadResult.Failed("فایل خالی است");
|
|
}
|
|
|
|
if (file.Length > maxFileSizeBytes)
|
|
{
|
|
var maxSizeMb = maxFileSizeBytes / (1024 * 1024);
|
|
return FileUploadResult.Failed($"حجم فایل بیش از حد مجاز است (حداکثر {maxSizeMb}MB)");
|
|
}
|
|
|
|
using var stream = file.OpenReadStream();
|
|
return await UploadFileFromStreamAsync(
|
|
stream,
|
|
file.FileName,
|
|
file.ContentType,
|
|
category,
|
|
uploadedByUserId,
|
|
maxFileSizeBytes);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "خطا در آپلود فایل {FileName}", file.FileName);
|
|
return FileUploadResult.Failed($"خطا در آپلود فایل: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
public async Task<FileUploadResult> UploadFileFromStreamAsync(
|
|
Stream fileStream,
|
|
string fileName,
|
|
string contentType,
|
|
FileCategory category,
|
|
long uploadedByUserId,
|
|
long maxFileSizeBytes = 100 * 1024 * 1024)
|
|
{
|
|
UploadedFile? uploadedFile = null;
|
|
|
|
try
|
|
{
|
|
// تشخیص نوع فایل
|
|
var fileType = DetectFileType(contentType, Path.GetExtension(fileName));
|
|
|
|
// ایجاد رکورد فایل در دیتابیس
|
|
uploadedFile = new UploadedFile(
|
|
originalFileName: fileName,
|
|
fileSizeBytes: fileStream.Length,
|
|
mimeType: contentType,
|
|
fileType: fileType,
|
|
category: category,
|
|
uploadedByUserId: uploadedByUserId,
|
|
storageProvider: StorageProvider.LocalFileSystem
|
|
);
|
|
|
|
await _fileRepository.AddAsync(uploadedFile);
|
|
await _fileRepository.SaveChangesAsync();
|
|
|
|
// آپلود فایل به استوریج
|
|
var categoryFolder = category.ToString();
|
|
var uploadResult = await _fileStorageService.UploadAsync(
|
|
fileStream,
|
|
uploadedFile.UniqueFileName,
|
|
categoryFolder
|
|
);
|
|
|
|
// بهروزرسانی اطلاعات آپلود
|
|
uploadedFile.CompleteUpload(uploadResult.StoragePath, uploadResult.StorageUrl);
|
|
|
|
// پردازشهای خاص بر اساس نوع فایل
|
|
string? thumbnailUrl = null;
|
|
if (fileType == FileType.Image)
|
|
{
|
|
thumbnailUrl = await ProcessImageAsync(uploadedFile, uploadResult.StoragePath, categoryFolder);
|
|
}
|
|
else if (fileType == FileType.Video)
|
|
{
|
|
thumbnailUrl = await ProcessVideoAsync(uploadedFile, uploadResult.StoragePath, categoryFolder);
|
|
}
|
|
|
|
// ذخیره تغییرات نهایی
|
|
await _fileRepository.UpdateAsync(uploadedFile);
|
|
await _fileRepository.SaveChangesAsync();
|
|
|
|
_logger.LogInformation(
|
|
"فایل {FileName} با شناسه {FileId} با موفقیت آپلود شد",
|
|
fileName,
|
|
uploadedFile.Id);
|
|
|
|
return FileUploadResult.Success(uploadedFile.Id, uploadResult.StorageUrl, thumbnailUrl);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "خطا در آپلود فایل {FileName}", fileName);
|
|
|
|
// در صورت خطا، فایل آپلود شده را حذف کنیم
|
|
if (uploadedFile != null)
|
|
{
|
|
try
|
|
{
|
|
await _fileRepository.DeleteAsync(uploadedFile);
|
|
await _fileRepository.SaveChangesAsync();
|
|
}
|
|
catch (Exception deleteEx)
|
|
{
|
|
_logger.LogError(deleteEx, "خطا در حذف فایل ناموفق {FileId}", uploadedFile.Id);
|
|
}
|
|
}
|
|
|
|
return FileUploadResult.Failed($"خطا در آپلود فایل: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// پردازش تصویر (ابعاد و thumbnail)
|
|
/// </summary>
|
|
private async Task<string?> ProcessImageAsync(UploadedFile file, string storagePath, string categoryFolder)
|
|
{
|
|
try
|
|
{
|
|
// دریافت ابعاد تصویر
|
|
var dimensions = await _thumbnailService.GetImageDimensionsAsync(storagePath);
|
|
if (dimensions.HasValue)
|
|
{
|
|
file.SetImageDimensions(dimensions.Value.Width, dimensions.Value.Height);
|
|
}
|
|
|
|
// تولید thumbnail
|
|
var thumbnail = await _thumbnailService.GenerateImageThumbnailAsync(
|
|
storagePath,
|
|
category: categoryFolder);
|
|
|
|
if (thumbnail.HasValue)
|
|
{
|
|
file.SetThumbnail(thumbnail.Value.ThumbnailUrl);
|
|
return thumbnail.Value.ThumbnailUrl;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "خطا در پردازش تصویر {FileId}", file.Id);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// پردازش ویدیو (thumbnail)
|
|
/// </summary>
|
|
private async Task<string?> ProcessVideoAsync(UploadedFile file, string storagePath, string categoryFolder)
|
|
{
|
|
try
|
|
{
|
|
// تولید thumbnail از ویدیو
|
|
var thumbnail = await _thumbnailService.GenerateVideoThumbnailAsync(
|
|
storagePath,
|
|
category: categoryFolder);
|
|
|
|
if (thumbnail.HasValue)
|
|
{
|
|
file.SetThumbnail(thumbnail.Value.ThumbnailUrl);
|
|
return thumbnail.Value.ThumbnailUrl;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "خطا در پردازش ویدیو {FileId}", file.Id);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// تشخیص نوع فایل از روی MIME type و extension
|
|
/// </summary>
|
|
private FileType DetectFileType(string mimeType, string extension)
|
|
{
|
|
if (mimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
|
|
return FileType.Image;
|
|
|
|
if (mimeType.StartsWith("video/", StringComparison.OrdinalIgnoreCase))
|
|
return FileType.Video;
|
|
|
|
if (mimeType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase))
|
|
return FileType.Audio;
|
|
|
|
if (new[] { ".zip", ".rar", ".7z", ".tar", ".gz" }.Contains(extension.ToLower()))
|
|
return FileType.Archive;
|
|
|
|
return FileType.Document;
|
|
}
|
|
|
|
}
|
|
|