From 0044643ac42d727778a3a0d4500bccedaa9ff43b Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Mon, 8 Dec 2025 17:27:10 +0330 Subject: [PATCH] Update for Better Supports ... --- Interfaces/IXBaseFileProvider.cs | 24 +- Interfaces/IXFileProvider.cs | 37 +- Providers/XBaseFileProvider.cs | 781 ++++++++++++++++++++++++++++++- Providers/XFileProvider.cs | 53 ++- Providers/XFileTagProvider.cs | 5 +- 5 files changed, 849 insertions(+), 51 deletions(-) diff --git a/Interfaces/IXBaseFileProvider.cs b/Interfaces/IXBaseFileProvider.cs index a88c7b7..139a782 100644 --- a/Interfaces/IXBaseFileProvider.cs +++ b/Interfaces/IXBaseFileProvider.cs @@ -22,18 +22,12 @@ namespace xFileService.Interfaces /// /// Specified Provider ... /// - string ProvideFor { get; } + string ProvidedFor { get; } /// /// Specified Provider Repositroy ... /// IXFileProvider Provider { get; } - - /// - /// Tag Provider for Specified File ... - /// - /// - IXBaseTagProvider TagProvider { get; } #endregion // @@ -47,7 +41,7 @@ namespace xFileService.Interfaces #endregion // - #region Implementation ... + #region Tools ... /// /// Stream Specified File ... /// @@ -60,7 +54,7 @@ namespace xFileService.Interfaces /// /// /// - Task Stream(string fileName); + Task Stream(string fileName); /// @@ -80,10 +74,12 @@ namespace xFileService.Interfaces /// /// Upload Files ... /// + /// /// /// /// Task> Upload( + TKey forProvidedId, IFormFileCollection files, XUserClaimsInfoDto userInfo = null ); @@ -91,10 +87,12 @@ namespace xFileService.Interfaces /// /// Remove Specified Files ... /// + /// /// /// /// Task> Remove( + TKey forProvidedId, string ids, XUserClaimsInfoDto userInfo = null ); @@ -120,7 +118,6 @@ namespace xFileService.Interfaces /// Get Specified File Model ... /// /// - /// /// Task Get( Guid id @@ -133,6 +130,13 @@ namespace xFileService.Interfaces /// Task> GetAll(); + /// + /// Get All Exists File Models ... + /// + /// + /// + Task> GetAllFor(TKey forProvidedId); + /// /// find an Entity by providing a Conditional Expression ... /// diff --git a/Interfaces/IXFileProvider.cs b/Interfaces/IXFileProvider.cs index 8d279ac..c5f8757 100644 --- a/Interfaces/IXFileProvider.cs +++ b/Interfaces/IXFileProvider.cs @@ -64,7 +64,7 @@ namespace xFileService.Interfaces /// /// Task TagAttach( - string tag, + string tag, Guid id, XUserClaimsInfoDto userInfo = null ); @@ -77,7 +77,7 @@ namespace xFileService.Interfaces /// /// Task TagDetach( - string tag, + string tag, Guid id, XUserClaimsInfoDto userInfo = null ); @@ -90,7 +90,7 @@ namespace xFileService.Interfaces /// /// Task TagsAttach( - IEnumerable tags, + IEnumerable tags, Guid id, XUserClaimsInfoDto userInfo = null ); @@ -103,11 +103,11 @@ namespace xFileService.Interfaces /// /// Task TagsDetach( - IEnumerable tags, + IEnumerable tags, Guid id, XUserClaimsInfoDto userInfo = null ); - + /// /// Detach all Attached Tags for Specified File ... /// @@ -193,20 +193,23 @@ namespace xFileService.Interfaces /// Get Reference Identifier for Specified Provider and Specified File ... /// /// - /// + /// /// - string GetIdentifier( - string providedFor, - Guid id + string GetIdentifier( + string providedFor, + TKey forProvidedId ); /// /// Check Specified File has Refernce to Provider ... /// /// + /// + /// /// - Task IsProvidedFor( - string providedFor, + Task IsProvidedFor( + string providedFor, + TKey forProvidedId, Guid id ); @@ -214,11 +217,13 @@ namespace xFileService.Interfaces /// Add Specified Reference to Specified File ... /// /// + /// /// /// /// - Task AddReference( - string providedFor, + Task AddReference( + string providedFor, + TKey forProvidedId, Guid id, XUserClaimsInfoDto userInfo = null ); @@ -227,11 +232,13 @@ namespace xFileService.Interfaces /// Remove Specified Reference from Specified File ... /// /// + /// /// /// /// - Task RemoveReference( - string providedFor, + Task RemoveReference( + string providedFor, + TKey forProvidedId, Guid id, XUserClaimsInfoDto userInfo = null ); diff --git a/Providers/XBaseFileProvider.cs b/Providers/XBaseFileProvider.cs index 0b2bfd2..777826b 100644 --- a/Providers/XBaseFileProvider.cs +++ b/Providers/XBaseFileProvider.cs @@ -1,33 +1,794 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using xCommons.Extensions; +using xExceptions.Constants; using xFileService.Interfaces; -using xTagService.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 class XBaseFileProvider : IXBaseFileProvider + public abstract class XBaseFileProvider : IXBaseFileProvider { // #region Props ... /// /// Specified Provider ... /// - public string ProvideFor { get; } + public string ProvidedFor { get; } /// /// Specified Provider Repositroy ... /// public IXFileProvider Provider { get; } - - /// - /// Tag Provider for Specified File ... - /// - /// - public IXBaseTagProvider TagProvider { get; } #endregion - + // + #region Constructor ... + public XBaseFileProvider( + string providedFor, + IXFileProvider provider + ) + { + // + Provider = provider; + ProvidedFor = providedFor; + } + #endregion + + // + #region Helper ... + /// + /// Get Specified Identifier ... + /// + /// + /// + public string GetIdentifier(TKey forProvidedId) + { + // + return Provider.GetIdentifier( + providedFor: ProvidedFor, + forProvidedId: forProvidedId + ); + } + #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 Provider.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 Provider.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 Provider.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 Provider.Download(fileName); + return result; + } + + /// + /// Upload Files ... + /// + /// + /// + /// + /// + public async Task> Upload( + TKey forProvidedId, + IFormFileCollection files, + XUserClaimsInfoDto userInfo = null + ) + { + // + // Validate ... + var isValid = !forProvidedId.IsNull(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Here we are Following Custom Senario ... + var dtos = await Provider.Upload( + files: files, + userInfo: userInfo + ); + + // + // Validate Dtos ... + isValid = !dtos.IsNull() && dtos.HasChild(); + if (isValid) + { + // + foreach (var dto in dtos) + { + // + await AddReference( + id: dto.Id, + userInfo: userInfo, + forProvidedId: forProvidedId + ); + } + } + + // + var result = new List(); + + // + isValid = !dtos.IsNull() && dtos.HasChild(); + if (isValid) + { + // + foreach (var dto in dtos) + { + // + var idto = await Provider.Get(dto.Id); + isValid = !idto.IsNullOrDefault() && + await IsOwned(idto.Id); + if (isValid) + { + result.Add(idto); + } + } + } + + // + return result; + } + + /// + /// Remove Specified Files ... + /// + /// + /// + /// + /// + public async Task> Remove( + TKey forProvidedId, + string ids = null, + XUserClaimsInfoDto userInfo = null + ) + { + // + // Validate ... + var isValid = userInfo.IsNullOrDefault(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // if ids Provided, Find all id's Specified Dtos ... + // if not, gell all models which Owned and has Reference to forProvidedId ... + var dtos = await GetAll(); + if (!forProvidedId.IsNull()) + { + // + var identifier = GetIdentifier(forProvidedId); + dtos = dtos + .Where(e => e.References.Any(er => er.ToNormalString() == identifier.ToNormalString())); + } + + // + // Filter Provided IDS ... + if (!ids.IsNullOrEmpty()) + { + // + var idsList = ids.ParseListGuid(); + dtos = dtos.Where(d => !idsList.Contains(d.Id)); + } + + // + var result = new List(); + isValid = !dtos.IsNullOrDefault() && dtos.HasChild(); + if (isValid) + { + // + foreach (var dto in dtos) + { + // + var dtoIds = new List { dto.Id.ToString() }.ToListString(); + var removeIds = await Provider.Remove(dtoIds, userInfo); + isValid = !removeIds.IsNull() && removeIds.HasChild() && removeIds.Contains(dto.Id); + if (isValid) + { + result.Add(dto.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 Provider.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 Provider.GetFileDescriptor(fileName); + return result; + } + #endregion + + // + #region Data Model ... + /// + /// Get Specified File Model ... + /// + /// + /// + public async Task Get( + 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 Provider.Get(id); + return result; + } + + /// + /// Get All Exists File Models ... + /// + /// + public async Task> GetAll() + { + // + var result = await Provider + .FindMany(e => e.References.ToNormalString().Contains(ProvidedFor.ToNormalString())); + return result; + } + + /// + /// Get All Exists File Models ... + /// + /// + /// + public async Task> GetAllFor(TKey forProvidedId) + { + // + // Validate ... + if (forProvidedId.IsNull()) + { + XException.InvalidArgs.Throw(); + } + + // + var identifier = GetIdentifier(forProvidedId); + var result = await Provider + .FindMany(e => e.References.ToNormalString().Contains(identifier.ToNormalString())); + return result; + } + + /// + /// find an Entity by providing a Conditional Expression ... + /// + /// + public async Task FindOne(Expression> whereClause) + { + // + // Validate ... + if (whereClause.IsNull()) + { + XException.InvalidArgs.Throw(); + } + + // + var whereFunc = whereClause.Compile(); + var result = await Provider + .FindOne(e => whereFunc(e) && e.References.ToNormalString().Contains(ProvidedFor.ToNormalString())); + return result; + } + + /// + /// find a collection of Entities by proving a Conditional Expression ... + /// + /// + /// + public async Task> FindMany( + Expression> whereClause + ) + { + // + // Validate ... + if (whereClause.IsNull()) + { + XException.InvalidArgs.Throw(); + } + + // + var whereFunc = whereClause.Compile(); + var result = await Provider + .FindMany(e => whereFunc(e) && e.References.ToNormalString().Contains(ProvidedFor.ToNormalString())); + return result; + } + + /// + /// retrieve Entities based on XQuery Pagination structure ... + /// + /// + /// + public async Task> Query( + XQuery query + ) + { + // + // Define Owning Conditions ... + Expression> whereClause = e => e.References + .ToNormalString() + .Contains(ProvidedFor.ToNormalString()); + + // + var result = await Provider.ConditionalQuery( + query: query, + whereClause: whereClause + ); + return result; + } + + /// + /// retrieve Entities based on XQuery Pagination structure by providing a Conditional Expression ... + /// + /// + /// + /// + public async Task> ConditionalQuery( + Expression> whereClause, + XQuery query + ) + { + // + // Validate ... + if (whereClause.IsNull()) + { + XException.InvalidArgs.Throw(); + } + + // + // Prepare a Combination Where Condition ... + var whereFunc = whereClause.Compile(); + Expression> condition = e => whereFunc(e) && + e.References.ToNormalString().Contains(ProvidedFor.ToNormalString()); + + // + var result = await Provider.ConditionalQuery( + query: query, + whereClause: condition + ); + return result; + } + + /// + /// Update an Entity values ... + /// + /// + /// + /// + /// + public async Task Update( + Guid id, + XFileDto item, + XUserClaimsInfoDto userInfo = null + ) + { + // + // Validate ... + var isValid = + !id.IsNull() && + !id.IsDefaultGuid() && + !item.IsNullOrDefault() && + !userInfo.IsNullOrDefault(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Validate Own ... + isValid = await IsOwned(item.Id); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + var result = await Provider.Update(item.Id, item, userInfo); + 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(); + } + + // + // Validate Owned ... + isValid = await IsOwned(id); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + var result = await Provider.Remove(id, userInfo); + return result; + } + + /// + /// count all exists Entities ... + /// + /// + public async Task Count() + { + // + var result = (await GetAll()).Count(); + return result; + } + + /// + /// Check an Entity exists or not ... + /// + /// + /// + public async Task IsExists( + Guid id + ) + { + // + var result = await IsOwned(id); + return result; + } + #endregion + + // + #region Private ... + /// + /// 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 Provider.IsExists(id); + if (!result) + { + XException.NotFound.Throw(); + } + + // + // Retrieve Dto ... + var dto = await Provider.Get(id); + result = !dto.IsNullOrDefault(); + if (!result) + { + XException.ActionFailed.Throw(); + } + + // + result = !dto.References.IsNull() && + dto.References.HasChild() && + dto.References.Any(r => r.ToNormalString().Contains(ProvidedFor.ToNormalString())); + + // + return result; + } + + /// + /// Get Specified Owned Dto by File Name ... + /// + /// + /// + private async Task GetDto(string fileName) + { + // + XFileDto result = null; + + // + if (!fileName.IsNullOrEmpty()) + { + // + try + { + // + result = await Provider.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; + } + + /// + /// Get Specified Provided ID's Related Files ... + /// + /// + /// + private async Task> GetDtos(TKey forProvidedId) + { + // + var result = new List(); + + // + var identifier = GetIdentifier(forProvidedId); + if (!forProvidedId.IsNull()) + { + // + result = (await Provider + .FindMany(e => e.References.ToNormalString().Contains(identifier.ToNormalString()))) + .ToList(); + } + + // + return result; + } + + /// + /// Check Specified File has Refernce to Provider ... + /// + /// + /// + /// + private async Task IsProvidedFor( + TKey forProvidedId, + Guid id + ) + { + // + var result = await Provider.IsProvidedFor( + id: id, + providedFor: ProvidedFor, + forProvidedId: forProvidedId + ); + + // + return result; + } + + /// + /// Add Specified Reference to Specified File ... + /// + /// + /// + /// + /// + private async Task AddReference( + TKey forProvidedId, + Guid id, + XUserClaimsInfoDto userInfo = null + ) + { + // + await Provider.AddReference( + id: id, + userInfo: userInfo, + providedFor: ProvidedFor, + forProvidedId: forProvidedId + ); + } + + /// + /// Remove Specified Reference from Specified File ... + /// + /// + /// + /// + /// + private async Task RemoveReference( + TKey forProvidedId, + Guid id, + XUserClaimsInfoDto userInfo = null + ) + { + // + await Provider.RemoveReference( + id: id, + userInfo: userInfo, + providedFor: ProvidedFor, + forProvidedId: forProvidedId + ); + } + #endregion } } \ No newline at end of file diff --git a/Providers/XFileProvider.cs b/Providers/XFileProvider.cs index 61149cd..5b02c6f 100644 --- a/Providers/XFileProvider.cs +++ b/Providers/XFileProvider.cs @@ -918,23 +918,26 @@ namespace xFileService.Providers /// Get Reference Identifier for Specified Provider and Specified File ... /// /// - /// + /// /// - public string GetIdentifier( + public string GetIdentifier( string providedFor, - Guid id + TKey forProvidedId ) { - return $"{providedFor}_{id}"; + return $"{providedFor}_{forProvidedId}"; } /// /// Check Specified File has Refernce to Provider ... /// /// + /// + /// /// - public async Task IsProvidedFor( + public async Task IsProvidedFor( string providedFor, + TKey forProvidedId, Guid id ) { @@ -943,7 +946,8 @@ namespace xFileService.Providers var isValid = !providedFor.IsNullOrEmpty() && !id.IsNull() && - !id.IsDefaultGuid(); + !id.IsDefaultGuid() && + !forProvidedId.IsNull(); if (!isValid) { XException.InvalidArgs.Throw(); @@ -966,7 +970,10 @@ namespace xFileService.Providers } // - var identifier = GetIdentifier(providedFor, id); + var identifier = GetIdentifier( + providedFor: providedFor, + forProvidedId: forProvidedId + ); var result = dto.References.IsNull() && dto.References.HasChild() && @@ -980,11 +987,13 @@ namespace xFileService.Providers /// Add Specified Reference to Specified File ... /// /// + /// /// /// /// - public async Task AddReference( + public async Task AddReference( string providedFor, + TKey forProvidedId, Guid id, XUserClaimsInfoDto userInfo = null ) @@ -995,6 +1004,7 @@ namespace xFileService.Providers !providedFor.IsNullOrEmpty() && !id.IsNull() && !id.IsDefaultGuid() && + !providedFor.IsNull() && !userInfo.IsNullOrDefault(); if (!isValid) { @@ -1003,7 +1013,11 @@ namespace xFileService.Providers // // Check Has Reference or not ... - isValid = await IsProvidedFor(providedFor, id); + isValid = await IsProvidedFor( + providedFor: providedFor, + forProvidedId: forProvidedId, + id: id + ); if (!isValid) { // @@ -1026,7 +1040,10 @@ namespace xFileService.Providers } // - var identifier = GetIdentifier(providedFor, id); + var identifier = GetIdentifier( + providedFor: providedFor, + forProvidedId: forProvidedId + ); dto.References.Add(identifier); // @@ -1047,11 +1064,13 @@ namespace xFileService.Providers /// Remove Specified Reference from Specified File ... /// /// + /// /// /// /// - public async Task RemoveReference( + public async Task RemoveReference( string providedFor, + TKey forProvidedId, Guid id, XUserClaimsInfoDto userInfo = null ) @@ -1062,6 +1081,7 @@ namespace xFileService.Providers !providedFor.IsNullOrEmpty() && !id.IsNull() && !id.IsDefaultGuid() && + !forProvidedId.IsNull() && !userInfo.IsNullOrDefault(); if (!isValid) { @@ -1070,7 +1090,11 @@ namespace xFileService.Providers // // Check Has Reference or not ... - isValid = await IsProvidedFor(providedFor, id); + isValid = await IsProvidedFor( + providedFor: providedFor, + forProvidedId: forProvidedId, + id: id + ); if (isValid) { // @@ -1094,7 +1118,10 @@ namespace xFileService.Providers } // - var identifier = GetIdentifier(providedFor, id); + var identifier = GetIdentifier( + providedFor: providedFor, + forProvidedId: forProvidedId + ); dto.References = dto.References .Where(r => r.ToNormalString() != identifier.ToNormalString()) .ToList(); diff --git a/Providers/XFileTagProvider.cs b/Providers/XFileTagProvider.cs index 8dc49bc..d3eb296 100644 --- a/Providers/XFileTagProvider.cs +++ b/Providers/XFileTagProvider.cs @@ -9,10 +9,9 @@ namespace xFileService.Providers public class XFileTagProvider : XBaseTagProvider, IXFileTagProvider { public XFileTagProvider( - IXTagProvider tagProvider, - string providedFor = nameof(XFile) + IXTagProvider tagProvider ) : base( - providedFor: providedFor, + providedFor: nameof(XFile), tagProvider: tagProvider ) { }