using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using xCommons.Extensions; using xDataService.Extensions; using xDataService.Models; using xExceptions.Constants; using xFileService.Interfaces; using xFileService.Models.Dtos; using xFileService.Models.Entities; using xIdentityModels.Models; using xModels.Dtos; using XFileDto = xFileService.Models.Dtos.XFileDto; namespace xFileService.Providers { public abstract class XBaseFileProvider : IXBaseFileProvider { // #region Props ... /// /// Provider Identifier ... /// public string Provider { get; } /// /// Tag Provider for Maipulating Tags ... /// public IXFileProvider FileProvider { get; } #endregion // #region Constructor ... public XBaseFileProvider( string providedFor, IXFileProvider fileProvider ) { // Provider = providedFor; FileProvider = fileProvider; } #endregion // #region Identifier ... public async Task LastIndex(TKey providedForId) { return await Task.FromResult(GetLastIndex(providedForId)); } #endregion // #region Tools ... /// /// Stream Specified File ... /// /// /// public async Task Stream(Guid id) { // // Check Validation and Owning ... var isValid = await IsOwned(id); if (!isValid) { XException.NotAllowed.Throw(); } // var result = await FileProvider.Stream(id); return result; } /// /// Stream Specified File ... /// /// /// public async Task Stream(string fileName) { // // Validate ... var isValid = !fileName.IsNullOrEmpty(); if (!isValid) { XException.InvalidArgs.Throw(); } // // Retrieve Dto and also Checking Owned ... var dto = await GetDto(fileName); isValid = !dto.IsNullOrDefault(); if (!isValid) { XException.NotAllowed.Throw(); } // var result = await FileProvider.Stream(fileName); return result; } /// /// Download Specified File ... /// /// /// public async Task Download(Guid id) { // // Validate ... var isValid = await IsOwned(id); if (!isValid) { XException.NotAllowed.Throw(); } // var result = await FileProvider.Download(id); return result; } /// /// Download Specified File ... /// /// /// public async Task Download(string fileName) { // // Validate ... var isValid = !fileName.IsNullOrEmpty(); if (!isValid) { XException.InvalidArgs.Throw(); } // // Retrieve Dto and also Checking Owned ... var dto = await GetDto(fileName); isValid = !dto.IsNullOrDefault(); if (!isValid) { XException.NotAllowed.Throw(); } // var result = await FileProvider.Download(fileName); return result; } /// /// Upload Files ... /// /// /// /// /// /// public async Task> Upload( TKey providedForId, IFormFileCollection files, string connectionId = null, XUserClaimsInfoDto userInfo = null ) { // // Validate ... var isValid = !providedForId.IsNull(); if (!isValid) { XException.InvalidArgs.Throw(); } // // Here we are Following Custom Senario ... var dtos = await FileProvider.Upload( files: files, userInfo: userInfo, connectionId: connectionId ); // // Validate Dtos ... isValid = !dtos.IsNull() && dtos.HasChild(); if (isValid) { // // Preparing Index ... int index = GetLastIndex(providedForId); if (index >= 0) { index++; } // var isReferenced = false; foreach (var dto in dtos) { // // Try to Add Reference to Specified DTO ... isReferenced = await AddReference( model: dto, forIndex: index, userInfo: userInfo, connectionId: connectionId, providedForId: providedForId ); if (isReferenced) { index++; } } } // var result = new List(); // isValid = !dtos.IsNull() && dtos.HasChild(); if (isValid) { // foreach (var dto in dtos) { // var idto = await FileProvider.Get(dto.Id); isValid = !idto.IsNullOrDefault() && await IsOwned(idto.Id); if (isValid) { result.Add(idto); } } } // return result; } /// /// Remove Specified Files ... /// /// /// if null, Remove all Files /// /// /// public async Task> RemoveFiles( TKey providedForId, string ids = null, string connectionId = null, XUserClaimsInfoDto userInfo = null ) { // // Validate ... if (providedForId.IsNull()) { XException.InvalidArgs.Throw(); } // // Parse Provided IDS ... var idsList = new List(); IEnumerable entities = null; if (!ids.IsNullOrEmpty()) { // idsList = ids .ParseListGuid() .ToList(); } else { // var identifier = GetProvidedID(providedForId); // // Select All Referenced Files ... idsList = FileProvider.FileRepository .AsQueryable() .Where(f => f.References.Contains(identifier)) .Select(f => f.Id) .ToList(); } // // Retrieve Entities ... entities = FileProvider.FileRepository .AsQueryable() .Where(d => idsList.Contains(d.Id) && d.References.Contains(Provider)); // var result = new List(); var isValid = !entities.IsNull() && entities.HasChild(); if (isValid) { // foreach (var entity in entities) { // // Remove File ... var idsToRemove = new List { entity.Id.ToString() }.ToListString(); var removeIds = await FileProvider.Remove( ids: idsToRemove, userInfo: userInfo, connectionId: connectionId ); isValid = !removeIds.IsNull() && removeIds.HasChild() && removeIds.Contains(entity.Id); if (isValid) { result.Add(entity.Id); } } } // return result; } /// /// Retrieve Specified File Streaming Info ... /// /// /// public async Task GetFileDescriptor(Guid id) { // // Validate ... var isValid = !id.IsNull() && !id.IsDefaultGuid(); if (!isValid) { XException.InvalidArgs.Throw(); } // // Check Owned ... isValid = await IsOwned(id); if (!isValid) { XException.NotAllowed.Throw(); } // var result = await FileProvider.GetFileDescriptor(id); return result; } /// /// Retrieve Specified File Streaming Info ... /// /// /// public async Task GetFileDescriptor(string fileName) { // // Validate ... var isValid = !fileName.IsNullOrEmpty(); if (!isValid) { XException.InvalidArgs.Throw(); } // // Check Owned ... var dto = GetDto(fileName); isValid = !dto.IsNullOrDefault(); if (!isValid) { XException.NotAllowed.Throw(); } // var result = await FileProvider.GetFileDescriptor(fileName); return result; } #endregion // #region Referenced Actions ... /// /// Get Specified Indexed Reference for Specific Provided ID ... /// /// /// /// public async Task GetReference( TKey providedForId, int forIndex = 0 ) { // // Validate ... if (providedForId.IsNull()) { XException.InvalidArgs.Throw(); } // // Normalize ... if (forIndex < 0) { forIndex = 0; } // // Retrieve Last Index ... var lastIndex = GetLastIndex(providedForId); if (forIndex > lastIndex) { XException.NotFound.Throw(); } // var indexedIdentifier = GetIndexedProvidedID( forIndex: forIndex, providedForId: providedForId ); var entity = FileProvider.FileRepository .AsQueryable() .Where(t => t.References.Contains(indexedIdentifier)) .FirstOrDefault(); if (entity.IsNullOrDefault()) { XException.NotFound.Throw(); } // var result = await FileProvider.ToDto(entity); return result; } /// /// Retrieve all Exists References of Specific Provided ID ... /// /// /// public async Task> GetAllReferences(TKey providedForId) { // // Validate ... if (providedForId.IsNull()) { XException.InvalidArgs.Throw(); } // var identifier = GetProvidedID(providedForId); var entities = FileProvider.FileRepository .AsQueryable() .Where(t => t.References.Contains(identifier)) .AsEnumerable(); // var dtos = new List(); foreach (var entity in entities) { // var dto = await FileProvider.ToDto(entity); if (!dto.IsNullOrDefault()) { dtos.Add(dto); } } // List result = dtos; if (dtos.HasChild()) { // // Sorting Result Based on Indexes ... var lastIndex = GetLastIndex(providedForId); if (lastIndex > 0) { // result.Clear(); for (int i = 0; i <= lastIndex; i++) { // var dto = dtos .FirstOrDefault(d => d.References .Any(dr => dr.Index == i && dr.ReferencedTo == $"{providedForId}")); if (!dto.IsNullOrDefault()) { result.Add(dto); } } } } // return await Task.FromResult(result); } /// /// Retrieve References of Specific Provided ID as Query ... /// /// /// public async Task> QueryReferences( XQuery query, TKey providedForId ) { // // Validate ... if (query.IsNull() || providedForId.IsNull()) { XException.InvalidArgs.Throw(); } // // Normalize ... query = query.NormalizeQuery(FileProvider.DataSercviceConfiguration); // var items = await GetAllReferences(providedForId); var totalItemsCount = items.Count(); // // Apply Filter ... if (!query.Filter.IsNullOrEmpty()) { // items = items .ApplyFilter(query.Filter); } int filteredItemsCount = items.Count(); // // Count Pages ... var totalPagesCount = query.CountPages(totalItemsCount); var filteredPagesCount = query.CountPages(filteredItemsCount); // // Apply Paging and Sorting ... if (totalItemsCount > 0 && filteredItemsCount > 0) { // // Apply Sorting ... items = items .ToList() .ApplySorting( query.SortBy, query.IsAscending ); // // Apply Paging ... items = items .ToList() .ApplyPaging( query.Page, query.PageSize ); } // // Prepare Result ... var result = new XQueryResult { Page = query.Page, Items = items.ToList(), PageSize = query.PageSize, TotalPages = totalPagesCount, TotalItems = totalItemsCount, TotalFilteredPages = filteredPagesCount, TotalFilteredItems = filteredItemsCount }; // return result; } /// /// Add Reference a Model to Specific Provided ID ... /// /// /// /// /// /// /// public async Task AddReference( XFileDto model, TKey providedForId, int forIndex = 0, string connectionId = null, XUserClaimsInfoDto userInfo = null ) { // var result = false; // // Validate ... var isValid = !model.IsNullOrDefault() && !model.Name.IsNullOrEmpty() && !model.Id.IsNull() && !model.Id.IsDefaultGuid() && !providedForId.IsNull(); if (!isValid) { XException.InvalidArgs.Throw(); } // // Check Model Exists ... isValid = await FileProvider.IsExists(model.Id); if (!isValid) { XException.NotFound.Throw(); } // // Update Model by Retrieving ... model = await FileProvider.Get(model.Id); // var lastIndex = GetLastIndex(providedForId); if (lastIndex == -1) { // // This Means there isnot any Reference ... forIndex = 0; model.References.Add(new XReference { Index = forIndex, ProvidedFor = Provider, ReferencedTo = $"{providedForId}" }); } else { // forIndex = lastIndex + 1; // // Add New Reference ... model.References.Add(new XReference { Index = forIndex, ProvidedFor = Provider, ReferencedTo = $"{providedForId}" }); } // // Update Data Base ... model = await FileProvider .Update( item: model, id: model.Id, userInfo: userInfo, connectionId: connectionId ); result = !model.IsNullOrDefault(); // return result; } /// /// Add Reference a Model to Specific XRefence ... /// /// /// /// /// /// public async Task AddReference( XFileDto model, XReference reference, string connectionId = null, XUserClaimsInfoDto userInfo = null ) { // // Validate ... // Since other Validations Handled in Calling, we Ignore them here ... if (model.IsNull() || reference.IsNullOrDefault() || (!reference.ProvidedFor.IsNullOrEmpty() && reference.ProvidedFor != Provider)) { XException.InvalidArgs.Throw(); } // var result = await AddReference( model: model, userInfo: userInfo, connectionId: connectionId, providedForId: reference.ReferencedTo ); // return result; } /// /// Remove Reference a Model for Specific Provided ID ... /// /// /// /// if null, removes all /// /// /// public async Task RemoveReference( XFileDto model, TKey providedForId, int? forIndex = null, string connectionId = null, XUserClaimsInfoDto userInfo = null ) { // // Validate ... if (model.IsNull() || providedForId.IsNull() || model.Id.IsNull() || model.Id.IsDefaultGuid()) { XException.InvalidArgs.Throw(); } // // Retrieve Model ... model = await FileProvider.Get(model.Id); if (model.IsNullOrDefault()) { XException.NotFound.Throw(); } // // Check Model Reference to ID ... var isReferenced = model.References .Any(r => r.ProvidedFor == Provider && r.ReferencedTo == $"{providedForId}" && (!forIndex.HasValue || r.Index == forIndex.Value)); // var result = false; if (isReferenced) { // model.References = model.References .Where(r => r.ProvidedFor != Provider || (r.ProvidedFor == Provider && r.ReferencedTo != $"{providedForId}" && (!forIndex.HasValue || r.Index == forIndex.Value))) .ToList(); // model = await FileProvider.Update( item: model, id: model.Id, userInfo: userInfo, connectionId: connectionId ); result = !model.IsNullOrDefault(); } // return result; } /// /// Remove Reference a Model for Specific XRefence ... /// /// /// /// /// /// public async Task RemoveReference( XFileDto model, XReference reference, string connectionId = null, XUserClaimsInfoDto userInfo = null ) { // if (model.IsNullOrDefault() || reference.IsNullOrDefault() || reference.ReferencedTo.IsNull() || reference.ProvidedFor != Provider) { XException.InvalidArgs.Throw(); } // var result = await RemoveReference( model: model, userInfo: userInfo, forIndex: reference.Index, connectionId: connectionId, providedForId: reference.ReferencedTo ); // return result; } /// /// Remove All References to Specified Key ... /// /// /// /// /// public async Task RemoveReferences( TKey providedForId, string connectionId = null, XUserClaimsInfoDto userInfo = null ) { // // Validate ... if (providedForId.IsNull()) { XException.InvalidArgs.Throw(); } // var result = false; var references = await GetAllReferences(providedForId); if (!references.IsNull() && references.HasChild()) { // foreach (var reference in references) { // // Remove Reference ... reference.References = reference.References .Where(r => r.ProvidedFor != Provider || (r.ProvidedFor == Provider && r.ReferencedTo != $"{providedForId}")) .ToList(); var updatedModel = await FileProvider.Update( item: reference, id: reference.Id, userInfo: userInfo, connectionId: connectionId ); if (!updatedModel.IsNullOrDefault()) { result = true; } } } // return result; } #endregion // #region Private ... private string GetProvidedID( TKey providedForId, char splitter = '_' ) { // // Validate ... if (providedForId.IsNull()) { XException.InvalidArgs.Throw(); } // var result = $"{Provider}{splitter}{providedForId}"; return result; } private string GetIndexedProvidedID( TKey providedForId, int forIndex, char splitter = '_' ) { // var result = $"{GetProvidedID(providedForId, splitter)}{splitter}{providedForId}"; // return result; } private int GetLastIndex(TKey providedForId) { // var result = -1; // // Validate ... var isValid = !providedForId.IsNull(); if (!isValid) { XException.InvalidArgs.Throw(); } // var identifier = GetProvidedID(providedForId); // var all = FileProvider.FileRepository .AsQueryable() .Where(t => t.References .Contains(identifier)) .Select(t => t.References) .AsEnumerable(); if (all.IsNull() || !all.HasChild()) { result = -1; } else { // var references = all .SelectMany(a => a.ParseXReferenceList()) .OrderByDescending(r => r.Index) .ToList(); if (!references.IsNull() && references.HasChild()) { result = references[0].Index; } else { result = -1; } } // return result; } /// /// Check Specified Dto is Has Reference to Provider ... /// /// /// private async Task IsOwned(Guid id) { // // Validate ... var result = !id.IsNull() && !id.IsDefaultGuid(); if (!result) { XException.InvalidArgs.Throw(); } // // Check Exists ... result = await FileProvider.IsExists(id); if (!result) { XException.NotFound.Throw(); } // // Retrieve Dto ... var dto = await FileProvider.Get(id); result = !dto.IsNullOrDefault(); if (!result) { XException.ActionFailed.Throw(); } // result = !dto.References.IsNull() && dto.References.HasChild() && dto.References.Any(r => r.ProvidedFor == Provider); // return result; } /// /// Get Specified Owned Dto by File Name ... /// /// /// private async Task GetDto(string fileName) { // XFileDto result = null; // if (!fileName.IsNullOrEmpty()) { // try { // result = await FileProvider.FindOne(d => d.Name == fileName || d.Thumb == fileName || d.FileName == fileName || d.Path.Contains(fileName) || d.ThumbPath.Contains(fileName) ); if (!result.IsNullOrDefault()) { // // Check Owning ... var isOwned = await IsOwned(result.Id); if (!isOwned) { result = null; } } } catch { } } // return result; } #endregion } }