using Microsoft.Extensions.Logging;
using DomainResults.Common;
using MongoDB.Driver;
using MongoDB.Driver.GridFS;
using DataProviders.Buckets.Abstractions;
using MongoDB.Bson;
using Extensions;
namespace DataProviders.Buckets {
///
///
///
public interface IImageBucketDataProvider {
///
///
///
///
///
///
///
(Guid?, IDomainResult) Upload(BucketFile file);
///
///
///
///
///
///
///
(List?, IDomainResult) UploadMany(List files);
///
///
///
///
///
///
(BucketFile?, IDomainResult) Download(Guid siteId, Guid fileId);
///
///
///
///
///
///
///
(BucketFile?, IDomainResult) Download(Guid siteId, Guid userId, Guid fileId);
(List?, IDomainResult) DownloadMany(Guid siteId, Guid userId, List fileIds);
///
///
///
///
///
///
///
IDomainResult DeleteOne(Guid siteId, Guid userId, Guid fileId);
///
///
///
///
///
///
IDomainResult DeleteMany(Guid siteId, Guid userId);
}
///
///
///
public class ImageBucketDataProvider : BucketDataProviderBase, IImageBucketDataProvider {
///
///
///
///
///
public ImageBucketDataProvider(
ILogger logger,
IMongoClient client
) : base(logger, client, "reactredux", "images") { }
#region Upload many
protected override async Task<(List?, IDomainResult)> UploadManyAsync(List files) {
var options = new GridFSUploadOptions {
ChunkSizeBytes = 64512, // 63KB
};
try {
var result = new List();
foreach (var file in files) {
options.Metadata = new BsonDocument {
{ "siteId", $"{file.SiteId}"},
{ "userId", $"{file.UserId}"},
{ "published", file.Published.ToString() },
{ "fileName", file.Name },
{ "contentType", file.ContentType }
};
await _bucket.UploadFromBytesAsync($"{file.Id}", file.Bytes, options);
result.Add(file.Id);
}
return result.Count > 0
? IDomainResult.Success(result)
: IDomainResult.Failed?>();
}
catch (Exception ex) {
_logger.LogError(ex, "Bucket data provider error");
return IDomainResult.Failed?>();
}
}
#endregion
#region Download
///
///
///
///
///
///
public (BucketFile?, IDomainResult) Download(Guid siteId, Guid fileId) {
var filter = Builders.Filter.And(
Builders.Filter.Eq(x => x.Metadata["siteId"], $"{siteId}"),
Builders.Filter.Not(Builders.Filter.Eq(x => x.Metadata["published"], "")),
Builders.Filter.Eq(x => x.Filename, $"{fileId}")
);
var (list, result) = Download(filter);
if (!result.IsSuccess || list == null)
return (null, result);
return (list.First(), result);
}
///
///
///
///
///
///
///
public (BucketFile?, IDomainResult) Download(Guid siteId, Guid userId, Guid fileId) {
var filter = Builders.Filter.And(
Builders.Filter.Eq(x => x.Metadata["siteId"], $"{siteId}"),
Builders.Filter.Eq(x => x.Metadata["userId"], $"{userId}"),
Builders.Filter.Eq(x => x.Filename, $"{fileId}")
);
var (list, result) = Download(filter);
if (!result.IsSuccess || list == null)
return (null, result);
return (list.First(), result);
}
#endregion
#region Download many
///
///
///
///
///
///
///
public (List?, IDomainResult) DownloadMany(Guid siteId, Guid userId, List fileIds) {
var builder = Builders.Filter;
FilterDefinition? filter = default;
foreach (var fileId in fileIds) {
filter |= builder.And(
Builders.Filter.Eq(x => x.Metadata["siteId"], $"{siteId}"),
Builders.Filter.Eq(x => x.Metadata["userId"], $"{userId}"),
Builders.Filter.Eq(x => x.Filename, $"{fileId}")
);
}
if (filter == null)
return IDomainResult.Failed?>();
var result = Download(filter);
return result;
}
protected override async Task<(List?, IDomainResult)> DownloadAsync(FilterDefinition filter) {
try {
var sort = Builders.Sort.Descending(x => x.UploadDateTime);
using var cursor = await _bucket.FindAsync(filter, new GridFSFindOptions {
Sort = sort,
});
var result = new List();
// fileInfo either has the matching file information or is null
foreach (var fileInfo in await cursor.ToListAsync()) {
if (fileInfo == null)
return IDomainResult.NotFound?>();
var id = fileInfo.Filename.ToGuid();
var userId = fileInfo.Metadata["userId"].ToString()?.ToNullableGuid();
var siteId = fileInfo.Metadata["siteId"].ToString()?.ToNullableGuid();
var published = fileInfo.Metadata["published"].ToString()?.ToNullableDateTime();
var fileName = fileInfo.Metadata["fileName"].ToString() ?? "";
var bytes = await _bucket.DownloadAsBytesByNameAsync($"{fileInfo.Filename}", new GridFSDownloadByNameOptions {
Revision = -1
});
var contentType = fileInfo.Metadata["contentType"].ToString() ?? "";
if (siteId == null || userId == null || bytes == null)
return IDomainResult.Failed?>();
result.Add(new BucketFile(id, siteId.Value, userId.Value, published, fileName, bytes, contentType));
}
return result.Count > 0
? IDomainResult.Success(result)
: IDomainResult.NotFound?>();
}
catch (Exception ex) {
_logger.LogError(ex, "Bucket data provider error");
return IDomainResult.Failed?>();
}
}
#endregion
#region Delete
public IDomainResult DeleteOne(Guid siteId, Guid userId, Guid fileId) =>
DeleteOneAsync(siteId, userId, fileId).Result;
public Task DeleteOneAsync(Guid siteId, Guid userId, Guid fileId) =>
DeleteAsync(Builders.Filter.And(
Builders.Filter.Eq(x => x.Metadata["siteId"], $"{siteId}"),
Builders.Filter.Eq(x => x.Metadata["userId"], $"{userId}"),
Builders.Filter.Eq(x => x.Filename, $"{fileId}")
));
public IDomainResult DeleteMany(Guid siteId, Guid userId) =>
DeleteManyAsync(siteId, userId).Result;
public Task DeleteManyAsync(Guid siteId, Guid userId) =>
DeleteAsync(Builders.Filter.And(
Builders.Filter.Eq(x => x.Metadata["siteId"], $"{siteId}"),
Builders.Filter.Eq(x => x.Metadata["userId"], $"{userId}")
));
#endregion
}
}