push
This commit is contained in:
@@ -9,7 +9,7 @@ public interface IRepositoryBase<T, TId>
|
|||||||
Task UpdateAsync(T entity, CancellationToken cancellationToken = default);
|
Task UpdateAsync(T entity, CancellationToken cancellationToken = default);
|
||||||
Task DeleteAsync(T entity, CancellationToken cancellationToken = default);
|
Task DeleteAsync(T entity, CancellationToken cancellationToken = default);
|
||||||
Task DeleteById(TId id, CancellationToken cancellationToken = default);
|
Task DeleteById(TId id, CancellationToken cancellationToken = default);
|
||||||
Task<T?> GetById(TId id, CancellationToken cancellationToken = default);
|
Task<T?> GetByIdAsync(TId id, CancellationToken cancellationToken = default);
|
||||||
Task<bool> Exists(Expression<Func<T,bool>> predicate, CancellationToken cancellationToken = default);
|
Task<bool> ExistsAsync(Expression<Func<T,bool>> predicate, CancellationToken cancellationToken = default);
|
||||||
Task<T?> Get(Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default);
|
Task<T?> GetAsync(Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,13 +49,13 @@ namespace VizhTalk.BuildingBlocks.Infrastructure
|
|||||||
entity.SetDeleted(true);
|
entity.SetDeleted(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> Exists(Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
|
public async Task<bool> ExistsAsync(Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
|
||||||
=> await _dbContext.Set<T>().Where(predicate).AnyAsync(cancellationToken);
|
=> await _dbContext.Set<T>().Where(predicate).AnyAsync(cancellationToken);
|
||||||
|
|
||||||
public async Task<T?> Get(Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
|
public async Task<T?> GetAsync(Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
|
||||||
=> await _dbContext.Set<T>().Where(predicate).FirstOrDefaultAsync(predicate, cancellationToken);
|
=> await _dbContext.Set<T>().FirstOrDefaultAsync(predicate, cancellationToken);
|
||||||
|
|
||||||
public async Task<T?> GetById(TId id, CancellationToken cancellationToken = default)
|
public async Task<T?> GetByIdAsync(TId id, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace VizhTalk.Gateway.Web.BFF.Mappers
|
|||||||
{
|
{
|
||||||
public static async Task<UploadFile> AsFile(this IFile file)
|
public static async Task<UploadFile> AsFile(this IFile file)
|
||||||
{
|
{
|
||||||
MemoryStream stream = new MemoryStream();
|
using MemoryStream stream = new MemoryStream();
|
||||||
await file.CopyToAsync(stream);
|
await file.CopyToAsync(stream);
|
||||||
return new UploadFile()
|
return new UploadFile()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ builder.Services.AddScoped<LanguageMutation>();
|
|||||||
|
|
||||||
builder.AddGraphQL()
|
builder.AddGraphQL()
|
||||||
.AddQueryType<LanguageQuery>()
|
.AddQueryType<LanguageQuery>()
|
||||||
.AddMutationType<LanguageMutation>();
|
.AddMutationType<LanguageMutation>()
|
||||||
|
.AddType<UploadType>();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class CreateLanguageCommandHandler(IUnitOfWork unitOfWork,
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var title = request.Title.Trim();
|
var title = request.Title.Trim();
|
||||||
if (await unitOfWork.Language.Exists(x => x.Title == title))
|
if (await unitOfWork.Language.ExistsAsync(x => x.Title == title))
|
||||||
throw new LanguageTitleAlreadyExistsException();
|
throw new LanguageTitleAlreadyExistsException();
|
||||||
|
|
||||||
var fileGroup = await unitOfWork.FileGroup.GetByFileGroupKey(FileGroupKey.IconLanguage);
|
var fileGroup = await unitOfWork.FileGroup.GetByFileGroupKey(FileGroupKey.IconLanguage);
|
||||||
@@ -71,7 +71,7 @@ public class UpdateLanguageCommandHandler(IUnitOfWork unitOfWork, CDNGrpc.CDNGrp
|
|||||||
{
|
{
|
||||||
public async Task<LanguageDTO> Handle(UpdateLanguageCommand request, CancellationToken cancellationToken)
|
public async Task<LanguageDTO> Handle(UpdateLanguageCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var language = await unitOfWork.Language.GetById(new LanguageId(request.Id), cancellationToken);
|
var language = await unitOfWork.Language.GetByIdAsync(new LanguageId(request.Id), cancellationToken);
|
||||||
if (language == null)
|
if (language == null)
|
||||||
throw new LanguageNotFoundException();
|
throw new LanguageNotFoundException();
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public class LanguageService(ILearningModule learningModule) : LanguageGrpc.Lang
|
|||||||
}
|
}
|
||||||
public override async Task<LanguageDTO> GetByTitle(GetLanguageByTitleQuery request, ServerCallContext context)
|
public override async Task<LanguageDTO> GetByTitle(GetLanguageByTitleQuery request, ServerCallContext context)
|
||||||
{
|
{
|
||||||
|
await Task.Delay(10000);
|
||||||
return await learningModule.Execute(request, context.CancellationToken);
|
return await learningModule.Execute(request, context.CancellationToken);
|
||||||
}
|
}
|
||||||
public override async Task<GetAllLanguageDTO> GetAll(GetAllLanguageQuery request, ServerCallContext context)
|
public override async Task<GetAllLanguageDTO> GetAll(GetAllLanguageQuery request, ServerCallContext context)
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ namespace VizhTalk.Grpc.Learning
|
|||||||
public sealed partial class Pagination
|
public sealed partial class Pagination
|
||||||
{
|
{
|
||||||
public int Skip()
|
public int Skip()
|
||||||
=> PageNumber * (PageSize == 0 ? 10 : PageSize);
|
=> (PageNumber - 1) * (PageSize == 0 ? 10 : PageSize);
|
||||||
public int Take()
|
public int Take()
|
||||||
=> PageNumber;
|
=> PageSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
using System.Security.Cryptography;
|
using System.IO;
|
||||||
using Grpc.Core;
|
using System.Security.Cryptography;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.StaticFiles;
|
using Microsoft.AspNetCore.StaticFiles;
|
||||||
using Vizhtalk.CDN.Presentation.Application.Exceptions;
|
using Vizhtalk.CDN.Presentation.Application.Exceptions;
|
||||||
using Vizhtalk.CDN.Presentation.Domain.Entities;
|
using Vizhtalk.CDN.Presentation.Domain.Entities;
|
||||||
|
using Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
||||||
using Vizhtalk.CDN.Presentation.Domain.ValueObjects;
|
using Vizhtalk.CDN.Presentation.Domain.ValueObjects;
|
||||||
|
using Vizhtalk.CDN.Presentation.FileManagerServices;
|
||||||
using VizhTalk.BuildingBlocks.Application.Configuration.Commnad;
|
using VizhTalk.BuildingBlocks.Application.Configuration.Commnad;
|
||||||
using VizhTalk.Grpc.CDN;
|
using VizhTalk.Grpc.CDN;
|
||||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
|
||||||
|
|
||||||
namespace Vizhtalk.CDN.Presentation.Application.CommandHandlers;
|
namespace Vizhtalk.CDN.Presentation.Application.CommandHandlers;
|
||||||
|
|
||||||
@@ -17,11 +20,11 @@ public class CreateMediaGroupCommandHandler(IUnitOfWork unitOfWork, CDNGrpc.CDNG
|
|||||||
{
|
{
|
||||||
var title = request.Title.Trim();
|
var title = request.Title.Trim();
|
||||||
|
|
||||||
if (await unitOfWork.MediaGroup.Exists(a => a.Key == request.Key))
|
if (await unitOfWork.MediaGroup.ExistsAsync(a => a.Key == request.Key))
|
||||||
throw new MediaGroupKeyAlreadyExistsException();
|
throw new MediaGroupKeyAlreadyExistsException();
|
||||||
|
|
||||||
|
|
||||||
var mediaGroup = MediaGroup.CreateNew(title,request.Key,request.IsSecure);
|
var mediaGroup = MediaGroup.CreateNew(title, request.Key, request.IsSecure);
|
||||||
await unitOfWork.MediaGroup.AddAsync(mediaGroup, cancellationToken);
|
await unitOfWork.MediaGroup.AddAsync(mediaGroup, cancellationToken);
|
||||||
await unitOfWork.SaveChangeAsync(cancellationToken);
|
await unitOfWork.SaveChangeAsync(cancellationToken);
|
||||||
return mediaGroup.Adapt<MediaGroupDTO>();
|
return mediaGroup.Adapt<MediaGroupDTO>();
|
||||||
@@ -29,25 +32,44 @@ public class CreateMediaGroupCommandHandler(IUnitOfWork unitOfWork, CDNGrpc.CDNG
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UploadFileCommandHandler(IUnitOfWork unitOfWork, CDNGrpc.CDNGrpcClient cdnClient) : ICommandHandler<UploadFileCommand, UploadFileDTO>
|
public class UploadFileCommandHandler(IUnitOfWork unitOfWork, CDNGrpc.CDNGrpcClient cdnClient, IFileManagerService fileManager) : ICommandHandler<UploadFileCommand, UploadFileDTO>
|
||||||
{
|
{
|
||||||
public async Task<UploadFileDTO> Handle(UploadFileCommand request, CancellationToken cancellationToken)
|
public async Task<UploadFileDTO> Handle(UploadFileCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
var fileBytes = request.File.ToByteArray();
|
var mediaGroup = await unitOfWork.MediaGroup.GetByIdAsync(new MediaGroupId(request.MediaGroupId));
|
||||||
|
if (mediaGroup == null)
|
||||||
|
throw new NotFoundMediaGroupException();
|
||||||
|
if (mediaGroup.IsSecure && string.IsNullOrEmpty(request.ClientId))
|
||||||
|
throw new MediaGroupIsSecureAndClientIsEmptyException();
|
||||||
|
|
||||||
|
var fileBytes = request.File.File.ToArray();
|
||||||
var hash = ToSHA512Hash(fileBytes);
|
var hash = ToSHA512Hash(fileBytes);
|
||||||
|
|
||||||
var media = await unitOfWork.Media.Get(a => a.Hash == hash);
|
var media = await unitOfWork.Media.GetAsync(a => a.Hash == hash);
|
||||||
|
|
||||||
if (media is null)
|
if (media is null)
|
||||||
{
|
{
|
||||||
|
var extension = ContentType.ContentTypeExtension.GetValueOrDefault(request.File.ContentType);
|
||||||
|
if (extension == null)
|
||||||
|
throw new ThisContentFileIsNotSupportedException();
|
||||||
|
|
||||||
using MemoryStream stream = new MemoryStream(fileBytes);
|
var path = await fileManager.SaveFile(fileBytes, extension, mediaGroup.Id);
|
||||||
|
media = Media.CreateNew(new ContentType(request.File.ContentType, fileBytes), fileBytes.Length, hash, path);
|
||||||
}
|
}
|
||||||
|
var mediaGroupMedia = mediaGroup.AddMedia(new FileName(request.File.Name), media);
|
||||||
|
if (!string.IsNullOrEmpty(request.ClientId))
|
||||||
|
mediaGroupMedia.AddMediaPermission(media, Client.CreateNew(new ClientId(request.ClientId)));
|
||||||
|
|
||||||
throw new NotImplementedException();
|
await unitOfWork.MediaGroup.AddAsync(mediaGroup, cancellationToken);
|
||||||
|
await unitOfWork.SaveChangeAsync(cancellationToken);
|
||||||
|
|
||||||
|
return new UploadFileDTO()
|
||||||
|
{
|
||||||
|
ContentType = request.File.ContentType,
|
||||||
|
MediaGroupMediaId = mediaGroupMedia.Id.Value,
|
||||||
|
Size = fileBytes.Length
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ToSHA512Hash(byte[] data)
|
public string ToSHA512Hash(byte[] data)
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
using VizhTalk.BuildingBlocks.Application.Exceptions;
|
||||||
|
|
||||||
|
namespace Vizhtalk.CDN.Presentation.Application.Exceptions
|
||||||
|
{
|
||||||
|
public class MediaGroupIsSecureAndClientIsEmptyException : BaseException
|
||||||
|
{
|
||||||
|
public MediaGroupIsSecureAndClientIsEmptyException() : base("Media is a security group and the client is empty")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using VizhTalk.BuildingBlocks.Application.Exceptions;
|
||||||
|
|
||||||
|
namespace Vizhtalk.CDN.Presentation.Application.Exceptions
|
||||||
|
{
|
||||||
|
public class NotFoundMediaGroupException : BaseException
|
||||||
|
{
|
||||||
|
public NotFoundMediaGroupException() : base("not found media group")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
using VizhTalk.BuildingBlocks.Application.Exceptions;
|
||||||
|
|
||||||
|
namespace Vizhtalk.CDN.Presentation.Application.Exceptions
|
||||||
|
{
|
||||||
|
public class ThisContentFileIsNotSupportedException : BaseException
|
||||||
|
{
|
||||||
|
public ThisContentFileIsNotSupportedException() : base("This content file is not supported")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ public class MapperConfig
|
|||||||
var config = TypeAdapterConfig<MediaGroup, MediaGroupDTO>.NewConfig()
|
var config = TypeAdapterConfig<MediaGroup, MediaGroupDTO>.NewConfig()
|
||||||
.MapWith(lan => new MediaGroupDTO()
|
.MapWith(lan => new MediaGroupDTO()
|
||||||
{
|
{
|
||||||
Id = lan.Id.Value
|
Id = lan.Id.Value,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,17 @@ namespace Vizhtalk.CDN.Presentation.Domain.Entities;
|
|||||||
|
|
||||||
public class Client : Entity<ClientId>
|
public class Client : Entity<ClientId>
|
||||||
{
|
{
|
||||||
private List<MediaClient> _mediaClients = new();
|
private Client()
|
||||||
public IReadOnlyList<MediaClient> MediaClients => _mediaClients;
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
private Client(ClientId id)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
private List<MediaPermission> _mediaClients = new();
|
||||||
|
public IReadOnlyList<MediaPermission> MediaClients => _mediaClients;
|
||||||
|
|
||||||
|
public static Client CreateNew(ClientId clientId)
|
||||||
|
=> new(clientId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,6 @@ public class Media : Entity<MediaId>
|
|||||||
public IReadOnlyList<MediaGroupMedia> MediaGroupMedias => _mediaGroupMedia;
|
public IReadOnlyList<MediaGroupMedia> MediaGroupMedias => _mediaGroupMedia;
|
||||||
|
|
||||||
|
|
||||||
public static Media Create(ContentType contentType, int size, string hash, string path)
|
public static Media CreateNew(ContentType contentType, int size, string hash, string path)
|
||||||
=> new (contentType, size, hash, path);
|
=> new (contentType, size, hash, path);
|
||||||
}
|
}
|
||||||
@@ -23,4 +23,10 @@ public class MediaGroup : Entity<MediaGroupId>
|
|||||||
public static MediaGroup CreateNew(string title, string Key, bool isSecure)
|
public static MediaGroup CreateNew(string title, string Key, bool isSecure)
|
||||||
=> new (new MediaGroupTitle(title), Key, isSecure);
|
=> new (new MediaGroupTitle(title), Key, isSecure);
|
||||||
|
|
||||||
|
public MediaGroupMedia AddMedia(FileName fileName, Media media)
|
||||||
|
{
|
||||||
|
var mediaGroupMedia = MediaGroupMedia.CreateNew(fileName, media, this);
|
||||||
|
_mediaGroupMedia.Add(mediaGroupMedia);
|
||||||
|
return mediaGroupMedia;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,33 @@
|
|||||||
using Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
using Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
||||||
|
using Vizhtalk.CDN.Presentation.Domain.ValueObjects;
|
||||||
using VizhTalk.BuildingBlocks.Domain;
|
using VizhTalk.BuildingBlocks.Domain;
|
||||||
|
|
||||||
namespace Vizhtalk.CDN.Presentation.Domain.Entities;
|
namespace Vizhtalk.CDN.Presentation.Domain.Entities;
|
||||||
|
|
||||||
public class MediaGroupMedia : Entity<MediaGroupMediaId>
|
public class MediaGroupMedia : Entity<MediaGroupMediaId>
|
||||||
{
|
{
|
||||||
private List<MediaClient> _mediaClient = new();
|
private List<MediaPermission> _mediaPermissions = new();
|
||||||
public MediaId MediaId { get; set; }
|
|
||||||
public MediaGroupId MediaGroupId { get; set; }
|
private MediaGroupMedia(FileName fileName,
|
||||||
public Media Media { get; set; }
|
Media media,
|
||||||
public MediaGroup MediaGroup { get; set; }
|
MediaGroup mediaGroup)
|
||||||
public IReadOnlyList<MediaClient> MediaClients => _mediaClient;
|
{
|
||||||
|
Name = fileName;
|
||||||
|
Media = media;
|
||||||
|
MediaGroup = mediaGroup;
|
||||||
|
}
|
||||||
|
public FileName Name { get; private set; }
|
||||||
|
public MediaId MediaId { get; private set; }
|
||||||
|
public MediaGroupId MediaGroupId { get; private set; }
|
||||||
|
public Media Media { get; private set; }
|
||||||
|
public MediaGroup MediaGroup { get; private set; }
|
||||||
|
public IReadOnlyList<MediaPermission> MediaPermissions => _mediaPermissions;
|
||||||
|
|
||||||
|
internal static MediaGroupMedia CreateNew(FileName fileName,
|
||||||
|
Media media,
|
||||||
|
MediaGroup mediaGroup)
|
||||||
|
=> new(fileName, media, mediaGroup);
|
||||||
|
|
||||||
|
public void AddMediaPermission(Media media, Client client)
|
||||||
|
=> _mediaPermissions.Add(MediaPermission.CreateNew(media, client, this));
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-3
@@ -1,12 +1,20 @@
|
|||||||
using Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
using Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
||||||
using Vizhtalk.CDN.Presentation.Domain.ValueObjects;
|
|
||||||
using VizhTalk.BuildingBlocks.Domain;
|
using VizhTalk.BuildingBlocks.Domain;
|
||||||
|
|
||||||
namespace Vizhtalk.CDN.Presentation.Domain.Entities;
|
namespace Vizhtalk.CDN.Presentation.Domain.Entities;
|
||||||
|
|
||||||
public class MediaClient : Entity<MediaClientId>
|
public class MediaPermission : Entity<MediaClientId>
|
||||||
{
|
{
|
||||||
public MediaClientName Name { get; private set; }
|
private MediaPermission()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
private MediaPermission(Media media, Client client, MediaGroupMedia mediaGroupMedia)
|
||||||
|
{
|
||||||
|
Media = media;
|
||||||
|
Client = client;
|
||||||
|
MediaGroupMedia = mediaGroupMedia;
|
||||||
|
}
|
||||||
public MediaId MediaId { get; private set; }
|
public MediaId MediaId { get; private set; }
|
||||||
public ClientId ClientId { get; private set; }
|
public ClientId ClientId { get; private set; }
|
||||||
public MediaGroupMediaId MediaGroupMediaId { get; set; }
|
public MediaGroupMediaId MediaGroupMediaId { get; set; }
|
||||||
@@ -14,4 +22,7 @@ public class MediaClient : Entity<MediaClientId>
|
|||||||
public Client Client { get; private set; }
|
public Client Client { get; private set; }
|
||||||
public Media Media { get; private set; }
|
public Media Media { get; private set; }
|
||||||
public MediaGroupMedia MediaGroupMedia { get; private set; }
|
public MediaGroupMedia MediaGroupMedia { get; private set; }
|
||||||
|
|
||||||
|
public static MediaPermission CreateNew(Media media, Client client, MediaGroupMedia mediaGroupMedia)
|
||||||
|
=> new(media, client, mediaGroupMedia);
|
||||||
}
|
}
|
||||||
@@ -4,4 +4,4 @@ using VizhTalk.BuildingBlocks.Domain;
|
|||||||
|
|
||||||
namespace Vizhtalk.CDN.Presentation.Domain.Repositories;
|
namespace Vizhtalk.CDN.Presentation.Domain.Repositories;
|
||||||
|
|
||||||
public interface IMediaClientRepository : IRepositoryBase<MediaClient, MediaClientId>;
|
public interface IMediaClientRepository : IRepositoryBase<MediaPermission, MediaClientId>;
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
namespace Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
namespace Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
||||||
|
|
||||||
public class MediaGroupId : TypeIdValueBase<long>
|
public class MediaGroupId : TypeIdValueBase<Guid>
|
||||||
{
|
{
|
||||||
public MediaGroupId(long value) : base(value)
|
public MediaGroupId(Guid value) : base(value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,42 @@ namespace Vizhtalk.CDN.Presentation.Domain.ValueObjects;
|
|||||||
|
|
||||||
public class ContentType : ValueObject
|
public class ContentType : ValueObject
|
||||||
{
|
{
|
||||||
|
public static readonly Dictionary<string, string> ContentTypeExtension = new()
|
||||||
|
{
|
||||||
|
// Images
|
||||||
|
{ "image/jpeg", ".jpg" },
|
||||||
|
{ "image/png", ".png" },
|
||||||
|
{ "image/gif", ".gif" },
|
||||||
|
{ "image/webp", ".webp" },
|
||||||
|
{ "image/bmp", ".bmp" },
|
||||||
|
{ "image/tiff", ".tiff" },
|
||||||
|
{ "image/svg+xml", ".svg" },
|
||||||
|
|
||||||
|
// Videos
|
||||||
|
{ "video/mp4", ".mp4" },
|
||||||
|
{ "video/webm", ".webm" },
|
||||||
|
{ "video/ogg", ".ogv" },
|
||||||
|
{ "video/mpeg", ".mpeg" },
|
||||||
|
{ "video/3gpp", ".3gp" },
|
||||||
|
{ "video/3gpp2", ".3g2" },
|
||||||
|
{ "video/x-msvideo", ".avi" },
|
||||||
|
{ "video/x-matroska", ".mkv" },
|
||||||
|
|
||||||
|
// Audios
|
||||||
|
{ "audio/mpeg", ".mp3" },
|
||||||
|
{ "audio/wav", ".wav" },
|
||||||
|
{ "audio/ogg", ".ogg" },
|
||||||
|
{ "audio/webm", ".weba" },
|
||||||
|
{ "audio/aac", ".aac" },
|
||||||
|
{ "audio/flac", ".flac" },
|
||||||
|
{ "audio/mp4", ".m4a" },
|
||||||
|
{ "audio/3gpp", ".3gp" },
|
||||||
|
{ "audio/3gpp2", ".3g2" }
|
||||||
|
};
|
||||||
|
|
||||||
private ContentType()
|
private ContentType()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
public ContentType(string contentType, byte[] fileBytes)
|
public ContentType(string contentType, byte[] fileBytes)
|
||||||
{
|
{
|
||||||
|
|||||||
+4
-4
@@ -3,12 +3,12 @@ using VizhTalk.BuildingBlocks.Domain.Guards;
|
|||||||
|
|
||||||
namespace Vizhtalk.CDN.Presentation.Domain.ValueObjects
|
namespace Vizhtalk.CDN.Presentation.Domain.ValueObjects
|
||||||
{
|
{
|
||||||
public class MediaClientName : ValueObject
|
public class FileName : ValueObject
|
||||||
{
|
{
|
||||||
public MediaClientName(string value)
|
public FileName(string value)
|
||||||
{
|
{
|
||||||
value.NullOrEmpty(nameof(MediaClientName));
|
value.NullOrEmpty(nameof(FileName));
|
||||||
value.MaxLength(nameof(MediaClientName), 150);
|
value.MaxLength(nameof(FileName), 150);
|
||||||
|
|
||||||
Value = value;
|
Value = value;
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using VizhTalk.BuildingBlocks.Domain.Exceptions;
|
using VizhTalk.BuildingBlocks.Domain.Exceptions;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Vizhtalk.CDN.Presentation.Domain.ValueObjects.Rules;
|
namespace Vizhtalk.CDN.Presentation.Domain.ValueObjects.Rules;
|
||||||
|
|
||||||
@@ -12,7 +13,7 @@ public class ValidContentTypeRule(string contentType, byte[] fileBytes) : IBusin
|
|||||||
public bool IsBroken()
|
public bool IsBroken()
|
||||||
{
|
{
|
||||||
// اول MimeType بررسی میشه
|
// اول MimeType بررسی میشه
|
||||||
if (!_validContentTypes.Contains(contentType))
|
if (!ContentType.ContentTypeExtension.ContainsKey(contentType))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// بعد Magic Number بررسی میشه
|
// بعد Magic Number بررسی میشه
|
||||||
@@ -29,39 +30,6 @@ public class ValidContentTypeRule(string contentType, byte[] fileBytes) : IBusin
|
|||||||
return false; // یعنی مشکلی نیست
|
return false; // یعنی مشکلی نیست
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly HashSet<string> _validContentTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
|
||||||
{
|
|
||||||
// Images
|
|
||||||
"image/jpeg",
|
|
||||||
"image/png",
|
|
||||||
"image/gif",
|
|
||||||
"image/webp",
|
|
||||||
"image/bmp",
|
|
||||||
"image/tiff",
|
|
||||||
"image/svg+xml",
|
|
||||||
|
|
||||||
// Videos
|
|
||||||
"video/mp4",
|
|
||||||
"video/webm",
|
|
||||||
"video/ogg",
|
|
||||||
"video/mpeg",
|
|
||||||
"video/3gpp",
|
|
||||||
"video/3gpp2",
|
|
||||||
"video/x-msvideo",
|
|
||||||
"video/x-matroska",
|
|
||||||
|
|
||||||
// Audios
|
|
||||||
"audio/mpeg",
|
|
||||||
"audio/wav",
|
|
||||||
"audio/ogg",
|
|
||||||
"audio/webm",
|
|
||||||
"audio/aac",
|
|
||||||
"audio/flac",
|
|
||||||
"audio/mp4",
|
|
||||||
"audio/3gpp",
|
|
||||||
"audio/3gpp2"
|
|
||||||
};
|
|
||||||
|
|
||||||
private static bool HasValidMagicNumber(string contentType, byte[] fileBytes)
|
private static bool HasValidMagicNumber(string contentType, byte[] fileBytes)
|
||||||
{
|
{
|
||||||
if (fileBytes == null || fileBytes.Length < 4)
|
if (fileBytes == null || fileBytes.Length < 4)
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using Vizhtalk.CDN.Presentation.Domain.Entities;
|
||||||
|
using Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
||||||
|
|
||||||
|
namespace Vizhtalk.CDN.Presentation.FileManagerServices;
|
||||||
|
|
||||||
|
public class FileManagerService(IWebHostEnvironment env) : IFileManagerService
|
||||||
|
{
|
||||||
|
public async Task<string> SaveFile(byte[] fileBytes,string extension, MediaGroupId mediaGroupId)
|
||||||
|
{
|
||||||
|
var root = Path.Combine(env.ContentRootPath, "Files", mediaGroupId.Value.ToString());
|
||||||
|
if (!Directory.Exists(root))
|
||||||
|
Directory.CreateDirectory(root);
|
||||||
|
|
||||||
|
|
||||||
|
var fileName = Guid.NewGuid().ToString() + extension;
|
||||||
|
var filePath = Path.Combine(root, fileName);
|
||||||
|
using var streamFile = new FileStream(filePath, FileMode.Create);
|
||||||
|
await streamFile.WriteAsync(fileBytes, 0, fileBytes.Length);
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
||||||
|
|
||||||
|
namespace Vizhtalk.CDN.Presentation.FileManagerServices;
|
||||||
|
|
||||||
|
public interface IFileManagerService
|
||||||
|
{
|
||||||
|
Task<string> SaveFile(byte[] fileBytes,string fileExtension, MediaGroupId mediaGroupId);
|
||||||
|
}
|
||||||
+6
-8
@@ -4,18 +4,16 @@ using Vizhtalk.CDN.Presentation.Domain.Entities;
|
|||||||
|
|
||||||
namespace Vizhtalk.CDN.Presentation.Infrastructure.EF.Configurations;
|
namespace Vizhtalk.CDN.Presentation.Infrastructure.EF.Configurations;
|
||||||
|
|
||||||
public class MediaClientConfiguration : IEntityTypeConfiguration<MediaClient>
|
public class MediaClientConfiguration : IEntityTypeConfiguration<MediaPermission>
|
||||||
{
|
{
|
||||||
public void Configure(EntityTypeBuilder<MediaClient> builder)
|
public void Configure(EntityTypeBuilder<MediaPermission> builder)
|
||||||
{
|
{
|
||||||
builder.ToTable(nameof(MediaClient));
|
builder.ToTable(nameof(MediaPermission));
|
||||||
builder.HasKey(x => x.Id);
|
builder.HasKey(x => x.Id);
|
||||||
|
|
||||||
builder.Property(x => x.Id)
|
builder.Property(x => x.Id)
|
||||||
.HasConversion(x => x.Value, x => new Domain.TypeIds.MediaClientId(x));
|
.HasConversion(x => x.Value, x => new Domain.TypeIds.MediaClientId(x));
|
||||||
|
|
||||||
builder.Property(x => x.Name)
|
|
||||||
.HasConversion(x => x.Value, x => new Domain.ValueObjects.MediaClientName(x));
|
|
||||||
|
|
||||||
builder.Property(x => x.ClientId)
|
builder.Property(x => x.ClientId)
|
||||||
.HasConversion(x => x.Value, x => new Domain.TypeIds.ClientId(x));
|
.HasConversion(x => x.Value, x => new Domain.TypeIds.ClientId(x));
|
||||||
@@ -26,11 +24,11 @@ public class MediaClientConfiguration : IEntityTypeConfiguration<MediaClient>
|
|||||||
builder.Property(x => x.MediaId)
|
builder.Property(x => x.MediaId)
|
||||||
.HasConversion(x => x.Value, x => new Domain.TypeIds.MediaId(x));
|
.HasConversion(x => x.Value, x => new Domain.TypeIds.MediaId(x));
|
||||||
|
|
||||||
builder.Metadata.FindNavigation(nameof(MediaClient.Media))?
|
builder.Metadata.FindNavigation(nameof(MediaPermission.Media))?
|
||||||
.SetPropertyAccessMode(PropertyAccessMode.Property);
|
.SetPropertyAccessMode(PropertyAccessMode.Property);
|
||||||
builder.Metadata.FindNavigation(nameof(MediaClient.Client))?
|
builder.Metadata.FindNavigation(nameof(MediaPermission.Client))?
|
||||||
.SetPropertyAccessMode(PropertyAccessMode.Property);
|
.SetPropertyAccessMode(PropertyAccessMode.Property);
|
||||||
builder.Metadata.FindNavigation(nameof(MediaClient.MediaGroupMedia))?
|
builder.Metadata.FindNavigation(nameof(MediaPermission.MediaGroupMedia))?
|
||||||
.SetPropertyAccessMode(PropertyAccessMode.Property);
|
.SetPropertyAccessMode(PropertyAccessMode.Property);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -16,6 +16,9 @@ public class MediaGroupMediaConfiguration : IEntityTypeConfiguration<MediaGroupM
|
|||||||
builder.Property(x => x.MediaId)
|
builder.Property(x => x.MediaId)
|
||||||
.HasConversion(x => x.Value, x => new Domain.TypeIds.MediaId(x));
|
.HasConversion(x => x.Value, x => new Domain.TypeIds.MediaId(x));
|
||||||
|
|
||||||
|
builder.Property(x => x.Name)
|
||||||
|
.HasConversion(x => x.Value, x => new Domain.ValueObjects.FileName(x));
|
||||||
|
|
||||||
builder.Property(x => x.MediaGroupId)
|
builder.Property(x => x.MediaGroupId)
|
||||||
.HasConversion(x => x.Value, x => new Domain.TypeIds.MediaGroupId(x));
|
.HasConversion(x => x.Value, x => new Domain.TypeIds.MediaGroupId(x));
|
||||||
|
|
||||||
@@ -26,7 +29,7 @@ public class MediaGroupMediaConfiguration : IEntityTypeConfiguration<MediaGroupM
|
|||||||
.SetPropertyAccessMode(PropertyAccessMode.Property);
|
.SetPropertyAccessMode(PropertyAccessMode.Property);
|
||||||
|
|
||||||
|
|
||||||
builder.Metadata.FindNavigation(nameof(MediaGroupMedia.MediaClients))?
|
builder.Metadata.FindNavigation(nameof(MediaGroupMedia.MediaPermissions))?
|
||||||
.SetPropertyAccessMode(PropertyAccessMode.Property);
|
.SetPropertyAccessMode(PropertyAccessMode.Property);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using MongoDB.Driver.Core.Configuration;
|
using MongoDB.Driver.Core.Configuration;
|
||||||
|
using Vizhtalk.CDN.Presentation.FileManagerServices;
|
||||||
using Vizhtalk.CDN.Presentation.Infrastructure;
|
using Vizhtalk.CDN.Presentation.Infrastructure;
|
||||||
using Vizhtalk.CDN.Presentation.Services;
|
using Vizhtalk.CDN.Presentation.Services;
|
||||||
|
|
||||||
@@ -7,6 +8,7 @@ var builder = WebApplication.CreateBuilder(args);
|
|||||||
var connectionString = builder.Configuration.GetConnectionString("VizhTalk.CDN")!;
|
var connectionString = builder.Configuration.GetConnectionString("VizhTalk.CDN")!;
|
||||||
var databaseName = builder.Configuration.GetConnectionString("VizhTalk.CDN.DatabaseName")!;
|
var databaseName = builder.Configuration.GetConnectionString("VizhTalk.CDN.DatabaseName")!;
|
||||||
|
|
||||||
|
builder.Services.AddScoped<IFileManagerService, FileManagerService>();
|
||||||
builder.Services.Initialize(connectionString, databaseName);
|
builder.Services.Initialize(connectionString, databaseName);
|
||||||
builder.Services.AddGrpc();
|
builder.Services.AddGrpc();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user