(feat): mongo grid fs

This commit is contained in:
Maksym Sadovnychyy 2022-09-04 23:26:15 +02:00
parent 9c97e50c53
commit 6e37619ac0
32 changed files with 1064 additions and 273 deletions

View File

@ -1183,6 +1183,138 @@
"response": [] "response": []
} }
] ]
},
{
"name": "File",
"item": [
{
"name": "01-Get",
"request": {
"method": "GET",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"type": "default"
},
{
"key": "Accept",
"value": "application/json",
"type": "default"
}
],
"url": {
"raw": "https://localhost:7151/api/File/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/3930ff55-67e1-4763-be59-37407f91e0a9",
"protocol": "https",
"host": [
"localhost"
],
"port": "7151",
"path": [
"api",
"File",
"404c8232-9048-4519-bfba-6e78dc7005ca",
"fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60",
"3930ff55-67e1-4763-be59-37407f91e0a9"
]
}
},
"response": []
}
]
},
{
"name": "Files",
"item": [
{
"name": "01-Post",
"request": {
"method": "POST",
"header": [
{
"warning": "This is a duplicate header and will be overridden by the Content-Type header generated by Postman.",
"key": "Content-Type",
"value": "application/json",
"type": "default"
},
{
"key": "Accept",
"value": "application/json",
"type": "default"
}
],
"body": {
"mode": "formdata",
"formdata": [
{
"key": "file",
"type": "file",
"src": "/C:/Users/maksym/Pictures/IMG_0146.JPG"
}
]
},
"url": {
"raw": "https://localhost:7151/api/Files/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60",
"protocol": "https",
"host": [
"localhost"
],
"port": "7151",
"path": [
"api",
"Files",
"404c8232-9048-4519-bfba-6e78dc7005ca",
"fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60"
]
}
},
"response": []
},
{
"name": "02-Delete",
"request": {
"method": "DELETE",
"header": [
{
"warning": "This is a duplicate header and will be overridden by the Content-Type header generated by Postman.",
"key": "Content-Type",
"value": "application/json",
"type": "default"
},
{
"key": "Accept",
"value": "application/json",
"type": "default"
}
],
"body": {
"mode": "formdata",
"formdata": [
{
"key": "file",
"type": "file",
"src": "/C:/Users/maksym/Pictures/IMG_0146.JPG"
}
]
},
"url": {
"raw": "https://localhost:7151/api/Files/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60",
"protocol": "https",
"host": [
"localhost"
],
"port": "7151",
"path": [
"api",
"Files",
"404c8232-9048-4519-bfba-6e78dc7005ca",
"fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60"
]
}
},
"response": []
}
]
} }
] ]
} }

View File

