Files
xFileService/Providers/XBaseFileProvider.cs
T
2025-12-17 20:59:37 +03:30

1045 lines
30 KiB
C#

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<TKey> : IXBaseFileProvider<TKey>
{
//
#region Props ...
/// <summary>
/// Provider Identifier ...
/// </summary>
public string Provider { get; }
/// <summary>
/// Tag Provider for Maipulating Tags ...
/// </summary>
public IXFileProvider FileProvider { get; }
#endregion
//
#region Constructor ...
public XBaseFileProvider(
string providedFor,
IXFileProvider fileProvider
)
{
//
Provider = providedFor;
FileProvider = fileProvider;
}
#endregion
//
#region Identifier ...
public async Task<int> LastIndex(TKey providedForId)
{
return await Task.FromResult(GetLastIndex(providedForId));
}
#endregion
//
#region Tools ...
/// <summary>
/// Stream Specified File ...
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<FileStreamResult> 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;
}
/// <summary>
/// Stream Specified File ...
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public async Task<FileStreamResult> 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;
}
/// <summary>
/// Download Specified File ...
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<PhysicalFileResult> Download(Guid id)
{
//
// Validate ...
var isValid = await IsOwned(id);
if (!isValid)
{
XException.NotAllowed.Throw();
}
//
var result = await FileProvider.Download(id);
return result;
}
/// <summary>
/// Download Specified File ...
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public async Task<PhysicalFileResult> 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;
}
/// <summary>
/// Upload Files ...
/// </summary>
/// <param name="providedForId"></param>
/// <param name="files"></param>
/// <param name="connectionId"></param>
/// <param name="userInfo"></param>
/// <returns></returns>
public async Task<IEnumerable<XFileDto>> 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<XFileDto>();
//
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;
}
/// <summary>
/// Remove Specified Files ...
/// </summary>
/// <param name="providedForId"></param>
/// <param name="ids">if null, Remove all Files</param>
/// <param name="connectionId"></param>
/// <param name="userInfo"></param>
/// <returns></returns>
public async Task<IEnumerable<Guid>> 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<Guid>();
IEnumerable<XFile> 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<Guid>();
var isValid = !entities.IsNull() && entities.HasChild();
if (isValid)
{
//
foreach (var entity in entities)
{
//
// Remove File ...
var idsToRemove = new List<string> { 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;
}
/// <summary>
/// Retrieve Specified File Streaming Info ...
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<XFileStreamDescriptorDto> 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;
}
/// <summary>
/// Retrieve Specified File Streaming Info ...
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public async Task<XFileStreamDescriptorDto> 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 ...
/// <summary>
/// Get Specified Indexed Reference for Specific Provided ID ...
/// </summary>
/// <param name="providedForId"></param>
/// <param name="forIndex"></param>
/// <returns></returns>
public async Task<XFileDto> 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;
}
/// <summary>
/// Retrieve all Exists References of Specific Provided ID ...
/// </summary>
/// <param name="providedForId"></param>
/// <returns></returns>
public async Task<IEnumerable<XFileDto>> 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<XFileDto>();
foreach (var entity in entities)
{
//
var dto = await FileProvider.ToDto(entity);
if (!dto.IsNullOrDefault())
{
dtos.Add(dto);
}
}
//
List<XFileDto> 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);
}
/// <summary>
/// Retrieve References of Specific Provided ID as Query ...
/// </summary>
/// <param name="providedForId"></param>
/// <returns></returns>
public async Task<XQueryResult<XFileDto>> 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<XFileDto>
{
Page = query.Page,
Items = items.ToList(),
PageSize = query.PageSize,
TotalPages = totalPagesCount,
TotalItems = totalItemsCount,
TotalFilteredPages = filteredPagesCount,
TotalFilteredItems = filteredItemsCount
};
//
return result;
}
/// <summary>
/// Add Reference a Model to Specific Provided ID ...
/// </summary>
/// <param name="model"></param>
/// <param name="providedForId"></param>
/// <param name="forIndex"></param>
/// <param name="connectionId"></param>
/// <param name="userInfo"></param>
/// <returns></returns>
public async Task<bool> 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 == 0)
{
//
// This Means there isnot any Reference ...
forIndex = 0;
model.References.Add(new XReference<string>
{
Index = forIndex,
ProvidedFor = Provider,
ReferencedTo = $"{providedForId}"
});
}
else
{
//
// Check Provided Index Exists or not ...
var isExists = model.References.Any(r => r.Index == forIndex);
if (!isExists)
{
//
// Normalize For Index ...
if (forIndex > lastIndex + 1)
{
forIndex = lastIndex + 1;
}
//
// Add New Reference ...
model.References.Add(new XReference<string>
{
Index = forIndex,
ProvidedFor = Provider,
ReferencedTo = $"{providedForId}"
});
}
else
{
}
}
//
// Update Data Base ...
model = await FileProvider
.Update(
item: model,
id: model.Id,
userInfo: userInfo,
connectionId: connectionId
);
result = !model.IsNullOrDefault();
//
return result;
}
/// <summary>
/// Add Reference a Model to Specific XRefence<TKey> ...
/// </summary>
/// <param name="model"></param>
/// <param name="reference"></param>
/// <param name="connectionId"></param>
/// <param name="userInfo"></param>
/// <returns></returns>
public async Task<bool> AddReference(
XFileDto model,
XReference<TKey> 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;
}
/// <summary>
/// Remove Reference a Model for Specific Provided ID ...
/// </summary>
/// <param name="model"></param>
/// <param name="providedForId"></param>
/// <param name="forIndex">if null, removes all</param>
/// <param name="connectionId"></param>
/// <param name="userInfo"></param>
/// <returns></returns>
public async Task<bool> 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;
}
/// <summary>
/// Remove Reference a Model for Specific XRefence<TKey> ...
/// </summary>
/// <param name="model"></param>
/// <param name="providedForId"></param>
/// <param name="connectionId"></param>
/// <param name="userInfo"></param>
/// <returns></returns>
public async Task<bool> RemoveReference(
XFileDto model,
XReference<TKey> 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;
}
/// <summary>
/// Remove All References to Specified Key ...
/// </summary>
/// <param name="providedForId"></param>
/// <param name="connectionId"></param>
/// <param name="userInfo"></param>
/// <returns></returns>
public async Task<bool> 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 = 0;
//
// 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 = 0;
}
else
{
//
var references = all
.SelectMany(a => a.ParseXReferenceList<TKey>())
.OrderByDescending(r => r.Index)
.ToList();
if (!references.IsNull() && references.HasChild())
{
result = references[0].Index;
}
else
{
result = 0;
}
}
//
return result;
}
/// <summary>
/// Check Specified Dto is Has Reference to Provider ...
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
private async Task<bool> 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;
}
/// <summary>
/// Get Specified Owned Dto by File Name ...
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
private async Task<XFileDto> 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
}
}