diff --git a/src/FluentCMS.Application/Dtos/PagingRequest.cs b/src/FluentCMS.Application/Dtos/PagingRequest.cs new file mode 100644 index 000000000..ed26394c8 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/PagingRequest.cs @@ -0,0 +1,6 @@ +namespace FluentCMS.Application.Dtos; +public class PagingRequest +{ + public int PageIndex { get; set; } + public int PageSize { get; set; } +} diff --git a/src/FluentCMS.Application/Dtos/PagingResponse.cs b/src/FluentCMS.Application/Dtos/PagingResponse.cs new file mode 100644 index 000000000..d3cebe24a --- /dev/null +++ b/src/FluentCMS.Application/Dtos/PagingResponse.cs @@ -0,0 +1,6 @@ +namespace FluentCMS.Application.Dtos; +public class PagingResponse +{ + public IEnumerable Data { get; set; } = new List(); + public long Total { get; set; } +} diff --git a/src/FluentCMS.Application/Dtos/Sites/AddSiteUrlRequest.cs b/src/FluentCMS.Application/Dtos/Sites/AddSiteUrlRequest.cs new file mode 100644 index 000000000..b0434a4e4 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Sites/AddSiteUrlRequest.cs @@ -0,0 +1,18 @@ +using FluentValidation; + +namespace FluentCMS.Application.Dtos.Sites; + +public class AddSiteUrlRequest +{ + public Guid SiteId { get; set; } + public string NewUrl { get; set; } = ""; +} + +public class AddSiteUrlRequestValidator : AbstractValidator +{ + public AddSiteUrlRequestValidator() + { + RuleFor(x => x.SiteId).NotEmpty(); + RuleFor(x => x.NewUrl).NotEmpty().MaximumLength(50); + } +} diff --git a/src/FluentCMS.Application/Dtos/Sites/CreateSiteRequest.cs b/src/FluentCMS.Application/Dtos/Sites/CreateSiteRequest.cs new file mode 100644 index 000000000..653cc441f --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Sites/CreateSiteRequest.cs @@ -0,0 +1,21 @@ +using FluentValidation; + +namespace FluentCMS.Application.Dtos.Sites; + +public class CreateSiteRequest +{ + public string Name { get; set; } = ""; + public string Description { get; set; } = ""; + public string[] URLs { get; set; } = []; + public Guid RoleId { get; set; } +} + +public class CreateSiteRequestValidator : AbstractValidator +{ + public CreateSiteRequestValidator() + { + RuleFor(x => x.Name).NotEmpty().MaximumLength(64); + RuleFor(x => x.Description).MaximumLength(100).When(x => string.IsNullOrWhiteSpace(x.Description) == false); + RuleFor(x => x.URLs).NotNull().Must(x => x.Any()); + } +} diff --git a/src/FluentCMS.Application/Dtos/Sites/DeleteSiteRequest.cs b/src/FluentCMS.Application/Dtos/Sites/DeleteSiteRequest.cs new file mode 100644 index 000000000..1d9539326 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Sites/DeleteSiteRequest.cs @@ -0,0 +1,16 @@ +using FluentValidation; + +namespace FluentCMS.Application.Dtos.Sites; + +public class DeleteSiteRequest +{ + public Guid Id { get; set; } +} + +public class DeleteSiteRequestValidator : AbstractValidator +{ + public DeleteSiteRequestValidator() + { + RuleFor(x => x.Id).NotEmpty(); + } +} diff --git a/src/FluentCMS.Application/Dtos/Sites/EditSiteRequest.cs b/src/FluentCMS.Application/Dtos/Sites/EditSiteRequest.cs new file mode 100644 index 000000000..e7b3d9321 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Sites/EditSiteRequest.cs @@ -0,0 +1,23 @@ +using FluentValidation; + +namespace FluentCMS.Application.Dtos.Sites; + +public class EditSiteRequest +{ + public Guid Id { get; set; } + public string Name { get; set; } = ""; + public string Description { get; set; } = ""; + public Guid RoleId { get; set; } + public ICollection URLs { get; set; } = new List(); +} + +public class EditSiteRequestValidator : AbstractValidator +{ + public EditSiteRequestValidator() + { + RuleFor(x => x.Id).NotEmpty(); + RuleFor(x => x.Name).NotEmpty().MaximumLength(64); + RuleFor(x => x.Description).MaximumLength(100).When(x => string.IsNullOrWhiteSpace(x.Description) == false); + RuleFor(x => x.URLs).NotNull().Must(x => x.Any()); + } +} diff --git a/src/FluentCMS.Application/Dtos/Sites/RemoveSiteUrlRequest.cs b/src/FluentCMS.Application/Dtos/Sites/RemoveSiteUrlRequest.cs new file mode 100644 index 000000000..1744159f1 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Sites/RemoveSiteUrlRequest.cs @@ -0,0 +1,18 @@ +using FluentValidation; + +namespace FluentCMS.Application.Dtos.Sites; + +public class RemoveSiteUrlRequest +{ + public Guid SiteId { get; set; } + public string Url { get; set; } = ""; +} + +public class RemoveSiteUrlRequestValidator : AbstractValidator +{ + public RemoveSiteUrlRequestValidator() + { + RuleFor(x => x.SiteId).NotEmpty(); + RuleFor(x => x.Url).NotEmpty().MaximumLength(50); + } +} diff --git a/src/FluentCMS.Application/Dtos/Sites/SearchSiteRequest.cs b/src/FluentCMS.Application/Dtos/Sites/SearchSiteRequest.cs new file mode 100644 index 000000000..8c6683ed6 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Sites/SearchSiteRequest.cs @@ -0,0 +1,4 @@ +namespace FluentCMS.Application.Dtos.Sites; +public class SearchSiteRequest : PagingRequest +{ +} diff --git a/src/FluentCMS.Application/Dtos/Sites/SearchSiteResponse.cs b/src/FluentCMS.Application/Dtos/Sites/SearchSiteResponse.cs new file mode 100644 index 000000000..a0f039ab0 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Sites/SearchSiteResponse.cs @@ -0,0 +1,4 @@ +namespace FluentCMS.Application.Dtos.Sites; +public class SearchSiteResponse : PagingResponse +{ +} diff --git a/src/FluentCMS.Application/Dtos/Sites/SiteDto.cs b/src/FluentCMS.Application/Dtos/Sites/SiteDto.cs new file mode 100644 index 000000000..56b616b01 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Sites/SiteDto.cs @@ -0,0 +1,13 @@ +namespace FluentCMS.Application.Dtos.Sites; +public class SiteDto +{ + public Guid Id { get; set; } + public string CreatedBy { get; set; } = ""; + public DateTime CreatedAt { get; set; } = default; + public string LastUpdatedBy { get; set; } = ""; + public DateTime LastUpdatedAt { get; set; } = default; + public string Name { get; set; } = ""; + public string Description { get; set; } = ""; + public List Urls { get; set; } = []; + public Guid RoleId { get; set; } +} diff --git a/src/FluentCMS.Application/Dtos/Users/CreateRoleRequest.cs b/src/FluentCMS.Application/Dtos/Users/CreateRoleRequest.cs new file mode 100644 index 000000000..444fef83b --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Users/CreateRoleRequest.cs @@ -0,0 +1,20 @@ +using FluentValidation; + +namespace FluentCMS.Application.Dtos.Users; + +public class CreateRoleRequest +{ + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + public bool AutoAssigned { get; set; } + public Guid? SiteId { get; set; } +} + +public class CreateRoleRequestValidator : AbstractValidator +{ + public CreateRoleRequestValidator() + { + RuleFor(x => x.Name).NotEmpty().MaximumLength(50); + RuleFor(x => x.Description).MaximumLength(100).When(x => string.IsNullOrWhiteSpace(x.Description) == false); + } +} diff --git a/src/FluentCMS.Application/Dtos/Users/CreateUserRequest.cs b/src/FluentCMS.Application/Dtos/Users/CreateUserRequest.cs new file mode 100644 index 000000000..e67c7f5cb --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Users/CreateUserRequest.cs @@ -0,0 +1,21 @@ +using FluentValidation; + +namespace FluentCMS.Application.Dtos.Users; + +public class CreateUserRequest +{ + public string Name { get; set; } = string.Empty; + public string Username { get; set; } = string.Empty; + public string Password { get; set; } = string.Empty; + public ICollection Roles { get; set; } = new List(); +} + +public class CreateUserRequestValidator : AbstractValidator +{ + public CreateUserRequestValidator() + { + RuleFor(x => x.Name).NotEmpty().MaximumLength(64); + RuleFor(x => x.Username).NotEmpty().MinimumLength(3).MaximumLength(50); + RuleFor(x => x.Password).NotEmpty().MinimumLength(3).MaximumLength(50); + } +} diff --git a/src/FluentCMS.Application/Dtos/Users/DeleteRoleRequest.cs b/src/FluentCMS.Application/Dtos/Users/DeleteRoleRequest.cs new file mode 100644 index 000000000..59d45ee94 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Users/DeleteRoleRequest.cs @@ -0,0 +1,16 @@ +using FluentValidation; + +namespace FluentCMS.Application.Dtos.Users; + +public class DeleteRoleRequest +{ + public required Guid Id { get; set; } +} + +public class DeleteRoleRequestValidator : AbstractValidator +{ + public DeleteRoleRequestValidator() + { + RuleFor(x => x.Id).NotEmpty(); + } +} diff --git a/src/FluentCMS.Application/Dtos/Users/DeleteUserRequest.cs b/src/FluentCMS.Application/Dtos/Users/DeleteUserRequest.cs new file mode 100644 index 000000000..e1f12e8d3 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Users/DeleteUserRequest.cs @@ -0,0 +1,16 @@ +using FluentValidation; + +namespace FluentCMS.Application.Dtos.Users; + +public class DeleteUserRequest +{ + public Guid Id { get; set; } +} + +public class DeleteUserRequestValidator : AbstractValidator +{ + public DeleteUserRequestValidator() + { + RuleFor(x => x.Id).NotEmpty(); + } +} diff --git a/src/FluentCMS.Application/Dtos/Users/EditRoleRequest.cs b/src/FluentCMS.Application/Dtos/Users/EditRoleRequest.cs new file mode 100644 index 000000000..3fc036fdd --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Users/EditRoleRequest.cs @@ -0,0 +1,22 @@ +using FluentValidation; + +namespace FluentCMS.Application.Dtos.Users; + +public class EditRoleRequest +{ + public required Guid Id { get; set; } + public required string Name { get; set; } + public string? Description { get; set; } + public required bool AutoAssigned { get; set; } + public Guid? SiteId { get; set; } +} + +public class EditRoleRequestValidator : AbstractValidator +{ + public EditRoleRequestValidator() + { + RuleFor(x => x.Id).NotEmpty(); + RuleFor(x => x.Name).NotEmpty().MaximumLength(50); + RuleFor(x => x.Description).MaximumLength(100).When(x => string.IsNullOrWhiteSpace(x.Description) == false); + } +} diff --git a/src/FluentCMS.Application/Dtos/Users/EditUserRequest.cs b/src/FluentCMS.Application/Dtos/Users/EditUserRequest.cs new file mode 100644 index 000000000..a1df2819f --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Users/EditUserRequest.cs @@ -0,0 +1,24 @@ +using FluentValidation; + +namespace FluentCMS.Application.Dtos.Users; + +public class EditUserRequest +{ + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string Username { get; set; } = string.Empty; + public string Password { get; set; } = string.Empty; + public ICollection Roles { get; set; } = new List(); +} + +public class EditUserRequestValidator : AbstractValidator +{ + public EditUserRequestValidator() + { + RuleFor(x => x.Id).NotEmpty(); + RuleFor(x => x.Name).NotEmpty().MaximumLength(50); + RuleFor(x => x.Username).NotEmpty().MinimumLength(3).MaximumLength(50); + RuleFor(x => x.Password).MinimumLength(3).MaximumLength(50) + .When(x => string.IsNullOrWhiteSpace(x.Password) == false); + } +} diff --git a/src/FluentCMS.Application/Dtos/Users/RoleDto.cs b/src/FluentCMS.Application/Dtos/Users/RoleDto.cs new file mode 100644 index 000000000..ddc85f302 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Users/RoleDto.cs @@ -0,0 +1,15 @@ +namespace FluentCMS.Application.Dtos.Users; +public class RoleDto +{ + public required Guid Id { get; set; } + public required string CreatedBy { get; set; } + public required DateTime CreatedAt { get; set; } + public required string LastUpdatedBy { get; set; } + public required DateTime LastUpdatedAt { get; set; } + + public required string Name { get; set; } + public string? Description { get; set; } + public required bool AutoAssigned { get; set; } + + public Guid? SiteId { get; set; } +} diff --git a/src/FluentCMS.Application/Dtos/Users/SearchRoleRequest.cs b/src/FluentCMS.Application/Dtos/Users/SearchRoleRequest.cs new file mode 100644 index 000000000..f6bcb00a7 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Users/SearchRoleRequest.cs @@ -0,0 +1,4 @@ +namespace FluentCMS.Application.Dtos.Users; +public class SearchRoleRequest : PagingRequest +{ +} diff --git a/src/FluentCMS.Application/Dtos/Users/SearchRoleResponse.cs b/src/FluentCMS.Application/Dtos/Users/SearchRoleResponse.cs new file mode 100644 index 000000000..a6b1d4e85 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Users/SearchRoleResponse.cs @@ -0,0 +1,4 @@ +namespace FluentCMS.Application.Dtos.Users; +public class SearchRoleResponse : PagingResponse +{ +} diff --git a/src/FluentCMS.Application/Dtos/Users/SearchUserRequest.cs b/src/FluentCMS.Application/Dtos/Users/SearchUserRequest.cs new file mode 100644 index 000000000..74b416ad4 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Users/SearchUserRequest.cs @@ -0,0 +1,5 @@ +namespace FluentCMS.Application.Dtos.Users; +public class SearchUserRequest : PagingRequest +{ + public string? Name { get; set; } +} diff --git a/src/FluentCMS.Application/Dtos/Users/SearchUserResponse.cs b/src/FluentCMS.Application/Dtos/Users/SearchUserResponse.cs new file mode 100644 index 000000000..727f72581 --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Users/SearchUserResponse.cs @@ -0,0 +1,4 @@ +namespace FluentCMS.Application.Dtos.Users; +public class SearchUserResponse : PagingResponse +{ +} diff --git a/src/FluentCMS.Application/Dtos/Users/UserDto.cs b/src/FluentCMS.Application/Dtos/Users/UserDto.cs new file mode 100644 index 000000000..5f0e3dc3b --- /dev/null +++ b/src/FluentCMS.Application/Dtos/Users/UserDto.cs @@ -0,0 +1,14 @@ +namespace FluentCMS.Application.Dtos.Users; +public class UserDto +{ + public required Guid Id { get; set; } + public required string CreatedBy { get; set; } + public required DateTime CreatedAt { get; set; } + public required string LastUpdatedBy { get; set; } + public required DateTime LastUpdatedAt { get; set; } + + public string Name { get; set; } = string.Empty; + public string Username { get; set; } = string.Empty; + + public virtual IEnumerable UserRoles { get; set; } = Enumerable.Empty(); +} diff --git a/src/FluentCMS.Application/Extensions.cs b/src/FluentCMS.Application/Extensions.cs index 6efe627ca..9094a1b69 100644 --- a/src/FluentCMS.Application/Extensions.cs +++ b/src/FluentCMS.Application/Extensions.cs @@ -1,4 +1,5 @@ -using FluentCMS.Repository; +using FluentCMS.Application.Services; +using FluentValidation; using Microsoft.Extensions.DependencyInjection; namespace FluentCMS.Application; @@ -7,7 +8,14 @@ public static class Extensions public static FluentCMSBuilder AddApplication(this FluentCMSBuilder fcBuilder) { // register mediatR - fcBuilder.Services.AddMediatR(c => c.RegisterServicesFromAssembly(typeof(Extensions).Assembly)); + fcBuilder.Services.AddScoped(); + fcBuilder.Services.AddScoped(); + fcBuilder.Services.AddScoped(); + fcBuilder.Services.AddScoped(); + + // register automapper + fcBuilder.Services.AddAutoMapper(typeof(Extensions).Assembly); + fcBuilder.Services.AddValidatorsFromAssembly(typeof(Extensions).Assembly); return fcBuilder; } diff --git a/src/FluentCMS.Application/FluentCMS.Application.csproj b/src/FluentCMS.Application/FluentCMS.Application.csproj index bbb787650..2e52de3c6 100644 --- a/src/FluentCMS.Application/FluentCMS.Application.csproj +++ b/src/FluentCMS.Application/FluentCMS.Application.csproj @@ -7,7 +7,10 @@ - + + + + diff --git a/src/FluentCMS.Application/Mappings/SiteMappings.cs b/src/FluentCMS.Application/Mappings/SiteMappings.cs new file mode 100644 index 000000000..09ff8034a --- /dev/null +++ b/src/FluentCMS.Application/Mappings/SiteMappings.cs @@ -0,0 +1,12 @@ +using AutoMapper; +using FluentCMS.Application.Dtos.Sites; +using FluentCMS.Entities.Sites; + +namespace FluentCMS.Application.Mappings; +internal class SiteMappings : Profile +{ + public SiteMappings() + { + CreateMap(); + } +} diff --git a/src/FluentCMS.Application/Mappings/UserMappingProfile.cs b/src/FluentCMS.Application/Mappings/UserMappingProfile.cs new file mode 100644 index 000000000..de18e54a3 --- /dev/null +++ b/src/FluentCMS.Application/Mappings/UserMappingProfile.cs @@ -0,0 +1,15 @@ +using AutoMapper; +using FluentCMS.Application.Dtos.Users; +using FluentCMS.Entities.Users; + +namespace FluentCMS.Application.Mappings; +internal class UserMappingProfile : Profile +{ + public UserMappingProfile() + { + CreateMap() + .ForMember(x => x.UserRoles, cfg => cfg.MapFrom(y => y.UserRoles.Select(z => z.RoleId.ToString()))); + + CreateMap(); + } +} diff --git a/src/FluentCMS.Domain/Services/ContentTypeService.cs b/src/FluentCMS.Application/Services/ContentTypeService.cs similarity index 80% rename from src/FluentCMS.Domain/Services/ContentTypeService.cs rename to src/FluentCMS.Application/Services/ContentTypeService.cs index 9e168d691..09f43ff87 100644 --- a/src/FluentCMS.Domain/Services/ContentTypeService.cs +++ b/src/FluentCMS.Application/Services/ContentTypeService.cs @@ -2,8 +2,19 @@ using FluentCMS.Entities.ContentTypes; using FluentCMS.Repository; -namespace FluentCMS.Services; -public class ContentTypeService +namespace FluentCMS.Application.Services; + +public interface IContentTypeService +{ + Task GetById(Guid id); + Task GetBySlug(string slug); + Task> Search(); + Task Create(ContentType contentType); + Task Edit(ContentType contentType); + Task Delete(Guid id); +} + +internal class ContentTypeService : IContentTypeService { private readonly IContentTypeRepository _contentTypeRepository; @@ -12,11 +23,28 @@ public ContentTypeService(IContentTypeRepository contentTypeRepository) _contentTypeRepository = contentTypeRepository; } + public async Task GetById(Guid id) + { + return await _contentTypeRepository.GetById(id) + ?? throw new ApplicationException("Requested contentType does not exists."); + } + + public async Task GetBySlug(string slug) + { + return await _contentTypeRepository.GetBySlug(slug); + } + + public async Task> Search() + { + return await _contentTypeRepository.GetAll(); + } + public async Task Create(ContentType contentType) { Guard.Against.Null(contentType); Guard.Against.NullOrEmpty(contentType.Title); Guard.Against.NullOrEmpty(contentType.Slug); + await CheckForDuplicateSlug(contentType); await _contentTypeRepository.Create(contentType); } @@ -26,6 +54,7 @@ public async Task Edit(ContentType contentType) Guard.Against.Null(contentType); Guard.Against.NullOrEmpty(contentType.Title); Guard.Against.NullOrEmpty(contentType.Slug); + await CheckForDuplicateSlug(contentType); await _contentTypeRepository.Update(contentType); } @@ -36,22 +65,6 @@ public async Task Delete(Guid id) await _contentTypeRepository.Delete(id); } - public async Task> GetAll() - { - return await _contentTypeRepository.GetAll(); - } - - public async Task GetById(Guid id) - { - return await _contentTypeRepository.GetById(id) - ?? throw new ApplicationException("Requested contentType does not exists."); - } - - public async Task GetBySlug(string slug) - { - return await _contentTypeRepository.GetBySlug(slug); - } - private async Task CheckForDuplicateSlug(ContentType contentType) { // todo: add this query to repository? diff --git a/src/FluentCMS.Application/Services/RoleService.cs b/src/FluentCMS.Application/Services/RoleService.cs new file mode 100644 index 000000000..4eed5b9e6 --- /dev/null +++ b/src/FluentCMS.Application/Services/RoleService.cs @@ -0,0 +1,87 @@ +using Ardalis.GuardClauses; +using FluentCMS.Application.Dtos.Users; +using FluentCMS.Entities.Users; +using FluentCMS.Repository; + +namespace FluentCMS.Application.Services; + +public interface IRoleService +{ + Task GetById(Guid id); + Task Search(SearchRoleRequest request); + Task Create(CreateRoleRequest request, CancellationToken cancellationToken = default); + Task Edit(EditRoleRequest request, CancellationToken cancellationToken = default); + Task Delete(DeleteRoleRequest request, CancellationToken cancellationToken = default); +} + +internal class RoleService(AutoMapper.IMapper mapper, IGenericRepository roleRepository) : IRoleService +{ + public async Task GetById(Guid id) + { + var roles = await roleRepository.GetById(id) + ?? throw new ApplicationException("Requested role does not exists."); + return mapper.Map(roles); + } + + public async Task Search(SearchRoleRequest request) + { + var roles = await roleRepository.GetAll(); + return new SearchRoleResponse + { + Data = roles.Select(x => mapper.Map(x)), + Total = roles.Count(), + }; + } + + public async Task Create(CreateRoleRequest request, CancellationToken cancellationToken = default) + { + Guard.Against.Null(request); + Guard.Against.NullOrWhiteSpace(request.Name); + + var role = new Role + { + Id = Guid.NewGuid(), + CreatedAt = DateTime.UtcNow, + LastUpdatedAt = DateTime.UtcNow, + CreatedBy = "", + LastUpdatedBy = "", + Name = request.Name, + Description = request.Description, + AutoAssigned = request.AutoAssigned, + SiteId = request.SiteId, + }; + await roleRepository.Create(role, cancellationToken); + return role.Id; + } + + public async Task Edit(EditRoleRequest request, CancellationToken cancellationToken = default) + { + Guard.Against.Null(request); + Guard.Against.Default(request.Id); + Guard.Against.NullOrWhiteSpace(request.Name); + + var role = await roleRepository.GetById(request.Id); + if (role == null) + throw new ApplicationException("Provided RoleId does not exists."); + + role.LastUpdatedAt = DateTime.UtcNow; + role.LastUpdatedBy = ""; + role.Name = request.Name; + role.Description = request.Description; + role.AutoAssigned = request.AutoAssigned; + role.SiteId = request.SiteId; + await roleRepository.Update(role, cancellationToken); + } + + public async Task Delete(DeleteRoleRequest request, CancellationToken cancellationToken = default) + { + Guard.Against.Null(request); + Guard.Against.Default(request.Id); + + var role = await roleRepository.GetById(request.Id); + if (role == null) + throw new ApplicationException("Provided RoleId does not exists."); + + await roleRepository.Delete(role.Id, cancellationToken); + } +} diff --git a/src/FluentCMS.Application/Services/SiteService.cs b/src/FluentCMS.Application/Services/SiteService.cs new file mode 100644 index 000000000..72f65f6cc --- /dev/null +++ b/src/FluentCMS.Application/Services/SiteService.cs @@ -0,0 +1,114 @@ +using Ardalis.GuardClauses; +using FluentCMS.Application.Dtos.Sites; +using FluentCMS.Entities.Sites; +using FluentCMS.Repository; + +namespace FluentCMS.Application.Services; + +public interface ISiteService +{ + Task GetById(Guid id); + Task GetByUrl(string Url); + Task Search(SearchSiteRequest request); + Task Create(CreateSiteRequest request); + Task Edit(EditSiteRequest request); + Task Delete(DeleteSiteRequest request); + Task AddSiteUrl(AddSiteUrlRequest request); + Task RemoveSiteUrl(RemoveSiteUrlRequest request); +} + +internal class SiteService(AutoMapper.IMapper mapper, ISiteRepository siteRepository) : ISiteService +{ + public async Task GetById(Guid id) + { + Guard.Against.Default(id); + + var site = await siteRepository.GetById(id) + ?? throw new ApplicationException("Provided SiteId does not exists."); + + return mapper.Map(site); + } + + public async Task GetByUrl(string Url) + { + Guard.Against.NullOrEmpty(Url); + + var site = await siteRepository.GetByUrl(Url) + ?? throw new ApplicationException("Provided Url does not exists."); + + return mapper.Map(site); + } + + public async Task Search(SearchSiteRequest request) + { + var data = await siteRepository.GetAll(); + return new SearchSiteResponse + { + Data = data.Select(x => mapper.Map(x)), + Total = data.Count(), + }; + } + + public async Task Create(CreateSiteRequest request) + { + Guard.Against.Null(request); + Guard.Against.NullOrWhiteSpace(request.Name); + + var newId = Guid.NewGuid(); + var site = new Site(newId, request.Name, request.Description, request.URLs, request.RoleId); + await siteRepository.Create(site); + return newId; + } + + public async Task Edit(EditSiteRequest request) + { + Guard.Against.Null(request); + Guard.Against.NullOrWhiteSpace(request.Name); + + var site = await siteRepository.GetById(request.Id) + ?? throw new ApplicationException("Provided SiteId does not exists."); + + if (site.Name != request.Name) site.SetName(request.Name); + if (site.Description != request.Description) site.SetDescription(request.Description); + if (site.RoleId != request.RoleId) site.SetRoleId(request.RoleId); + site.Urls = request.URLs.ToList(); + await siteRepository.Update(site); + } + + public async Task Delete(DeleteSiteRequest request) + { + Guard.Against.Null(request); + Guard.Against.Default(request.Id); + + var site = await siteRepository.GetById(request.Id) + ?? throw new ApplicationException("Provided SiteId does not exists."); + + await siteRepository.Delete(site.Id); + } + + public async Task AddSiteUrl(AddSiteUrlRequest request) + { + Guard.Against.Null(request); + Guard.Against.Default(request.SiteId); + Guard.Against.NullOrWhiteSpace(request.NewUrl); + + var site = await siteRepository.GetById(request.SiteId) + ?? throw new ApplicationException("Provided SiteId does not exists."); + + site.AddUrl(request.NewUrl); + await siteRepository.Update(site); + } + + public async Task RemoveSiteUrl(RemoveSiteUrlRequest request) + { + Guard.Against.Null(request); + Guard.Against.Default(request.SiteId); + Guard.Against.NullOrWhiteSpace(request.Url); + + var site = await siteRepository.GetById(request.SiteId) + ?? throw new ApplicationException("Provided SiteId does not exists."); + + site.RemoveUrl(request.Url); + await siteRepository.Update(site); + } +} diff --git a/src/FluentCMS.Application/Services/UserService.cs b/src/FluentCMS.Application/Services/UserService.cs new file mode 100644 index 000000000..66673d904 --- /dev/null +++ b/src/FluentCMS.Application/Services/UserService.cs @@ -0,0 +1,120 @@ +using Ardalis.GuardClauses; +using FluentCMS.Application.Dtos.Users; +using FluentCMS.Entities.Users; +using FluentCMS.Repository; + +namespace FluentCMS.Application.Services; +public interface IUserService +{ + Task GetById(Guid id); + Task GetByUsername(string username); + Task Search(SearchUserRequest request); + Task Create(CreateUserRequest request, CancellationToken cancellationToken = default); + Task Edit(EditUserRequest request, CancellationToken cancellationToken = default); + Task Delete(DeleteUserRequest request, CancellationToken cancellationToken = default); +} + +internal class UserService : IUserService +{ + private readonly AutoMapper.IMapper _mapper; + private readonly IUserRepository _userRepository; + public UserService( + AutoMapper.IMapper mapper, + IUserRepository userRepository) + { + _mapper = mapper; + _userRepository = userRepository; + } + + public async Task GetById(Guid id) + { + var user = await _userRepository.GetById(id) + ?? throw new ApplicationException("Requested user does not exists."); + return _mapper.Map(user); + } + + public async Task GetByUsername(string username) + { + var user = await _userRepository.GetByUsername(username) + ?? throw new ApplicationException("Requested user does not exists."); + return _mapper.Map(user); + } + + public async Task Search(SearchUserRequest request) + { + var users = await _userRepository.GetAll(x => + string.IsNullOrWhiteSpace(request.Name) || x.Name.Contains(request.Name)); + return new SearchUserResponse + { + Data = users.Select(x => _mapper.Map(x)), + Total = users.Count(), + }; + } + + public async Task Create(CreateUserRequest request, CancellationToken cancellationToken = default) + { + Guard.Against.Null(request); + Guard.Against.NullOrWhiteSpace(request.Name); + Guard.Against.NullOrWhiteSpace(request.Username); + + var userId = Guid.NewGuid(); + var user = new User + { + Id = userId, + CreatedAt = DateTime.UtcNow, + LastUpdatedAt = DateTime.UtcNow, + CreatedBy = "", + LastUpdatedBy = "", + Name = request.Name, + Username = request.Username, + Password = request.Password, + UserRoles = request.Roles?.Select(r => new UserRole + { + Id = Guid.NewGuid(), + UserId = userId, + RoleId = r, + }).ToList() ?? [], + }; + + await _userRepository.Create(user, cancellationToken); + return userId; + } + + public async Task Edit(EditUserRequest request, CancellationToken cancellationToken = default) + { + Guard.Against.Null(request); + Guard.Against.Default(request.Id); + Guard.Against.NullOrWhiteSpace(request.Name); + Guard.Against.NullOrWhiteSpace(request.Username); + + var user = await _userRepository.GetById(request.Id); + if (user == null) + throw new ApplicationException("Provided UserId does not exists."); + + user.LastUpdatedAt = DateTime.UtcNow; + user.LastUpdatedBy = ""; + user.Name = request.Name; + user.Username = request.Username; + user.Password = request.Password; + user.UserRoles = request.Roles?.Select(r => new UserRole + { + Id = Guid.NewGuid(), + UserId = user.Id, + RoleId = r, + }).ToList() ?? []; + + await _userRepository.Update(user, cancellationToken); + } + + public async Task Delete(DeleteUserRequest request, CancellationToken cancellationToken = default) + { + Guard.Against.Null(request); + Guard.Against.Default(request.Id); + + var user = await _userRepository.GetById(request.Id); + if (user == null) + throw new ApplicationException("Provided UserId does not exists."); + + await _userRepository.Delete(user.Id, cancellationToken); + } +} diff --git a/src/FluentCMS.Application/Sites/AddSiteUrlCommand.cs b/src/FluentCMS.Application/Sites/AddSiteUrlCommand.cs deleted file mode 100644 index d2a531457..000000000 --- a/src/FluentCMS.Application/Sites/AddSiteUrlCommand.cs +++ /dev/null @@ -1,9 +0,0 @@ -using MediatR; - -namespace FluentCMS.Application.Sites; - -public class AddSiteUrlCommand : IRequest -{ - public Guid SideId { get; set; } - public string NewUrl { get; set; } = ""; -} diff --git a/src/FluentCMS.Application/Sites/CreateSiteCommand.cs b/src/FluentCMS.Application/Sites/CreateSiteCommand.cs deleted file mode 100644 index 7ae667ea6..000000000 --- a/src/FluentCMS.Application/Sites/CreateSiteCommand.cs +++ /dev/null @@ -1,10 +0,0 @@ -using MediatR; - -namespace FluentCMS.Application.Sites; -public class CreateSiteCommand : IRequest -{ - public string Name { get; set; } = ""; - public string Description { get; set; } = ""; - public string[] URLs { get; set; } = []; - public Guid RoleId { get; set; } -} diff --git a/src/FluentCMS.Application/Sites/DeleteSiteCommand.cs b/src/FluentCMS.Application/Sites/DeleteSiteCommand.cs deleted file mode 100644 index 951f75607..000000000 --- a/src/FluentCMS.Application/Sites/DeleteSiteCommand.cs +++ /dev/null @@ -1,8 +0,0 @@ -using MediatR; - -namespace FluentCMS.Application.Sites; - -public class DeleteSiteCommand : IRequest -{ - public Guid Id { get; set; } -} diff --git a/src/FluentCMS.Application/Sites/EditSiteCommand.cs b/src/FluentCMS.Application/Sites/EditSiteCommand.cs deleted file mode 100644 index 89f724a26..000000000 --- a/src/FluentCMS.Application/Sites/EditSiteCommand.cs +++ /dev/null @@ -1,12 +0,0 @@ -using MediatR; - -namespace FluentCMS.Application.Sites; - -public class EditSiteCommand : IRequest -{ - public Guid Id { get; set; } - public string Name { get; set; } = ""; - public string Description { get; set; } = ""; - public Guid RoleId { get; set; } - public string[] URLs { get; set; } = Array.Empty(); -} diff --git a/src/FluentCMS.Application/Sites/GetSiteByIdQuery.cs b/src/FluentCMS.Application/Sites/GetSiteByIdQuery.cs deleted file mode 100644 index 5e4c5d771..000000000 --- a/src/FluentCMS.Application/Sites/GetSiteByIdQuery.cs +++ /dev/null @@ -1,9 +0,0 @@ -using FluentCMS.Entities.Sites; -using MediatR; - -namespace FluentCMS.Application.Sites; - -public class GetSiteByIdQuery : IRequest -{ - public Guid Id { get; set; } -} diff --git a/src/FluentCMS.Application/Sites/GetSiteByUrlQuery.cs b/src/FluentCMS.Application/Sites/GetSiteByUrlQuery.cs deleted file mode 100644 index 7d16d4180..000000000 --- a/src/FluentCMS.Application/Sites/GetSiteByUrlQuery.cs +++ /dev/null @@ -1,9 +0,0 @@ -using FluentCMS.Entities.Sites; -using MediatR; - -namespace FluentCMS.Application.Sites; - -public class GetSiteByUrlQuery : IRequest -{ - public string Url { get; set; } = ""; -} \ No newline at end of file diff --git a/src/FluentCMS.Application/Sites/GetSitesQuery.cs b/src/FluentCMS.Application/Sites/GetSitesQuery.cs deleted file mode 100644 index 1ea753799..000000000 --- a/src/FluentCMS.Application/Sites/GetSitesQuery.cs +++ /dev/null @@ -1,9 +0,0 @@ -using FluentCMS.Entities.Sites; -using MediatR; - -namespace FluentCMS.Application.Sites; - -public class GetSitesQuery : IRequest> -{ - //todo: add paging, sorting, filtering, etc. -} diff --git a/src/FluentCMS.Application/Sites/RemoveSiteUrlCommand.cs b/src/FluentCMS.Application/Sites/RemoveSiteUrlCommand.cs deleted file mode 100644 index 4343b406b..000000000 --- a/src/FluentCMS.Application/Sites/RemoveSiteUrlCommand.cs +++ /dev/null @@ -1,9 +0,0 @@ -using MediatR; - -namespace FluentCMS.Application.Sites; - -public class RemoveSiteUrlCommand : IRequest -{ - public Guid SiteId { get; set; } - public string Url { get; set; } = ""; -} diff --git a/src/FluentCMS.Application/Sites/SiteHandlers.cs b/src/FluentCMS.Application/Sites/SiteHandlers.cs deleted file mode 100644 index 8f91ed47b..000000000 --- a/src/FluentCMS.Application/Sites/SiteHandlers.cs +++ /dev/null @@ -1,67 +0,0 @@ -using FluentCMS.Entities.Sites; -using FluentCMS.Services; -using MediatR; - -namespace FluentCMS.Application.Sites; -public class SiteHandlers(SiteService siteService) : - IRequestHandler, - IRequestHandler, - IRequestHandler>, - IRequestHandler, - IRequestHandler, - IRequestHandler, - IRequestHandler, - IRequestHandler -{ - public async Task Handle(GetSiteByIdQuery request, CancellationToken cancellationToken) - { - return await siteService.GetById(request.Id); - } - - public async Task Handle(GetSiteByUrlQuery request, CancellationToken cancellationToken) - { - return await siteService.GetByUrl(request.Url); - } - - public async Task> Handle(GetSitesQuery request, CancellationToken cancellationToken) - { - return await siteService.GetAll(); - } - - public async Task Handle(CreateSiteCommand request, CancellationToken cancellationToken) - { - var newId = Guid.NewGuid(); - var site = new Site(newId, request.Name, request.Description, request.URLs, request.RoleId); - await siteService.Create(site); - return newId; - } - - public async Task Handle(EditSiteCommand request, CancellationToken cancellationToken) - { - var site = await siteService.GetById(request.Id); - if (site.Name != request.Name) site.SetName(request.Name); - if (site.Description != request.Description) site.SetDescription(request.Description); - if (site.RoleId != request.RoleId) site.SetRoleId(request.RoleId); - site.Urls = request.URLs.ToList(); - await siteService.Update(site); - return request.Id; - } - - public async Task Handle(DeleteSiteCommand request, CancellationToken cancellationToken) - { - await siteService.Delete(request.Id); - return request.Id; - } - - public async Task Handle(AddSiteUrlCommand request, CancellationToken cancellationToken) - { - var site = await siteService.GetById(request.SideId); - site.AddUrl(request.NewUrl); - await siteService.Update(site); - } - - public async Task Handle(RemoveSiteUrlCommand request, CancellationToken cancellationToken) - { - await siteService.Delete(request.SiteId); - } -} diff --git a/src/FluentCMS.Application/Users/CreateRoleCommand.cs b/src/FluentCMS.Application/Users/CreateRoleCommand.cs deleted file mode 100644 index 3fd6c55a9..000000000 --- a/src/FluentCMS.Application/Users/CreateRoleCommand.cs +++ /dev/null @@ -1,10 +0,0 @@ -using MediatR; - -namespace FluentCMS.Application.Users; -public class CreateRoleCommand : IRequest -{ - public string Name { get; set; } = string.Empty; - public string? Description { get; set; } - public bool AutoAssigned { get; set; } - public Guid? SiteId { get; set; } -} diff --git a/src/FluentCMS.Application/Users/CreateUserCommand.cs b/src/FluentCMS.Application/Users/CreateUserCommand.cs deleted file mode 100644 index 4eb2c48f8..000000000 --- a/src/FluentCMS.Application/Users/CreateUserCommand.cs +++ /dev/null @@ -1,10 +0,0 @@ -using MediatR; - -namespace FluentCMS.Application.Users; -public class CreateUserCommand : IRequest -{ - public string Name { get; set; } = string.Empty; - public string Username { get; set; } = string.Empty; - public string Password { get; set; } = string.Empty; - public ICollection Roles { get; set; } = new List(); -} diff --git a/src/FluentCMS.Application/Users/DeleteRoleCommand.cs b/src/FluentCMS.Application/Users/DeleteRoleCommand.cs deleted file mode 100644 index 645c00105..000000000 --- a/src/FluentCMS.Application/Users/DeleteRoleCommand.cs +++ /dev/null @@ -1,7 +0,0 @@ -using MediatR; - -namespace FluentCMS.Application.Users; -public class DeleteRoleCommand : IRequest -{ - public required Guid Id { get; set; } -} diff --git a/src/FluentCMS.Application/Users/DeleteUserCommand.cs b/src/FluentCMS.Application/Users/DeleteUserCommand.cs deleted file mode 100644 index 886173d77..000000000 --- a/src/FluentCMS.Application/Users/DeleteUserCommand.cs +++ /dev/null @@ -1,7 +0,0 @@ -using MediatR; - -namespace FluentCMS.Application.Users; -public class DeleteUserCommand : IRequest -{ - public Guid Id { get; set; } -} diff --git a/src/FluentCMS.Application/Users/EditRoleCommand.cs b/src/FluentCMS.Application/Users/EditRoleCommand.cs deleted file mode 100644 index a27ff997f..000000000 --- a/src/FluentCMS.Application/Users/EditRoleCommand.cs +++ /dev/null @@ -1,11 +0,0 @@ -using MediatR; - -namespace FluentCMS.Application.Users; -public class EditRoleCommand : IRequest -{ - public required Guid Id { get; set; } - public required string Name { get; set; } - public string? Description { get; set; } - public required bool AutoAssigned { get; set; } - public Guid? SiteId { get; set; } -} diff --git a/src/FluentCMS.Application/Users/EditUserCommand.cs b/src/FluentCMS.Application/Users/EditUserCommand.cs deleted file mode 100644 index 309f93b19..000000000 --- a/src/FluentCMS.Application/Users/EditUserCommand.cs +++ /dev/null @@ -1,11 +0,0 @@ -using MediatR; - -namespace FluentCMS.Application.Users; -public class EditUserCommand : IRequest -{ - public Guid Id { get; set; } - public string Name { get; set; } = string.Empty; - public string Username { get; set; } = string.Empty; - public string Password { get; set; } = string.Empty; - public ICollection Roles { get; set; } = new List(); -} diff --git a/src/FluentCMS.Application/Users/GetRolesQuery.cs b/src/FluentCMS.Application/Users/GetRolesQuery.cs deleted file mode 100644 index a1e2561db..000000000 --- a/src/FluentCMS.Application/Users/GetRolesQuery.cs +++ /dev/null @@ -1,7 +0,0 @@ -using FluentCMS.Entities.Users; -using MediatR; - -namespace FluentCMS.Application.Users; -public class GetRolesQuery : IRequest> -{ -} diff --git a/src/FluentCMS.Application/Users/GetUserByIdQuery.cs b/src/FluentCMS.Application/Users/GetUserByIdQuery.cs deleted file mode 100644 index 184ee701b..000000000 --- a/src/FluentCMS.Application/Users/GetUserByIdQuery.cs +++ /dev/null @@ -1,8 +0,0 @@ -using FluentCMS.Entities.Users; -using MediatR; - -namespace FluentCMS.Application.Users; -public class GetUserByIdQuery : IRequest -{ - public Guid Id { get; set; } -} diff --git a/src/FluentCMS.Application/Users/GetUsersQuery.cs b/src/FluentCMS.Application/Users/GetUsersQuery.cs deleted file mode 100644 index 91390f18b..000000000 --- a/src/FluentCMS.Application/Users/GetUsersQuery.cs +++ /dev/null @@ -1,7 +0,0 @@ -using FluentCMS.Entities.Users; -using MediatR; - -namespace FluentCMS.Application.Users; -public class GetUsersQuery : IRequest> -{ -} diff --git a/src/FluentCMS.Application/Users/RoleHandlers.cs b/src/FluentCMS.Application/Users/RoleHandlers.cs deleted file mode 100644 index e887b476c..000000000 --- a/src/FluentCMS.Application/Users/RoleHandlers.cs +++ /dev/null @@ -1,61 +0,0 @@ -using FluentCMS.Entities.Users; -using FluentCMS.Services; -using MediatR; - -namespace FluentCMS.Application.Users; -internal class RoleHandlers : - IRequestHandler>, - IRequestHandler, - IRequestHandler, - IRequestHandler -{ - private readonly RoleService _roleService; - - public RoleHandlers(RoleService roleService) - { - _roleService = roleService; - } - - public async Task> Handle(GetRolesQuery request, CancellationToken cancellationToken) - { - var roles = await _roleService.GetAll(); - return roles; - } - - public async Task Handle(CreateRoleCommand request, CancellationToken cancellationToken) - { - var role = new Role - { - Id = Guid.NewGuid(), - CreatedAt = DateTime.UtcNow, - LastUpdatedAt = DateTime.UtcNow, - CreatedBy = "", - LastUpdatedBy = "", - Name = request.Name, - Description = request.Description, - AutoAssigned = request.AutoAssigned, - SiteId = request.SiteId, - }; - await _roleService.Create(role); - return role.Id; - } - - public async Task Handle(EditRoleCommand request, CancellationToken cancellationToken) - { - var user = await _roleService.GetById(request.Id); - user.LastUpdatedAt = DateTime.UtcNow; - user.LastUpdatedBy = ""; - user.Name = request.Name; - user.Description = request.Description; - user.AutoAssigned = request.AutoAssigned; - user.SiteId = request.SiteId; - - await _roleService.Update(user); - } - - public async Task Handle(DeleteRoleCommand request, CancellationToken cancellationToken) - { - var user = await _roleService.GetById(request.Id); - await _roleService.Delete(user); - } -} diff --git a/src/FluentCMS.Application/Users/UserHandlers.cs b/src/FluentCMS.Application/Users/UserHandlers.cs deleted file mode 100644 index f0ec09d29..000000000 --- a/src/FluentCMS.Application/Users/UserHandlers.cs +++ /dev/null @@ -1,79 +0,0 @@ -using FluentCMS.Entities.Users; -using FluentCMS.Services; -using MediatR; - -namespace FluentCMS.Application.Users; -internal class UserHandlers : - IRequestHandler>, - IRequestHandler, - IRequestHandler, - IRequestHandler, - IRequestHandler -{ - private readonly UserService _userService; - - public UserHandlers(UserService userService) - { - _userService = userService; - } - - public async Task> Handle(GetUsersQuery request, CancellationToken cancellationToken) - { - var users = await _userService.GetAll(); - return users; - } - - public async Task Handle(GetUserByIdQuery request, CancellationToken cancellationToken) - { - var user = await _userService.GetById(request.Id); - return user; - } - - public async Task Handle(CreateUserCommand request, CancellationToken cancellationToken) - { - var userId = Guid.NewGuid(); - var user = new User - { - Id = userId, - CreatedAt = DateTime.UtcNow, - LastUpdatedAt = DateTime.UtcNow, - CreatedBy = "", - LastUpdatedBy = "", - Name = request.Name, - Username = request.Username, - Password = request.Password, - UserRoles = request.Roles?.Select(r => new UserRole - { - Id = Guid.NewGuid(), - UserId = userId, - RoleId = r, - }).ToList() ?? [], - }; - await _userService.Create(user, cancellationToken); - return user.Id; - } - - public async Task Handle(EditUserCommand request, CancellationToken cancellationToken) - { - var user = await _userService.GetById(request.Id); - user.LastUpdatedAt = DateTime.UtcNow; - user.LastUpdatedBy = ""; - user.Name = request.Name; - user.Username = request.Username; - user.Password = request.Password; - user.UserRoles = request.Roles?.Select(r => new UserRole - { - Id = Guid.NewGuid(), - UserId = user.Id, - RoleId = r, - }).ToList() ?? []; - - await _userService.Update(user); - } - - public async Task Handle(DeleteUserCommand request, CancellationToken cancellationToken) - { - var user = await _userService.GetById(request.Id); - await _userService.Delete(user); - } -} diff --git a/src/FluentCMS.Domain/Extensions.cs b/src/FluentCMS.Domain/Extensions.cs index 4a2428f1e..64efe1c25 100644 --- a/src/FluentCMS.Domain/Extensions.cs +++ b/src/FluentCMS.Domain/Extensions.cs @@ -1,5 +1,4 @@ -using FluentCMS.Services; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; namespace FluentCMS; @@ -7,12 +6,6 @@ public static class Extensions { public static FluentCMSBuilder AddFluentCMSCore(this IServiceCollection services) { - // register domain services - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - return FluentCMSBuilder.Create(services); } } diff --git a/src/FluentCMS.Domain/Services/RoleService.cs b/src/FluentCMS.Domain/Services/RoleService.cs deleted file mode 100644 index 34f0d6365..000000000 --- a/src/FluentCMS.Domain/Services/RoleService.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Ardalis.GuardClauses; -using FluentCMS.Entities.Users; -using FluentCMS.Repository; - -namespace FluentCMS.Services; - -public class RoleService -{ - private readonly IGenericRepository _roleRepository; - - public RoleService(IGenericRepository roleRepository) - { - _roleRepository = roleRepository; - } - - public async Task> GetAll() - { - var roles = await _roleRepository.GetAll(); - return roles; - } - - public async Task GetById(Guid id) - { - var roles = await _roleRepository.GetById(id) - ?? throw new ApplicationException("Requested role does not exists."); - return roles; - } - - public Task Create(Role role, CancellationToken cancellationToken = default) - { - Guard.Against.Null(role); - Guard.Against.NullOrWhiteSpace(role.Name); - - return _roleRepository.Create(role, cancellationToken); - } - - public async Task Update(Role role, CancellationToken cancellationToken = default) - { - Guard.Against.Null(role); - Guard.Against.Default(role.Id); - Guard.Against.NullOrWhiteSpace(role.Name); - - var oldRole = await _roleRepository.GetById(role.Id); - if (oldRole == null) - throw new ApplicationException("Provided RoleId does not exists."); - - await _roleRepository.Update(role, cancellationToken); - } - - public async Task Delete(Role role, CancellationToken cancellationToken = default) - { - Guard.Against.Null(role); - Guard.Against.Default(role.Id); - - var oldRole = await _roleRepository.GetById(role.Id); - if (oldRole == null) - throw new ApplicationException("Provided RoleId does not exists."); - - await _roleRepository.Delete(role.Id, cancellationToken); - } -} diff --git a/src/FluentCMS.Domain/Services/SiteService.cs b/src/FluentCMS.Domain/Services/SiteService.cs deleted file mode 100644 index ae4e3ff95..000000000 --- a/src/FluentCMS.Domain/Services/SiteService.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Ardalis.GuardClauses; -using FluentCMS.Entities.Sites; -using FluentCMS.Repository; - -namespace FluentCMS.Services; -public class SiteService(ISiteRepository siteRepository) -{ - public async Task Create(Site site) - { - Guard.Against.Null(site); - await siteRepository.Create(site); - } - - public async Task GetById(Guid id) - { - Guard.Against.NullOrEmpty(id); - return await siteRepository.GetById(id) - ?? throw new ApplicationException("Provided SiteId does not exists."); - } - - public async Task GetByUrl(string Url) - { - Guard.Against.NullOrEmpty(Url); - return await siteRepository.GetByUrl(Url) - ?? throw new ApplicationException("Provided Url does not exists."); - } - - public async Task> GetAll() - { - return await siteRepository.GetAll(); - } - - public async Task Update(Site site) - { - Guard.Against.Null(site); - _ = await siteRepository.GetById(site.Id) - ?? throw new ApplicationException("Provided SiteId does not exists."); - await siteRepository.Update(site); - } - - public async Task Delete(Guid id) - { - Guard.Against.NullOrEmpty(id); - _ = await siteRepository.GetById(id) - ?? throw new ApplicationException("Provided SiteId does not exists."); - await siteRepository.Delete(id); - } -} diff --git a/src/FluentCMS.Domain/Services/UserService.cs b/src/FluentCMS.Domain/Services/UserService.cs deleted file mode 100644 index 69010114b..000000000 --- a/src/FluentCMS.Domain/Services/UserService.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Ardalis.GuardClauses; -using FluentCMS.Entities.Users; -using FluentCMS.Repository; - -namespace FluentCMS.Services; - -public class UserService -{ - private readonly IUserRepository _userRepository; - public UserService(IUserRepository userRepository) - { - _userRepository = userRepository; - } - - public async Task> GetAll() - { - var users = await _userRepository.GetAll(); - return users; - } - - public async Task GetById(Guid id) - { - var user = await _userRepository.GetById(id) - ?? throw new ApplicationException("Requested user does not exists."); - return user!; - } - - public async Task GetByUsername(string username) - { - var user = await _userRepository.GetByUsername(username) - ?? throw new ApplicationException("Requested user does not exists."); - return user!; - } - - public async Task Create(User user, CancellationToken cancellationToken = default) - { - Guard.Against.Null(user); - Guard.Against.NullOrWhiteSpace(user.Name); - Guard.Against.NullOrWhiteSpace(user.Username); - - await _userRepository.Create(user, cancellationToken); - } - - public async Task Update(User user, CancellationToken cancellationToken = default) - { - Guard.Against.Null(user); - Guard.Against.Default(user.Id); - Guard.Against.NullOrWhiteSpace(user.Name); - Guard.Against.NullOrWhiteSpace(user.Username); - - var oldUser = await _userRepository.GetById(user.Id); - if (oldUser == null) - throw new ApplicationException("Provided UserId does not exists."); - - await _userRepository.Update(user, cancellationToken); - } - - public async Task Delete(User user, CancellationToken cancellationToken = default) - { - Guard.Against.Null(user); - Guard.Against.Default(user.Id); - - var oldUser = await _userRepository.GetById(user.Id); - if (oldUser == null) - throw new ApplicationException("Provided UserId does not exists."); - - await _userRepository.Delete(user.Id, cancellationToken); - } -} diff --git a/src/FluentCMS.Repository.LiteDb.Tests/Entities/ContentTypes/ContentType_Tests.cs b/src/FluentCMS.Repository.LiteDb.Tests/Entities/ContentTypes/ContentType_Tests.cs index 02e20855d..e48a17a46 100644 --- a/src/FluentCMS.Repository.LiteDb.Tests/Entities/ContentTypes/ContentType_Tests.cs +++ b/src/FluentCMS.Repository.LiteDb.Tests/Entities/ContentTypes/ContentType_Tests.cs @@ -1,5 +1,6 @@ -using FluentCMS.Entities.ContentTypes; -using FluentCMS.Services; +using FluentCMS.Application; +using FluentCMS.Application.Services; +using FluentCMS.Entities.ContentTypes; using Microsoft.Extensions.DependencyInjection; using Shouldly; @@ -11,14 +12,16 @@ public class ContentType_Tests public ContentType_Tests() { var services = new ServiceCollection(); - services.AddFluentCMSCore().AddLiteDbRepository(b => b.UseInMemory()); + services.AddFluentCMSCore() + .AddApplication() + .AddLiteDbRepository(b => b.UseInMemory()); _serviceProvider = services.BuildServiceProvider(); } [Fact] public async Task Should_Create() { - var service = _serviceProvider.GetRequiredService(); + var service = _serviceProvider.GetRequiredService(); var id = Guid.NewGuid(); var title = "Test 1"; var contentType = new ContentType(id, title); @@ -33,7 +36,7 @@ public async Task Should_Create() [Fact] public async Task Should_Delete() { - var service = _serviceProvider.GetRequiredService(); + var service = _serviceProvider.GetRequiredService(); var id = Guid.NewGuid(); var title = "Test 1"; var contentType = new ContentType(id, title); @@ -44,14 +47,14 @@ public async Task Should_Delete() result.Title.ShouldBe(title); result.Slug.ShouldBe("test-1"); await service.Delete(id); - var all = await service.GetAll(); + var all = await service.Search(); all.Count().ShouldBe(0); } [Fact] public async Task Should_Update() { - var service = _serviceProvider.GetRequiredService(); + var service = _serviceProvider.GetRequiredService(); var id = Guid.NewGuid(); var title = "Test 1"; var contentType = new ContentType(id, title); @@ -74,7 +77,7 @@ public async Task Should_Update() [Fact] public async Task Should_NotAllowDuplicateSlugOn_Update() { - var service = _serviceProvider.GetRequiredService(); + var service = _serviceProvider.GetRequiredService(); var id = Guid.NewGuid(); var title = "Test 1"; var contentType = new ContentType(id, title); @@ -89,7 +92,7 @@ public async Task Should_NotAllowDuplicateSlugOn_Update() [Fact] public async Task Should_GetAll() { - var service = _serviceProvider.GetRequiredService(); + var service = _serviceProvider.GetRequiredService(); const int count = 10; var ids = Enumerable.Range(1, count).Select(_ => Guid.NewGuid()).ToList(); @@ -100,7 +103,7 @@ public async Task Should_GetAll() var contentType = new ContentType(id, title); await service.Create(contentType); } - var result = await service.GetAll(); + var result = await service.Search(); result.ShouldNotBeNull(); result.Count().ShouldBe(count); result.All(x => ids.Contains(x.Id)).ShouldBeTrue(); @@ -109,7 +112,7 @@ public async Task Should_GetAll() [Fact] public async Task Should_GetById() { - var service = _serviceProvider.GetRequiredService(); + var service = _serviceProvider.GetRequiredService(); var id = Guid.NewGuid(); var title = "Test 1"; var contentType = new ContentType(id, title); @@ -124,7 +127,7 @@ public async Task Should_GetById() [Fact] public async Task Should_GetBySlug() { - var service = _serviceProvider.GetRequiredService(); + var service = _serviceProvider.GetRequiredService(); var id = Guid.NewGuid(); var title = "Test 1"; var slug = "test-1"; @@ -141,7 +144,7 @@ public async Task Should_GetBySlug() [Fact] public async Task Should_AddContentTypeField() { - var service = _serviceProvider.GetRequiredService(); + var service = _serviceProvider.GetRequiredService(); var id = Guid.NewGuid(); var title = "Test 1"; var contentType = new ContentType(id, title); @@ -174,7 +177,7 @@ public async Task Should_AddContentTypeField() [Fact] public async Task Should_NotAddDuplicateContentTypeField() { - var service = _serviceProvider.GetRequiredService(); + var service = _serviceProvider.GetRequiredService(); var id = Guid.NewGuid(); var title = "Test 1"; var contentType = new ContentType(id, title); @@ -195,7 +198,7 @@ await Task.Run(() => [Fact] public void Should_RemoveContentTypeField() { - var service = _serviceProvider.GetRequiredService(); + var service = _serviceProvider.GetRequiredService(); var id = Guid.NewGuid(); var title = "Test 1"; var contentType = new ContentType(id, title); diff --git a/src/FluentCMS.Repository.LiteDb.Tests/Entities/Sites/SiteService_Tests.cs b/src/FluentCMS.Repository.LiteDb.Tests/Entities/Sites/SiteService_Tests.cs index 8acf5430f..2e077af5f 100644 --- a/src/FluentCMS.Repository.LiteDb.Tests/Entities/Sites/SiteService_Tests.cs +++ b/src/FluentCMS.Repository.LiteDb.Tests/Entities/Sites/SiteService_Tests.cs @@ -1,5 +1,6 @@ -using FluentCMS.Entities.Sites; -using FluentCMS.Services; +using FluentCMS.Application; +using FluentCMS.Application.Dtos.Sites; +using FluentCMS.Application.Services; using Microsoft.Extensions.DependencyInjection; using Shouldly; @@ -11,7 +12,8 @@ public SiteService_Tests() { var services = new ServiceCollection(); services.AddFluentCMSCore() - .AddLiteDbRepository(x => x.UseInMemory()); + .AddApplication() + .AddLiteDbRepository(x => x.UseInMemory()); _serviceProvider = services.BuildServiceProvider(); } @@ -20,11 +22,15 @@ public SiteService_Tests() public async Task Should_Create_New_Site() { var scope = _serviceProvider.CreateScope(); - var service = scope.ServiceProvider.GetRequiredService(); - var siteId = Guid.NewGuid(); + var service = scope.ServiceProvider.GetRequiredService(); var roleId = Guid.NewGuid(); - var site = new Site(siteId, "test site", "test site description", ["test.com"], roleId); - await service.Create(site); + var siteId = await service.Create(new CreateSiteRequest + { + Name = "test site", + Description = "test site description", + URLs = ["test.com"], + RoleId = roleId, + }); var result = await service.GetById(siteId); result.Name.ShouldBe("test site"); result.Description.ShouldBe("test site description"); @@ -37,17 +43,29 @@ public async Task Should_Create_New_Site() public async Task Should_Update_Site() { var scope = _serviceProvider.CreateScope(); - var service = scope.ServiceProvider.GetRequiredService(); - var siteId = Guid.NewGuid(); + var service = scope.ServiceProvider.GetRequiredService(); var roleId = Guid.NewGuid(); - var site = new Site(siteId, "test site", "test site description", ["test.com"], roleId); - await service.Create(site); + var siteId = await service.Create(new CreateSiteRequest + { + Name = "test site", + Description = "test site description", + URLs = ["test.com"], + RoleId = roleId, + }); var dbSite = await service.GetById(siteId); - dbSite.SetName("test site edited"); - dbSite.SetDescription("test site description edited"); - dbSite.AddUrl("testEdited.com"); - dbSite.SetRoleId(roleId); - await service.Update(dbSite); + await service.Edit(new EditSiteRequest + { + Id = siteId, + Name = "test site edited", + Description = "test site description edited", + URLs = dbSite.Urls.ToArray(), + RoleId = roleId, + }); + await service.AddSiteUrl(new AddSiteUrlRequest + { + SiteId = siteId, + NewUrl = "testEdited.com", + }); var result = await service.GetById(siteId); result.Name.ShouldBe("test site edited"); result.Description.ShouldBe("test site description edited"); @@ -60,14 +78,18 @@ public async Task Should_Update_Site() public async Task Should_Delete_Site() { var scope = _serviceProvider.CreateScope(); - var service = scope.ServiceProvider.GetRequiredService(); - var siteId = Guid.NewGuid(); + var service = scope.ServiceProvider.GetRequiredService(); var roleId = Guid.NewGuid(); - var site = new Site(siteId, "test site", "test site description", ["test.com"], roleId); - await service.Create(site); - await service.Delete(siteId); - var result = await service.GetAll(); - result.Count().ShouldBe(0); + var siteId = await service.Create(new CreateSiteRequest + { + Name = "test site", + Description = "test site description", + URLs = ["test.com"], + RoleId = roleId, + }); + await service.Delete(new DeleteSiteRequest { Id = siteId }); + var result = await service.Search(new SearchSiteRequest()); + result.Total.ShouldBe(0); } //Should Get Site @@ -75,11 +97,15 @@ public async Task Should_Delete_Site() public async Task Should_Get_Site() { var scope = _serviceProvider.CreateScope(); - var service = scope.ServiceProvider.GetRequiredService(); - var siteId = Guid.NewGuid(); + var service = scope.ServiceProvider.GetRequiredService(); var roleId = Guid.NewGuid(); - var site = new Site(siteId, "test site", "test site description", ["test.com"], roleId); - await service.Create(site); + var siteId = await service.Create(new CreateSiteRequest + { + Name = "test site", + Description = "test site description", + URLs = ["test.com"], + RoleId = roleId, + }); var result = await service.GetById(siteId); result.Name.ShouldBe("test site"); result.Description.ShouldBe("test site description"); @@ -92,11 +118,15 @@ public async Task Should_Get_Site() public async Task Should_GetByUrl_Site() { var scope = _serviceProvider.CreateScope(); - var service = scope.ServiceProvider.GetRequiredService(); - var siteId = Guid.NewGuid(); + var service = scope.ServiceProvider.GetRequiredService(); var roleId = Guid.NewGuid(); - var site = new Site(siteId, "test site", "test site description", ["test.com"], roleId); - await service.Create(site); + var siteId = await service.Create(new CreateSiteRequest + { + Name = "test site", + Description = "test site description", + URLs = ["test.com"], + RoleId = roleId, + }); var result = await service.GetByUrl("test.com"); result.Name.ShouldBe("test site"); result.Description.ShouldBe("test site description"); @@ -109,24 +139,24 @@ public async Task Should_GetByUrl_Site() public async Task Should_GetAll_Site() { var scope = _serviceProvider.CreateScope(); - var service = scope.ServiceProvider.GetRequiredService(); + var service = scope.ServiceProvider.GetRequiredService(); // create 10 sites const int count = 10; - var siteIds = Enumerable.Range(1, count).Select(_ => Guid.NewGuid()); var roleId = Guid.NewGuid(); - foreach (var siteId in siteIds) + for (var i = 1; i <= 10; i++) { - var site = new Site(siteId, - $"test site {siteId}", - $"test site description {siteId}", - [$"{siteId}.com"], - roleId); - await service.Create(site); + var siteId = await service.Create(new CreateSiteRequest + { + Name = $"test site {i}", + Description = $"test site description {i}", + URLs = [$"site-{i}.com"], + RoleId = roleId, + }); } - var result = (await service.GetAll()).ToList(); - result.Count.ShouldBe(count); - result.ForEach(x => x.Name.ShouldBe($"test site {x.Id}")); - result.ForEach(x => x.Description.ShouldBe($"test site description {x.Id}")); - result.ForEach(x => x.Urls.Contains($"{x.Id}.com").ShouldBeTrue()); + var result = await service.Search(new SearchSiteRequest()); + result.Total.ShouldBe(count); + result.Data.ToList().ForEach(x => x.Name.ShouldBe($"test site {x.Id}")); + result.Data.ToList().ForEach(x => x.Description.ShouldBe($"test site description {x.Id}")); + result.Data.ToList().ForEach(x => x.Urls.Contains($"{x.Id}.com").ShouldBeTrue()); } } diff --git a/src/FluentCMS.Repository.LiteDb.Tests/FluentCMS.Repository.LiteDb.Tests.csproj b/src/FluentCMS.Repository.LiteDb.Tests/FluentCMS.Repository.LiteDb.Tests.csproj index 70059f85e..2c23a97b3 100644 --- a/src/FluentCMS.Repository.LiteDb.Tests/FluentCMS.Repository.LiteDb.Tests.csproj +++ b/src/FluentCMS.Repository.LiteDb.Tests/FluentCMS.Repository.LiteDb.Tests.csproj @@ -24,6 +24,7 @@ + diff --git a/src/FluentCMS.Repository.LiteDb.Tests/UserServiceTests.cs b/src/FluentCMS.Repository.LiteDb.Tests/UserServiceTests.cs index 39b608de6..f985972fc 100644 --- a/src/FluentCMS.Repository.LiteDb.Tests/UserServiceTests.cs +++ b/src/FluentCMS.Repository.LiteDb.Tests/UserServiceTests.cs @@ -1,4 +1,5 @@ -using FluentCMS.Entities.Users; +using FluentCMS.Application.Dtos.Users; +using FluentCMS.Application.Services; using Microsoft.Extensions.DependencyInjection; using Shouldly; @@ -18,45 +19,34 @@ public UserServiceTests() public async Task Should_Create() { using var scope = _serviceProvider.CreateScope(); - var userService = scope.ServiceProvider.GetRequiredService(); + var userService = scope.ServiceProvider.GetRequiredService(); var username = "testuser"; - var userToCreate = new User + var createdUserId = await userService.Create(new CreateUserRequest { - Id = Guid.NewGuid(), - CreatedAt = DateTime.UtcNow, - LastUpdatedAt = DateTime.UtcNow, - CreatedBy = "", - LastUpdatedBy = "", Name = "TestUser", Username = username, Password = "password", - UserRoles = new List(), - }; - await userService.Create(userToCreate); + Roles = [] + }); var loadedUser = await userService.GetByUsername(username); loadedUser.ShouldNotBeNull(); - loadedUser.Id.ShouldBe(userToCreate.Id); + loadedUser.Id.ShouldBe(createdUserId); } [Fact] public async Task Should_Not_Create_Unprovided_Username() { using var scope = _serviceProvider.CreateScope(); - var userService = scope.ServiceProvider.GetRequiredService(); + var userService = scope.ServiceProvider.GetRequiredService(); - var userToCreate = new User + var userToCreate = new CreateUserRequest { - Id = Guid.NewGuid(), - CreatedAt = DateTime.UtcNow, - LastUpdatedAt = DateTime.UtcNow, - CreatedBy = "", - LastUpdatedBy = "", Name = "TestUser", - Username = "", + Username = "testuser", Password = "password", - UserRoles = new List(), + Roles = [] }; // it should throw a ApplicationException diff --git a/src/FluentCMS.Shared/Controllers/BaseController.cs b/src/FluentCMS.Shared/Controllers/BaseController.cs index bd3ad3209..7895d3c3e 100644 --- a/src/FluentCMS.Shared/Controllers/BaseController.cs +++ b/src/FluentCMS.Shared/Controllers/BaseController.cs @@ -9,7 +9,7 @@ namespace FluentCMS.Web.Controllers; public abstract class BaseController : ControllerBase { - public ApiResult SuccessResult(TData data) + public ApiResult SuccessResult(TData? data) { return new ApiResult { diff --git a/src/FluentCMS.Shared/Controllers/RolesController.cs b/src/FluentCMS.Shared/Controllers/RolesController.cs index 3618e7dbd..f086ff283 100644 --- a/src/FluentCMS.Shared/Controllers/RolesController.cs +++ b/src/FluentCMS.Shared/Controllers/RolesController.cs @@ -1,44 +1,43 @@ -using FluentCMS.Application.Users; -using FluentCMS.Entities.Users; +using FluentCMS.Application.Dtos.Users; +using FluentCMS.Application.Services; using FluentCMS.Models; -using FluentCMS.Web.Controllers; using Microsoft.AspNetCore.Mvc; -namespace FluentCMS.Shared.Controllers; -public class RolesController(MediatR.IMediator mediator) : BaseController +namespace FluentCMS.Web.Controllers; +public class RolesController(IRoleService roleService) : BaseController { [HttpGet] - public async Task>>> GetAll() + public async Task>> Search([FromQuery] SearchRoleRequest request) { - var data = await mediator.Send(new GetRolesQuery()); + var data = await roleService.Search(request); return SuccessResult(data); } [HttpGet("{id}")] - public async Task>> GetById([FromRoute] Guid id) + public async Task>> GetById([FromRoute] Guid id) { - var data = await mediator.Send(new GetRolesQuery()); - return SuccessResult(data.FirstOrDefault(x => x.Id == id)); + var data = await roleService.GetById(id); + return SuccessResult(data); } [HttpPost] - public async Task>> Create(CreateRoleCommand request) + public async Task>> Create(CreateRoleRequest request) { - await mediator.Send(request); - return SuccessResult(true); + var result = await roleService.Create(request); + return SuccessResult(result); } [HttpPut] - public async Task>> Edit(EditRoleCommand request) + public async Task>> Edit(EditRoleRequest request) { - await mediator.Send(request); + await roleService.Edit(request); return SuccessResult(true); } [HttpDelete("{id}")] - public async Task>> Delete([FromRoute] DeleteRoleCommand request) + public async Task>> Delete([FromRoute] DeleteRoleRequest request) { - await mediator.Send(request); + await roleService.Delete(request); return SuccessResult(true); } } diff --git a/src/FluentCMS.Shared/Controllers/SiteController.cs b/src/FluentCMS.Shared/Controllers/SiteController.cs index 8071295b8..7742c4c0a 100644 --- a/src/FluentCMS.Shared/Controllers/SiteController.cs +++ b/src/FluentCMS.Shared/Controllers/SiteController.cs @@ -1,68 +1,61 @@ -using FluentCMS.Application.Sites; -using FluentCMS.Entities.Sites; -using FluentCMS.Web.Controllers; -using Microsoft.AspNetCore.Mvc; -using MediatR; +using FluentCMS.Application.Dtos.Sites; +using FluentCMS.Application.Services; using FluentCMS.Models; +using Microsoft.AspNetCore.Mvc; -namespace FluentCMS.Shared.Controllers; -public class SiteController(IMediator mediator) : BaseController +namespace FluentCMS.Web.Controllers; +public class SiteController(ISiteService siteService) : BaseController { - //GetAll [HttpGet] - public async Task>>> GetAll() + public async Task>> Search([FromQuery] SearchSiteRequest request) { - return SuccessResult(await mediator.Send(new GetSitesQuery())); + return SuccessResult(await siteService.Search(request)); } - //GetById [HttpGet("{id}")] - public async Task>> GetById(Guid id) + public async Task>> GetById(Guid id) { - return SuccessResult(await mediator.Send(new GetSiteByIdQuery { Id = id })); + return SuccessResult(await siteService.GetById(id)); } [HttpGet("[action]")] - //GetByUrl - public async Task>> GetByUrl([FromQuery] string url) + public async Task>> GetByUrl([FromQuery] string url) { - return SuccessResult(await mediator.Send(new GetSiteByUrlQuery { Url = url })); + return SuccessResult(await siteService.GetByUrl(url)); } - //Create - [HttpPost()] - public async Task>> Create(CreateSiteCommand request) + [HttpPost] + public async Task>> Create(CreateSiteRequest request) { - return SuccessResult(await mediator.Send(request)); + var result = await siteService.Create(request); + return SuccessResult(result); } - //Update [HttpPatch] - public async Task>> Update(EditSiteCommand request) + public async Task>> Edit(EditSiteRequest request) { - return SuccessResult(await mediator.Send(request)); + await siteService.Edit(request); + return SuccessResult(true); } [HttpDelete("{id}")] - //Delete - public async Task>> Delete(Guid id) + public async Task>> Delete([FromRoute] DeleteSiteRequest request) { - return SuccessResult(await mediator.Send(new DeleteSiteCommand { Id = id })); + await siteService.Delete(request); + return SuccessResult(true); } [HttpPut("[action]")] - //AddUrl - public async Task AddUrl(AddSiteUrlCommand request) + public async Task>> AddUrl(AddSiteUrlRequest request) { - await mediator.Send(request); - return Ok(); + await siteService.AddSiteUrl(request); + return SuccessResult(true); } [HttpDelete("[action]")] - //RemoveUrl - public async Task RemoveUrl(RemoveSiteUrlCommand request) + public async Task>> RemoveUrl(RemoveSiteUrlRequest request) { - await mediator.Send(request); - return Ok(); + await siteService.RemoveSiteUrl(request); + return SuccessResult(true); } } diff --git a/src/FluentCMS.Shared/Controllers/UsersController.cs b/src/FluentCMS.Shared/Controllers/UsersController.cs index ffc61fc86..1dbfcf09e 100644 --- a/src/FluentCMS.Shared/Controllers/UsersController.cs +++ b/src/FluentCMS.Shared/Controllers/UsersController.cs @@ -1,51 +1,43 @@ -using FluentCMS.Application.Users; -using FluentCMS.Entities.Users; +using FluentCMS.Application.Dtos.Users; +using FluentCMS.Application.Services; using FluentCMS.Models; using Microsoft.AspNetCore.Mvc; -using MediatR; namespace FluentCMS.Web.Controllers; -public class UsersController : BaseController +public class UsersController(IUserService userService) : BaseController { - private readonly IMediator _mediator; - - public UsersController(IMediator mediator) - { - _mediator = mediator; - } - [HttpGet] - public async Task>>> GetUsers() + public async Task>> Search([FromQuery] SearchUserRequest request) { - var data = await _mediator.Send(new GetUsersQuery()); + var data = await userService.Search(request); return SuccessResult(data); } [HttpGet("{id}")] - public async Task>> GetUserById([FromRoute] Guid id) + public async Task>> GetById([FromRoute] Guid id) { - var data = await _mediator.Send(new GetUserByIdQuery { Id = id }); + var data = await userService.GetById(id); return SuccessResult(data); } [HttpPost] - public async Task>> CreateUser(CreateUserCommand request) + public async Task>> Create(CreateUserRequest request) { - var result = await _mediator.Send(request); + var result = await userService.Create(request); return SuccessResult(result); } [HttpPut] - public async Task>> EditUser(EditUserCommand request) + public async Task>> Edit(EditUserRequest request) { - await _mediator.Send(request); + await userService.Edit(request); return SuccessResult(true); } [HttpDelete("{id}")] - public async Task>> DeleteUser([FromRoute] DeleteUserCommand request) + public async Task>> Delete([FromRoute] DeleteUserRequest request) { - await _mediator.Send(request); + await userService.Delete(request); return SuccessResult(true); } } diff --git a/src/FluentCMS.Shared/FluentCMS.Shared.csproj b/src/FluentCMS.Shared/FluentCMS.Shared.csproj index 4d673c0cf..df6d5a342 100644 --- a/src/FluentCMS.Shared/FluentCMS.Shared.csproj +++ b/src/FluentCMS.Shared/FluentCMS.Shared.csproj @@ -8,6 +8,7 @@ + diff --git a/src/FluentCMS.Shared/Models/ApiResult.cs b/src/FluentCMS.Shared/Models/ApiResult.cs index f3fe6ab21..1f8c86b96 100644 --- a/src/FluentCMS.Shared/Models/ApiResult.cs +++ b/src/FluentCMS.Shared/Models/ApiResult.cs @@ -4,6 +4,6 @@ public class ApiResult { public TData? Data { get; set; } public string? ErrorType { get; set; } - public ICollection Errors { get; set; } = new List(); - public bool IsSuccess { get => !Errors.Any(); } + public IDictionary? Errors { get; set; } + public bool IsSuccess { get => Errors == null || !Errors.Any(); } } diff --git a/src/FluentCMS.Shared/UtilityServices/ApiClientService.cs b/src/FluentCMS.Shared/UtilityServices/ApiClientService.cs deleted file mode 100644 index bf337dffb..000000000 --- a/src/FluentCMS.Shared/UtilityServices/ApiClientService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace FluentCMS.Shared.UtilityServices; -internal class ApiClientService -{ -} diff --git a/src/FluentCMS.Shared/ValidationExtensions.cs b/src/FluentCMS.Shared/ValidationExtensions.cs new file mode 100644 index 000000000..8828e24bc --- /dev/null +++ b/src/FluentCMS.Shared/ValidationExtensions.cs @@ -0,0 +1,33 @@ +using FluentCMS.Models; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; +using SharpGrip.FluentValidation.AutoValidation.Mvc.Extensions; +using SharpGrip.FluentValidation.AutoValidation.Mvc.Results; + +namespace FluentCMS.Web; +public static class ValidationExtensions +{ + public static IServiceCollection AddRequestValidation(this IServiceCollection services) + { + services.AddFluentValidationAutoValidation(configuration => + { + // Replace the default result factory with a custom implementation. + configuration.OverrideDefaultResultFactoryWith(); + }); + + return services; + } +} + +public class CustomResultFactory : IFluentValidationAutoValidationResultFactory +{ + public IActionResult CreateActionResult(ActionExecutingContext context, ValidationProblemDetails? validationProblemDetails) + { + return new BadRequestObjectResult(new ApiResult + { + ErrorType = "validation", + Errors = validationProblemDetails?.Errors.ToDictionary(k => k.Key, k => (object)k.Value) + }); + } +} diff --git a/src/FluentCMS.Web.UI/Pages/Sites/SiteEdit.razor b/src/FluentCMS.Web.UI/Pages/Sites/SiteEdit.razor index 59bb14a9e..19ce59cdc 100644 --- a/src/FluentCMS.Web.UI/Pages/Sites/SiteEdit.razor +++ b/src/FluentCMS.Web.UI/Pages/Sites/SiteEdit.razor @@ -74,7 +74,7 @@ //Create if (Id == null) { - var createCommand = new Application.Sites.CreateSiteCommand() + var createCommand = new Application.Dtos.Sites.CreateSiteRequest() { Name = Site.Name, Description = Site.Description, @@ -83,8 +83,8 @@ }; try { - await _httpClient.PostAsJsonAsync($"site", createCommand); - _navigationManager.NavigateTo("/sites"); + await _httpClient.PostAsJsonAsync($"site", createCommand); + _navigationManager.NavigateTo("/admin/sites"); } catch (Exception) { @@ -95,7 +95,7 @@ //Edit else { - var editCommand = new Application.Sites.EditSiteCommand() + var editCommand = new Application.Dtos.Sites.EditSiteRequest { Id = Id.Value, Name = Site.Name, @@ -105,8 +105,8 @@ }; try { - await _httpClient.PatchAsJsonAsync($"site", editCommand); - _navigationManager.NavigateTo("/sites"); + await _httpClient.PatchAsJsonAsync($"site", editCommand); + _navigationManager.NavigateTo("/admin/sites"); } catch (Exception) { diff --git a/src/FluentCMS.Web.UI/Pages/Sites/SiteList.razor b/src/FluentCMS.Web.UI/Pages/Sites/SiteList.razor index 3302d4a3e..2890f6d6f 100644 --- a/src/FluentCMS.Web.UI/Pages/Sites/SiteList.razor +++ b/src/FluentCMS.Web.UI/Pages/Sites/SiteList.razor @@ -49,16 +49,16 @@ else @code { - private List? sites; + private IEnumerable? sites; public async Task Fetch() { try { - var response = await _httpClient.GetFromJsonAsync>>("site"); + var response = await _httpClient.GetFromJsonAsync>>("site"); if (response.IsSuccess) { - sites = response.Data!.ToList(); + sites = response.Data!.Data; } } catch (Exception ex) diff --git a/src/FluentCMS.Web.UI/Pages/Users/RoleEdit.razor b/src/FluentCMS.Web.UI/Pages/Users/RoleEdit.razor index 670d40efe..2e73b37a8 100644 --- a/src/FluentCMS.Web.UI/Pages/Users/RoleEdit.razor +++ b/src/FluentCMS.Web.UI/Pages/Users/RoleEdit.razor @@ -31,7 +31,7 @@ [Parameter] public Guid? Id { get; set; } - private Application.Users.CreateRoleCommand data = new(); + private Application.Dtos.Users.CreateRoleRequest data = new(); protected override async Task OnParametersSetAsync() { @@ -41,7 +41,7 @@ { try { - var response = await _httpClient.GetFromJsonAsync>($"roles/{Id.Value}"); + var response = await _httpClient.GetFromJsonAsync>($"roles/{Id.Value}"); if (response != null && response.IsSuccess) { data.Name = response.Data!.Name; @@ -64,7 +64,7 @@ try { await _httpClient.PostAsJsonAsync($"roles", data); - _navigationManager.NavigateTo("/roles"); + _navigationManager.NavigateTo("/admin/roles"); } catch (Exception) { @@ -74,7 +74,7 @@ //Edit else { - var editCommand = new Application.Users.EditRoleCommand + var editCommand = new Application.Dtos.Users.EditRoleRequest { Id = Id.Value, Name = data.Name, @@ -84,7 +84,7 @@ try { await _httpClient.PutAsJsonAsync($"roles", editCommand); - _navigationManager.NavigateTo("/roles"); + _navigationManager.NavigateTo("/admin/roles"); } catch (Exception) { diff --git a/src/FluentCMS.Web.UI/Pages/Users/RoleList.razor b/src/FluentCMS.Web.UI/Pages/Users/RoleList.razor index 1a7252968..e0b3b2a66 100644 --- a/src/FluentCMS.Web.UI/Pages/Users/RoleList.razor +++ b/src/FluentCMS.Web.UI/Pages/Users/RoleList.razor @@ -38,16 +38,16 @@ else } @code { - private List? roles; + private IEnumerable? roles; private async Task LoadRoles() { try { - var response = await httpClient.GetFromJsonAsync>>("roles"); + var response = await httpClient.GetFromJsonAsync>>("roles"); if (response != null && response.IsSuccess) { - roles = response.Data!.ToList(); + roles = response.Data!.Data; } } catch (Exception ex) diff --git a/src/FluentCMS.Web.UI/Pages/Users/UserEdit.razor b/src/FluentCMS.Web.UI/Pages/Users/UserEdit.razor index b26d30522..b159610a4 100644 --- a/src/FluentCMS.Web.UI/Pages/Users/UserEdit.razor +++ b/src/FluentCMS.Web.UI/Pages/Users/UserEdit.razor @@ -15,8 +15,10 @@
- - + +
@@ -49,15 +51,15 @@ [Parameter] public Guid? Id { get; set; } - private IEnumerable? roles; - private Application.Users.CreateUserCommand data = new(); + private IEnumerable? roles; + private Application.Dtos.Users.CreateUserRequest data = new(); protected override async Task OnInitializedAsync() { - var getRolesResponse = await _httpClient.GetFromJsonAsync>>("roles"); + var getRolesResponse = await _httpClient.GetFromJsonAsync>>("roles"); if (getRolesResponse != null && getRolesResponse.IsSuccess) { - roles = getRolesResponse.Data; + roles = getRolesResponse.Data!.Data; } } @@ -69,13 +71,13 @@ { try { - var response = await _httpClient.GetFromJsonAsync>($"users/{Id.Value}"); + var response = await _httpClient.GetFromJsonAsync>($"users/{Id.Value}"); if (response != null && response.IsSuccess) { data.Name = response.Data!.Name; data.Username = response.Data!.Username; - data.Password = response.Data!.Password; - data.Roles = response.Data.UserRoles.Select(r => r.RoleId).ToList(); + data.Password = ""; + data.Roles = response.Data.UserRoles.ToList(); } } catch (Exception) @@ -93,7 +95,7 @@ try { await _httpClient.PostAsJsonAsync($"users", data); - _navigationManager.NavigateTo("/users"); + _navigationManager.NavigateTo("/admin/users"); } catch (Exception) { @@ -103,7 +105,7 @@ //Edit else { - var editCommand = new Application.Users.EditUserCommand + var editCommand = new Application.Dtos.Users.EditUserRequest { Id = Id.Value, Name = data.Name, @@ -114,7 +116,7 @@ try { await _httpClient.PutAsJsonAsync($"users", editCommand); - _navigationManager.NavigateTo("/users"); + _navigationManager.NavigateTo("/admin/users"); } catch (Exception) { @@ -123,6 +125,9 @@ } } + private Dictionary addRequiredAttribute(bool isRequired) => + new Dictionary() { ["required"] = isRequired }; + private Dictionary addCheckedAttribute(bool isChecked) => new Dictionary() { ["checked"] = isChecked }; diff --git a/src/FluentCMS.Web.UI/Pages/Users/UserList.razor b/src/FluentCMS.Web.UI/Pages/Users/UserList.razor index f1810283f..bafe3e6e2 100644 --- a/src/FluentCMS.Web.UI/Pages/Users/UserList.razor +++ b/src/FluentCMS.Web.UI/Pages/Users/UserList.razor @@ -36,16 +36,16 @@ else } @code { - private List? users; + private IEnumerable? users; private async Task LoadUsers() { try { - var response = await httpClient.GetFromJsonAsync>>("users"); + var response = await httpClient.GetFromJsonAsync>>("users"); if (response != null && response.IsSuccess) { - users = response.Data!.ToList(); + users = response.Data!.Data; } } catch (Exception ex) diff --git a/src/FluentCMS.Web.UI/Program.cs b/src/FluentCMS.Web.UI/Program.cs index 8b367dcea..7cb4e9757 100644 --- a/src/FluentCMS.Web.UI/Program.cs +++ b/src/FluentCMS.Web.UI/Program.cs @@ -2,6 +2,7 @@ using FluentCMS.Application; using FluentCMS.Repository.LiteDb; using FluentCMS.Web.UI; +using FluentCMS.Web; var builder = WebApplication.CreateBuilder(args); @@ -25,6 +26,7 @@ .AddInteractiveServerComponents(); services.AddControllers(); +services.AddRequestValidation(); services.AddApiDocumentation(); diff --git a/src/FluentCMS.Web.UI/_Imports.razor b/src/FluentCMS.Web.UI/_Imports.razor index 5105a4d9a..39fe50c1e 100644 --- a/src/FluentCMS.Web.UI/_Imports.razor +++ b/src/FluentCMS.Web.UI/_Imports.razor @@ -5,6 +5,7 @@ @using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Web.Virtualization @using Microsoft.JSInterop +@using FluentCMS.Application.Dtos @using FluentCMS.Web.UI @using FluentCMS.Web.UI.Components @using FluentCMS.Web.UI.Layout