Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File Management #143

Open
wants to merge 21 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using uBeac.Repositories;

namespace uBeac.FileManagement;

public interface IFileRepository<TKey, TEntity> : IEntityRepository<TKey, TEntity>
where TKey : IEquatable<TKey>
where TEntity : IFileEntity<TKey>
{
Task<IEnumerable<TEntity>> Search(SearchFileRequest<TKey> request, CancellationToken cancellationToken = default);
}

public interface IFileRepository<TEntity> : IFileRepository<Guid, TEntity>, IEntityRepository<TEntity>
where TEntity : IFileEntity
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using uBeac.Services;

namespace uBeac.FileManagement;

public interface IFileService : IService
{
Task<IEnumerable<IFileEntity>> Search(SearchFileRequest request, CancellationToken cancellationToken = default);
Task<FileModel> Get(GetFileRequest request, CancellationToken cancellationToken = default);
Task<IFileEntity> Create(FileModel model, CancellationToken cancellationToken = default);
}

public interface IFileService<TKey, TEntity> : IFileService
where TKey : IEquatable<TKey>
where TEntity : IFileEntity<TKey>
{
Task<IEnumerable<TEntity>> Search(SearchFileRequest<TKey> request, CancellationToken cancellationToken = default);
Task<TEntity> Create(FileModel model, TEntity entity, CancellationToken cancellationToken = default);
}

public interface IFileService<TEntity> : IFileService<Guid, TEntity>
where TEntity : IFileEntity
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace uBeac.FileManagement;