@ -1,7 +1,7 @@
using Core.Abstractions.DomainObjects; using Core.Abstractions.DomainObjects;
using Core.DomainObjects.L10n; using Core.DomainObjects.L10n;
namespace Core.DomainObjects { namespace Core.DomainObjects.Documents {
public class Category : DomainObjectDocumentBase<Category> { public class Category : DomainObjectDocumentBase<Category> {
public Guid SiteId { get; set; } public Guid SiteId { get; set; }
public List<CategoryL10n> L10n { get; set; } public List<CategoryL10n> L10n { get; set; }

View File

@ -0,0 +1,199 @@
using Microsoft.Extensions.Logging;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.GridFS;
using DomainResults.Common;
namespace DataProviders.Abstractions {
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class BucketDataProviderBase : DataProviderBase<BucketDataProviderBase> {
/// <summary>
///
/// </summary>
/// <param name="logger"></param>
/// <param name="client"></param>
public BucketDataProviderBase(
ILogger<BucketDataProviderBase> logger,
IMongoClient client
) : base (logger, client){ }
#region Upload
private protected (Guid?, IDomainResult) Upload(Guid siteId, Guid userId, BucketFile file, string bucketName) =>
UploadAsync(siteId, userId, file, bucketName).Result;
private protected Task<(Guid?, IDomainResult)> UploadAsync(Guid siteId, Guid userId, BucketFile file, string bucketName) =>
UploadAsyncCore(siteId, userId, file, bucketName);
#endregion
#region Upload many
private protected (List<Guid>?, IDomainResult) UploadMany(Guid siteId, Guid userId, List<BucketFile> files, string bucketName) =>
UploadAsync(siteId, userId, files, bucketName).Result;
private protected Task<(List<Guid>?, IDomainResult)> UploadAsync(Guid siteId, Guid userId, List<BucketFile> files, string bucketName) =>
UploadManyAsyncCore(siteId, userId, files, bucketName);
#endregion
#region Download
private protected (BucketFile?, IDomainResult) Download(Guid siteId, Guid userId, Guid fileId, string bucketName) =>
DownloadAsync(siteId, userId, fileId, bucketName).Result;
private protected Task<(BucketFile?, IDomainResult)> DownloadAsync(Guid siteId, Guid userId, Guid fileId, string bucketName) =>
DownloadAsyncCore(siteId, userId, fileId, bucketName);
#endregion
#region Delete
private protected IDomainResult DeleteOne(Guid siteId, Guid userId, Guid fileId, string bucketName) =>
DeleteOneAsync(siteId, userId, fileId, bucketName).Result;
private protected Task<IDomainResult> DeleteOneAsync(Guid siteId, Guid userId, Guid fileId, string bucketName) =>
DeleteOneAsyncCore(siteId, userId, fileId, bucketName);
#endregion
#region Delete many
private protected IDomainResult DeleteMany(Guid siteId, Guid userId, string bucketName) =>
DeleteManyAsync(siteId, userId, bucketName).Result;
private protected Task<IDomainResult> DeleteManyAsync(Guid siteId, Guid userId, string bucketName) =>
DeleteManyAsyncCore(siteId, userId, bucketName);
#endregion
#region Core methods
private GridFSBucket CreateBucket(string bucketName) => new GridFSBucket(_client.GetDatabase(_databaseName), new GridFSBucketOptions {
BucketName = bucketName,
ChunkSizeBytes = 1048576, // 1MB
WriteConcern = WriteConcern.WMajority,
ReadPreference = ReadPreference.Secondary
});
private async Task<(Guid?, IDomainResult)> UploadAsyncCore(Guid siteId, Guid userId, BucketFile file, string bucketName) {
var (list, result) = await UploadManyAsyncCore(siteId, userId, new List<BucketFile> { file }, bucketName);
if (!result.IsSuccess || list == null)
return (null, result);
return (list.First(), result);
}
public async Task<(List<Guid>?, IDomainResult)> UploadManyAsyncCore(Guid siteId, Guid userId, List<BucketFile> files, string bucketName) {
var options = new GridFSUploadOptions {
ChunkSizeBytes = 64512, // 63KB
};
try {
var bucket = CreateBucket(bucketName);
var result = new List<Guid>();
foreach (var file in files) {
options.Metadata = new BsonDocument {
{ "siteId", $"{siteId}"},
{ "userId", $"{userId}"},
{ "fileName", file.Name },
{ "contentType", file.ContentType }
};
var fileId = Guid.NewGuid();
await bucket.UploadFromBytesAsync($"{fileId}", file.Bytes, options);
result.Add(fileId);
}
return result.Count > 0
? IDomainResult.Success(result)
: IDomainResult.Failed<List<Guid>?>();
}
catch (Exception ex) {
_logger.LogError(ex, "Bucket data provider error");
return IDomainResult.Failed<List<Guid>?>();
}
}
private async Task<(BucketFile?, IDomainResult)> DownloadAsyncCore(Guid siteId, Guid userId, Guid fileId, string bucketName) {
try {
var filter = Builders<GridFSFileInfo>.Filter.And(
Builders<GridFSFileInfo>.Filter.Eq(x => x.Metadata["siteId"], $"{siteId}"),
Builders<GridFSFileInfo>.Filter.Eq(x => x.Metadata["userId"], $"{userId}"),
Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, $"{fileId}")
);
var sort = Builders<GridFSFileInfo>.Sort.Descending(x => x.UploadDateTime);
var bucket = CreateBucket(bucketName);
using var cursor = await bucket.FindAsync(filter, new GridFSFindOptions {
Limit = 1,
Sort = sort,
});
// fileInfo either has the matching file information or is null
var fileInfo = (await cursor.ToListAsync()).FirstOrDefault();
if (fileInfo == null)
return IDomainResult.NotFound<BucketFile?>();
var fileName = fileInfo.Metadata["fileName"].ToString() ?? "";
if (fileName == null)
return IDomainResult.Failed<BucketFile?>();
var contentType = fileInfo.Metadata["contentType"].ToString() ?? "";
if (contentType == null)
return IDomainResult.Failed<BucketFile?>();
var bytes = await bucket.DownloadAsBytesByNameAsync($"{fileId}", new GridFSDownloadByNameOptions {
Revision = -1
});
if(bytes == null)
return IDomainResult.Failed<BucketFile?>();
return IDomainResult.Success(new BucketFile(fileName, bytes, contentType));
}
catch (Exception ex) {
_logger.LogError(ex, "Bucket data provider error");
return IDomainResult.Failed<BucketFile?>();
}
}
private Task<IDomainResult> DeleteOneAsyncCore(Guid siteId, Guid userId, Guid fileId, string bucketName) =>
DeleteAsyncCore(siteId, userId, Builders<GridFSFileInfo>.Filter.And(
Builders<GridFSFileInfo>.Filter.Eq(x => x.Metadata["siteId"], $"{siteId}"),
Builders<GridFSFileInfo>.Filter.Eq(x => x.Metadata["userId"], $"{userId}"),
Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, $"{fileId}")
), bucketName);
private Task<IDomainResult> DeleteManyAsyncCore(Guid siteId, Guid userId, string bucketName) =>
DeleteAsyncCore(siteId, userId, Builders<GridFSFileInfo>.Filter.And(
Builders<GridFSFileInfo>.Filter.Eq(x => x.Metadata["siteId"], $"{siteId}"),
Builders<GridFSFileInfo>.Filter.Eq(x => x.Metadata["userId"], $"{userId}")
), bucketName);
private async Task<IDomainResult> DeleteAsyncCore(Guid siteId, Guid userId, FilterDefinition<GridFSFileInfo> filter, string bucketName) {
try {
var bucket = CreateBucket(bucketName);
using var cursor = await bucket.FindAsync(filter);
var count = 0;
foreach (var fileInfo in await cursor.ToListAsync()) {
await bucket.DeleteAsync(fileInfo.Id);
count++;
}
return count > 0
? IDomainResult.Success()
: IDomainResult.NotFound();
}
catch (Exception ex) {
_logger.LogError(ex, "Bucket data provider error");
return IDomainResult.Failed();
}
}
#endregion
}
}

View File

@ -0,0 +1,220 @@
using System.Linq.Expressions;
using Microsoft.Extensions.Logging;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using DomainResults.Common;
using Core.Abstractions.DomainObjects;
namespace DataProviders.Abstractions {
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class CollectionDataProviderBase<T> : DataProviderBase<CollectionDataProviderBase<T>> where T : DomainObjectDocumentBase<T> {
private protected readonly IIdGenerator _idGenerator;
private protected readonly ISessionService _sessionService;
/// <summary>
/// Main constructor
/// </summary>
/// <param name="logger"></param>
/// <param name="client"></param>
/// <param name="idGenerator"></param>
/// <param name="dataProviderUtils"></param>
public CollectionDataProviderBase(
ILogger<CollectionDataProviderBase<T>> logger,
IMongoClient client,
IIdGenerator idGenerator,
ISessionService sessionService
) : base (logger, client){
_idGenerator = idGenerator;
_sessionService = sessionService;
}
#region Insert
private protected (Guid?, IDomainResult) Insert(T obj, string collectionName) =>
InsertAsync(obj, collectionName).Result;
private protected (Guid?, IDomainResult) Insert(T obj, string collectionName, Guid sessionId) =>
InsertAsync(obj, collectionName, sessionId).Result;
private protected Task<(Guid?, IDomainResult)> InsertAsync(T obj, string collectionName) =>
InsertAsyncCore(obj, collectionName, null);
private protected Task<(Guid?, IDomainResult)> InsertAsync(T obj, string collectionName, Guid sessionId) =>
InsertAsyncCore(obj, collectionName, sessionId);
#endregion
#region InsertMany
private protected (List<Guid>?, IDomainResult) InsertMany(List<T> objList, string collectionName) =>
InsertManyAsync(objList, collectionName).Result;
private protected (List<Guid>?, IDomainResult) InsertMany(List<T> objList, string collectionName, Guid sessionId) =>
InsertManyAsync(objList, collectionName, sessionId).Result;
private protected Task<(List<Guid>?, IDomainResult)> InsertManyAsync(List<T> objList, string collectionName) =>
InsertManyAsyncCore(objList, collectionName, null);
private protected Task<(List<Guid>?, IDomainResult)> InsertManyAsync(List<T> objList, string collectionName, Guid sessionId) =>
InsertManyAsyncCore(objList, collectionName, sessionId);
#endregion
#region Get
private protected (List<T>?, IDomainResult) GetWithPredicate(Expression<Func<T, bool>> predicate, string collectionName) =>
GetWithPredicateCore(predicate, 0, 0, collectionName);
private protected (List<T>?, IDomainResult) GetWithPredicate(Expression<Func<T, bool>> predicate, int skip, int limit, string collectionName) =>
GetWithPredicateCore(predicate, skip, limit, collectionName);
#endregion
#region Update
private protected (Guid?, IDomainResult) UpdateWithPredicate(T obj, Expression<Func<T, bool>> predicate, string collectionName) =>
UpdateWithPredicateAsync(obj, predicate, collectionName).Result;
private protected (Guid?, IDomainResult) UpdateWithPredicate(T obj, Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
UpdateWithPredicateAsync(obj, predicate, collectionName, sessionId).Result;
private protected Task<(Guid?, IDomainResult)> UpdateWithPredicateAsync(T obj, Expression<Func<T, bool>> predicate, string collectionName) =>
UpdateWithPredicateAsyncCore(obj, predicate, collectionName, null);
private protected Task<(Guid?, IDomainResult)> UpdateWithPredicateAsync(T obj, Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
UpdateWithPredicateAsyncCore(obj, predicate, collectionName, sessionId);
#endregion
#region Delete
private protected IDomainResult DeleteWithPredicate(Expression<Func<T, bool>> predicate, string collectionName) =>
DeleteWithPredicateAsync(predicate, collectionName).Result;
private protected IDomainResult DeleteWithPredicate(Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
DeleteWithPredicateAsync(predicate, collectionName, sessionId).Result;
private protected Task<IDomainResult> DeleteWithPredicateAsync(Expression<Func<T, bool>> predicate, string collectionName) =>
DeleteWithPredicateAsyncCore(predicate, collectionName, null);
private protected Task<IDomainResult> DeleteWithPredicateAsync(Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
DeleteWithPredicateAsyncCore(predicate, collectionName, sessionId);
#endregion
#region DeleteMany
private protected IDomainResult DeleteManyWithPredicate(Expression<Func<T, bool>> predicate, string collectionName) =>
DeleteManyWithPredicateAsync(predicate, collectionName).Result;
private protected IDomainResult DeleteManyWithPredicate(Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
DeleteManyWithPredicateAsync(predicate, collectionName, sessionId).Result;
private protected Task<IDomainResult> DeleteManyWithPredicateAsync(Expression<Func<T, bool>> predicate, string collectionName) =>
DeleteManyWithPredicateAsyncCore(predicate, collectionName, null);
private protected Task<IDomainResult> DeleteManyWithPredicateAsync(Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
DeleteManyWithPredicateAsyncCore(predicate, collectionName, sessionId);
#endregion
#region Core methods
private async protected Task<(Guid?, IDomainResult)> InsertAsyncCore(T obj, string collectionName, Guid? sessionId) {
try {
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.InsertOneAsync(_sessionService.GetSession(sessionId.Value), obj);
else
collection.InsertOne(obj);
return IDomainResult.Success(obj.Id);
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed<Guid?>();
}
}
private async Task<(List<Guid>?, IDomainResult)> InsertManyAsyncCore(List<T> objList, string collectionName, Guid? sessionId) {
try {
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.InsertManyAsync(_sessionService.GetSession(sessionId.Value), objList);
else
collection.InsertMany(objList);
return IDomainResult.Success(objList.Select(x => x.Id).ToList());
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed<List<Guid>?>();
}
}
private (List<T>?, IDomainResult) GetWithPredicateCore(Expression<Func<T, bool>> predicate, int skip, int limit, string collectionName) {
try {
var result = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName)
.Find(predicate).Skip(skip).Limit(limit).ToList();
return result != null && result.Count > 0
? IDomainResult.Success(result)
: IDomainResult.NotFound<List<T>?>();
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed<List<T>?>();
}
}
private async Task<(Guid?, IDomainResult)> UpdateWithPredicateAsyncCore(T obj, Expression<Func<T, bool>> predicate, string collectionName, Guid? sessionId) {
try {
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.ReplaceOneAsync(_sessionService.GetSession(sessionId.Value), predicate, obj);
else
await collection.ReplaceOneAsync(predicate, obj);
return IDomainResult.Success(obj.Id);
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed<Guid?>();
}
}
private async Task<IDomainResult> DeleteWithPredicateAsyncCore(Expression<Func<T, bool>> predicate, string collectionName, Guid? sessionId) {
try {
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.DeleteOneAsync<T>(_sessionService.GetSession(sessionId.Value), predicate);
else
await collection.DeleteOneAsync<T>(predicate);
return IDomainResult.Success();
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed();
}
}
private async Task<IDomainResult> DeleteManyWithPredicateAsyncCore(Expression<Func<T, bool>> predicate, string collectionName, Guid? sessionId) {
try {
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.DeleteManyAsync(_sessionService.GetSession(sessionId.Value), predicate);
else
await collection.DeleteManyAsync(predicate);
return IDomainResult.Success();
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed();
}
}
#endregion
}
}

View File

@ -1,264 +1,34 @@
using System.Linq.Expressions; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging;
using MongoDB.Bson.Serialization;
using MongoDB.Driver; using MongoDB.Driver;
using System;
using DomainResults.Common; using System.Collections.Generic;
using System.Linq;
using Core.Abstractions.DomainObjects; using System.Text;
using System.Threading.Tasks;
namespace DataProviders.Abstractions { namespace DataProviders.Abstractions {
public abstract class DataProviderBase<T> where T : DomainObjectDocumentBase<T> {
private protected const string _databaseName = "reactredux";
private protected readonly ILogger<DataProviderBase<T>> _logger;
private protected readonly IMongoClient _client;
private protected readonly IIdGenerator _idGenerator;
private protected readonly ISessionService _sessionService;
private protected List<T>? _collection;
/// <summary> /// <summary>
/// Main constructor ///
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class DataProviderBase<T> {
private protected const string _databaseName = "reactredux";
private protected readonly ILogger<T> _logger;
private protected readonly IMongoClient _client;
/// <summary>
///
/// </summary> /// </summary>
/// <param name="logger"></param> /// <param name="logger"></param>
/// <param name="client"></param> /// <param name="client"></param>
/// <param name="idGenerator"></param>
/// <param name="dataProviderUtils"></param>
public DataProviderBase( public DataProviderBase(
ILogger<DataProviderBase<T>> logger, ILogger<T> logger,
IMongoClient client, IMongoClient client
IIdGenerator idGenerator,
ISessionService sessionService
) { ) {
_logger = logger; _logger = logger;
_client = client; _client = client;
_idGenerator = idGenerator;
_sessionService = sessionService;
}
#region Insert
private protected (Guid?, IDomainResult) Insert(T obj, string collectionName) =>
InsertAsync(obj, collectionName).Result;
private protected (Guid?, IDomainResult) Insert(T obj, string collectionName, Guid sessionId) =>
InsertAsync(obj, collectionName, sessionId).Result;
private protected Task<(Guid?, IDomainResult)> InsertAsync(T obj, string collectionName) =>
InsertAsyncCore(obj, collectionName, null);
private protected Task<(Guid?, IDomainResult)> InsertAsync(T obj, string collectionName, Guid sessionId) =>
InsertAsyncCore(obj, collectionName, sessionId);
#endregion
#region InsertMany
private protected (List<Guid>?, IDomainResult) InsertMany(List<T> objList, string collectionName) =>
InsertManyAsync(objList, collectionName).Result;
private protected (List<Guid>?, IDomainResult) InsertMany(List<T> objList, string collectionName, Guid sessionId) =>
InsertManyAsync(objList, collectionName, sessionId).Result;
private protected Task<(List<Guid>?, IDomainResult)> InsertManyAsync(List<T> objList, string collectionName) =>
InsertManyAsyncCore(objList, collectionName, null);
private protected Task<(List<Guid>?, IDomainResult)> InsertManyAsync(List<T> objList, string collectionName, Guid sessionId) =>
InsertManyAsyncCore(objList, collectionName, sessionId);
#endregion
#region Get
private protected (List<T>?, IDomainResult) GetWithPredicate(Expression<Func<T, bool>> predicate, string collectionName) =>
GetWithPredicateCore(predicate, 0, 0, collectionName);
private protected (List<T>?, IDomainResult) GetWithPredicate(Expression<Func<T, bool>> predicate, int skip, int limit, string collectionName) =>
GetWithPredicateCore(predicate, skip, limit, collectionName);
#endregion
#region Update
private protected (Guid?, IDomainResult) UpdateWithPredicate(T obj, Expression<Func<T, bool>> predicate, string collectionName) =>
UpdateWithPredicateAsync(obj, predicate, collectionName).Result;
private protected (Guid?, IDomainResult) UpdateWithPredicate(T obj, Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
UpdateWithPredicateAsync(obj, predicate, collectionName, sessionId).Result;
private protected Task<(Guid?, IDomainResult)> UpdateWithPredicateAsync(T obj, Expression<Func<T, bool>> predicate, string collectionName) =>
UpdateWithPredicateAsyncCore(obj, predicate, collectionName, null);
private protected Task<(Guid?, IDomainResult)> UpdateWithPredicateAsync(T obj, Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
UpdateWithPredicateAsyncCore(obj, predicate, collectionName, sessionId);
#endregion
#region Exists
private protected (Guid?, IDomainResult) Exists(Guid id, string collectionName) {
var (_resultList, result) = GetWithPredicate(x => x.Id == id, 0, 0, collectionName);
return (result.Status != DomainOperationStatus.Failed && _resultList != null && _resultList.Count > 0
? id
:null,
result);
}
#endregion
#region Delete
private protected IDomainResult DeleteWithPredicate(Expression<Func<T, bool>> predicate, string collectionName) =>
DeleteWithPredicateAsync(predicate, collectionName).Result;
private protected IDomainResult DeleteWithPredicate(Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
DeleteWithPredicateAsync(predicate, collectionName, sessionId).Result;
private protected Task<IDomainResult> DeleteWithPredicateAsync(Expression<Func<T, bool>> predicate, string collectionName) =>
DeleteWithPredicateAsyncCore(predicate, collectionName, null);
private protected Task<IDomainResult> DeleteWithPredicateAsync(Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
DeleteWithPredicateAsyncCore(predicate, collectionName, sessionId);
#endregion
#region DeleteMany
private protected IDomainResult DeleteManyWithPredicate(Expression<Func<T, bool>> predicate, string collectionName) =>
DeleteManyWithPredicateAsync(predicate, collectionName).Result;
private protected IDomainResult DeleteManyWithPredicate(Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
DeleteManyWithPredicateAsync(predicate, collectionName, sessionId).Result;
private protected Task<IDomainResult> DeleteManyWithPredicateAsync(Expression<Func<T, bool>> predicate, string collectionName) =>
DeleteManyWithPredicateAsyncCore(predicate, collectionName, null);
private protected Task<IDomainResult> DeleteManyWithPredicateAsync(Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
DeleteManyWithPredicateAsyncCore(predicate, collectionName, sessionId);
#endregion
#region Core methods
private async protected Task<(Guid?, IDomainResult)> InsertAsyncCore(T obj, string collectionName, Guid? sessionId) {
try {
if (_collection != null) {
obj.Id = Guid.NewGuid();
_collection.Add(obj);
return IDomainResult.Success(obj.Id);
}
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.InsertOneAsync(_sessionService.GetSession(sessionId.Value), obj);
else
collection.InsertOne(obj);
return IDomainResult.Success(obj.Id);
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed<Guid?>();
} }
} }
private async Task<(List<Guid>?, IDomainResult)> InsertManyAsyncCore(List<T> objList, string collectionName, Guid? sessionId) {
try {
if (_collection != null) {
_collection = _collection.Concat(objList).ToList();
return IDomainResult.Success(objList.Select(x => x.Id).ToList());
}
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.InsertManyAsync(_sessionService.GetSession(sessionId.Value), objList);
else
collection.InsertMany(objList);
return IDomainResult.Success(objList.Select(x => x.Id).ToList());
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed<List<Guid>?>();
}
}
private (List<T>?, IDomainResult) GetWithPredicateCore(Expression<Func<T, bool>> predicate, int skip, int limit, string collectionName) {
try {
List<T>? result;
if (_collection != null) {
result = _collection?.AsQueryable()
.Where(predicate).ToList();
}
else {
result = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName)
.Find(predicate).Skip(skip).Limit(limit).ToList();
}
return result != null && result.Count > 0
? IDomainResult.Success(result)
: IDomainResult.NotFound<List<T>?>();
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed<List<T>?>();
}
}
private async Task<(Guid?, IDomainResult)> UpdateWithPredicateAsyncCore(T obj, Expression<Func<T, bool>> predicate, string collectionName, Guid? sessionId) {
try {
if (_collection != null) {
// remove element(s) from list
foreach (var element in _collection.AsQueryable().Where(predicate))
_collection = _collection.Where(x => x.Id != element.Id).ToList();
// add updated element
_collection.Add(obj);
}
else {
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.ReplaceOneAsync(_sessionService.GetSession(sessionId.Value), predicate, obj);
else
await collection.ReplaceOneAsync(predicate, obj);
}
return IDomainResult.Success(obj.Id);
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed<Guid?>();
}
}
private async Task<IDomainResult> DeleteWithPredicateAsyncCore(Expression<Func<T, bool>> predicate, string collectionName, Guid? sessionId) {
try {
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.DeleteOneAsync<T>(_sessionService.GetSession(sessionId.Value), predicate);
else
await collection.DeleteOneAsync<T>(predicate);
return IDomainResult.Success();
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed();
}
}
private async Task<IDomainResult> DeleteManyWithPredicateAsyncCore(Expression<Func<T, bool>> predicate, string collectionName, Guid? sessionId) {
try {
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.DeleteManyAsync(_sessionService.GetSession(sessionId.Value), predicate);
else
await collection.DeleteManyAsync(predicate);
return IDomainResult.Success();
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed();
}
}
#endregion
}
} }

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataProviders {
public class BucketFile {
public string Name { get; private set; }
public byte[] Bytes { get; private set; }
public string ContentType { get; private set; }
public BucketFile(string name, byte[] bytes, string contentType) {
Name = name;
Bytes = bytes;
ContentType = contentType;
}
}
}

View File

@ -0,0 +1,122 @@
using Microsoft.Extensions.Logging;
using DomainResults.Common;
using MongoDB.Driver;
using DataProviders.Abstractions;
namespace DataProviders.Buckets {
/// <summary>
///
/// </summary>
public interface IImagesBucketDataProvider {
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="file"></param>
/// <returns></returns>
(Guid?, IDomainResult) Upload(Guid siteId, Guid userId, BucketFile file);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="files"></param>
/// <returns></returns>
(List<Guid>?, IDomainResult) UploadMany(Guid siteId, Guid userId, List<BucketFile> files);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="fileId"></param>
/// <returns></returns>
(BucketFile?, IDomainResult) Download(Guid siteId, Guid userId, Guid fileId);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="fileId"></param>
/// <returns></returns>
IDomainResult DeleteOne(Guid siteId, Guid userId, Guid fileId);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <returns></returns>
IDomainResult DeletMany(Guid siteId, Guid userId);
}
/// <summary>
///
/// </summary>
public class ImagesBucketDataProvider : BucketDataProviderBase, IImagesBucketDataProvider {
private const string _bucketName = "images";
/// <summary>
///
/// </summary>
/// <param name="logger"></param>
/// <param name="client"></param>
public ImagesBucketDataProvider(
ILogger<BucketDataProviderBase> logger,
IMongoClient client
) : base(logger, client) { }
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="file"></param>
/// <returns></returns>
public (Guid?, IDomainResult) Upload(Guid siteId, Guid userId, BucketFile file) => Upload(siteId, userId, file, _bucketName);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="files"></param>
/// <returns></returns>
public (List<Guid>?, IDomainResult) UploadMany(Guid siteId, Guid userId, List<BucketFile> files) => UploadMany(siteId, userId, files, _bucketName);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="fileId"></param>
/// <returns></returns>
public (BucketFile?, IDomainResult) Download(Guid siteId, Guid userId, Guid fileId) => Download(siteId, userId, fileId, _bucketName);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="fileId"></param>
/// <returns></returns>
public IDomainResult DeleteOne(Guid siteId, Guid userId, Guid fileId) => DeleteOne(siteId, userId, fileId, _bucketName);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <returns></returns>
public IDomainResult DeletMany(Guid siteId, Guid userId) => DeleteMany(siteId, userId, _bucketName);
}
}

View File

@ -8,7 +8,7 @@ using MongoDB.Driver;
using DataProviders.Abstractions; using DataProviders.Abstractions;
using Core.DomainObjects.Documents; using Core.DomainObjects.Documents;
namespace DataProviders { namespace DataProviders.Collections {
public interface IBlogCatalogDataProvider { public interface IBlogCatalogDataProvider {
(Guid?, IDomainResult) Insert(BlogItem blogItem); (Guid?, IDomainResult) Insert(BlogItem blogItem);
(BlogItem?, IDomainResult) Get(Guid siteId, Guid blogId); (BlogItem?, IDomainResult) Get(Guid siteId, Guid blogId);
@ -20,12 +20,12 @@ namespace DataProviders {
IDomainResult DeleteAll(Guid siteId); IDomainResult DeleteAll(Guid siteId);
} }
public class BlogCatalogDataProvider : DataProviderBase<BlogItem>, IBlogCatalogDataProvider { public class BlogCatalogDataProvider : CollectionDataProviderBase<BlogItem>, IBlogCatalogDataProvider {
private const string _collectionName = "blogcatalog"; private const string _collectionName = "blogcatalog";
public BlogCatalogDataProvider( public BlogCatalogDataProvider(
ILogger<DataProviderBase<BlogItem>> logger, ILogger<CollectionDataProviderBase<BlogItem>> logger,
IMongoClient client, IMongoClient client,
IIdGenerator idGenerator, IIdGenerator idGenerator,
ISessionService sessionService) : base(logger, client, idGenerator, sessionService) { ISessionService sessionService) : base(logger, client, idGenerator, sessionService) {

View File

@ -6,9 +6,9 @@ using MongoDB.Bson.Serialization;
using DomainResults.Common; using DomainResults.Common;
using DataProviders.Abstractions; using DataProviders.Abstractions;
using Core.DomainObjects; using Core.DomainObjects.Documents;
namespace DataProviders { namespace DataProviders.Collections {
public interface ICategoryDataProvider { public interface ICategoryDataProvider {
(Guid?, IDomainResult) Insert(Category obj); (Guid?, IDomainResult) Insert(Category obj);
@ -21,11 +21,11 @@ namespace DataProviders {
IDomainResult DeleteAll(Guid siteId); IDomainResult DeleteAll(Guid siteId);
} }
public class CategoryDataProvider : DataProviderBase<Category>, ICategoryDataProvider { public class CategoryDataProvider : CollectionDataProviderBase<Category>, ICategoryDataProvider {
private const string _collectionName = "categories"; private const string _collectionName = "categories";
public CategoryDataProvider( public CategoryDataProvider(
ILogger<DataProviderBase<Category>> logger, ILogger<CollectionDataProviderBase<Category>> logger,
IMongoClient client, IMongoClient client,
IIdGenerator idGenerator, IIdGenerator idGenerator,
ISessionService sessionService) : base(logger, client, idGenerator, sessionService) { ISessionService sessionService) : base(logger, client, idGenerator, sessionService) {

View File

@ -1,21 +1,24 @@
using Core.DomainObjects.Documents; using Microsoft.Extensions.Logging;
using DataProviders.Abstractions;
using DomainResults.Common; using DomainResults.Common;
using Microsoft.Extensions.Logging;
using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization;
using MongoDB.Driver; using MongoDB.Driver;
namespace DataProviders { using DataProviders.Abstractions;
using Core.DomainObjects.Documents;
namespace DataProviders.Collections {
public interface IContentDataProvider { public interface IContentDataProvider {
(Content?, IDomainResult) Get(Guid siteId, string locale); (Content?, IDomainResult) Get(Guid siteId, string locale);
} }
public class ContentDataProvider : DataProviderBase<Content>, IContentDataProvider { public class ContentDataProvider : CollectionDataProviderBase<Content>, IContentDataProvider {
private const string _collectionName = "content"; private const string _collectionName = "content";
public ContentDataProvider( public ContentDataProvider(
ILogger<DataProviderBase<Content>> logger, ILogger<CollectionDataProviderBase<Content>> logger,
IMongoClient client, IMongoClient client,
IIdGenerator idGenerator, IIdGenerator idGenerator,
ISessionService sessionService) : base(logger, client, idGenerator, sessionService) { ISessionService sessionService) : base(logger, client, idGenerator, sessionService) {

View File

@ -8,7 +8,7 @@ using MongoDB.Driver;
using DataProviders.Abstractions; using DataProviders.Abstractions;
using Core.DomainObjects.Documents; using Core.DomainObjects.Documents;
namespace DataProviders { namespace DataProviders.Collections {
public interface IShopCartDataProvider { public interface IShopCartDataProvider {
(Guid?, IDomainResult) Insert(ShopCartItem obj); (Guid?, IDomainResult) Insert(ShopCartItem obj);
@ -19,10 +19,10 @@ namespace DataProviders {
IDomainResult DeleteAll(Guid siteId, Guid userId); IDomainResult DeleteAll(Guid siteId, Guid userId);
} }
public class ShopCartDataProvider : DataProviderBase<ShopCartItem>, IShopCartDataProvider { public class ShopCartDataProvider : CollectionDataProviderBase<ShopCartItem>, IShopCartDataProvider {
private const string _collectionName = "shopcart"; private const string _collectionName = "shopcart";
public ShopCartDataProvider( public ShopCartDataProvider(
ILogger<DataProviderBase<ShopCartItem>> logger, ILogger<CollectionDataProviderBase<ShopCartItem>> logger,
IMongoClient client, IMongoClient client,
IIdGenerator idGenerator, IIdGenerator idGenerator,
ISessionService sessionService) : base(logger, client, idGenerator, sessionService) { ISessionService sessionService) : base(logger, client, idGenerator, sessionService) {

View File

@ -8,7 +8,7 @@ using MongoDB.Driver;
using Core.DomainObjects.Documents; using Core.DomainObjects.Documents;
using DataProviders.Abstractions; using DataProviders.Abstractions;
namespace DataProviders { namespace DataProviders.Collections {
public interface IShopCatalogDataProvider { public interface IShopCatalogDataProvider {
(Guid?, IDomainResult) Insert(ShopItem obj); (Guid?, IDomainResult) Insert(ShopItem obj);
(ShopItem?, IDomainResult) Get(Guid siteId, string sku); (ShopItem?, IDomainResult) Get(Guid siteId, string sku);
@ -20,12 +20,12 @@ namespace DataProviders {
IDomainResult DeleteAll(Guid siteId); IDomainResult DeleteAll(Guid siteId);
} }
public class ShopCatalogDataProvider : DataProviderBase<ShopItem>, IShopCatalogDataProvider { public class ShopCatalogDataProvider : CollectionDataProviderBase<ShopItem>, IShopCatalogDataProvider {
private const string _collectionName = "shopcatalog"; private const string _collectionName = "shopcatalog";
public ShopCatalogDataProvider( public ShopCatalogDataProvider(
ILogger<DataProviderBase<ShopItem>> logger, ILogger<CollectionDataProviderBase<ShopItem>> logger,
IMongoClient client, IMongoClient client,
IIdGenerator idGenerator, IIdGenerator idGenerator,
ISessionService sessionService) : base(logger, client, idGenerator, sessionService) { ISessionService sessionService) : base(logger, client, idGenerator, sessionService) {

View File

@ -37,8 +37,6 @@ namespace DataProviders.Converters {
default: default:
throw new NotImplementedException($"No implementation to deserialize {type}"); throw new NotImplementedException($"No implementation to deserialize {type}");
} }
return response;
} }
private void Serialize(IBsonWriter writer, List<T> values) { private void Serialize(IBsonWriter writer, List<T> values) {
if (values != null) { if (values != null) {

View File

@ -11,6 +11,7 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="MongoDB.Driver" Version="2.17.1" /> <PackageReference Include="MongoDB.Driver" Version="2.17.1" />
<PackageReference Include="MongoDB.Driver.GridFS" Version="2.17.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -4,6 +4,9 @@ using MongoDB.Driver;
using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.IdGenerators; using MongoDB.Bson.Serialization.IdGenerators;
using DataProviders.Collections;
using DataProviders.Buckets;
namespace DataProviders.Extensions namespace DataProviders.Extensions
{ {
public static class ServiceCollectionExtensions { public static class ServiceCollectionExtensions {
@ -13,14 +16,21 @@ namespace DataProviders.Extensions
services.AddSingleton<IMongoClient>(x => new MongoClient(config.ConnectionString)); services.AddSingleton<IMongoClient>(x => new MongoClient(config.ConnectionString));
services.AddSingleton<IIdGenerator, GuidGenerator>(); services.AddSingleton<IIdGenerator, GuidGenerator>();
Mappings.RegisterClassMap();
services.AddSingleton<ISessionService, SessionService>(); services.AddSingleton<ISessionService, SessionService>();
#region Collections
services.AddSingleton<IContentDataProvider, ContentDataProvider>(); services.AddSingleton<IContentDataProvider, ContentDataProvider>();
services.AddSingleton<IShopCatalogDataProvider, ShopCatalogDataProvider>(); services.AddSingleton<IShopCatalogDataProvider, ShopCatalogDataProvider>();
services.AddSingleton<IShopCartDataProvider, ShopCartDataProvider>(); services.AddSingleton<IShopCartDataProvider, ShopCartDataProvider>();
services.AddSingleton<ICategoryDataProvider, CategoryDataProvider>(); services.AddSingleton<ICategoryDataProvider, CategoryDataProvider>();
services.AddSingleton<IBlogCatalogDataProvider, BlogCatalogDataProvider>(); services.AddSingleton<IBlogCatalogDataProvider, BlogCatalogDataProvider>();
Mappings.RegisterClassMap(); #endregion
#region Buckets
services.AddSingleton<IImagesBucketDataProvider, ImagesBucketDataProvider>();
#endregion
} }
} }
} }

View File

@ -0,0 +1,62 @@
using DomainResults.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Net.Http.Headers;
using WeatherForecast.Services;
namespace WeatherForecast.Controllers {
/// <summary>
///
/// </summary>
[ApiController]
[AllowAnonymous]
[Route("api/[controller]")]
public class FileController : Controller {
private readonly IFileService _fileService;
/// <summary>
///
/// </summary>
/// <param name="fileService"></param>
public FileController(
IFileService fileService
) {
_fileService = fileService;
}
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userid"></param>
/// <param name="fileId"></param>
/// <returns></returns>
[HttpGet("{siteId}/{userId}/{fileId}")]
public IActionResult Get([FromRoute] Guid siteId, [FromRoute] Guid userid, [FromRoute] Guid fileId) {
var (file, result) = _fileService.Get(siteId, userid, fileId);
if (!result.IsSuccess || file == null)
return result.ToActionResult();
var stream = new MemoryStream(file.Bytes);
return new FileStreamResult(stream, file.ContentType) {
FileDownloadName = file.Name
};
}
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="fileId"></param>
/// <returns></returns>
[HttpDelete("{siteId}/{userId}/{fileId}")]
public IActionResult Delete([FromRoute] Guid siteId, [FromRoute] Guid userId, [FromRoute] Guid fileId) {
var result = _fileService.Delete(siteId, userId, fileId);
return result.ToActionResult();
}
}
}

View File

@ -0,0 +1,54 @@
using DomainResults.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WeatherForecast.Services;
namespace WeatherForecast.Controllers {
/// <summary>
///
/// </summary>
[ApiController]
[AllowAnonymous]
[Route("api/[controller]")]
public class FilesController : Controller {
private readonly IFilesService _filesService;
/// <summary>
///
/// </summary>
/// <param name="filesService"></param>
public FilesController(
IFilesService filesService
) {
_filesService = filesService;
}
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="file"></param>
/// <returns></returns>
[HttpPost("{siteId}/{userId}")]
public IActionResult Post([FromRoute] Guid siteId, [FromRoute] Guid userId, List<IFormFile> file) {
var result = _filesService.Post(siteId, userId, file);
return result.ToActionResult();
}
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <returns></returns>
[HttpDelete("{siteId}/{userId}")]
public IActionResult Delete([FromRoute] Guid siteId, [FromRoute] Guid userId) {
var result = _filesService.Delete(siteId, userId);
return result.ToActionResult();
}
}
}

View File

@ -1,6 +1,6 @@
using Core.Abstractions.DomainObjects; using Core.Abstractions.DomainObjects;
using Core.Abstractions.Models; using Core.Abstractions.Models;
using Core.DomainObjects; using Core.DomainObjects.Documents;
using Core.Enumerations; using Core.Enumerations;
using WeatherForecast.Models.Responses; using WeatherForecast.Models.Responses;
using WeatherForecast.Models.Responses.L10n; using WeatherForecast.Models.Responses.L10n;

View File

@ -1,5 +1,5 @@
using Core.Abstractions.Models; using Core.Abstractions.Models;
using Core.DomainObjects; using Core.DomainObjects.Documents;
using Core.DomainObjects.L10n; using Core.DomainObjects.L10n;
using Core.Enumerations; using Core.Enumerations;
using Extensions; using Extensions;

View File

@ -1,5 +1,5 @@
using Core.Abstractions.Models; using Core.Abstractions.Models;
using Core.DomainObjects; using Core.DomainObjects.Documents;
using Core.Enumerations; using Core.Enumerations;
using WeatherForecast.Models.Responses.L10n; using WeatherForecast.Models.Responses.L10n;

View File

@ -4,11 +4,13 @@ using ExtensionMethods;
using DataProviders; using DataProviders;
using Core.DomainObjects; using Core.DomainObjects;
using Core.DomainObjects.Documents;
using Core.DomainObjects.L10n; using Core.DomainObjects.L10n;
using Core.Enumerations; using Core.Enumerations;
using WeatherForecast.Models.Requests; using WeatherForecast.Models.Requests;
using WeatherForecast.Models.Responses; using WeatherForecast.Models.Responses;
using DataProviders.Collections;
namespace WeatherForecast.Services { namespace WeatherForecast.Services {

View File

@ -7,6 +7,8 @@ using Core.DomainObjects;
using Core.Enumerations; using Core.Enumerations;
using WeatherForecast.Models.Responses; using WeatherForecast.Models.Responses;
using DataProviders.Collections;
using Core.DomainObjects.Documents;
namespace WeatherForecast.Services { namespace WeatherForecast.Services {

View File

@ -6,6 +6,7 @@ using Core.Enumerations;
using WeatherForecast.Models.Requests; using WeatherForecast.Models.Requests;
using WeatherForecast.Models.Responses; using WeatherForecast.Models.Responses;
using DataProviders.Collections;
namespace WeatherForecast.Services { namespace WeatherForecast.Services {

View File

@ -6,6 +6,7 @@ using Core.Abstractions;
using Core.Enumerations; using Core.Enumerations;
using WeatherForecast.Models.Responses; using WeatherForecast.Models.Responses;
using DataProviders.Collections;
namespace WeatherForecast.Services { namespace WeatherForecast.Services {

View File

@ -1,6 +1,6 @@
using DomainResults.Common; using DomainResults.Common;
using DataProviders; using DataProviders.Collections;
using WeatherForecast.Models.Responses; using WeatherForecast.Models.Responses;

View File

@ -0,0 +1,87 @@
using DataProviders;
using DataProviders.Buckets;
using DomainResults.Common;
namespace WeatherForecast.Services {
/// <summary>
///
/// </summary>
public interface IFileService {
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="fileId"></param>
/// <returns></returns>
(BucketFile?, IDomainResult) Get(Guid siteId, Guid userId, Guid fileId);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="fileId"></param>
/// <returns></returns>
IDomainResult Delete(Guid siteId, Guid userId, Guid fileId);
}
/// <summary>
///
/// </summary>
public class FileService : IFileService {
private readonly ILogger<FilesService> _logger;
private readonly IImagesBucketDataProvider _imageBucketDataProvider;
/// <summary>
///
/// </summary>
/// <param name="logger"></param>
/// <param name="imageBucketDataProvider"></param>
public FileService(
ILogger<FilesService> logger,
IImagesBucketDataProvider imageBucketDataProvider
) {
_logger = logger;
_imageBucketDataProvider = imageBucketDataProvider;
}
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="fileId"></param>
/// <returns></returns>
public (BucketFile?, IDomainResult) Get(Guid siteId, Guid userId, Guid fileId) {
try {
var (file, result) = _imageBucketDataProvider.Download(siteId, userId, fileId);
if (!result.IsSuccess || file == null)
return (null, result);
return IDomainResult.Success(file);
}
catch (Exception ex) {
return IDomainResult.Failed<BucketFile?>(ex.Message);
}
}
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="fileId"></param>
/// <returns></returns>
public IDomainResult Delete(Guid siteId, Guid userId, Guid fileId) {
try {
return _imageBucketDataProvider.DeleteOne(siteId, userId, fileId);
}
catch (Exception ex) {
return IDomainResult.Failed(ex.Message);
}
}
}
}

View File

@ -0,0 +1,100 @@
using DataProviders;
using DataProviders.Buckets;
using DomainResults.Common;
using Microsoft.AspNetCore.Mvc;
namespace WeatherForecast.Services {
/// <summary>
///
/// </summary>
public interface IFilesService {
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="files"></param>
/// <returns></returns>
(List<Guid>?, IDomainResult) Post(Guid siteId, Guid userId, List<IFormFile> files);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <returns></returns>
IDomainResult Delete(Guid siteId, Guid userId);
}
/// <summary>
///
/// </summary>
public class FilesService : IFilesService {
private readonly ILogger<FilesService> _logger;
private readonly IImagesBucketDataProvider _imageBucketDataProvider;
/// <summary>
///
/// </summary>
/// <param name="logger"></param>
/// <param name="imageBucketDataProvider"></param>
public FilesService(
ILogger<FilesService> logger,
IImagesBucketDataProvider imageBucketDataProvider
) {
_logger = logger;
_imageBucketDataProvider = imageBucketDataProvider;
}
/// <summary>
/// Process uploaded files
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="files"></param>
/// <returns></returns>
public (List<Guid>?, IDomainResult) Post(Guid siteId, Guid userId, List<IFormFile> files) {
try {
// Don't rely on or trust the FileName property without validation.
var newFiles = new List<BucketFile>();
foreach (var formFile in files) {
if (formFile.Length > 0) {
using var ms = new MemoryStream();
formFile.CopyTo(ms);
newFiles.Add(new BucketFile(formFile.FileName, ms.ToArray(), formFile.ContentType));
}
}
var (list, result) = _imageBucketDataProvider.UploadMany(siteId, userId, newFiles);
if (!result.IsSuccess || list == null)
return IDomainResult.Failed<List<Guid>?>();
return IDomainResult.Success(list);
}
catch (Exception ex) {
return IDomainResult.Failed<List<Guid>?> (ex.Message);
}
}
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <returns></returns>
public IDomainResult Delete(Guid siteId, Guid userId) {
try {
return _imageBucketDataProvider.DeletMany(siteId, userId);
}
catch (Exception ex) {
return IDomainResult.Failed(ex.Message);
}
}
}
}

View File

@ -1,6 +1,6 @@
using DomainResults.Common; using DomainResults.Common;
using DataProviders; using DataProviders.Collections;
using Core.Abstractions; using Core.Abstractions;
using Core.Enumerations; using Core.Enumerations;

View File

@ -6,6 +6,7 @@ using Core.Enumerations;
using Core.Abstractions; using Core.Abstractions;
using WeatherForecast.Models.Responses; using WeatherForecast.Models.Responses;
using DataProviders.Collections;
namespace WeatherForecast.Services { namespace WeatherForecast.Services {

View File

@ -10,6 +10,8 @@ using Core.Enumerations;
using WeatherForecast.Models; using WeatherForecast.Models;
using WeatherForecast.Models.Requests; using WeatherForecast.Models.Requests;
using DataProviders.Collections;
using Core.DomainObjects.Documents;
namespace WeatherForecast.Services { namespace WeatherForecast.Services {

View File

@ -8,6 +8,8 @@ using Core.Enumerations;
using WeatherForecast.Models; using WeatherForecast.Models;
using WeatherForecast.Models.Responses; using WeatherForecast.Models.Responses;
using DataProviders.Collections;
using Core.DomainObjects.Documents;
namespace WeatherForecast.Services { namespace WeatherForecast.Services {

View File

@ -80,6 +80,9 @@ namespace WeatherForecast {
services.AddScoped<ICategoryItemService, CategoryItemService>(); services.AddScoped<ICategoryItemService, CategoryItemService>();
services.AddScoped<ICategoryItemsService, CategoryItemsService>(); services.AddScoped<ICategoryItemsService, CategoryItemsService>();
services.AddScoped<IFileService, FileService>();
services.AddScoped<IFilesService, FilesService>();
services.RegisterDataproviders(appSettings); services.RegisterDataproviders(appSettings);
#region Swagger #region Swagger