From ce846b3f68b55b82043cabe93ba3d489f3ffeb37 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sun, 7 Dec 2025 16:01:07 +0330 Subject: [PATCH] Implement XFile Provider ... --- DI/XDIHelperExtension.cs | 103 +++ Extensions/xFileServiceExtensions.cs | 45 ++ Hubs/XFileEntityHub.cs | 16 + Interfaces/IXFileProvider.cs | 217 ++++++ Providers/XFileProvider.cs | 967 +++++++++++++++++++++++++++ 5 files changed, 1348 insertions(+) create mode 100644 DI/XDIHelperExtension.cs create mode 100644 Extensions/xFileServiceExtensions.cs create mode 100644 Hubs/XFileEntityHub.cs create mode 100644 Interfaces/IXFileProvider.cs create mode 100644 Providers/XFileProvider.cs diff --git a/DI/XDIHelperExtension.cs b/DI/XDIHelperExtension.cs new file mode 100644 index 0000000..d7a041f --- /dev/null +++ b/DI/XDIHelperExtension.cs @@ -0,0 +1,103 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using xCommons.Extensions; +using xExceptions.Constants; +using xFileService.Interfaces; +using xFileService.Providers; + +namespace xFileService.DI +{ + public static class XDIHelperExtension + { + /// + /// Register Module Provided Service on DI + /// + /// + /// + public static void AddXFileService( + this IServiceCollection services, + ServiceLifetime lifeTime + ) + { + // + AddFileService( + services, + lifeTime + ); + } + + // + #region Private ... + /// + /// a LogTag for Service ... + /// + private static string XLogTag = "XFileService"; + + /// + /// print a log in Console ... + /// + /// + private static void Log(string message) + { + Console.WriteLine($"{XLogTag} => {message}"); + } + + /// + /// Register Push Service ... + /// + /// + /// + private static void AddFileService( + IServiceCollection services, + ServiceLifetime lifeTime + ) + { + // + var exception = XException.InvalidArgs.ToException(); ; + + // + // Services ... + var isServicesExists = !services.IsNull(); + if (!isServicesExists) + { + // + Log("AddFileService failed, services not provided ..."); + throw exception; + } + + // + // Lifetime ... + var isLifetimeExists = !lifeTime.IsNull(); + if (!isLifetimeExists) + { + // + Log("AddFileService failed, lifetime not provided ..."); + throw exception; + } + + // + // Check String Repository Exists ... + var isRepositoryExists = !services + .GetRegisteredService() + .IsNull(); + if (!isRepositoryExists) + { + // + Log("AddFileService failed, IXTagRepository not provided ..."); + throw exception; + } + + // + // Register Main Provider ... + services.Add(new ServiceDescriptor(typeof(IXFileProvider), typeof(XFileProvider), lifeTime)); + + // + Log("AddFileService Succeed ..."); + } + #endregion + } + + internal class IXTagRepository + { + } +} \ No newline at end of file diff --git a/Extensions/xFileServiceExtensions.cs b/Extensions/xFileServiceExtensions.cs new file mode 100644 index 0000000..6ea5897 --- /dev/null +++ b/Extensions/xFileServiceExtensions.cs @@ -0,0 +1,45 @@ +using xCommons.Extensions; +using xFileService.Models.Dtos; +using xFileService.Models.Entities; + +namespace xFileService.Extensions +{ + public static class xFileServiceExtensions + { + /// + /// Map Global Properties From XFile to XFile Dto ... + /// + /// + /// + public static XFileDto ToXFileDto(this XFile source) + { + // + XFileDto result = null; + + // + if (!source.IsNullOrDefault()) + { + // + result = new XFileDto(); + result = result.UpdateData(source); + + // + // result = new XFileDto + // { + // Id = source.Id, + // Type = source.Type, + // OwnerId = source.OwnerId, + // Name = source.Name, + // Path = source.Path, + // Thumb = source.Thumb, + // ThumbPath = source.ThumbPath, + // UploadedOn = source.UploadedOn, + // FileName = source.FileName + // }; + } + + // + return result; + } + } +} \ No newline at end of file diff --git a/Hubs/XFileEntityHub.cs b/Hubs/XFileEntityHub.cs new file mode 100644 index 0000000..2b0e4ed --- /dev/null +++ b/Hubs/XFileEntityHub.cs @@ -0,0 +1,16 @@ +using System; +using Microsoft.Extensions.Logging; +using xFileService.Models.Entities; +using xPushService.Base; + +namespace xFileService.Hubs +{ + public class XFileEntityHub : XBaseEntityHub + { + // + #region Constructor ... + public XFileEntityHub(ILogger logger) : base(logger) + { } + #endregion + } +} \ No newline at end of file diff --git a/Interfaces/IXFileProvider.cs b/Interfaces/IXFileProvider.cs new file mode 100644 index 0000000..d6fe1b5 --- /dev/null +++ b/Interfaces/IXFileProvider.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; +using xDataService.Configuration; +using xFileService.Hubs; +using xFileService.Interfaces.Entities; +using xFileService.Models.Dtos; +using xFileService.Models.Entities; +using xIdentityModels.Models; +using xIdentityService.Interfaces; +using xModels.Dtos; +using xStorageService.Interfaces; +using XFileDto = xFileService.Models.Dtos.XFileDto; + +namespace xFileService.Interfaces +{ + public interface IXFileProvider + { + // + #region Props ... + IHubContext Hub { get; } + IXFileRepository FileRepository { get; } + IXStorageProvider StorageProvider { get; } + IXIdentityProvider IdentityProvider { get; } + XDataServiceConfiguration DataSercviceConfiguration { get; } + #endregion + + // + #region Tools ... + /// + /// Stream Specified File ... + /// + /// + /// + Task Stream(Guid id); + + /// + /// Stream Specified File ... + /// + /// + /// + Task Stream(string fileName); + + /// + /// Download Specified File ... + /// + /// + /// + Task Download(Guid id); + + /// + /// Download Specified File ... + /// + /// + /// + Task Download(string fileName); + + /// + /// Upload Files ... + /// + /// + /// + /// + Task> Upload( + IFormFileCollection files, + XUserClaimsInfoDto userInfo = null + ); + + /// + /// Remove Specified Files ... + /// + /// + /// + /// + Task> Remove( + string ids, + XUserClaimsInfoDto userInfo = null + ); + + /// + /// Retrieve Specified File Streaming Info ... + /// + /// + /// + Task GetFileDescriptor(Guid id); + + /// + /// Retrieve Specified File Streaming Info ... + /// + /// + /// + Task GetFileDescriptor(string fileName); + #endregion + + // + #region Data Model ... + /// + /// Get Specified File Model ... + /// + /// + /// + /// + Task Get( + Guid id + ); + + /// + /// Get All Exists File Models ... + /// + /// + /// + Task> GetAll(); + + /// + /// find an Entity by providing a Conditional Expression ... + /// + /// + Task FindOne(Expression> whereClause); + + /// + /// find a collection of Entities by proving a Conditional Expression ... + /// + /// + /// + Task> FindMany( + Expression> whereClause + ); + + /// + /// retrieve Entities based on XQuery Pagination structure ... + /// + /// + /// + Task> Query( + XQuery query + ); + + /// + /// retrieve Entities based on XQuery Pagination structure by providing a Conditional Expression ... + /// + /// + /// + /// + Task> ConditionalQuery( + Expression> whereClause, + XQuery query + ); + + /// + /// Update an Entity values ... + /// + /// + /// + /// + /// + Task Update( + Guid id, + XFileDto item, + XUserClaimsInfoDto userInfo = null + ); + + /// + /// remove an Entity ... + /// + /// + /// + /// + Task Remove( + Guid id, + XUserClaimsInfoDto userInfo = null + ); + + /// + /// count all exists Entities ... + /// + /// + Task Count(); + + /// + /// Check an Entity exists or not ... + /// + /// + /// + Task IsExists( + Guid id + ); + #endregion + + // + #region Helpers ... + /// + /// Converts an Entity to Dto ... + /// + /// + /// + Task ToXFileDto(XFile model); + + /// + /// Convert a List of Entities to Dto ... + /// + /// + /// + Task> ToXDtoList(IEnumerable list); + + /// + /// Converts an Entity Query Result to Dto ... + /// + /// + /// + Task> ToXDtoQueryResult(XQueryResult queryResult); + #endregion + } +} \ No newline at end of file diff --git a/Providers/XFileProvider.cs b/Providers/XFileProvider.cs new file mode 100644 index 0000000..97ba421 --- /dev/null +++ b/Providers/XFileProvider.cs @@ -0,0 +1,967 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; +using xCommons.Extensions; +using xDataService.Configuration; +using xExceptions.Constants; +using xFileService.Extensions; +using xFileService.Hubs; +using xFileService.Interfaces; +using xFileService.Interfaces.Entities; +using xFileService.Models.Dtos; +using xFileService.Models.Entities; +using xIdentityModels.Models; +using xIdentityService.Interfaces; +using xModels.Dtos; +using xIdentityService.Extensions; +using XFileDto = xFileService.Models.Dtos.XFileDto; +using xStorageService.Interfaces; +using System.IO; +using Microsoft.Extensions.FileProviders; +using Microsoft.AspNetCore.StaticFiles; +using System.Linq; + +namespace xFileService.Providers +{ + public class XFileProvider : IXFileProvider + { + // + #region Props ... + public IHubContext Hub { get; } + public IXFileRepository FileRepository { get; } + public IXStorageProvider StorageProvider { get; } + public IXIdentityProvider IdentityProvider { get; } + public XDataServiceConfiguration DataSercviceConfiguration { get; } + #endregion + + // + #region Constructor ... + public XFileProvider( + IXFileRepository fileRepository, + IXStorageProvider storageProvider, + IXIdentityProvider identityProvider, + XDataServiceConfiguration dataSercviceConfiguration, + IHubContext hub = null + ) + { + // + Hub = hub; + FileRepository = fileRepository; + StorageProvider = storageProvider; + IdentityProvider = identityProvider; + DataSercviceConfiguration = dataSercviceConfiguration; + } + #endregion + + // + #region Tools ... + /// + /// Stream Specified File ... + /// + /// + /// + public async Task Stream(Guid id) + { + // + // Validate Args ... + var isValid = !id.IsNull() && + !id.IsDefaultGuid(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Generate Stream Info and Validate it ... + var stream = await GetFileDescriptor(id); + if (stream.IsNull()) + { + XException.NotFound.Throw(); + } + + // + // Generate Result Model ... + var result = new FileStreamResult( + stream.Stream, + stream.MIMEType + ) + { + FileDownloadName = stream.Name + }; + + // + return result; + } + + /// + /// Stream Specified File ... + /// + /// + /// + public async Task Stream(string fileName) + { + // + // Validate Args ... + var isValid = !fileName.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Generate Stream Info and Validate it ... + var stream = await GetFileDescriptor(fileName); + if (stream.IsNull()) + { + XException.NotFound.Throw(); + } + + // + // Generate Result Model ... + var result = new FileStreamResult( + stream.Stream, + stream.MIMEType + ) + { + FileDownloadName = stream.Name + }; + + // + return result; + } + + /// + /// Download Specified File ... + /// + /// + /// + public async Task Download(Guid id) + { + // + // Validate Args ... + var isValid = !id.IsNull() && + !id.IsDefaultGuid(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Generate Stream Info and Validate it ... + var stream = await GetFileDescriptor(id); + if (stream.IsNull()) + { + XException.NotFound.Throw(); + } + + // + // Generate Result Model ... + var result = new PhysicalFileResult( + stream.Path, + stream.MIMEType + ) + { + FileDownloadName = stream.Name + }; + + // + return result; + } + + /// + /// Download Specified File ... + /// + /// + /// + public async Task Download(string fileName) + { + // + // Validate Args ... + var isValid = !fileName.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Generate Stream Info and Validate it ... + var stream = await GetFileDescriptor(fileName); + if (stream.IsNull()) + { + XException.NotFound.Throw(); + } + + // + // Generate Result Model ... + var result = new PhysicalFileResult( + stream.Path, + stream.MIMEType + ) + { + FileDownloadName = stream.Name + }; + + // + return result; + } + + /// + /// Upload Files ... + /// + /// + /// + /// + public async Task> Upload( + IFormFileCollection files, + XUserClaimsInfoDto userInfo = null + ) + { + // + // Validate Args ... + var isValid = !files.IsNull() && + files.HasChild() && + !userInfo.IsNullOrDefault(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Save Files On Server Side Physically ... + // and Validate it ... + var uploadResults = await StorageProvider.HandleFilesSave(files); + isValid = uploadResults.HasChild(); + if (!isValid) + { + XException.ActionFailed.Throw(); + } + + // + // Prepare Result ... + var entities = new List(); + foreach (var ur in uploadResults) + { + // + var fileType = StorageProvider.GetFileType(ur.FileName); + + // + // Create Entity Model ... + var entity = new XFile + { + Type = fileType, + FileName = ur.Name, + Name = ur.FileName, + Path = ur.FilePath, + Thumb = ur.Thmbnail, + OwnerId = userInfo.UserId, + ThumbPath = ur.ThmbnailPath, + UploadedOn = DateTime.UtcNow, + }; + + // + try + { + // + // Add Entity Model to DB ... + entity = await FileRepository.AddAsync(entity); + + // + if (!entity.IsNullOrDefault()) + { + entities.Add(entity); + } + } + catch { } + } + + // + // Preparing Result ... + var result = await ToXDtoList(entities); + + // + return result; + } + + /// + /// Remove Specified Files ... + /// + /// + /// + public async Task> Remove( + string ids, + XUserClaimsInfoDto userInfo = null + ) + { + // + // Validate Args ... + var isValid = !ids.IsNullOrEmpty() && + !userInfo.IsNullOrDefault(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Parse ID(s) List ... + var idsList = ids.ParseListGuid(); + isValid = !idsList.IsNull() && + idsList.HasChild(); + if (!isValid) + { + XException.ActionFailed.Throw(); + } + + // + // Loop Through Parsed Ids and Try to Remove ... + var result = new List(); + foreach (var id in idsList) + { + // + // Retrieve XFileDto and Validate it ... + var model = await Get(id); + isValid = !model.IsNull() && !model.Id.IsNull() && !model.Id.IsDefaultGuid(); + if (!isValid) + { + continue; + } + + // + // Check Physical File Exists or not ... + var fileFullPath = StorageProvider.GetFileFullPath(model.Name); + var thumbFullPath = model.Thumb.IsNullOrEmpty() + ? "" + : StorageProvider.GetThumbnailFileFullPath(model.Thumb); + var isFileExists = StorageProvider.IsFileExists(fileFullPath); + var isThumbExists = model.Thumb.IsNullOrEmpty() + ? false + : StorageProvider.IsFileExists(thumbFullPath); + + // + // Remove Physical Thumbnail File ... + if (isThumbExists) + { + // + try + { + // + StorageProvider.DeleteFile( + fileFullPath: thumbFullPath, + forceFileExists: false + ); + } + catch { } + } + + // + // Remove Pgysical File ... + if (isFileExists) + { + // + try + { + // + StorageProvider.DeleteFile( + fileFullPath: fileFullPath, + forceFileExists: false + ); + } + catch { } + } + + // + // Remove File Entty ... + await FileRepository.RemoveAsync(model.Id); + result.Add(model.Id); + } + + // + return result; + } + + /// + /// Retrieve Specified File Streaming Info ... + /// + /// + /// + public async Task GetFileDescriptor(Guid id) + { + // + // Check File Model Exists or not ... + var isExists = await IsExists( + id: id + ); + if (!isExists) + { + XException.NotFound.Throw(); + } + + // + // Retrieve Entity and Validate it ... + var entity = await Get( + id: id + ); + if (entity.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Generate Physical File Path and Validate it ... + var fileFullPath = StorageProvider.GetFileFullPath(entity.Name); + isExists = StorageProvider.IsFileExists(fileFullPath); + var filePath = StorageProvider.FilePathResolver(fileFullPath); + filePath = Path.Combine("wwwroot", filePath); + if (!isExists) + { + XException.NotFound.Throw(); + } + + // + // Generate Physical File Info ... + IFileInfo fileInfo = StorageProvider.FileProvider.GetFileInfo(filePath); + + // + // Prepare Default Streaming Requirements ... + var mimeType = "application/octetstream"; + var readStream = fileInfo.CreateReadStream(); + var fileMimeProvider = new FileExtensionContentTypeProvider(); + var fileName = entity.Name; + + // + // Try to Find Physical File's Content Type ... + fileMimeProvider.TryGetContentType(filePath, out mimeType); + + // + // Prepare Result Model ... + var result = new XFileStreamDescriptorDto + { + Stream = readStream, + MIMEType = mimeType, + Name = fileName, + Path = fileFullPath + }; + + // + return result; + } + + /// + /// Retrieve Specified File Streaming Info ... + /// + /// + /// + public async Task GetFileDescriptor(string fileName) + { + // + if (fileName.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + var entity = await FindOne(e => + e.Name.Contains(fileName) || + e.Path.Contains(fileName) || + e.Thumb.Contains(fileName) || + e.FileName.Contains(fileName) || + e.ThumbPath.Contains(fileName) + ); + var isExists = !entity.IsNullOrDefault(); + if (!isExists) + { + XException.NotFound.Throw(); + } + + // + // Extract File Name ... + fileName = Path.GetFileName(fileName); + + // + // Check File is Thumbnail or File ... + var isThumb = fileName.StartsWith(StorageProvider.Configuration.ThumbPrefix); + var isFile = fileName.StartsWith(StorageProvider.Configuration.FilePrefix); + + // + // Check File Type is Valid ... + isExists = isThumb || isFile; + if (!isExists) + { + XException.UnsupportedFileType.Throw(); + } + + // + // Extract File Full Path ... + var fileFullPath = ""; + if (isThumb) + { + fileFullPath = StorageProvider.GetThumbnailFileFullPath(fileName); + } + else + { + fileFullPath = StorageProvider.GetFileFullPath(fileName); + } + + // + // Check Physical File Exists or Not ... + isExists = StorageProvider.IsFileExists(fileFullPath); + if (!isExists) + { + XException.NotFound.Throw(); + } + + // + // Generate Physical File Info ... + var filePath = StorageProvider.FilePathResolver(fileFullPath); + filePath = Path.Combine("wwwroot", filePath); + IFileInfo fileInfo = StorageProvider.FileProvider.GetFileInfo(filePath); + + // + // Prepare Default Streaming Requirements ... + var mimeType = "application/octetstream"; + var readStream = fileInfo.CreateReadStream(); + var fileMimeProvider = new FileExtensionContentTypeProvider(); + + // + // Try to Find Physical File's Content Type ... + fileMimeProvider.TryGetContentType(filePath, out mimeType); + + // + // Prepare Result Model ... + var result = new XFileStreamDescriptorDto + { + Stream = readStream, + MIMEType = mimeType, + Name = fileName, + Path = fileFullPath + }; + + // + return result; + } + #endregion + + // + #region Data Model ... + /// + /// Get Specified File Model ... + /// + /// + /// + /// + public async Task Get( + Guid id + ) + { + // + // Validate ... + if (id.IsNull() || id.IsDefaultGuid()) + { + XException.InvalidArgs.Throw(); + } + + // + var entitiy = await FileRepository.GetAsync(id); + if (entitiy.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + var result = await ToXFileDto(entitiy); + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + /// + /// Get All Exists File Models ... + /// + /// + /// + public async Task> GetAll() + { + // + var result = new List(); + + // + var entities = await FileRepository.GetAllAsync(); + if (!entities.IsNull() && entities.HasChild()) + { + // + result = (await ToXDtoList(entities)) + .ToList(); + } + + // + return result; + } + + /// + /// find an Entity by providing a Conditional Expression ... + /// + /// + public async Task FindOne(Expression> whereClause) + { + // + var result = new XFileDto(); + + // + var entity = await FileRepository.FindOneAsync(whereClause); + if (!entity.IsNullOrDefault()) + { + result = await ToXFileDto(entity); + } + + // + return result; + } + + /// + /// find a collection of Entities by proving a Conditional Expression ... + /// + /// + /// + public async Task> FindMany( + Expression> whereClause + ) + { + // + var result = new List(); + + // + var entities = await FileRepository.FindManyAsync(whereClause); + if (!entities.IsNull() && entities.HasChild()) + { + // + result = (await ToXDtoList(entities)) + .ToList(); + } + + // + return result; + } + + /// + /// retrieve Entities based on XQuery Pagination structure ... + /// + /// + /// + public async Task> Query( + XQuery query + ) + { + // + var result = new XQueryResult(); + + // + var queryResult = await FileRepository.QueryAsync(query); + if (!queryResult.IsNullOrDefault()) + { + result = await ToXDtoQueryResult(queryResult); + } + + // + return result; + } + + /// + /// retrieve Entities based on XQuery Pagination structure by providing a Conditional Expression ... + /// + /// + /// + /// + public async Task> ConditionalQuery( + Expression> whereClause, + XQuery query + ) + { + // + var result = new XQueryResult(); + + // + var queryResult = await FileRepository.ConditionalQueryAsync( + query: query, + whereClause: whereClause + ); + if (!queryResult.IsNullOrDefault()) + { + result = await ToXDtoQueryResult(queryResult); + } + + // + return result; + } + + /// + /// Update an Entity values ... + /// + /// + /// + /// + /// + public async Task Update( + Guid id, + XFileDto item, + XUserClaimsInfoDto userInfo = null + ) + { + // + // Validate ... + bool isValid = !id.IsNull() && + !id.IsDefaultGuid() && + !item.IsNullOrDefault() && + !userInfo.IsNullOrDefault(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Entitiy Exists and Retrieve it ... + isValid = await IsExists(id); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var entity = await FileRepository.GetAsync(id); + if (entity.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Fill Data for Update ... + entity = entity.UpdateData( + updateWith: item, + propertyBlackList: new List + { + nameof(XFile.Id), + nameof(XFile.Deleted), + nameof(XFileDto.Owner) + } + ); + if (entity.IsNullOrDefault()) + { + XException.InvalidData.Throw(); + } + + // + entity = await FileRepository.UpdateAsync(id, entity); + if (entity.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + // Validate Action ... + isValid = + entity.OwnerId == userInfo.UserId || + userInfo.Roles.Any(r => r.ToNormalString() == "admin".ToNormalString()); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + var result = await ToXFileDto(entity); + + // + return result; + } + + /// + /// remove an Entity ... + /// + /// + /// + /// + public async Task Remove( + Guid id, + XUserClaimsInfoDto userInfo = null + ) + { + // + // Validate ... + var isValid = !id.IsNull() && + !id.IsDefaultGuid() && + !userInfo.IsNullOrDefault(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Entity Exists and Retrieve it ... + isValid = await IsExists(id); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var result = await Get(id); + isValid = !result.IsNullOrDefault(); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + // Validate Action ... + isValid = + result.OwnerId == userInfo.UserId || + userInfo.Roles.Any(r => r.ToNormalString() == "admin".ToNormalString()); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + var entitiy = await FileRepository.RemoveAsync(id); + if (entitiy.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + result = await ToXFileDto(entitiy); + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + /// + /// count all exists Entities ... + /// + /// + public async Task Count() + { + return await FileRepository.CountAsync(); + } + + /// + /// Check an Entity exists or not ... + /// + /// + /// + public async Task IsExists( + Guid id + ) + { + return await FileRepository.IsExistsAsync(id); + } + #endregion + + // + #region Helpers ... + /// + /// Converts an Entity to Dto ... + /// + /// + /// + public async Task ToXFileDto(XFile model) + { + // + XFileDto result = null; + + // + if (!model.IsNullOrDefault()) + { + // + result = model.ToXFileDto(); + + // + // Prepare Inner API Providers Device Dto ... + var device = IdentityProvider.GetDevice(); + var userInfo = await IdentityProvider.GetUserInfo( + device: device, + userSelectByParam: model.OwnerId + ); + if (userInfo.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + result.Owner = userInfo.ToXPersonDto(); + } + + // + return result; + } + + /// + /// Convert a List of Entities to Dto ... + /// + /// + /// + public async Task> ToXDtoList(IEnumerable list) + { + // + var result = new List(); + + // + if (!list.IsNull() && list.HasChild()) + { + // + foreach (var item in list) + { + // + var dto = await ToXFileDto(item); + if (!dto.IsNullOrDefault()) + { + result.Add(dto); + } + } + } + + // + return result; + } + + /// + /// Converts an Entity Query Result to Dto ... + /// + /// + /// + public async Task> ToXDtoQueryResult(XQueryResult queryResult) + { + // + var result = new XQueryResult(); + + // + if (!queryResult.IsNullOrDefault()) + { + // + result.Page = queryResult.Page; + result.PageSize = queryResult.PageSize; + result.TotalItems = queryResult.TotalItems; + result.TotalPages = queryResult.TotalPages; + result.TotalFilteredItems = queryResult.TotalFilteredItems; + result.TotalFilteredPages = queryResult.TotalFilteredPages; + + // + if (!queryResult.Items.IsNull() && queryResult.Items.HasChild()) + { + result.Items = await ToXDtoList(queryResult.Items); + } + } + + // + return result; + } + #endregion + } +} \ No newline at end of file