public interface IFileStorageProvider
{
string Name { get; }

Task Create(Stream stream, string fileName, CancellationToken cancellationToken = default);
Task<FileStream> Get(string fileName, CancellationToken cancellationToken = default);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace uBeac.FileManagement;

public interface IFileValidator
{
IFileValidationResult Validate(FileModel model);
}

public interface IFileValidationResult
{
bool Validated { get; set; }
Exception Exception { get; set; }
}

public class FileValidationResult : IFileValidationResult
{
public FileValidationResult()
{
Validated = true;
Exception = null;
}

public FileValidationResult(Exception exception)
{
Validated = false;
Exception = exception;
}

public bool Validated { get; set; }
public Exception Exception { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace uBeac;

public interface IFileEntity<TKey> : IAuditEntity<TKey>
where TKey : IEquatable<TKey>
{
string Name { get; set; }
string Extension { get; set; }
string Provider { get; set; }
string Category { get; set; }
}

public interface IFileEntity : IFileEntity<Guid>, IAuditEntity
{
}

public class FileEntity<TKey> : AuditEntity<TKey>, IFileEntity<TKey>
where TKey : IEquatable<TKey>
{
public string Name { get; set; }
public string Extension { get; set; }
public string Provider { get; set; }
public string Category { get; set; }
}

public class FileEntity : FileEntity<Guid>, IFileEntity
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace uBeac.FileManagement;

public class FileModel : IDisposable, IAsyncDisposable
{
public Stream Stream { get; set; }
public string Extension { get; set; }
public string Category { get; set; }

public void Dispose() => Stream.Dispose();

public async ValueTask DisposeAsync() => await Stream.DisposeAsync();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace uBeac.FileManagement;

public class GetFileRequest
{
public string Name { get; set; }
public string Category { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace uBeac.FileManagement;


public class SearchFileRequest<TKey> where TKey : IEquatable<TKey>
{
public string Category { get; set; }
public IEnumerable<TKey> Ids { get; set; }
public IEnumerable<string> Names { get; set; }
public IEnumerable<string> Extensions { get; set; }
public IEnumerable<string> Providers { get; set; }
}

public class SearchFileRequest : SearchFileRequest<Guid>
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<PackageId>uBeac.FileManagement.Abstractions</PackageId>
<Authors>uBeac</Authors>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<Description>Contains abstractions of file management.</Description>
<PackageIcon>ubeac-logo.jpg</PackageIcon>
<PackageProjectUrl>https://github.com/ubeac/ubeac-api</PackageProjectUrl>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Common\uBeac.Core.Common\uBeac.Core.Common.csproj" />
<ProjectReference Include="..\..\Repository\uBeac.Core.Repositories.Abstractions\uBeac.Core.Repositories.Abstractions.csproj" />
<ProjectReference Include="..\..\Service\uBeac.Core.Services.Abstractions\uBeac.Core.Services.Abstractions.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
namespace uBeac.FileManagement;

public class FileService<TKey, TEntity> : IFileService<TKey, TEntity>
where TKey : IEquatable<TKey>
where TEntity : IFileEntity<TKey>, new()
{
protected readonly List<IFileValidator> Validators;
protected readonly IFileRepository<TKey, TEntity> Repository;
protected readonly IFileStorageProvider Provider;

public FileService(IEnumerable<IFileValidator> validators, IFileRepository<TKey, TEntity> repository, IFileStorageProvider provider)
{
Validators = validators.ToList();
Repository = repository;
Provider = provider;
}

public async Task<IEnumerable<TEntity>> Search(SearchFileRequest<TKey> request, CancellationToken cancellationToken = default)
=> await Repository.Search(request, cancellationToken);

public async Task<IEnumerable<IFileEntity>> Search(SearchFileRequest request, CancellationToken cancellationToken = default)
=> (IEnumerable<IFileEntity>) await Search(request as SearchFileRequest<TKey>, cancellationToken);

public async Task<FileModel> Get(GetFileRequest request, CancellationToken cancellationToken = default)
{
var entity = (await Search(new SearchFileRequest
{
Category = request.Category,
Names = new[] { request.Name }
}, cancellationToken)).First();

return new FileModel
{
Stream = await Provider.Get(entity.Name, cancellationToken),
Category = request.Category,
Extension = entity.Extension
};
}

public async Task<TEntity> Create(FileModel model, TEntity entity, CancellationToken cancellationToken = default)
{
ThrowExceptionIfNotValid(model);

var fileName = Path.GetRandomFileName();

entity.Name = fileName;
entity.Extension = model.Extension;
entity.Provider = Provider.Name;
entity.Category = model.Category;

await Provider.Create(model.Stream, fileName, cancellationToken);
await Repository.Create(entity, cancellationToken);

return entity;
}

public async Task<IFileEntity> Create(FileModel model, CancellationToken cancellationToken = default)
{
return (IFileEntity) await Create(model, new TEntity(), cancellationToken);
}

protected void ThrowExceptionIfNotValid(FileModel model) => Validators.ForEach(validator =>
{
var result = validator.Validate(model);
if (!result.Validated) throw result.Exception;
});
}

public class FileService<TEntity> : FileService<Guid, TEntity>, IFileService<TEntity>
where TEntity : IFileEntity, new()
{
public FileService(IEnumerable<IFileValidator> validators, IFileRepository<TEntity> repository, IFileStorageProvider provider) : base(validators, repository, provider)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<PackageId>uBeac.FileManagement.Services</PackageId>
<Authors>uBeac</Authors>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<Description>Implements file management service.</Description>
<PackageIcon>ubeac-logo.jpg</PackageIcon>
<PackageProjectUrl>https://github.com/ubeac/ubeac-api</PackageProjectUrl>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\uBeac.Core.FileManagement.Abstractions\uBeac.Core.FileManagement.Abstractions.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using uBeac;
using uBeac.FileManagement;

namespace Microsoft.Extensions.DependencyInjection;

public class FileManagementBuilder<TKey, TEntity> : IFileManagementBuilder<TKey, TEntity> where TKey : IEquatable<TKey> where TEntity : IFileEntity<TKey>, new()
{
protected readonly IServiceCollection Services;

public FileManagementBuilder(IServiceCollection services)
{
Services = services;
}

public IFileServiceBuilder<TKey, TEntity> AddCategory(string categoryName)
{
var builder = new FileServiceBuilder<TKey, TEntity>();

Services.AddScoped(serviceProvider =>
{
var service = builder.Build(serviceProvider);
return new FileCategory { CategoryName = categoryName, Service = service };
});

return builder;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using uBeac;
using uBeac.FileManagement;

namespace Microsoft.Extensions.DependencyInjection;

public class FileServiceBuilder<TKey, TEntity> : IFileServiceBuilder<TKey, TEntity>
where TKey : IEquatable<TKey>
where TEntity : IFileEntity<TKey>, new()
{
public List<Func<IServiceProvider, IFileValidator>> Validators { get; } = new();
public Func<IServiceProvider, IFileRepository<TKey, TEntity>> Repository { get; set; }
public Func<IServiceProvider, IFileStorageProvider> Provider { get; set; }

public IFileServiceBuilder<TKey, TEntity> AddValidator(IFileValidator validator)
{
Validators.Add(_ => validator);
return this;
}

public IFileServiceBuilder<TKey, TEntity> StoreInfoIn<TRepository>() where TRepository : IFileRepository<TKey, TEntity>
{
Repository = serviceProvider => serviceProvider.GetRequiredService<TRepository>();
return this;
}

public IFileServiceBuilder<TKey, TEntity> StoreInfoIn<TRepository>(TRepository repository) where TRepository : IFileRepository<TKey, TEntity>
{
Repository = _ => repository;
return this;
}

public IFileServiceBuilder<TKey, TEntity> StoreInfoIn(Func<IServiceProvider, IFileRepository<TKey, TEntity>> builder)
{
Repository = builder;
return this;
}

public IFileServiceBuilder<TKey, TEntity> StoreFilesIn<TStorageProvider>() where TStorageProvider : IFileStorageProvider
{
Provider = serviceProvider => serviceProvider.GetRequiredService<TStorageProvider>();
return this;
}

public IFileServiceBuilder<TKey, TEntity> StoreFilesIn<TStorageProvider>(TStorageProvider provider) where TStorageProvider : IFileStorageProvider
{
Provider = _ => provider;
return this;
}

public IFileServiceBuilder<TKey, TEntity> StoreFilesIn(Func<IServiceProvider, IFileStorageProvider> builder)
{
Provider = builder;
return this;
}

internal IFileService<TKey, TEntity> Build(IServiceProvider serviceProvider)
{
var validators = Validators.Select(validator => validator(serviceProvider));
var repository = Repository(serviceProvider);
var provider = Provider(serviceProvider);

return new FileService<TKey, TEntity>(validators, repository, provider);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace uBeac.FileManagement;

public interface IFileManagementBuilder<TKey, TEntity> where TKey : IEquatable<TKey> where TEntity : IFileEntity<TKey>
{
IFileServiceBuilder<TKey, TEntity> AddCategory(string categoryName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace uBeac.FileManagement;

public interface IFileServiceBuilder<TKey, TEntity>
where TKey : IEquatable<TKey>
where TEntity : IFileEntity<TKey>
{
IFileServiceBuilder<TKey, TEntity> AddValidator(IFileValidator validator);

IFileServiceBuilder<TKey, TEntity> StoreInfoIn<TRepository>() where TRepository : IFileRepository<TKey, TEntity>;
IFileServiceBuilder<TKey, TEntity> StoreInfoIn<TRepository>(TRepository repository) where TRepository : IFileRepository<TKey, TEntity>;
IFileServiceBuilder<TKey, TEntity> StoreInfoIn(Func<IServiceProvider, IFileRepository<TKey, TEntity>> builder);

IFileServiceBuilder<TKey, TEntity> StoreFilesIn<TStorageProvider>() where TStorageProvider : IFileStorageProvider;
IFileServiceBuilder<TKey, TEntity> StoreFilesIn<TStorageProvider>(TStorageProvider provider) where TStorageProvider : IFileStorageProvider;
IFileServiceBuilder<TKey, TEntity> StoreFilesIn(Func<IServiceProvider, IFileStorageProvider> builder);
}
Loading