Rob / Application /Services /FileService.cs
danylokhodus's picture
Initial clean backend commit
70556b7
Raw
History Blame Contribute Delete
9.33 kB
using Application.Abstractions.Interfaces;
using Application.DTOs.FileDTOs;
using Entities.Interfaces;
using FileEntity = Entities.Models.File;
namespace Application.Services
{
public class FileService : IFileService
{
private readonly IFileRepository _fileRepository;
private readonly IUserRepository _userRepository;
private readonly IOrderRepository _orderRepository;
private readonly string[] _allowedExtensions = { ".jpg", ".jpeg", ".png", ".gif" };
private const long MaxFileSize = 5 * 1024 * 1024; // 5MB
public FileService(
IFileRepository fileRepository,
IUserRepository userRepository,
IOrderRepository orderRepository)
{
_fileRepository = fileRepository;
_userRepository = userRepository;
_orderRepository = orderRepository;
}
public async Task<FileResponseDTO> UploadProfilePhotoAsync(int userId, FileUploadDTO file, string contentRootPath)
{
// Validate user exists
var user = await _userRepository.GetByIdAsync(userId);
if (user == null)
{
throw new ArgumentException("User not found");
}
// Validate file
ValidateFile(file);
// Delete old profile photo if exists
if (user.ProfilePhotoId.HasValue)
{
await DeleteProfilePhotoAsync(userId, contentRootPath);
}
// Create upload directory
var uploadsPath = Path.Combine(contentRootPath, "Uploads", "Profiles");
Directory.CreateDirectory(uploadsPath);
// Generate unique filename
var extension = Path.GetExtension(file.FileName).ToLowerInvariant();
var uniqueFileName = $"{userId}_{Guid.NewGuid()}{extension}";
var filePath = Path.Combine(uploadsPath, uniqueFileName);
// Save file to disk
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
await file.Content.CopyToAsync(fileStream);
}
// Create file entity
var fileEntity = new FileEntity
{
FileName = file.FileName,
FilePath = $"/Uploads/Profiles/{uniqueFileName}",
ContentType = file.ContentType,
FileSize = file.Length,
UserId = userId,
UploadedAt = DateTime.UtcNow
};
await _fileRepository.AddAsync(fileEntity);
await _fileRepository.SaveChangesAsync();
// Update user's profile photo reference
user.ProfilePhotoId = fileEntity.Id;
await _userRepository.UpdateAsync(user);
await _userRepository.SaveChangesAsync();
return MapToResponseDTO(fileEntity);
}
public async Task<List<FileResponseDTO>> UploadOrderImagesAsync(int orderId, List<FileUploadDTO> files, string contentRootPath)
{
// Validate order exists
var order = await _orderRepository.GetByIdAsync(orderId);
if (order == null)
{
throw new ArgumentException("Order not found");
}
if (files == null || files.Count == 0)
{
throw new ArgumentException("No files provided");
}
var uploadedFiles = new List<FileResponseDTO>();
// Create upload directory
var uploadsPath = Path.Combine(contentRootPath, "Uploads", "Orders", orderId.ToString());
Directory.CreateDirectory(uploadsPath);
foreach (var file in files)
{
// Validate file
ValidateFile(file);
// Generate unique filename
var extension = Path.GetExtension(file.FileName).ToLowerInvariant();
var uniqueFileName = $"{Guid.NewGuid()}{extension}";
var filePath = Path.Combine(uploadsPath, uniqueFileName);
// Save file to disk
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
await file.Content.CopyToAsync(fileStream);
}
// Create file entity
var fileEntity = new FileEntity
{
FileName = file.FileName,
FilePath = $"/Uploads/Orders/{orderId}/{uniqueFileName}",
ContentType = file.ContentType,
FileSize = file.Length,
OrderId = orderId,
UploadedAt = DateTime.UtcNow
};
await _fileRepository.AddAsync(fileEntity);
uploadedFiles.Add(MapToResponseDTO(fileEntity));
}
await _fileRepository.SaveChangesAsync();
return uploadedFiles;
}
public async Task<FileResponseDTO?> GetFileByIdAsync(int fileId)
{
var file = await _fileRepository.GetByIdAsync(fileId);
return file == null ? null : MapToResponseDTO(file);
}
public async Task<List<FileResponseDTO>> GetOrderFilesAsync(int orderId)
{
var files = await _fileRepository.GetByOrderIdAsync(orderId);
return files.Select(MapToResponseDTO).ToList();
}
public async Task<bool> DeleteFileAsync(int fileId, string contentRootPath)
{
var file = await _fileRepository.GetByIdAsync(fileId);
if (file == null)
{
return false;
}
// Delete file from disk
var diskPath = Path.Combine(contentRootPath, file.FilePath.TrimStart('/'));
if (File.Exists(diskPath))
{
File.Delete(diskPath);
}
// Delete from database
await _fileRepository.DeleteAsync(fileId);
await _fileRepository.SaveChangesAsync();
return true;
}
public async Task<bool> DeleteProfilePhotoAsync(int userId, string contentRootPath)
{
var user = await _userRepository.GetByIdAsync(userId);
if (user == null || !user.ProfilePhotoId.HasValue)
{
return false;
}
var photo = await _fileRepository.GetByIdAsync(user.ProfilePhotoId.Value);
if (photo != null)
{
// Delete file from disk
var oldFilePath = Path.Combine(contentRootPath, photo.FilePath.TrimStart('/'));
if (File.Exists(oldFilePath))
{
File.Delete(oldFilePath);
}
await _fileRepository.DeleteAsync(photo.Id);
await _fileRepository.SaveChangesAsync();
}
return true;
}
public async Task<byte[]?> GetFileContentAsync(int fileId, string contentRootPath)
{
var file = await _fileRepository.GetByIdAsync(fileId);
if (file == null)
{
return null;
}
var filePath = Path.Combine(contentRootPath, file.FilePath.TrimStart('/'));
if (!File.Exists(filePath))
{
return null;
}
return await File.ReadAllBytesAsync(filePath);
}
public async Task<bool> IsUserAuthorizedForFileAsync(int fileId, int userId, bool isAdmin)
{
var file = await _fileRepository.GetByIdAsync(fileId);
if (file == null)
{
return false;
}
// Admin has access to all files
if (isAdmin)
{
return true;
}
// Check if user owns this file (either through order or profile photo)
if (file.OrderId.HasValue)
{
var order = await _orderRepository.GetByIdAsync(file.OrderId.Value);
if (order != null && order.SenderId == userId)
{
return true;
}
}
else if (file.UserId.HasValue && file.UserId == userId)
{
return true;
}
return false;
}
private void ValidateFile(FileUploadDTO file)
{
var extension = Path.GetExtension(file.FileName).ToLowerInvariant();
if (!_allowedExtensions.Contains(extension))
{
throw new ArgumentException($"Invalid file extension. Allowed: {string.Join(", ", _allowedExtensions)}");
}
if (file.Length > MaxFileSize)
{
throw new ArgumentException("File exceeds maximum size of 5MB");
}
}
private static FileResponseDTO MapToResponseDTO(FileEntity file)
{
return new FileResponseDTO
{
Id = file.Id,
FileName = file.FileName,
FilePath = file.FilePath,
ContentType = file.ContentType,
FileSize = file.FileSize,
UploadedAt = file.UploadedAt
};
}
}
}