using AsbCloudApp.Data; using AsbCloudApp.Services; using AsbCloudDb.Model; using AsbCloudInfrastructure.Services.Cache; using Mapster; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services { public class FileService : IFileService { public string RootPath { get; private set; } private readonly IAsbCloudDbContext db; private readonly CacheTable cacheCompanies; public FileService(IAsbCloudDbContext db, Cache.CacheDb cacheDb) { RootPath = "files"; this.db = db; cacheCompanies = cacheDb.GetCachedTable((DbContext)db); } public async Task SaveAsync(int idWell, int idUser, int idCategory, string fileFullName, Stream fileStream, CancellationToken token = default) { //save info to db var fileInfo = new AsbCloudDb.Model.FileInfo() { IdWell = idWell, IdAuthor = idUser, IdCategory = idCategory, Name = Path.GetFileName(fileFullName), UploadDate = DateTime.Now, IsDeleted = false, Size = fileStream.Length, }; var entry = db.Files.Add(fileInfo); db.SaveChanges(); var fileId = entry.Entity.Id; //save stream to disk var relativePath = Path.Combine(RootPath, $"{idWell}", $"{idCategory}", $"{fileId}" + $"{Path.GetExtension(fileFullName)}"); Directory.CreateDirectory(Path.GetDirectoryName(relativePath)); using (var newfileStream = new FileStream(relativePath, FileMode.Create)) { await fileStream.CopyToAsync(newfileStream); } var dto = entry.Entity.Adapt(); return dto; } public async Task> GetInfosByCategoryAsync(int idWell, int idCategory, CancellationToken token = default) { var entities = await db.Files .Include(f => f.Author) .Where(e => e.IdWell == idWell && e.IdCategory == idCategory) .AsNoTracking() .ToListAsync(token) .ConfigureAwait(false); var dtos = entities.Adapt(async (d,s) => { d.Author = s.Author?.Adapt(); var company = await cacheCompanies.FirstOrDefaultAsync(c => c.Id == s.Author?.IdCompany, token) .ConfigureAwait(false); d.Company = company?.Caption; }); return dtos; } public async Task> GetInfosAsync(int idWell, int idCategory, IEnumerable companies = default, string fileName = default, DateTime begin = default, DateTime end = default, int skip = 0, int take = 32, CancellationToken token = default) { var query = db.Files .Include(f => f.Author) .Where(e => e.IdWell == idWell && e.IdCategory == idCategory); query = query.Where(e => !e.IsDeleted); if (companies.Any()) query.Include(file => file.Author).ThenInclude(a => a.Company) .Where(e => companies.Contains(e.Author.Company.Id)); if (!string.IsNullOrEmpty(fileName)) query = query.Where(e => e.Name.ToLower().Contains(fileName.ToLower())); if (begin != default) query = query.Where(e => e.UploadDate >= begin); if (end != default) query = query.Where(e => e.UploadDate <= end); var count = await query.CountAsync(token).ConfigureAwait(false); var result = new PaginationContainer(count) { Skip = skip, Take = take, Count = count, }; if (count <= skip) return result; query = query.OrderBy(e => e.UploadDate); if (skip > 0) query = query.Skip(skip); query = query.Take(take); var entities = await query .Take(take).AsNoTracking().ToListAsync(token) .ConfigureAwait(false); var dtos = entities.Adapt(async (d, s) => { d.Author = s.Author?.Adapt(); var company = await cacheCompanies.FirstOrDefaultAsync(c => c.Id == s.Author?.IdCompany, token) .ConfigureAwait(false); d.Company = company?.Caption; }); result.Items.AddRange(dtos); return result; } public async Task GetInfoAsync(int fileId, CancellationToken token = default) { var entity = await db.Files .Include(f => f.Author) .AsNoTracking() .FirstOrDefaultAsync(f => f.Id == fileId, token) .ConfigureAwait(false); if (entity is null) return null; var dto = entity.Adapt(); dto.Author = entity.Author?.Adapt(); return dto; } public async Task MarkAsDeletedAsync(int idFile, CancellationToken token = default) { var fileInfo = await db.Files.FirstOrDefaultAsync(f => f.Id == idFile, token).ConfigureAwait(false); if (fileInfo is null) return 0; fileInfo.IsDeleted = true; return await db.SaveChangesAsync(token).ConfigureAwait(false); } public async Task DeletedAsync(int idFile, CancellationToken token) { var fileInfo = await db.Files .FirstOrDefaultAsync(f => f.Id == idFile, token) .ConfigureAwait(false); if (fileInfo is null) return 0; var fileName = GetFileName(fileInfo.Adapt()); if (File.Exists(fileName)) File.Delete(fileName); db.Files.Remove(fileInfo); return await db.SaveChangesAsync(token).ConfigureAwait(false); } public string GetFileName(FileInfoDto fileInfo) { var fileName = $"{fileInfo.Id}{Path.GetExtension(fileInfo.Name)}"; fileName = Path.Combine(RootPath, fileInfo.IdWell.ToString(), fileInfo.IdCategory.ToString(), fileName); fileName = Path.GetFullPath(fileName); return fileName; } } }