Compare commits
10 Commits
ad4c92f4c0
...
68def54d9f
| Author | SHA1 | Date | |
|---|---|---|---|
| 68def54d9f | |||
| d4b01b5c28 | |||
| 421df4a379 | |||
| 09ef1b979e | |||
| 9e65e7e042 | |||
| 54b10d0d02 | |||
| c52cdc17a2 | |||
| a6d6506e38 | |||
| c7d97fe9bd | |||
| 338895a1ad |
@@ -358,6 +358,8 @@ MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
.idea/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
FodyWeavers.xsd
|
||||
/Vizhtalk.CDN.Presentation/Files/
|
||||
|
||||
@@ -5,4 +5,5 @@ public interface IGenericDapper<T> : IDisposable
|
||||
{
|
||||
Task<T?> GetAsync(string sql, object? param = null);
|
||||
Task<IEnumerable<T>> GetAllAsync(string sql, object? param = null);
|
||||
Task<int> CountAsync(string schema,string tableName, string where, object? param = null, string? alias = null);
|
||||
}
|
||||
|
||||
@@ -7,12 +7,10 @@ namespace VizhTalk.Gateway.Web.BFF.Mappers
|
||||
{
|
||||
public static async Task<UploadFile> AsFile(this IFile file)
|
||||
{
|
||||
using MemoryStream stream = new MemoryStream();
|
||||
await file.CopyToAsync(stream);
|
||||
return new UploadFile()
|
||||
{
|
||||
ContentType = file.ContentType,
|
||||
File = ByteString.FromStream(stream),
|
||||
File = ByteString.FromStream(file.OpenReadStream()),
|
||||
Name = file.Name,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
using VizhTalk.Grpc.Learning;
|
||||
|
||||
namespace VizhTalk.Gateway.Web.BFF.Models;
|
||||
|
||||
public record CreateCourseRequest(string title, string description, IFile image, Id languageid);
|
||||
public record UpdateCourseRequest(Id id, string title, string description, Int32 order, IFile image, Id languageid);
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace VizhTalk.Gateway.Web.BFF.Models;
|
||||
|
||||
public record CreateLanguageRequest(string Title,IFile Icon);
|
||||
public record UpdateLanguageRequest(IdRequest Id, string Title,IFile Icon);
|
||||
public record UpdateLanguageRequest(IdRequest Id, string Title, IFile? Icon);
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
using VizhTalk.Gateway.Web.BFF.Mappers;
|
||||
using VizhTalk.Gateway.Web.BFF.Models;
|
||||
using VizhTalk.Grpc.Learning;
|
||||
using VizhTalk.Grpc.Learning.Language;
|
||||
|
||||
namespace VizhTalk.Gateway.Web.BFF.Mutations;
|
||||
|
||||
public class LanguageMutation(LanguageGrpc.LanguageGrpcClient client)
|
||||
{
|
||||
[GraphQLName("CreateLanguage")]
|
||||
public async Task<LanguageDTO> CreateLanguage(CreateLanguageRequest request)
|
||||
{
|
||||
return await client.CreateAsync(new CreateLanguageCommand()
|
||||
{
|
||||
Title = request.Title,
|
||||
Icon = await request.Icon.AsFile()
|
||||
});
|
||||
}
|
||||
|
||||
[GraphQLName("UpdateLanguage")]
|
||||
public async Task<LanguageDTO> UpdateLanguage(UpdateLanguageRequest request)
|
||||
{
|
||||
return await client.UpdateAsync(new UpdateLanguageCommand()
|
||||
{
|
||||
Id = new Id(request.Id.Value),
|
||||
Title = request.Title,
|
||||
Icon = await request.Icon.AsFile()
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using VizhTalk.Gateway.Web.BFF.Mappers;
|
||||
using VizhTalk.Gateway.Web.BFF.Models;
|
||||
using VizhTalk.Grpc.Learning;
|
||||
using VizhTalk.Grpc.Learning.Course;
|
||||
using VizhTalk.Grpc.Learning.Language;
|
||||
|
||||
namespace VizhTalk.Gateway.Web.BFF.Mutations;
|
||||
|
||||
public class Mutation(LanguageGrpc.LanguageGrpcClient languageClient,
|
||||
CourseGrpc.CourseGrpcClient courseClient)
|
||||
{
|
||||
[GraphQLName("CreateLanguage")]
|
||||
public async Task<LanguageDTO> CreateLanguage(CreateLanguageRequest request)
|
||||
{
|
||||
return await languageClient.CreateAsync(new CreateLanguageCommand()
|
||||
{
|
||||
Title = request.Title,
|
||||
Icon = await request.Icon.AsFile()
|
||||
});
|
||||
}
|
||||
|
||||
[GraphQLName("UpdateLanguage")]
|
||||
public async Task<LanguageDTO> UpdateLanguage(UpdateLanguageRequest request)
|
||||
{
|
||||
UploadFile file = null;
|
||||
if (request.Icon != null)
|
||||
{
|
||||
file = await request.Icon.AsFile();
|
||||
}
|
||||
return await languageClient.UpdateAsync(new UpdateLanguageCommand()
|
||||
{
|
||||
Id = new Id()
|
||||
{
|
||||
Value = request.Id.Value
|
||||
},
|
||||
Title = request.Title,
|
||||
Icon = file
|
||||
});
|
||||
}
|
||||
|
||||
[GraphQLName("CreateCourse")]
|
||||
public async Task<CourseDTO> CreateCourse(CreateCourseRequest input)
|
||||
{
|
||||
return await courseClient.CreateAsync(new CreateCourseCommand()
|
||||
{
|
||||
Title = input.title,
|
||||
Image = await input.image.AsFile(),
|
||||
Description = input.description,
|
||||
Languageid = input.languageid
|
||||
});
|
||||
}
|
||||
|
||||
[GraphQLName("UpdateCourse")]
|
||||
public async Task<CourseDTO> UpdateCourse(UpdateCourseRequest input)
|
||||
{
|
||||
UploadFile file = null;
|
||||
if (input.image != null)
|
||||
{
|
||||
file = await input.image.AsFile();
|
||||
}
|
||||
return await courseClient.UpdateAsync(new UpdateCourseCommand()
|
||||
{
|
||||
Id = new Id()
|
||||
{
|
||||
Value = input.id.Value
|
||||
},
|
||||
Order = input.order,
|
||||
Title = input.title,
|
||||
Image = file,
|
||||
Description = input.description,
|
||||
Languageid = input.languageid
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using VizhTalk.Gateway.Web.BFF.Mutations;
|
||||
using VizhTalk.Gateway.Web.BFF.Queries;
|
||||
using VizhTalk.Grpc.Learning.Course;
|
||||
using VizhTalk.Grpc.Learning.Language;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
@@ -8,13 +9,20 @@ builder.Services.AddGrpcClient<LanguageGrpc.LanguageGrpcClient>(o =>
|
||||
o.Address = new Uri("https://localhost:5000");
|
||||
});
|
||||
|
||||
builder.Services.AddScoped<LanguageQuery>();
|
||||
builder.Services.AddScoped<LanguageMutation>();
|
||||
builder.Services.AddGrpcClient<CourseGrpc.CourseGrpcClient>(o =>
|
||||
{
|
||||
o.Address = new Uri("https://localhost:5000");
|
||||
});
|
||||
|
||||
|
||||
builder.Services.AddScoped<Query>();
|
||||
builder.Services.AddScoped<Mutation>();
|
||||
|
||||
builder.AddGraphQL()
|
||||
.AddQueryType<LanguageQuery>()
|
||||
.AddMutationType<LanguageMutation>()
|
||||
.AddType<UploadType>();
|
||||
.AddQueryType<Query>()
|
||||
.AddMutationType<Mutation>()
|
||||
.AddType<UploadType>()
|
||||
.AddMutationConventions();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
using VizhTalk.Grpc.Learning.Language;
|
||||
|
||||
namespace VizhTalk.Gateway.Web.BFF.Queries
|
||||
{
|
||||
public class LanguageQuery(LanguageGrpc.LanguageGrpcClient client)
|
||||
{
|
||||
[GraphQLName("Languages")]
|
||||
public async Task<GetAllLanguageDTO> GetAllLanguage(GetAllLanguageQuery request)
|
||||
=> await client.GetAllAsync(request);
|
||||
|
||||
[GraphQLName("LanguageByTitle")]
|
||||
public async Task<LanguageDTO> GetLanguageByTitle(GetLanguageByTitleQuery request)
|
||||
=> await client.GetByTitleAsync(request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using VizhTalk.Grpc.Learning.Course;
|
||||
using VizhTalk.Grpc.Learning.Language;
|
||||
|
||||
namespace VizhTalk.Gateway.Web.BFF.Queries;
|
||||
|
||||
public class Query(
|
||||
LanguageGrpc.LanguageGrpcClient languageClient,
|
||||
CourseGrpc.CourseGrpcClient courseClient
|
||||
)
|
||||
{
|
||||
[GraphQLName("Languages")]
|
||||
public async Task<GetAllLanguageDTO> GetAllLanguage(GetAllLanguageQuery request)
|
||||
=> await languageClient.GetAllAsync(request);
|
||||
|
||||
[GraphQLName("LanguageByTitle")]
|
||||
public async Task<LanguageDTO> GetLanguageByTitle(GetLanguageByTitleQuery request)
|
||||
=> await languageClient.GetByTitleAsync(request);
|
||||
|
||||
[GraphQLName("Courses")]
|
||||
public async Task<GetAllCourseDTO> GetAllCourses(GetAllCourseQuery request)
|
||||
=> await courseClient.GetAllAsync(request);
|
||||
|
||||
[GraphQLName("CourseByTitle")]
|
||||
public async Task<CourseDTO> GetCourseByTitle(GetCoursesByTitleQuery request)
|
||||
=> await courseClient.GetByTitleAsync(request);
|
||||
|
||||
[GraphQLName("CourseByCourseId")]
|
||||
public async Task<CourseDTO> GetCourseById(GetCourseByIdQuery request)
|
||||
=> await courseClient.GetByIdAsync(request);
|
||||
}
|
||||
@@ -10,7 +10,6 @@ message UploadFileCommand{
|
||||
UploadFile file = 1;
|
||||
Id mediaGroupId = 2;
|
||||
string clientId = 3;
|
||||
string fileName = 4;
|
||||
}
|
||||
message CreateMediaGroupCommand{
|
||||
string key = 1;
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
using Mapster;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Sockets;
|
||||
using VizhTalk.BuildingBlocks.Application.Configuration.Commnad;
|
||||
using VizhTalk.Grpc.CDN;
|
||||
using VizhTalk.Grpc.Learning.Course;
|
||||
using VizhTalk.Learning.Application.Exceptions;
|
||||
using VizhTalk.Learning.Domain.Entities;
|
||||
using VizhTalk.Learning.Domain.TypeIds;
|
||||
using VizhTalk.Learning.Domain.ValueObjects;
|
||||
|
||||
namespace VizhTalk.Learning.Application.CommandHandlers;
|
||||
|
||||
|
||||
public class CreateCourseCommandHandler(IUnitOfWork unitOfWork, CDNGrpc.CDNGrpcClient cdnClient) : ICommandHandler<CreateCourseCommand, CourseDTO>
|
||||
{
|
||||
public async Task<CourseDTO> Handle(CreateCourseCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var language = await unitOfWork.Language.GetLanguageWithCoursesById(new LanguageId(request.Languageid), cancellationToken);
|
||||
if (language == null)
|
||||
throw new LanguageNotFoundException();
|
||||
|
||||
var fileGroup = await unitOfWork.FileGroup.GetByFileGroupKey(FileGroupKey.ImageCourse);
|
||||
if (fileGroup == null)
|
||||
{
|
||||
var group = await cdnClient.CreateMediaGroupAsync(new CreateMediaGroupCommand()
|
||||
{
|
||||
IsSecure = false,
|
||||
Key = FileGroupKey.ImageCourse.Value,
|
||||
Title = nameof(FileGroupKey.ImageCourse)
|
||||
});
|
||||
|
||||
fileGroup = FileGroup.CreateNew(FileGroupKey.IconLanguage, new FileGroupTitle(nameof(FileGroupKey.IconLanguage)), false, group.Id);
|
||||
await unitOfWork.FileGroup.AddAsync(fileGroup, cancellationToken);
|
||||
}
|
||||
var upload = await cdnClient.UploadFileAsync(new UploadFileCommand()
|
||||
{
|
||||
File = new UploadFile()
|
||||
{
|
||||
ContentType = request.Image.ContentType,
|
||||
File = request.Image.File,
|
||||
Name = request.Image.Name,
|
||||
},
|
||||
MediaGroupId = fileGroup.MediaGroupId,
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
var media = Media.CreateNew(request.Image.Name, upload.ContentType, upload.Size, upload.MediaGroupMediaId, new EntityType(EntityTypeEnum.Course));
|
||||
var course = language.AddCourse(request.Title, media, request.Description);
|
||||
await unitOfWork.Language.UpdateAsync(language, cancellationToken);
|
||||
await unitOfWork.SaveChangeAsync(cancellationToken);
|
||||
return course.Adapt<CourseDTO>();
|
||||
}
|
||||
}
|
||||
|
||||
public class UpdateCourseCommandHandler(IUnitOfWork unitOfWork, CDNGrpc.CDNGrpcClient cdnClient) : ICommandHandler<UpdateCourseCommand, CourseDTO>
|
||||
{
|
||||
public async Task<CourseDTO> Handle(UpdateCourseCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var language = await unitOfWork.Language.GetLanguageWithCoursesById(new LanguageId(request.Languageid), cancellationToken);
|
||||
if (language == null)
|
||||
throw new LanguageNotFoundException();
|
||||
if (!language.Courses.Any(x => x.Id == new CourseId(request.Id)))
|
||||
throw new CourseNotFoundException();
|
||||
|
||||
Media image = null;
|
||||
if (request.Image != null)
|
||||
{
|
||||
var fileGroup = await unitOfWork.FileGroup.GetByFileGroupKey(FileGroupKey.ImageCourse);
|
||||
|
||||
var upload = await cdnClient.UploadFileAsync(new UploadFileCommand()
|
||||
{
|
||||
File = new UploadFile()
|
||||
{
|
||||
ContentType = request.Image.ContentType,
|
||||
File = request.Image.File,
|
||||
Name = request.Image.Name,
|
||||
},
|
||||
MediaGroupId = fileGroup.MediaGroupId,
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
var media = await unitOfWork.Media.GetByIdAsync(language.Icon.Id);
|
||||
|
||||
if (media == null)
|
||||
media = Media.CreateNew(request.Title, upload.ContentType, upload.Size, upload.MediaGroupMediaId, new EntityType(EntityTypeEnum.Language));
|
||||
else
|
||||
{
|
||||
media.SetName(request.Image.Name);
|
||||
media.SetContentType(request.Image.ContentType);
|
||||
media.SetSize(upload.Size);
|
||||
media.SetFileId(upload.MediaGroupMediaId);
|
||||
}
|
||||
image = media;
|
||||
}
|
||||
var course = language.UpdateCourse(new CourseId(request.Id), new CourseTitle(request.Title), request.Order, image,
|
||||
string.IsNullOrEmpty(request.Description) ? null : new CourseDescription(request.Description));
|
||||
|
||||
await unitOfWork.Language.UpdateAsync(language, cancellationToken);
|
||||
|
||||
return course.Adapt<CourseDTO>();
|
||||
}
|
||||
}
|
||||
@@ -47,16 +47,13 @@ public class CreateLanguageCommandHandler(IUnitOfWork unitOfWork,
|
||||
File = request.Icon.File,
|
||||
Name = request.Icon.Name,
|
||||
},
|
||||
FileName = title,
|
||||
MediaGroupId = fileGroup.MediaGroupId
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
var language = Language.CreateNew(new LanguageTitle(title));
|
||||
var media = Media.CreateNew(title, upload.ContentType, upload.Size, upload.MediaGroupMediaId, new EntityType(EntityTypeEnum.Language));
|
||||
var language = Language.CreateNew(new LanguageTitle(title), media);
|
||||
await unitOfWork.Language.AddAsync(language, cancellationToken);
|
||||
await unitOfWork.SaveChangeAsync(cancellationToken);
|
||||
var media = Media.CreateNew(title, upload.ContentType, upload.Size, new EntityType(language.Id.Value.ToString(), EntityTypeEnum.Language));
|
||||
await unitOfWork.Media.AddAsync(media, cancellationToken);
|
||||
language.SetIcon(media);
|
||||
return language.Adapt<LanguageDTO>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -76,7 +73,7 @@ public class UpdateLanguageCommandHandler(IUnitOfWork unitOfWork, CDNGrpc.CDNGrp
|
||||
throw new LanguageNotFoundException();
|
||||
|
||||
language.SetTitle(new LanguageTitle(request.Title));
|
||||
if(request.Icon != null)
|
||||
if (request.Icon != null)
|
||||
{
|
||||
var fileGroup = await unitOfWork.FileGroup.GetByFileGroupKey(FileGroupKey.IconLanguage);
|
||||
|
||||
@@ -88,11 +85,19 @@ public class UpdateLanguageCommandHandler(IUnitOfWork unitOfWork, CDNGrpc.CDNGrp
|
||||
File = request.Icon.File,
|
||||
Name = request.Icon.Name,
|
||||
},
|
||||
FileName = request.Title,
|
||||
MediaGroupId = fileGroup.MediaGroupId
|
||||
}, cancellationToken: cancellationToken);
|
||||
var media = await unitOfWork.Media.GetByIdAsync(language.Icon.Id);
|
||||
|
||||
var media = Media.CreateNew(request.Title, upload.ContentType, upload.Size, new EntityType(language.Id.Value.ToString(), EntityTypeEnum.Language));
|
||||
if(media == null)
|
||||
media = Media.CreateNew(request.Title, upload.ContentType, upload.Size, upload.MediaGroupMediaId, new EntityType(EntityTypeEnum.Language));
|
||||
else
|
||||
{
|
||||
media.SetName(request.Icon.Name);
|
||||
media.SetContentType(request.Icon.ContentType);
|
||||
media.SetSize(upload.Size);
|
||||
media.SetFileId(upload.MediaGroupMediaId);
|
||||
}
|
||||
|
||||
language.SetIcon(media);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VizhTalk.BuildingBlocks.Application.Exceptions;
|
||||
|
||||
namespace VizhTalk.Learning.Application.Exceptions
|
||||
{
|
||||
public class CourseNotFoundException : BaseException
|
||||
{
|
||||
public CourseNotFoundException() : base("course not found")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Mapster;
|
||||
using VizhTalk.Grpc.Learning;
|
||||
using VizhTalk.Grpc.Learning.Course;
|
||||
using VizhTalk.Grpc.Learning.Language;
|
||||
using VizhTalk.Learning.Domain.Entities;
|
||||
|
||||
@@ -9,16 +10,20 @@ namespace VizhTalk.Learning.Application.Mappers
|
||||
{
|
||||
public static void Process()
|
||||
{
|
||||
TypeAdapterConfig<Language, LanguageDTO>.NewConfig()
|
||||
.MapWith(lan => new LanguageDTO()
|
||||
{
|
||||
Id = lan.Id.Value,
|
||||
Title = lan.Title.Value,
|
||||
}).Compile();
|
||||
|
||||
var config = TypeAdapterConfig<Language, LanguageDTO>.NewConfig()
|
||||
.MapWith(lan => new LanguageDTO()
|
||||
{
|
||||
Id = lan.Id.Value,
|
||||
Title = lan.Title.Value,
|
||||
});
|
||||
TypeAdapterConfig<Course, CourseDTO>.NewConfig()
|
||||
.MapWith(lan => new CourseDTO()
|
||||
{
|
||||
Id = lan.Id.Value,
|
||||
Title = lan.Title.Value,
|
||||
}).Compile();
|
||||
|
||||
|
||||
config.Compile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,23 @@ public class GetAllLanguageQueryHandler(IGenericDapper<LanguageDTO> languageDapp
|
||||
{
|
||||
public async Task<GetAllLanguageDTO> Handle(GetAllLanguageQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var where = $"@Search is null or lan.{nameof(LanguageDTO.Title)} like N'%@Search%' ";
|
||||
var result = new GetAllLanguageDTO();
|
||||
var sql = $"select * from Learning.Languages " +
|
||||
$"where @Search is null or {nameof(LanguageDTO.Title)} like N'%@Search%' " +
|
||||
$"order by createOn OFFSET {request.Pagination.Skip()} ROWS FETCH NEXT {request.Pagination.Take()} ROWS ONLY;";
|
||||
var sql = $"select " +
|
||||
$"lan.{nameof(Language.Title)} as {nameof(LanguageDTO.Title)}," +
|
||||
$"lan.{nameof(Language.Id)} as {nameof(LanguageDTO.Id)}," +
|
||||
$"CONVERT(nvarchar(max),m.FileId) as {nameof(LanguageDTO.Icon)}" +
|
||||
$" from Learning.Languages as lan " +
|
||||
$"inner join Learning.Medias as m on m.{nameof(Media.Id)} = lan.iconId " +
|
||||
$"where {where}" +
|
||||
$"order by lan.{nameof(Language.CreateOn)} OFFSET {request.Pagination.Skip()} ROWS FETCH NEXT {request.Pagination.Take()} ROWS ONLY";
|
||||
|
||||
var language = await languageDapper.GetAllAsync(sql, new { request.Pagination.Search });
|
||||
result.Languages.AddRange(language);
|
||||
result.TotalData = await languageDapper.CountAsync("Learning", "Languages",
|
||||
where,
|
||||
new { request.Pagination.Search },"lan");
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -23,7 +33,13 @@ public class GetLanguageByTitleQueryHandler(IGenericDapper<LanguageDTO> language
|
||||
{
|
||||
public async Task<LanguageDTO> Handle(GetLanguageByTitleQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var sql = $"select * from Learning.Languages where Title = @{nameof(Language.Title)}";
|
||||
var sql = $"select " +
|
||||
$"lan.{nameof(Language.Title)} as {nameof(LanguageDTO.Title)}," +
|
||||
$"lan.{nameof(Language.Id)} as {nameof(LanguageDTO.Id)}," +
|
||||
$"CONVERT(nvarchar(max),m.FileId) as {nameof(LanguageDTO.Icon)}" +
|
||||
$" from Learning.Languages as lan " +
|
||||
$"inner join Learning.Medias as m on m.{nameof(Media.Id)} = lan.iconId " +
|
||||
$"where lan.{nameof(Language.Title)} = @Title";
|
||||
|
||||
var language = await languageDapper.GetAsync(sql, new { request.Title });
|
||||
return language;
|
||||
@@ -33,8 +49,11 @@ public class GetLanguageByIdQueryHandler(IGenericDapper<LanguageDTO> languageDap
|
||||
{
|
||||
public async Task<LanguageDTO> Handle(GetLanguageByIdQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var sql = $"select * from Learning.Languages where Id = " +
|
||||
$" @{nameof(Language.Id)}";
|
||||
var sql = $"select " +
|
||||
$"lan.{nameof(Language.Title)} as {nameof(LanguageDTO.Title)}," +
|
||||
$"lan.{nameof(Language.Id)} as {nameof(LanguageDTO.Id)}," +
|
||||
$"CONVERT(nvarchar(max),m.FileId) as {nameof(LanguageDTO.Icon)}" +
|
||||
$"from Learning.Languages as lan where lan.Id = @{nameof(Language.Id)}";
|
||||
|
||||
var language = await languageDapper.GetAsync(sql, new { request.Id });
|
||||
return language;
|
||||
|
||||
@@ -10,21 +10,26 @@ public class Course : Entity<CourseId>
|
||||
{
|
||||
|
||||
}
|
||||
private Course(CourseTitle title, int order)
|
||||
private Course(CourseTitle title, int order, Media image, CourseDescription? description)
|
||||
{
|
||||
Title = title;
|
||||
Order = order;
|
||||
Image = image;
|
||||
Description = description;
|
||||
}
|
||||
public CourseTitle Title { get; private set; }
|
||||
public Media Image { get; private set; }
|
||||
public CourseDescription? Description { get; set; }
|
||||
public int Order { get; private set; }
|
||||
|
||||
internal static Course CreateNew(CourseTitle title, int order)
|
||||
=> new(title, order);
|
||||
internal static Course CreateNew(CourseTitle title, int order, Media image, CourseDescription? description)
|
||||
=> new(title, order, image, description);
|
||||
public void SetTitle(CourseTitle title)
|
||||
=> Title = title;
|
||||
public void SetOrder(int order)
|
||||
=> Order = order;
|
||||
public void SetImage(Media media)
|
||||
=> Image = media;
|
||||
public void SetDescription(CourseDescription? description)
|
||||
=> Description = description;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ public class FileGroup : Entity<FileGroupId>
|
||||
private FileGroup(FileGroupKey key,
|
||||
FileGroupTitle title,
|
||||
bool isSecure,
|
||||
long mediaGroupId)
|
||||
Guid mediaGroupId)
|
||||
{
|
||||
Title = title;
|
||||
MediaGroupId = mediaGroupId;
|
||||
@@ -22,12 +22,12 @@ public class FileGroup : Entity<FileGroupId>
|
||||
}
|
||||
public FileGroupTitle Title { get; set; }
|
||||
public FileGroupKey Key { get; private set; }
|
||||
public long MediaGroupId { get; private set; }
|
||||
public Guid MediaGroupId { get; private set; }
|
||||
public bool IsSecure { get; set; }
|
||||
|
||||
public static FileGroup CreateNew(FileGroupKey key,
|
||||
FileGroupTitle title,
|
||||
bool isSecure,
|
||||
long mediaGroupId)
|
||||
Guid mediaGroupId)
|
||||
=> new(key,title, isSecure, mediaGroupId);
|
||||
}
|
||||
|
||||
@@ -12,15 +12,16 @@ public class Language : Entity<LanguageId>, IAggregateRoot
|
||||
{
|
||||
// only EF
|
||||
}
|
||||
private Language(LanguageTitle title)
|
||||
private Language(LanguageTitle title, Media icon)
|
||||
{
|
||||
Title = title;
|
||||
Icon = icon;
|
||||
}
|
||||
public LanguageTitle Title { get; private set; }
|
||||
public Media Icon { get; private set; }
|
||||
public IReadOnlyList<Course> Courses => _courses;
|
||||
public static Language CreateNew(LanguageTitle title)
|
||||
=> new(title);
|
||||
public static Language CreateNew(LanguageTitle title, Media icon)
|
||||
=> new(title, icon);
|
||||
|
||||
public void SetTitle(LanguageTitle title)
|
||||
=> Title = title;
|
||||
@@ -31,27 +32,28 @@ public class Language : Entity<LanguageId>, IAggregateRoot
|
||||
|
||||
Icon = icon;
|
||||
}
|
||||
public Course AddCourse(CourseTitle courseTitle)
|
||||
public Course AddCourse(CourseTitle courseTitle, Media image, CourseDescription? courseDescription)
|
||||
{
|
||||
var order = Courses.Count;
|
||||
var course = Course.CreateNew(courseTitle, order);
|
||||
var course = Course.CreateNew(courseTitle, order, image, courseDescription);
|
||||
_courses.Add(course);
|
||||
return course;
|
||||
}
|
||||
public Course UpdateCourse(Course course)
|
||||
public Course UpdateCourse(CourseId courseId,CourseTitle courseTitle,int order, Media? image, CourseDescription? courseDescription)
|
||||
{
|
||||
var _course = _courses.FirstOrDefault(x => x.Id == course.Id) ?? throw new CourseNotFoundException(Title);
|
||||
if(course.Image != null)
|
||||
_course.SetImage(course.Image);
|
||||
_course.SetTitle(course.Title);
|
||||
var _course = _courses.FirstOrDefault(x => x.Id == courseId) ?? throw new CourseNotFoundException(Title);
|
||||
if (image != null)
|
||||
_course.SetImage(image);
|
||||
_course.SetTitle(courseTitle);
|
||||
_course.SetDescription(courseDescription);
|
||||
|
||||
if(_course.Order != course.Order)
|
||||
if (_course.Order != order)
|
||||
{
|
||||
var orderCourses = _courses.Where(x => x.Id != course.Id)
|
||||
var orderCourses = _courses.Where(x => x.Id != courseId)
|
||||
.OrderBy(x => x.Order)
|
||||
.ToList();
|
||||
_course.SetOrder(_course.Order);
|
||||
orderCourses.Insert(course.Order, _course);
|
||||
orderCourses.Insert(order, _course);
|
||||
}
|
||||
return _course;
|
||||
}
|
||||
|
||||
@@ -8,26 +8,41 @@ public class Media : Entity<MediaId>
|
||||
{
|
||||
private Media()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
private Media(string name,
|
||||
string contentType,
|
||||
int size,
|
||||
Guid fileId,
|
||||
EntityType type)
|
||||
{
|
||||
Name = name;
|
||||
ContentType = contentType;
|
||||
Size = size;
|
||||
FileId = fileId;
|
||||
EntityType = type;
|
||||
}
|
||||
public string Name { get; private set; }
|
||||
public string ContentType { get; private set; }
|
||||
public string ContentType { get; private set; }
|
||||
public int Size { get; private set; }
|
||||
public Guid FileId { get; set; }
|
||||
public EntityType EntityType { get; private set; }
|
||||
|
||||
public static Media CreateNew(string name,
|
||||
string contentType,
|
||||
int size,
|
||||
Guid fileId,
|
||||
EntityType type)
|
||||
=> new(name, contentType, size, type);
|
||||
=> new(name, contentType, size, fileId, type);
|
||||
|
||||
public void SetFileId(Guid fileId)
|
||||
=> FileId = fileId;
|
||||
public void SetName(string name)
|
||||
=> Name = name;
|
||||
public void SetContentType(string contentType)
|
||||
=> ContentType = contentType;
|
||||
public void SetSize(int size)
|
||||
=> Size = size;
|
||||
public void SetEntityType(EntityType entityType)
|
||||
=> EntityType = entityType;
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@ namespace VizhTalk.Learning.Domain.Repositories;
|
||||
|
||||
public interface ILanguageRepository : IRepositoryBase<Language,LanguageId>
|
||||
{
|
||||
|
||||
Task<Language?> GetLanguageWithCoursesById(LanguageId languageId ,CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace VizhTalk.Learning.Domain.TypeIds;
|
||||
|
||||
public class MediaId : TypeIdValueBase<Guid>
|
||||
public class MediaId : TypeIdValueBase<long>
|
||||
{
|
||||
public MediaId(Guid value) : base(value)
|
||||
public MediaId(long value) : base(value)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
using VizhTalk.BuildingBlocks.Domain.Guards;
|
||||
|
||||
namespace VizhTalk.Learning.Domain.ValueObjects;
|
||||
|
||||
public class CourseDescription : ValueObject
|
||||
{
|
||||
public const short MaxLength = 800;
|
||||
public CourseDescription(string description)
|
||||
{
|
||||
Guard.NullOrEmpty(description,nameof(CourseDescription));
|
||||
Guard.MaxLength(description, nameof(CourseDescription), MaxLength);
|
||||
Value = description;
|
||||
}
|
||||
public string Value { get; set; }
|
||||
|
||||
public static implicit operator string(CourseDescription title) => title.Value;
|
||||
public static implicit operator CourseDescription(string title) => new(title);
|
||||
}
|
||||
@@ -14,5 +14,6 @@ public class CourseTitle
|
||||
public string Value { get; private set; }
|
||||
|
||||
public static implicit operator string(CourseTitle title) => title.Value;
|
||||
public static implicit operator CourseTitle(string title) => new(title);
|
||||
|
||||
}
|
||||
|
||||
@@ -4,15 +4,14 @@ namespace VizhTalk.Learning.Domain.ValueObjects;
|
||||
|
||||
public class EntityType : ValueObject
|
||||
{
|
||||
public EntityType(string entityId, EntityTypeEnum type)
|
||||
public EntityType(EntityTypeEnum type)
|
||||
{
|
||||
EntityId = entityId;
|
||||
Type = type;
|
||||
}
|
||||
public string EntityId { get; private set; }
|
||||
public EntityTypeEnum Type { get; private set; }
|
||||
}
|
||||
public enum EntityTypeEnum
|
||||
{
|
||||
Language = 0
|
||||
Language = 0,
|
||||
Course = 1
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace VizhTalk.Learning.Domain.ValueObjects
|
||||
public class FileGroupKey : ValueObject
|
||||
{
|
||||
public static FileGroupKey IconLanguage = new("IconLanguage");
|
||||
public static FileGroupKey ImageCourse = new("ImageCourse");
|
||||
public FileGroupKey(string entityName, string? entityId = null)
|
||||
{
|
||||
Guard.NullOrEmpty(entityName, entityName);
|
||||
|
||||
@@ -9,6 +9,7 @@ public class FileGroupTitle : ValueObject
|
||||
{
|
||||
Guard.NullOrEmpty(value, nameof(FileGroupTitle));
|
||||
Guard.MaxLength(value, nameof(FileGroupTitle), 50);
|
||||
Value = value;
|
||||
}
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
@@ -21,10 +21,18 @@ public class GenericDapper<T> : IGenericDapper<T>
|
||||
{
|
||||
return await connection.QueryAsync<T>(sql, param);
|
||||
}
|
||||
|
||||
public async Task<int> CountAsync(string schema,string tableName, string where, object? param = null, string? alias = null)
|
||||
{
|
||||
string query = $"select count(1) as count from {schema}.{tableName} " +
|
||||
(string.IsNullOrEmpty(alias) ? "" : $"as {alias}") +
|
||||
$" where {where}";
|
||||
return await connection.QueryFirstAsync<int>(query, param);
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
connection.Dispose();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VizhTalk.Learning.Domain.Entities;
|
||||
using VizhTalk.Learning.Domain.ValueObjects;
|
||||
|
||||
namespace VizhTalk.Learning.Infrastructure.EF.Configurations
|
||||
{
|
||||
@@ -23,6 +19,12 @@ namespace VizhTalk.Learning.Infrastructure.EF.Configurations
|
||||
builder.Property(x => x.Title)
|
||||
.HasConversion(x => x.Value, x => new(x));
|
||||
|
||||
builder.Property(x => x.Description)
|
||||
.HasMaxLength(CourseDescription.MaxLength)
|
||||
.HasConversion(x => x.Value, x => new(x));
|
||||
|
||||
builder.Navigation(x => x.Image)
|
||||
.AutoInclude();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ internal class FileGroupConfiguration : IEntityTypeConfiguration<FileGroup>
|
||||
builder.Property(x => x.Id)
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasConversion(x => x.Value, x => new Domain.TypeIds.FileGroupId(x));
|
||||
|
||||
builder.Property(x => x.Title)
|
||||
.HasColumnName("Title")
|
||||
.HasConversion(x => x.Value, x => new FileGroupTitle(x));
|
||||
|
||||
@@ -24,6 +24,9 @@ namespace VizhTalk.Learning.Infrastructure.EF.Configurations
|
||||
builder.Property(x => x.Title)
|
||||
.HasConversion(x => x.Value, x => new LanguageTitle(x))
|
||||
.HasMaxLength(60);
|
||||
|
||||
builder.Navigation(x => x.Icon)
|
||||
.AutoInclude();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ internal class MediaConfiguration : IEntityTypeConfiguration<Media>
|
||||
builder.HasKey(x => x.Id);
|
||||
|
||||
builder.Property(x => x.Id)
|
||||
.HasConversion(x => x.Value, x => new Domain.TypeIds.MediaId(x));
|
||||
.HasConversion(x => x.Value, x => new Domain.TypeIds.MediaId(x))
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
builder.Property(x => x.Name)
|
||||
.HasMaxLength(150);
|
||||
@@ -24,10 +25,6 @@ internal class MediaConfiguration : IEntityTypeConfiguration<Media>
|
||||
op.Property(x => x.Type)
|
||||
.HasColumnName("EntityType")
|
||||
.HasMaxLength(200);
|
||||
|
||||
op.Property(x => x.EntityId)
|
||||
.HasColumnName("EntityId")
|
||||
.HasMaxLength(50);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure.EF.Helpers;
|
||||
using VizhTalk.Learning.Domain.Entities;
|
||||
using VizhTalk.Learning.Infrastructure.Configuration;
|
||||
|
||||
namespace VizhTalk.Learning.Infrastructure.EF;
|
||||
@@ -22,5 +23,6 @@ public class LearningDbContext : DbContext
|
||||
modelBuilder.FindEntities(Assemblies.Domain)
|
||||
.ApplyConfigurationsFromAssembly(Assemblies.Infrastructure, x => x.FullName.Contains("EF.Configurations"))
|
||||
.PluralizeEntities();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ using VizhTalk.BuildingBlocks.Application.Outbox;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure.DomainEventsDispatching;
|
||||
using VizhTalk.Grpc.CDN;
|
||||
using VizhTalk.Grpc.Learning.Language;
|
||||
using VizhTalk.Learning.Application;
|
||||
using VizhTalk.Learning.Application.Mappers;
|
||||
using VizhTalk.Learning.Infrastructure.Configuration;
|
||||
@@ -29,6 +30,10 @@ public static class LearningStartup
|
||||
{
|
||||
op.UseSqlServer(connectionString);
|
||||
});
|
||||
services.AddGrpcClient<CDNGrpc.CDNGrpcClient>(o =>
|
||||
{
|
||||
o.Address = new Uri("https://localhost:5001");
|
||||
});
|
||||
services.AddScoped<DbContext>(sp => sp.GetService<LearningDbContext>());
|
||||
services.AddScoped<ILearningModule, LearningModule>();
|
||||
services.AddScoped<IExecutor, LearningModule>();
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using VizhTalk.Learning.Infrastructure.EF;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(LearningDbContext))]
|
||||
[Migration("20250905153842_initial")]
|
||||
partial class initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasDefaultSchema("Learning")
|
||||
.HasAnnotation("ProductVersion", "8.0.19")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("VizhTalk.Learning.Domain.Entities.FileGroup", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreateOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<bool>("IsSecure")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("nvarchar(150)")
|
||||
.HasColumnName("Key");
|
||||
|
||||
b.Property<DateTime>("LastUpdate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<long>("MediaGroupId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)")
|
||||
.HasColumnName("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("FileGroups", "Attachment");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("VizhTalk.Learning.Domain.Entities.Language", b =>
|
||||
{
|
||||
b.Property<short>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("smallint");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<short>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreateOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid>("IconId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTime>("LastUpdate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(60)
|
||||
.HasColumnType("nvarchar(60)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IconId");
|
||||
|
||||
b.ToTable("Languages", "Learning");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("VizhTalk.Learning.Domain.Entities.Media", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("ContentType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("CreateOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTime>("LastUpdate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("nvarchar(150)");
|
||||
|
||||
b.Property<int>("Size")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Medias", "Learning");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("VizhTalk.Learning.Domain.Entities.Language", b =>
|
||||
{
|
||||
b.HasOne("VizhTalk.Learning.Domain.Entities.Media", "Icon")
|
||||
.WithMany()
|
||||
.HasForeignKey("IconId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Icon");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("VizhTalk.Learning.Domain.Entities.Media", b =>
|
||||
{
|
||||
b.OwnsOne("VizhTalk.Learning.Domain.ValueObjects.EntityType", "EntityType", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("MediaId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b1.Property<string>("EntityId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)")
|
||||
.HasColumnName("EntityId");
|
||||
|
||||
b1.Property<int>("Type")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("EntityType");
|
||||
|
||||
b1.HasKey("MediaId");
|
||||
|
||||
b1.ToTable("Medias", "Learning");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("MediaId");
|
||||
});
|
||||
|
||||
b.Navigation("EntityType")
|
||||
.IsRequired();
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Course : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Courses",
|
||||
schema: "Learning",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "bigint", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Title = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
ImageId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
Order = table.Column<int>(type: "int", nullable: false),
|
||||
LanguageId = table.Column<short>(type: "smallint", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false),
|
||||
CreateOn = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
LastUpdate = table.Column<DateTime>(type: "datetime2", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Courses", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Courses_Languages_LanguageId",
|
||||
column: x => x.LanguageId,
|
||||
principalSchema: "Learning",
|
||||
principalTable: "Languages",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_Courses_Medias_ImageId",
|
||||
column: x => x.ImageId,
|
||||
principalSchema: "Learning",
|
||||
principalTable: "Medias",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Courses_ImageId",
|
||||
schema: "Learning",
|
||||
table: "Courses",
|
||||
column: "ImageId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Courses_LanguageId",
|
||||
schema: "Learning",
|
||||
table: "Courses",
|
||||
column: "LanguageId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Courses",
|
||||
schema: "Learning");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@ using VizhTalk.Learning.Infrastructure.EF;
|
||||
namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(LearningDbContext))]
|
||||
[Migration("20250907192005_Course")]
|
||||
partial class Course
|
||||
[Migration("20250912083328_initial")]
|
||||
partial class initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
@@ -37,8 +37,8 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
b.Property<DateTime>("CreateOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid>("ImageId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
b.Property<long>("ImageId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
@@ -97,8 +97,8 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
b.Property<DateTime>("LastUpdate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<long>("MediaGroupId")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<Guid>("MediaGroupId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
@@ -121,8 +121,8 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
b.Property<DateTime>("CreateOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid>("IconId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
b.Property<long>("IconId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
@@ -147,8 +147,11 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
|
||||
modelBuilder.Entity("VizhTalk.Learning.Domain.Entities.Media", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("ContentType")
|
||||
.IsRequired()
|
||||
@@ -157,6 +160,9 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
b.Property<DateTime>("CreateOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid>("FileId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
@@ -209,14 +215,8 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
{
|
||||
b.OwnsOne("VizhTalk.Learning.Domain.ValueObjects.EntityType", "EntityType", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("MediaId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b1.Property<string>("EntityId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)")
|
||||
.HasColumnName("EntityId");
|
||||
b1.Property<long>("MediaId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b1.Property<int>("Type")
|
||||
.HasMaxLength(200)
|
||||
@@ -12,10 +12,10 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.EnsureSchema(
|
||||
name: "Attachment");
|
||||
name: "Learning");
|
||||
|
||||
migrationBuilder.EnsureSchema(
|
||||
name: "Learning");
|
||||
name: "Attachment");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "FileGroups",
|
||||
@@ -26,7 +26,7 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Title = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
Key = table.Column<string>(type: "nvarchar(150)", maxLength: 150, nullable: false),
|
||||
MediaGroupId = table.Column<long>(type: "bigint", nullable: false),
|
||||
MediaGroupId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
IsSecure = table.Column<bool>(type: "bit", nullable: false),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false),
|
||||
@@ -43,11 +43,12 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
schema: "Learning",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
Id = table.Column<long>(type: "bigint", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Name = table.Column<string>(type: "nvarchar(150)", maxLength: 150, nullable: false),
|
||||
ContentType = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
Size = table.Column<int>(type: "int", nullable: false),
|
||||
EntityId = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
FileId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
EntityType = table.Column<int>(type: "int", maxLength: 200, nullable: false),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false),
|
||||
@@ -67,7 +68,7 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
Id = table.Column<short>(type: "smallint", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Title = table.Column<string>(type: "nvarchar(60)", maxLength: 60, nullable: false),
|
||||
IconId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
IconId = table.Column<long>(type: "bigint", nullable: false),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false),
|
||||
CreateOn = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
@@ -85,6 +86,52 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Courses",
|
||||
schema: "Learning",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "bigint", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Title = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
ImageId = table.Column<long>(type: "bigint", nullable: false),
|
||||
Order = table.Column<int>(type: "int", nullable: false),
|
||||
LanguageId = table.Column<short>(type: "smallint", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false),
|
||||
CreateOn = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
LastUpdate = table.Column<DateTime>(type: "datetime2", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Courses", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Courses_Languages_LanguageId",
|
||||
column: x => x.LanguageId,
|
||||
principalSchema: "Learning",
|
||||
principalTable: "Languages",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_Courses_Medias_ImageId",
|
||||
column: x => x.ImageId,
|
||||
principalSchema: "Learning",
|
||||
principalTable: "Medias",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Courses_ImageId",
|
||||
schema: "Learning",
|
||||
table: "Courses",
|
||||
column: "ImageId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Courses_LanguageId",
|
||||
schema: "Learning",
|
||||
table: "Courses",
|
||||
column: "LanguageId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Languages_IconId",
|
||||
schema: "Learning",
|
||||
@@ -95,6 +142,10 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Courses",
|
||||
schema: "Learning");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "FileGroups",
|
||||
schema: "Attachment");
|
||||
@@ -34,8 +34,8 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
b.Property<DateTime>("CreateOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid>("ImageId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
b.Property<long>("ImageId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
@@ -94,8 +94,8 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
b.Property<DateTime>("LastUpdate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<long>("MediaGroupId")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<Guid>("MediaGroupId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
@@ -118,8 +118,8 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
b.Property<DateTime>("CreateOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid>("IconId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
b.Property<long>("IconId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
@@ -144,8 +144,11 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
|
||||
modelBuilder.Entity("VizhTalk.Learning.Domain.Entities.Media", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("ContentType")
|
||||
.IsRequired()
|
||||
@@ -154,6 +157,9 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
b.Property<DateTime>("CreateOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid>("FileId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
@@ -206,14 +212,8 @@ namespace VizhTalk.Learning.Infrastructure.Migrations
|
||||
{
|
||||
b.OwnsOne("VizhTalk.Learning.Domain.ValueObjects.EntityType", "EntityType", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("MediaId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b1.Property<string>("EntityId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)")
|
||||
.HasColumnName("EntityId");
|
||||
b1.Property<long>("MediaId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b1.Property<int>("Type")
|
||||
.HasMaxLength(200)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using VizhTalk.BuildingBlocks.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure;
|
||||
using VizhTalk.Learning.Domain.Entities;
|
||||
using VizhTalk.Learning.Domain.Repositories;
|
||||
using VizhTalk.Learning.Domain.TypeIds;
|
||||
@@ -8,8 +9,18 @@ namespace VizhTalk.Learning.Infrastructure.Repositories
|
||||
{
|
||||
internal class LanguageRepository : RepositoryBase<Language, LanguageId>, ILanguageRepository
|
||||
{
|
||||
private readonly LearningDbContext dbContext;
|
||||
|
||||
public LanguageRepository(LearningDbContext dbContext) : base(dbContext)
|
||||
{
|
||||
this.dbContext = dbContext;
|
||||
}
|
||||
|
||||
public async Task<Language?> GetLanguageWithCoursesById(LanguageId languageId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await dbContext.Set<Language>()
|
||||
.Include(x => x.Courses)
|
||||
.FirstOrDefaultAsync(x => x.Id == languageId, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using Grpc.Core.Interceptors;
|
||||
using Grpc.Core;
|
||||
|
||||
namespace VizhTalk.Learning.Presentation.Interceptors;
|
||||
|
||||
public class ExceptionInterceptor : Interceptor
|
||||
{
|
||||
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
|
||||
TRequest request,
|
||||
ServerCallContext context,
|
||||
UnaryServerMethod<TRequest, TResponse> continuation)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await continuation(request, context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RpcException(
|
||||
new Status(StatusCode.Internal, "Unhandled exception: " + ex.Message)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,18 @@
|
||||
using VizhTalk.Learning.Infrastructure;
|
||||
using VizhTalk.Learning.Presentation.Interceptors;
|
||||
using VizhTalk.Learning.Presentation.Services;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var connectionString = builder.Configuration.GetConnectionString("LearningDB")!;
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddGrpc();
|
||||
builder.Services.AddGrpc(op =>
|
||||
{
|
||||
op.MaxReceiveMessageSize = 200 * 1024 * 1024;
|
||||
op.MaxSendMessageSize = 200 * 1024 * 1024;
|
||||
op.Interceptors.Add<ExceptionInterceptor>();
|
||||
});
|
||||
builder.Services.Initialize(connectionString);
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
||||
@@ -15,4 +20,5 @@ var app = builder.Build();
|
||||
app.MapGrpcService<LanguageService>();
|
||||
|
||||
app.UseLearningModule();
|
||||
|
||||
app.Run();
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using Grpc.Core;
|
||||
using VizhTalk.Grpc.Learning.Course;
|
||||
using VizhTalk.Learning.Infrastructure.Configuration;
|
||||
|
||||
namespace VizhTalk.Learning.Presentation.Services;
|
||||
|
||||
public class CourseService(ILearningModule learningModule) : CourseGrpc.CourseGrpcBase
|
||||
{
|
||||
public override async Task<CourseDTO> Create(CreateCourseCommand request, ServerCallContext context)
|
||||
{
|
||||
return await learningModule.Execute(request, context.CancellationToken);
|
||||
}
|
||||
public async override Task<CourseDTO> Update(UpdateCourseCommand request, ServerCallContext context)
|
||||
{
|
||||
return await learningModule.Execute(request, context.CancellationToken);
|
||||
}
|
||||
|
||||
public async override Task<GetAllCourseDTO> GetAll(GetAllCourseQuery request, ServerCallContext context)
|
||||
{
|
||||
return await learningModule.Execute(request, context.CancellationToken);
|
||||
}
|
||||
|
||||
public async override Task<CourseDTO> GetById(GetCourseByIdQuery request, ServerCallContext context)
|
||||
{
|
||||
return await learningModule.Execute(request, context.CancellationToken);
|
||||
}
|
||||
|
||||
public async override Task<CourseDTO> GetByTitle(GetCoursesByTitleQuery request, ServerCallContext context)
|
||||
{
|
||||
return await learningModule.Execute(request, context.CancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@ public class LanguageService(ILearningModule learningModule) : LanguageGrpc.Lang
|
||||
}
|
||||
public override async Task<LanguageDTO> GetByTitle(GetLanguageByTitleQuery request, ServerCallContext context)
|
||||
{
|
||||
await Task.Delay(10000);
|
||||
return await learningModule.Execute(request, context.CancellationToken);
|
||||
}
|
||||
public override async Task<GetAllLanguageDTO> GetAll(GetAllLanguageQuery request, ServerCallContext context)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"LearningDB": "Server=.; Database=VizhTalk.Learning; Trusted_Connection=True; MultipleActiveResultSets=true;TrustServerCertificate=True;"
|
||||
"LearningDB": "Server=.\\SQLEXPRESS; Database=VizhTalk.Learning; Trusted_Connection=True; MultipleActiveResultSets=true;TrustServerCertificate=True;"
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Kestrel": {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
using VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
namespace VizhTalk.Grpc.Learning.Course;
|
||||
|
||||
public sealed partial class CreateCourseCommand: ICommand<CourseDTO>;
|
||||
public sealed partial class UpdateCourseCommand : ICommand<CourseDTO>;
|
||||
@@ -1,5 +1,4 @@
|
||||
using VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
using VizhTalk.Grpc.Learning.Language;
|
||||
|
||||
namespace VizhTalk.Grpc.Learning.Language;
|
||||
|
||||
|
||||
@@ -8,11 +8,16 @@ import "Proto/Shared.proto";
|
||||
|
||||
message CreateCourseCommand{
|
||||
string title = 1;
|
||||
bytes icon = 2;
|
||||
string description = 2;
|
||||
UploadFile image = 3;
|
||||
Id languageid = 4;
|
||||
}
|
||||
|
||||
message UpdateCourseCommand{
|
||||
Id Id = 1;
|
||||
string title = 2;
|
||||
optional bytes icon = 3;
|
||||
string description = 3;
|
||||
int32 order = 4;
|
||||
optional UploadFile image = 5;
|
||||
Id languageid = 6;
|
||||
}
|
||||
@@ -7,7 +7,10 @@ import "Proto/Shared.proto";
|
||||
|
||||
message CourseDTO {
|
||||
Id Id = 1;
|
||||
string title = 2;
|
||||
Id languageId = 2;
|
||||
string title = 3;
|
||||
string image = 4;
|
||||
string description = 5;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import "Proto/Shared.proto";
|
||||
message GetAllCourseQuery{
|
||||
Pagination pagination = 1;
|
||||
}
|
||||
message GetCourseByTitleQuery{
|
||||
message GetCoursesByTitleQuery{
|
||||
string title = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,6 @@ service CourseGrpc {
|
||||
rpc Create (CreateCourseCommand) returns (CourseDTO);
|
||||
rpc Update (UpdateCourseCommand) returns (CourseDTO);
|
||||
rpc GetAll (GetAllCourseQuery) returns (GetAllCourseDTO);
|
||||
rpc GetByTitle (GetCourseByTitleQuery) returns (CourseDTO);
|
||||
rpc GetByTitle (GetCoursesByTitleQuery) returns (CourseDTO);
|
||||
rpc GetById (GetCourseByIdQuery) returns (CourseDTO);
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import "Proto/Shared.proto";
|
||||
message LanguageDTO {
|
||||
Id Id = 1;
|
||||
string title = 2;
|
||||
string icon = 3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
using VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
namespace VizhTalk.Grpc.Learning.Course;
|
||||
|
||||
public sealed partial class GetAllCourseQuery : IQuery<GetAllCourseDTO>;
|
||||
public sealed partial class GetCoursesByTitleQuery : IQuery<CourseDTO>;
|
||||
public sealed partial class GetCourseByIdQuery : IQuery<CourseDTO>;
|
||||
|
||||
|
||||
|
||||
@@ -14,25 +14,24 @@ using VizhTalk.Grpc.CDN;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.Application.CommandHandlers;
|
||||
|
||||
public class CreateMediaGroupCommandHandler(IUnitOfWork unitOfWork, CDNGrpc.CDNGrpcClient cdnClient) : ICommandHandler<CreateMediaGroupCommand, MediaGroupDTO>
|
||||
public class CreateMediaGroupCommandHandler(IUnitOfWork unitOfWork) : ICommandHandler<CreateMediaGroupCommand, MediaGroupDTO>
|
||||
{
|
||||
public async Task<MediaGroupDTO> Handle(CreateMediaGroupCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var title = request.Title.Trim();
|
||||
|
||||
if (await unitOfWork.MediaGroup.ExistsAsync(a => a.Key == request.Key))
|
||||
throw new MediaGroupKeyAlreadyExistsException();
|
||||
var mediaGroup = await unitOfWork.MediaGroup.GetAsync(a => a.Key == request.Key);
|
||||
if (mediaGroup != null)
|
||||
return mediaGroup.Adapt<MediaGroupDTO>();
|
||||
|
||||
|
||||
var mediaGroup = MediaGroup.CreateNew(title, request.Key, request.IsSecure);
|
||||
mediaGroup = MediaGroup.CreateNew(title, request.Key, request.IsSecure);
|
||||
await unitOfWork.MediaGroup.AddAsync(mediaGroup, cancellationToken);
|
||||
await unitOfWork.SaveChangeAsync(cancellationToken);
|
||||
return mediaGroup.Adapt<MediaGroupDTO>();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class UploadFileCommandHandler(IUnitOfWork unitOfWork, CDNGrpc.CDNGrpcClient cdnClient, IFileManagerService fileManager) : ICommandHandler<UploadFileCommand, UploadFileDTO>
|
||||
public class UploadFileCommandHandler(IUnitOfWork unitOfWork, IFileManagerService fileManager) : ICommandHandler<UploadFileCommand, UploadFileDTO>
|
||||
{
|
||||
public async Task<UploadFileDTO> Handle(UploadFileCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -57,11 +56,11 @@ public class UploadFileCommandHandler(IUnitOfWork unitOfWork, CDNGrpc.CDNGrpcCli
|
||||
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);
|
||||
var mediaGroupMedia = mediaGroup.AddMedia(new FileName(request.File.Name), media);
|
||||
if (!string.IsNullOrEmpty(request.ClientId))
|
||||
mediaGroupMedia.AddMediaPermission(media, Client.CreateNew(new ClientId(request.ClientId)));
|
||||
|
||||
await unitOfWork.MediaGroup.AddAsync(mediaGroup, cancellationToken);
|
||||
await unitOfWork.MediaGroup.UpdateAsync(mediaGroup, cancellationToken);
|
||||
await unitOfWork.SaveChangeAsync(cancellationToken);
|
||||
|
||||
return new UploadFileDTO()
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Vizhtalk.CDN.Presentation.Application
|
||||
{
|
||||
IMediaRepository Media { get; }
|
||||
IClientRepository Client { get; }
|
||||
IMediaClientRepository MediaClient { get; }
|
||||
IMediaPermissionRepository MediaClient { get; }
|
||||
IMediaGroupRepository MediaGroup{ get; }
|
||||
IMediaGroupMediaRepository MediaGroupMedia { get; }
|
||||
|
||||
|
||||
@@ -1,20 +1,30 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Vizhtalk.CDN.Presentation.Application;
|
||||
using Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[Route("[controller]")]
|
||||
[ApiController]
|
||||
public class FileController : ControllerBase
|
||||
public class FileController(IUnitOfWork unitOfWork) : ControllerBase
|
||||
{
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public IActionResult Get(MediaGroupMediaId id)
|
||||
public async Task<IActionResult> Get(Guid id)
|
||||
{
|
||||
var mediaGroupMedia = await unitOfWork.MediaGroupMedia
|
||||
.GetDetailsById(new MediaGroupMediaId(id));
|
||||
|
||||
|
||||
if (mediaGroupMedia == null)
|
||||
return NotFound();
|
||||
|
||||
return Unauthorized();
|
||||
if(!mediaGroupMedia.MediaGroup.IsSecure)
|
||||
{
|
||||
var fileBytes = System.IO.File.ReadAllBytes(mediaGroupMedia.Media.Path);
|
||||
return File(fileBytes, mediaGroupMedia.Media.ContentType.Value);
|
||||
}
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,10 +7,13 @@ namespace Vizhtalk.CDN.Presentation.Domain.Entities;
|
||||
|
||||
public class Media : Entity<MediaId>
|
||||
{
|
||||
|
||||
private Media(ContentType contentType, int size , string hash , string path)
|
||||
private Media()
|
||||
{
|
||||
|
||||
}
|
||||
private Media(ContentType contentType, int size , string hash , string path)
|
||||
{
|
||||
Id = new MediaId(Guid.NewGuid());
|
||||
ContentType = contentType;
|
||||
Size = size;
|
||||
Hash = hash;
|
||||
|
||||
@@ -6,9 +6,13 @@ namespace Vizhtalk.CDN.Presentation.Domain.Entities;
|
||||
|
||||
public class MediaGroup : Entity<MediaGroupId>
|
||||
{
|
||||
|
||||
private MediaGroup()
|
||||
{
|
||||
|
||||
}
|
||||
private MediaGroup(MediaGroupTitle title, string key, bool isSecure)
|
||||
{
|
||||
Id = new MediaGroupId(Guid.NewGuid());
|
||||
Title = title;
|
||||
Key = key;
|
||||
IsSecure = isSecure;
|
||||
|
||||
@@ -7,11 +7,15 @@ namespace Vizhtalk.CDN.Presentation.Domain.Entities;
|
||||
public class MediaGroupMedia : Entity<MediaGroupMediaId>
|
||||
{
|
||||
private List<MediaPermission> _mediaPermissions = new();
|
||||
|
||||
private MediaGroupMedia()
|
||||
{
|
||||
|
||||
}
|
||||
private MediaGroupMedia(FileName fileName,
|
||||
Media media,
|
||||
MediaGroup mediaGroup)
|
||||
{
|
||||
Id = new MediaGroupMediaId(Guid.NewGuid());
|
||||
Name = fileName;
|
||||
Media = media;
|
||||
MediaGroup = mediaGroup;
|
||||
@@ -19,8 +23,8 @@ public class MediaGroupMedia : Entity<MediaGroupMediaId>
|
||||
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 Media Media { get; set; }
|
||||
public MediaGroup MediaGroup { get; set; }
|
||||
public IReadOnlyList<MediaPermission> MediaPermissions => _mediaPermissions;
|
||||
|
||||
internal static MediaGroupMedia CreateNew(FileName fileName,
|
||||
|
||||
@@ -3,7 +3,7 @@ using VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.Domain.Entities;
|
||||
|
||||
public class MediaPermission : Entity<MediaClientId>
|
||||
public class MediaPermission : Entity<MediaPermissionId>
|
||||
{
|
||||
private MediaPermission()
|
||||
{
|
||||
@@ -11,6 +11,7 @@ public class MediaPermission : Entity<MediaClientId>
|
||||
}
|
||||
private MediaPermission(Media media, Client client, MediaGroupMedia mediaGroupMedia)
|
||||
{
|
||||
Id = new MediaPermissionId(Guid.NewGuid());
|
||||
Media = media;
|
||||
Client = client;
|
||||
MediaGroupMedia = mediaGroupMedia;
|
||||
|
||||
@@ -4,4 +4,7 @@ using VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.Domain.Repositories;
|
||||
|
||||
public interface IMediaGroupMediaRepository : IRepositoryBase<MediaGroupMedia, MediaGroupMediaId>;
|
||||
public interface IMediaGroupMediaRepository : IRepositoryBase<MediaGroupMedia, MediaGroupMediaId>
|
||||
{
|
||||
Task<MediaGroupMedia?> GetDetailsById(MediaGroupMediaId mediaGroupMediaId,CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ using VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.Domain.Repositories;
|
||||
|
||||
public interface IMediaClientRepository : IRepositoryBase<MediaPermission, MediaClientId>;
|
||||
public interface IMediaPermissionRepository : IRepositoryBase<MediaPermission, MediaPermissionId>;
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
||||
|
||||
public class MediaId : TypeIdValueBase<long>
|
||||
public class MediaId : TypeIdValueBase<Guid>
|
||||
{
|
||||
public MediaId(long value) : base(value)
|
||||
public MediaId(Guid value) : base(value)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
||||
|
||||
public class MediaClientId : TypeIdValueBase<long>
|
||||
public class MediaPermissionId : TypeIdValueBase<Guid>
|
||||
{
|
||||
public MediaClientId(long value) : base(value)
|
||||
public MediaPermissionId(Guid value) : base(value)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 7.0 MiB |
|
After Width: | Height: | Size: 7.0 MiB |
|
After Width: | Height: | Size: 7.0 MiB |
|
After Width: | Height: | Size: 7.0 MiB |
|
After Width: | Height: | Size: 7.0 MiB |
|
After Width: | Height: | Size: 7.0 MiB |
|
After Width: | Height: | Size: 7.0 MiB |
|
After Width: | Height: | Size: 7.0 MiB |
@@ -1,6 +1,8 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MongoDB.Driver;
|
||||
using Vizhtalk.CDN.Presentation.Application;
|
||||
using Vizhtalk.CDN.Presentation.Application.Mappers;
|
||||
using Vizhtalk.CDN.Presentation.FileManagerServices;
|
||||
using Vizhtalk.CDN.Presentation.Infrastructure.Configuration;
|
||||
using Vizhtalk.CDN.Presentation.Infrastructure.EF;
|
||||
using VizhTalk.BuildingBlocks.Application;
|
||||
@@ -18,6 +20,9 @@ public static class CDNStartup
|
||||
{
|
||||
public static void Initialize(this IServiceCollection services, string connectionString, string databaseName)
|
||||
{
|
||||
var domainNotificationsMap = new BiDictionary<string, Type>();
|
||||
|
||||
|
||||
services.AddDbContext<CDNDbContext>(options =>
|
||||
{
|
||||
options.UseMongoDB(connectionString, databaseName);
|
||||
@@ -25,6 +30,46 @@ public static class CDNStartup
|
||||
|
||||
services.AddScoped<DbContext>(sp => sp.GetService<CDNDbContext>());
|
||||
|
||||
services.Scan(scan => scan.
|
||||
FromAssemblies(Assemblies.Application, Assemblies.Infrastructure)
|
||||
.AddClasses(classes => classes.AssignableTo(typeof(ICommandHandler<>)), publicOnly: false)
|
||||
.AsImplementedInterfaces()
|
||||
.WithScopedLifetime()
|
||||
.AddClasses(classes => classes.AssignableTo(typeof(ICommandHandler<,>)), publicOnly: false)
|
||||
.AsImplementedInterfaces()
|
||||
.WithScopedLifetime()
|
||||
.AddClasses(classes => classes.AssignableTo(typeof(IQueryHandler<,>)), publicOnly: false)
|
||||
.AsImplementedInterfaces()
|
||||
.WithScopedLifetime()
|
||||
.AddClasses(classes => classes.AssignableTo(typeof(ICommandHandler<>)), publicOnly: false)
|
||||
.AsImplementedInterfaces()
|
||||
.WithScopedLifetime());
|
||||
|
||||
services.AddScoped<IFileManagerService, FileManagerService>();
|
||||
services.AddScoped<DbContext>(sp => sp.GetService<CDNDbContext>());
|
||||
services.AddScoped<ICDNModule, CDNModule>();
|
||||
services.AddScoped<IExecutor, CDNModule>();
|
||||
services.AddScoped<IUnitOfWork, UnitOfWork>();
|
||||
services.AddScoped<IDomainEventsAccessor, DomainEventsAccessor>();
|
||||
services.AddScoped<IDomainEventsDispatcher, DomainEventsDispatcher>();
|
||||
services.AddScoped<IDomainNotificationsMapper, DomainNotificationsMapper>();
|
||||
services.AddScoped(sp => domainNotificationsMap);
|
||||
|
||||
MapperConfig.Process();
|
||||
services.AddScoped(sa =>
|
||||
{
|
||||
var notifications = sa.GetServices<IDomainEventNotification>();
|
||||
var notificationDic = new BiDictionary<string, Type>();
|
||||
foreach (var notification in notifications)
|
||||
notificationDic.Add(notification!.ToString()!, notification!.GetType());
|
||||
|
||||
return notificationDic;
|
||||
});
|
||||
|
||||
services.AddScoped<IOutbox>(sa =>
|
||||
{
|
||||
return null; // ToDo
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Vizhtalk.CDN.Presentation.Infrastructure.EF
|
||||
|
||||
public CDNDbContext(DbContextOptions<CDNDbContext> options) : base(options)
|
||||
{
|
||||
|
||||
Database.AutoTransactionBehavior = AutoTransactionBehavior.Never;
|
||||
}
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
@@ -19,6 +19,5 @@ namespace Vizhtalk.CDN.Presentation.Infrastructure.EF
|
||||
.ApplyConfigurationsFromAssembly(Assemblies.Infrastructure, x => x.FullName.Contains("EF.Configurations"))
|
||||
.PluralizeEntities();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ public class MediaClientConfiguration : IEntityTypeConfiguration<MediaPermission
|
||||
builder.HasKey(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.MediaPermissionId(x));
|
||||
|
||||
|
||||
builder.Property(x => x.ClientId)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Vizhtalk.CDN.Presentation.Domain.Entities;
|
||||
using Vizhtalk.CDN.Presentation.Domain.Repositories;
|
||||
using Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
||||
using Vizhtalk.CDN.Presentation.Infrastructure.EF;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.Infrastructure.Repositories
|
||||
{
|
||||
public class ClientRepository : RepositoryBase<Client, ClientId>, IClientRepository
|
||||
{
|
||||
public ClientRepository(CDNDbContext dbContext) : base(dbContext)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Vizhtalk.CDN.Presentation.Domain.Entities;
|
||||
using Vizhtalk.CDN.Presentation.Domain.Repositories;
|
||||
using Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
||||
using Vizhtalk.CDN.Presentation.Infrastructure.EF;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.Infrastructure.Repositories
|
||||
{
|
||||
public class MediaGroupMediaRepository : RepositoryBase<MediaGroupMedia, MediaGroupMediaId>, IMediaGroupMediaRepository
|
||||
{
|
||||
private readonly CDNDbContext dbContext;
|
||||
|
||||
public MediaGroupMediaRepository(CDNDbContext dbContext) : base(dbContext)
|
||||
{
|
||||
this.dbContext = dbContext;
|
||||
}
|
||||
|
||||
public async Task<MediaGroupMedia?> GetDetailsById(MediaGroupMediaId mediaGroupMediaId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var mediaGroupMedia = await dbContext.Set<MediaGroupMedia>()
|
||||
.FirstOrDefaultAsync(x => x.Id == mediaGroupMediaId, cancellationToken);
|
||||
|
||||
if (mediaGroupMedia == null)
|
||||
return null;
|
||||
|
||||
// پر کردن دستی navigation properties
|
||||
mediaGroupMedia.MediaGroup = await dbContext.Set<MediaGroup>()
|
||||
.FirstOrDefaultAsync(mg => mg.Id == mediaGroupMedia.MediaGroupId, cancellationToken);
|
||||
|
||||
mediaGroupMedia.Media = await dbContext.Set<Media>()
|
||||
.FirstOrDefaultAsync(m => m.Id == mediaGroupMedia.MediaId, cancellationToken);
|
||||
|
||||
return mediaGroupMedia;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Vizhtalk.CDN.Presentation.Domain.Entities;
|
||||
using Vizhtalk.CDN.Presentation.Domain.Repositories;
|
||||
using Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
||||
using Vizhtalk.CDN.Presentation.Infrastructure.EF;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.Infrastructure.Repositories
|
||||
{
|
||||
public class MediaGroupRepository : RepositoryBase<MediaGroup, MediaGroupId>, IMediaGroupRepository
|
||||
{
|
||||
public MediaGroupRepository(CDNDbContext dbContext) : base(dbContext)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Vizhtalk.CDN.Presentation.Domain.Entities;
|
||||
using Vizhtalk.CDN.Presentation.Domain.Repositories;
|
||||
using Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
||||
using Vizhtalk.CDN.Presentation.Infrastructure.EF;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.Infrastructure.Repositories
|
||||
{
|
||||
public class MediaPermissionRepository : RepositoryBase<MediaPermission, MediaPermissionId>, IMediaPermissionRepository
|
||||
{
|
||||
public MediaPermissionRepository(CDNDbContext dbContext) : base(dbContext)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Vizhtalk.CDN.Presentation.Domain.Entities;
|
||||
using Vizhtalk.CDN.Presentation.Domain.Repositories;
|
||||
using Vizhtalk.CDN.Presentation.Domain.TypeIds;
|
||||
using Vizhtalk.CDN.Presentation.Infrastructure.EF;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.Infrastructure.Repositories
|
||||
{
|
||||
public class MediaRepository : RepositoryBase<Media, MediaId>, IMediaRepository
|
||||
{
|
||||
public MediaRepository(CDNDbContext dbContext) : base(dbContext)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,21 +3,73 @@ using Vizhtalk.CDN.Presentation.Infrastructure.EF;
|
||||
using Vizhtalk.CDN.Presentation.Domain.Repositories;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure.DomainEventsDispatching;
|
||||
using Vizhtalk.CDN.Presentation.Infrastructure.Repositories;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.Infrastructure
|
||||
{
|
||||
public class UnitOfWork(CDNDbContext cdnDbContext, IDomainEventsDispatcher domainEventsDispatcher)
|
||||
: UnitOfWorkBase(cdnDbContext, domainEventsDispatcher)
|
||||
: UnitOfWorkBase(cdnDbContext, domainEventsDispatcher), IUnitOfWork
|
||||
{
|
||||
public IMediaRepository Media => throw new NotImplementedException();
|
||||
private IMediaRepository _mediaRepository;
|
||||
public IMediaRepository Media
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_mediaRepository == null)
|
||||
_mediaRepository = new MediaRepository(cdnDbContext);
|
||||
|
||||
public IClientRepository Client => throw new NotImplementedException();
|
||||
return _mediaRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public IMediaClientRepository MediaClient => throw new NotImplementedException();
|
||||
private IClientRepository _clientRepository;
|
||||
public IClientRepository Client
|
||||
{
|
||||
get
|
||||
{
|
||||
if(_clientRepository == null)
|
||||
_clientRepository = new ClientRepository(cdnDbContext);
|
||||
return _clientRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public IMediaGroupRepository MediaGroup => throw new NotImplementedException();
|
||||
private IMediaPermissionRepository _mediaPermissionRepository;
|
||||
public IMediaPermissionRepository MediaClient
|
||||
{
|
||||
get
|
||||
{
|
||||
if( _mediaPermissionRepository == null)
|
||||
_mediaPermissionRepository = new MediaPermissionRepository(cdnDbContext);
|
||||
|
||||
public IMediaGroupMediaRepository MediaGroupMedia => throw new NotImplementedException();
|
||||
return _mediaPermissionRepository;
|
||||
}
|
||||
}
|
||||
|
||||
private IMediaGroupRepository _mediaGroupRepository;
|
||||
public IMediaGroupRepository MediaGroup
|
||||
{
|
||||
get
|
||||
{
|
||||
if(_mediaGroupRepository == null)
|
||||
_mediaGroupRepository = new MediaGroupRepository(cdnDbContext);
|
||||
|
||||
return _mediaGroupRepository;
|
||||
}
|
||||
}
|
||||
|
||||
private IMediaGroupMediaRepository _mediaGroupMediaRepository;
|
||||
public IMediaGroupMediaRepository MediaGroupMedia
|
||||
{
|
||||
get
|
||||
{
|
||||
if(_mediaGroupMediaRepository == null)
|
||||
_mediaGroupMediaRepository = new MediaGroupMediaRepository(cdnDbContext);
|
||||
|
||||
return _mediaGroupMediaRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SaveChangeAsync(CancellationToken cancellationToken = default)
|
||||
=> await cdnDbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,18 +8,21 @@ var builder = WebApplication.CreateBuilder(args);
|
||||
var connectionString = builder.Configuration.GetConnectionString("VizhTalk.CDN")!;
|
||||
var databaseName = builder.Configuration.GetConnectionString("VizhTalk.CDN.DatabaseName")!;
|
||||
|
||||
builder.Services.AddScoped<IFileManagerService, FileManagerService>();
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.Initialize(connectionString, databaseName);
|
||||
builder.Services.AddGrpc();
|
||||
builder.Services.AddGrpc(op =>
|
||||
{
|
||||
op.MaxReceiveMessageSize = 500 * 1024 * 1024;
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
||||
|
||||
app.MapGet("/", () => "Hello World!");
|
||||
app.UseRouting();
|
||||
|
||||
app.MapGrpcService<CDNService>();
|
||||
|
||||
app.MapControllers();
|
||||
//app.UseCDNModule();
|
||||
|
||||
app.Run();
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"VizhTalk.CDN": "mongodb://localhost:27017",
|
||||
"VizhTalk.CDN.DatabaseName": "VizhTalk.CDN"
|
||||
"VizhTalk.CDN.DatabaseName": "VizhTalk_CDN"
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
|
||||