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 } }