Aplicação - Yago-Captain/GeneralNotes GitHub Wiki

MyGeneralNotes.Application

O diretório MyGeneralNotes.Application é a espinha dorsal da lógica de negócios da aplicação. Ele contém os principais casos de uso, validadores e a configuração de mapeamento do AutoMapper. Esses componentes são cruciais para garantir a correta manipulação e transformação dos dados entre diferentes camadas do sistema. A seguir, vamos detalhar os principais componentes e suas responsabilidades dentro deste diretório.

MappingConfig

A classe MappingConfig herda de Profile, uma classe do AutoMapper. O AutoMapper é uma biblioteca que ajuda a mapear um objeto para outro.

using AutoMapper;
using MyGeneralNotes.Communication.Requests;
using MyGeneralNotes.Communication.Responses;

namespace MyGeneralNotes.Application.Services.AutoMapper;
public class MappingConfig : Profile
{
    public MappingConfig()
    {
        RequestToEntity();
        EntityToRequest();
    }

    private void RequestToEntity()
    {
        CreateMap<RequestRegisteredUser, Domain.Entities.User>()
            .ForMember(to => to.Password, option => option.Ignore());
        CreateMap<RequestRoutine, Domain.Entities.Routine>()
            .ForMember(dest => dest.Exercises, opt => opt.MapFrom(to => to.Exercises));
        CreateMap<RequestExercise, Domain.Entities.Exercise>();

    }

    private void EntityToRequest()
    {
        CreateMap<Domain.Entities.User, ResponseUserProfile>();
        CreateMap<Domain.Entities.Routine, ResponseRoutine>();
        CreateMap<Domain.Entities.Exercise, ResponseExercice>();
        CreateMap<Domain.Entities.Exercise, RequestExercise>();
        CreateMap<Domain.Entities.Routine, ResponseRoutinesDashboard>()
            .ForMember(dest => dest.ExerciseCount, config => config.MapFrom(to => to.Exercises.Count));
    }
}
  • O construtor MappingConfig() é chamado quando você cria uma nova instância dessa classe. Ele chama os métodos RequestToEntity() e EntityToRequest() para configurar os mapeamentos.
  • RequestToEntity() define os mapeamentos de objetos de solicitação para entidades de domínio. Por exemplo, ele mapeia RequestRegisteredUser para User, ignorando a propriedade Password.
  • EntityToRequest() define os mapeamentos de entidades de domínio para objetos de resposta. Por exemplo, ele mapeia User para ResponseUserProfile.

PasswordValidator

A classe PasswordValidator<T> herda de PropertyValidator<T, string>, que é uma classe do FluentValidation. O FluentValidation é uma biblioteca que ajuda a validar objetos.

using FluentValidation;
using FluentValidation.Validators;
using MyGeneralNotes.Exceptions;

namespace MyGeneralNotes.Application.SharedValidators;
public class PasswordValidator<T> : PropertyValidator<T, string>
{
    public override bool IsValid(ValidationContext<T> context, string password)
    {
        if (string.IsNullOrWhiteSpace(password))
        {
            context.MessageFormatter.AppendArgument("ErrorMessage", MessagesException.PASSWORD_EMPTY);
            return false;
        }

        if (password.Length < 6)
        {
            context.MessageFormatter.AppendArgument("ErrorMessage", MessagesException.EMAIL_OR_PASSWORD_INVALID);
            return false;
        }
        return true;
    }

    public override string Name => "PasswordValidator";

    protected override string GetDefaultMessageTemplate(string errorCode) => "{ErrorMessage}";
}
  • O método IsValid(ValidationContext<T> context, string password) é chamado para validar uma senha.
  • Se a senha for nula ou uma string vazia, ele adiciona uma mensagem de erro PASSWORD_EMPTY ao contexto de validação e retorna false.
  • Se o comprimento da senha for menor que 6, ele adiciona uma mensagem de erro EMAIL_OR_PASSWORD_INVALID ao contexto de validação e retorna false.
  • Se a senha passar em ambas as verificações, ele retorna true.
  • Name é uma propriedade que retorna o nome do validador.
  • GetDefaultMessageTemplate(string errorCode) é um método que retorna a mensagem de erro padrão.

Casos de Uso

Register

IRegisterUserUseCase

Esta interface define um contrato para um caso de uso de registro de usuário.

using MyGeneralNotes.Communication.Requests;
using MyGeneralNotes.Communication.Response;

namespace MyGeneralNotes.Application.UseCases.User.Register;
public interface IRegisterUserUseCase
{
    public Task<ResponseRegisteredUser> Execute(RequestRegisteredUser request);
}
  • Define um método Execute que aceita um RequestRegisteredUser e retorna um Task<ResponseRegisteredUser>.
RegisterUserValidator

Esta classe herda de AbstractValidator<RequestRegisteredUser>, que é uma classe do FluentValidation.

using FluentValidation;
using MyGeneralNotes.Application.SharedValidators;
using MyGeneralNotes.Communication.Requests;
using MyGeneralNotes.Domain.Extensions;
using MyGeneralNotes.Exceptions;

namespace MyGeneralNotes.Application.UseCases.User.Register;
public class RegisterUserValidator : AbstractValidator<RequestRegisteredUser>
{
    public RegisterUserValidator()
    {
        RuleFor(user => user.Name).NotEmpty().WithMessage(MessagesException.NAME_EMPTY);
        RuleFor(user => user.Email).NotEmpty().WithMessage(MessagesException.EMAIL_EMPTY);
        RuleFor(user => user.Email).EmailAddress().WithMessage(MessagesException.EMAIL_IS_INVALID);
        RuleFor(user => user.Password).NotEmpty();
        RuleFor(user => user.Password).SetValidator(new PasswordValidator<RequestRegisteredUser>());

        When(user => string.IsNullOrWhiteSpace(user.Email).IsFalse(), () =>
        {
            RuleFor(user => user.Email).EmailAddress().WithMessage(MessagesException.EMAIL_IS_INVALID);
        });
    }
}
  • Define regras de validação para um RequestRegisteredUser.
  • Verifica se o nome, o email e a senha do usuário não estão vazios e se o email é um endereço de email válido.
RegisterUserUseCase

Esta classe implementa a interface IRegisterUserUseCase.

using AutoMapper;
using MyGeneralNotes.Communication.Requests;
using MyGeneralNotes.Communication.Response;
using MyGeneralNotes.Communication.Responses;
using MyGeneralNotes.Domain.Repositories;
using MyGeneralNotes.Domain.Repositories.User;
using MyGeneralNotes.Domain.Security.Cryptography;
using MyGeneralNotes.Domain.Security.Tokens;
using MyGeneralNotes.Exceptions;
using MyGeneralNotes.Exceptions.ExceptionsBase;

namespace MyGeneralNotes.Application.UseCases.User.Register;
public class RegisterUserUseCase(IUserWriteOnlyRepository userWriteOnlyRepository, IMapper mapper, IPasswordEncripter passwordEncripter, IUnitOfWork unitOfWork, IUserReadOnlyRepository userReadOnlyRepository, IAccessTokenGenerator accesTokenGenerator) : IRegisterUserUseCase
{
    private readonly IUserWriteOnlyRepository _userWriteOnlyRepository = userWriteOnlyRepository;
    private readonly IMapper _mapper = mapper;
    private readonly IPasswordEncripter _passwordEncripter = passwordEncripter;
    private readonly IUnitOfWork _unitOfWork = unitOfWork;
    private readonly IUserReadOnlyRepository _userReadOnlyRepository = userReadOnlyRepository;
    private readonly IAccessTokenGenerator _accesTokenGenerator = accesTokenGenerator;

    public async Task<ResponseRegisteredUser> Execute(RequestRegisteredUser request)
    {

        await ValidateRequest(request);

        var user = _mapper.Map<Domain.Entities.User>(request);
        user.Password = _passwordEncripter.Encrypt(request.Password);
        user.UserIdentifier = Guid.NewGuid();

        await _userWriteOnlyRepository.Add(user);

        await _unitOfWork.Commit();

        return new ResponseRegisteredUser
        {
            Name = request.Name,
            Tokens = new ResponseTokens
            {
                AccessToken = _accesTokenGenerator.Generate(user.UserIdentifier)
            }
        };
    }

    private async Task ValidateRequest(RequestRegisteredUser request)
    {
        var userValidator = new RegisterUserValidator();

        var result = userValidator.Validate(request);

        var emailExist = await _userReadOnlyRepository.ExistActiveUserWithEmail(request.Email);
        if (emailExist)
            result.Errors.Add(new FluentValidation.Results.ValidationFailure(string.Empty, MessagesException.EMAIL_ALREADY_REGISTARED));

        if (result.IsValid == false)
        {
            var errorMenssages = result.Errors.Select(e => e.ErrorMessage).ToList();

            throw new ErrorOnValidationException(errorMenssages);
        }
    }
}
  • Contém a lógica para registrar um novo usuário.
  • Valida o request usando o RegisterUserValidator.
  • Mapeia o request para um objeto User usando o AutoMapper.
  • Criptografa a senha do usuário usando o IPasswordEncripter.
  • Adiciona o usuário ao repositório usando o IUserWriteOnlyRepository.
  • Confirma as alterações usando o IUnitOfWork.
  • Retorna um ResponseRegisteredUser que contém o nome do usuário e um token de acesso.

Profile

IGetUserProfileUseCase

Esta interface define um contrato para um caso de uso de obtenção do perfil do usuário.

using MyGeneralNotes.Communication.Responses;

namespace MyGeneralNotes.Application.UseCases.User.Profile;
public interface IGetUserProfileUseCase
{
    public Task<ResponseUserProfile> Execute();
}
  • Define um método Execute que retorna um Task<ResponseUserProfile>.
GetUserProfileUseCase

Esta classe implementa a interface IGetUserProfileUseCase.

using AutoMapper;
using MyGeneralNotes.Communication.Responses;
using MyGeneralNotes.Domain.Services.LoggedUser;

namespace MyGeneralNotes.Application.UseCases.User.Profile;
public class GetUserProfileUseCase(ILoggedUser logged, IMapper mapper) : IGetUserProfileUseCase
{
    private readonly ILoggedUser _logged = logged;
    private readonly IMapper _mapper = mapper;

    public async Task<ResponseUserProfile> Execute()
    {
        var user = await _logged.User();

        return _mapper.Map<ResponseUserProfile>(user);

    }
}
  • Contém a lógica para obter o perfil do usuário atualmente logado.
  • Obtém o usuário atualmente logado usando o ILoggedUser.
  • Mapeia o usuário para um ResponseUserProfile usando o AutoMapper.
  • Retorna o ResponseUserProfile.

ChangePassword

IChangePasswordUseCase

Esta interface define um contrato para um caso de uso de alteração de senha.

using MyGeneralNotes.Communication.Requests;

namespace MyGeneralNotes.Application.UseCases.User.ChangePassword;
public interface IChangePasswordUseCase
{
    public Task Execute(RequestChangePassword request);
}
  • Define um método Execute que aceita um RequestChangePassword e retorna um Task.
ChangePasswordValidator

Esta classe herda de AbstractValidator<RequestChangePassword>, que é uma classe do FluentValidation.

using FluentValidation;
using MyGeneralNotes.Application.SharedValidators;
using MyGeneralNotes.Communication.Requests;

namespace MyGeneralNotes.Application.UseCases.User.ChangePassword;
public class ChangePasswordValidator : AbstractValidator<RequestChangePassword>
{
    public ChangePasswordValidator()
    {
        RuleFor(x => x.NewPassword).SetValidator(new PasswordValidator<RequestChangePassword>());
    }
}
  • Define regras de validação para um RequestChangePassword.
  • Verifica se a nova senha do usuário é válida usando o PasswordValidator.
ChangePasswordUseCase

Esta classe implementa a interface IChangePasswordUseCase.

using MyGeneralNotes.Communication.Requests;
using MyGeneralNotes.Domain.Extensions;
using MyGeneralNotes.Domain.Repositories;
using MyGeneralNotes.Domain.Repositories.User;
using MyGeneralNotes.Domain.Security.Cryptography;
using MyGeneralNotes.Domain.Services.LoggedUser;
using MyGeneralNotes.Exceptions;
using MyGeneralNotes.Exceptions.ExceptionsBase;

namespace MyGeneralNotes.Application.UseCases.User.ChangePassword;
public class ChangePasswordUseCase(ILoggedUser logged, IUserUpdateOnlyRepository repository, IUnitOfWork unitOfWork, IPasswordEncripter passwordEncripter) : IChangePasswordUseCase
{
    private readonly ILoggedUser _logged = logged;
    private readonly IUserUpdateOnlyRepository _repository = repository;
    private readonly IUnitOfWork _unitOfWork = unitOfWork;
    private readonly IPasswordEncripter _passwordEncripter = passwordEncripter;

    public async Task Execute(RequestChangePassword request)
    {
        var loggedUser = await _logged.User();

        Validate(request, loggedUser);

        var user = await _repository.GetById(loggedUser.Id);

        user.Password = _passwordEncripter.Encrypt(request.NewPassword);

        _repository.Update(user);

        await _unitOfWork.Commit();
    }

    private void Validate(RequestChangePassword request, Domain.Entities.User loggedUser)
    {
        var result = new ChangePasswordValidator().Validate(request);

        var currentPasswordEncripted = _passwordEncripter.Encrypt(request.Password);

        if (currentPasswordEncripted.Equals(loggedUser.Password).IsFalse())
            result.Errors.Add(new FluentValidation.Results.ValidationFailure(string.Empty, MessagesException.EMAIL_OR_PASSWORD_INVALID));
        if (result.IsValid.IsFalse())
            throw new ErrorOnValidationException(result.Errors.Select(e => e.ErrorMessage).ToList());
    }
}
  • Contém a lógica para alterar a senha do usuário atualmente logado.
  • Obtém o usuário atualmente logado usando o ILoggedUser.
  • Valida o request usando o ChangePasswordValidator.
  • Obtém o usuário do repositório usando o IUserUpdateOnlyRepository.
  • Criptografa a nova senha do usuário usando o IPasswordEncripter.
  • Atualiza o usuário no repositório usando o IUserUpdateOnlyRepository.
  • Confirma as alterações usando o IUnitOfWork.

UpdateUser

IUpdateUserUseCase

Esta interface define um contrato para um caso de uso de atualização de usuário.

using MyGeneralNotes.Communication.Requests;

namespace MyGeneralNotes.Application.UseCases.User.Update;
public interface IUpdateUserUseCase
{
    public Task Execute(RequestUpdateUser request);
}
  • Define um método Execute que aceita um RequestUpdateUser e retorna um Task.
UpdateUserValidator

Esta classe herda de AbstractValidator<RequestUpdateUser>, que é uma classe do FluentValidation.

using FluentValidation;
using MyGeneralNotes.Communication.Requests;
using MyGeneralNotes.Domain.Extensions;
using MyGeneralNotes.Exceptions;

namespace MyGeneralNotes.Application.UseCases.User.Update;
public class UpdateUserValidator : AbstractValidator<RequestUpdateUser>
{
    public UpdateUserValidator()
    {
        RuleFor(request => request.Name).NotEmpty().WithMessage(MessagesException.NAME_EMPTY);
        RuleFor(request => request.Email).NotEmpty().WithMessage(MessagesException.EMAIL_EMPTY);

        When(request => string.IsNullOrWhiteSpace(request.Email).IsFalse(), () =>
        {
            RuleFor(request => request.Email).EmailAddress().WithMessage(MessagesException.EMAIL_IS_INVALID);
        });
    }
}
  • Define regras de validação para um RequestUpdateUser.
  • Verifica se o nome e o email do usuário não estão vazios e se o email é um endereço de email válido.
UpdateUserUseCase

Esta classe implementa a interface IUpdateUserUseCase.

using MyGeneralNotes.Communication.Requests;
using MyGeneralNotes.Domain.Extensions;
using MyGeneralNotes.Domain.Repositories;
using MyGeneralNotes.Domain.Repositories.User;
using MyGeneralNotes.Domain.Services.LoggedUser;
using MyGeneralNotes.Exceptions;
using MyGeneralNotes.Exceptions.ExceptionsBase;

namespace MyGeneralNotes.Application.UseCases.User.Update;
public class UpdateUserUseCase(ILoggedUser logged, IUserUpdateOnlyRepository repository, IUserReadOnlyRepository userReadOnlyRepository, IUnitOfWork unitOfWork) : IUpdateUserUseCase
{
    private readonly ILoggedUser _logged = logged;
    private readonly IUserUpdateOnlyRepository _repository = repository;
    private readonly IUserReadOnlyRepository _userReadOnlyRepository = userReadOnlyRepository;
    private readonly IUnitOfWork _unitOfWork = unitOfWork;

    public async Task Execute(RequestUpdateUser request)
    {
        var loggedUser = await _logged.User();

        await Validate(request, loggedUser.Email);

        var user = await _repository.GetById(loggedUser.Id);

        user.Name = request.Name;
        user.Email = request.Email;

        _repository.Update(user);

        await _unitOfWork.Commit();
    }

    private async Task Validate(RequestUpdateUser request, string currentEmail)
    {
        var validator = new UpdateUserValidator();

        var result = validator.Validate(request);

        if (currentEmail.Equals(request.Email).IsFalse())
        {
            var userExist = await _userReadOnlyRepository.ExistActiveUserWithEmail(request.Email);
            if (userExist)
                result.Errors.Add(new FluentValidation.Results.ValidationFailure("email", MessagesException.EMAIL_ALREADY_REGISTARED));
        }

        if (result.IsValid.IsFalse())
        {
            var errorMessages = result.Errors.Select(x => x.ErrorMessage).ToList();

            throw new ErrorOnValidationException(errorMessages);
        }
    }
}
  • Contém a lógica para atualizar o usuário atualmente logado.
  • Obtém o usuário atualmente logado usando o ILoggedUser.
  • Valida o request usando o UpdateUserValidator.
  • Obtém o usuário do repositório usando o IUserUpdateOnlyRepository.
  • Atualiza o nome e o email do usuário.
  • Atualiza o usuário no repositório usando o IUserUpdateOnlyRepository.
  • Confirma as alterações usando o IUnitOfWork.

Routines

RoutineValidator

RoutineValidator é uma classe que herda de AbstractValidator<RequestRoutine>, que é uma classe do FluentValidation.

using FluentValidation;
using MyGeneralNotes.Communication.Requests;
using MyGeneralNotes.Exceptions;

namespace MyGeneralNotes.Application.UseCases.Routines;
public class RoutineValidator : AbstractValidator<RequestRoutine>
{
    public RoutineValidator()
    {
        RuleFor(r => r.Name).NotEmpty().WithMessage(MessagesException.ROUTINE_NAME_IN_BLANK);
        RuleFor(r => r.DayOfWeek).IsInEnum().NotEmpty();
        RuleFor(r => r.Exercises).NotEmpty().WithMessage(MessagesException.EXERCISES_IN_BLANK);
        RuleForEach(r => r.Exercises).ChildRules(exercices =>
        {
            exercices.RuleFor(e => e.Name).NotEmpty().WithMessage(MessagesException.EXERCISE_NAME_BLANK);
            exercices.RuleFor(e => e.Location).IsInEnum();
            exercices.RuleFor(e => e.Charge).NotEmpty().WithMessage(MessagesException.EXERCISE_WEIGHT_IN_WHITE);
            exercices.RuleFor(e => e.Repetitions).NotEmpty().WithMessage(MessagesException.EXERCISE_REPETITIONS_BLANK);
            exercices.RuleFor(e => e.RestTime).NotEmpty().WithMessage(MessagesException.WAIT_TIME_IN_BLANK);
            exercices.RuleFor(e => e.Equipment).NotEmpty().WithMessage(MessagesException.EQUIPMENT_EXERCISE_BLANK);
            exercices.RuleFor(e => e.Details).NotEmpty().WithMessage(MessagesException.DETAIL_EXERCISE_BLANK);
        });
    }
}
  • Define regras de validação para um RequestRoutine.
  • Verifica se o nome da rotina, o dia da semana e a lista de exercícios não estão vazios.
  • Aplica um conjunto de regras a cada exercício na lista de exercícios.

Register

IRegisterRoutineUseCase

Esta interface define um contrato para um caso de uso de registro de rotina.

namespace MyGeneralNotes.Application
{
    public interface IRegisterRoutineUseCase
    {
        Task<ResponseRoutine> Execute(RequestRoutine request);
    }
}
  • Define um método Execute que aceita um RequestRoutine e retorna um Task<ResponseRoutine>.

RegisterRoutineValidator

Esta classe herda de AbstractValidator<RequestRoutine>, que é uma classe do FluentValidation.

using FluentValidation;
using MyGeneralNotes.Communication.Requests;

namespace MyGeneralNotes.Application.UseCases.Routines.Register;
public class RegisterRoutineValidator : AbstractValidator<RequestRoutine>
{
    public RegisterRoutineValidator()
    {
        RuleFor(r => r).SetValidator(new RoutineValidator());
    }
}
  • Define regras de validação para um RequestRoutine.
  • Inclui as regras do RoutineValidator.

RegisterRoutineUseCase

Esta classe implementa a interface IRegisterRoutineUseCase.

using AutoMapper;
using MyGeneralNotes.Communication.Requests;
using MyGeneralNotes.Communication.Responses;
using MyGeneralNotes.Domain.Repositories;
using MyGeneralNotes.Domain.Repositories.Routine;
using MyGeneralNotes.Domain.Services.LoggedUser;
using MyGeneralNotes.Exceptions.ExceptionsBase;

namespace MyGeneralNotes.Application.UseCases.Routines.Register;
public class RegisterRoutineUseCase(IUnitOfWork unitOfWork, IMapper mapper, ILoggedUser logged, IRoutineWriteOnlyRepository repository) : IRegisterRoutineUseCase
{
    private readonly IUnitOfWork _unitOfWork = unitOfWork;
    private readonly IMapper _mapper = mapper;
    private readonly ILoggedUser _logged = logged;
    private readonly IRoutineWriteOnlyRepository _repository = repository;

    public async Task<ResponseRoutine> Execute(RequestRoutine request)
    {
        Validate(request);

        var loggedUser = await _logged.User();

        var routine = _mapper.Map<Domain.Entities.Routine>(request);
        routine.UserId = loggedUser.Id;

        await _repository.Register(routine);

        await _unitOfWork.Commit();

        return _mapper.Map<ResponseRoutine>(routine);
    }

    private static void Validate(RequestRoutine request)
    {
        var validator = new RegisterRoutineValidator();
        var result = validator.Validate(request);

        if (!result.IsValid)
        {
            var errorMenssages = result.Errors.Select(e => e.ErrorMessage).ToList();
            throw new ErrorOnValidationException(errorMenssages);
        }
    }
}
  • Contém a lógica para registrar uma nova rotina.
  • Valida o request usando o RegisterRoutineValidator.
  • Obtém o usuário atualmente logado usando o ILoggedUser.
  • Mapeia o request para um objeto Routine usando o AutoMapper.
  • Adiciona a rotina ao repositório usando o IRoutineWriteOnlyRepository.
  • Confirma as alterações usando o IUnitOfWork.
  • Retorna um ResponseRoutine que contém os detalhes da rotina registrada.

Update

IUpdateRoutineUseCase

Esta interface define um contrato para um caso de uso de atualização de rotina.

using MyGeneralNotes.Communication.Requests;

namespace MyGeneralNotes.Application.UseCases.Routines.Update;
public interface IUpdateRoutineUseCase
{
    Task Update(long routineId, RequestRoutine request);
}
  • Define um método Update que aceita um routineId e um RequestRoutine, e retorna um Task.

UpdateRoutineValidator

Esta classe herda de AbstractValidator<RequestRoutine>, que é uma classe do FluentValidation.

using FluentValidation;
using MyGeneralNotes.Communication.Requests;

namespace MyGeneralNotes.Application.UseCases.Routines.Update;
public class UpdateRoutineValidator : AbstractValidator<RequestRoutine>
{
    public UpdateRoutineValidator()
    {
        RuleFor(x => x).SetValidator(new RoutineValidator());
    }
}
  • Define regras de validação para um RequestRoutine.
  • Inclui as regras do RoutineValidator.

UpdateRoutineUseCase

Esta classe implementa a interface IUpdateRoutineUseCase.

using AutoMapper;
using MyGeneralNotes.Communication.Requests;
using MyGeneralNotes.Domain.Entities;
using MyGeneralNotes.Domain.Repositories;
using MyGeneralNotes.Domain.Repositories.Routine;
using MyGeneralNotes.Domain.Services.LoggedUser;
using MyGeneralNotes.Exceptions;
using MyGeneralNotes.Exceptions.ExceptionsBase;

namespace MyGeneralNotes.Application.UseCases.Routines.Update;
public class UpdateRoutineUseCase(IMapper mapper, IRoutineUpdateOnlyRepository repository, ILoggedUser logged, IUnitOfWork unitOfWork) : IUpdateRoutineUseCase
{
    private readonly IMapper _mapper = mapper;
    private readonly IRoutineUpdateOnlyRepository _repository = repository;
    private readonly ILoggedUser _logged = logged;
    private readonly IUnitOfWork _unitOfWork = unitOfWork;

    public async Task Update(long routineId, RequestRoutine request)
    {
        var loggedUser = await _logged.User();
        var routine = await _repository.GetById(routineId);

        Validate(loggedUser, routine, request);

        _mapper.Map(request, routine);

        _repository.Update(routine!);

        await _unitOfWork.Commit();
    }

    private static void Validate(Domain.Entities.User loggedUser, Routine? routine, RequestRoutine request)
    {
        if (routine is null || routine.UserId != loggedUser.Id)
            throw new ErrorOnValidationException([MessagesException.ROUTINE_NOT_FOUND]);

        var validator = new UpdateRoutineValidator();
        var result = validator.Validate(request);

        if (!result.IsValid)
        {
            var errorMenssages = result.Errors.Select(e => e.ErrorMessage).ToList();
            throw new ErrorOnValidationException(errorMenssages);
        }
    }
}
  • Contém a lógica para atualizar uma rotina existente.
  • Obtém o usuário atualmente logado usando o ILoggedUser.
  • Obtém a rotina do repositório usando o IRoutineUpdateOnlyRepository.
  • Valida o usuário logado, a rotina e o request usando o método Validate.
  • Mapeia o request para a rotina existente usando o AutoMapper.
  • Atualiza a rotina no repositório usando o IRoutineUpdateOnlyRepository.
  • Confirma as alterações usando o IUnitOfWork.

GetByID

IGetRoutineByIdUseCase

Esta interface define um contrato para um caso de uso de obtenção de rotina por ID.

using MyGeneralNotes.Communication.Responses;

namespace MyGeneralNotes.Application.UseCases.Routines.GetById;
public interface IGetRoutineByIdUseCase
{
    Task<ResponseRoutine> GetRoutineById(long routineId);
}
  • Define um método GetRoutineById que aceita um routineId e retorna um Task<ResponseRoutine>.

GetRoutineByIdUseCase

Esta classe implementa a interface IGetRoutineByIdUseCase.

using AutoMapper;
using MyGeneralNotes.Communication.Responses;
using MyGeneralNotes.Domain.Entities;
using MyGeneralNotes.Domain.Repositories.Routine;
using MyGeneralNotes.Domain.Services.LoggedUser;
using MyGeneralNotes.Exceptions;
using MyGeneralNotes.Exceptions.ExceptionsBase;

namespace MyGeneralNotes.Application.UseCases.Routines.GetById;
public class GetRoutineByIdUseCase(IMapper mapper, IRoutineReadOnlyRepository repositoy, ILoggedUser logged) : IGetRoutineByIdUseCase
{
    private readonly IMapper _mapper = mapper;
    private readonly IRoutineReadOnlyRepository _repositoy = repositoy;
    private readonly ILoggedUser _logged = logged;

    public async Task<ResponseRoutine> GetRoutineById(long routineId)
    {
        var loggedUser = await _logged.User();
        var routine = await _repositoy.GetRoutine(routineId);

        Validate(loggedUser, routine);

        return _mapper.Map<ResponseRoutine>(routine);
    }

    private static void Validate(Domain.Entities.User loggedUser, Routine? routine)
    {
        if (routine is null || routine.UserId != loggedUser.Id)
            throw new ErrorOnValidationException([MessagesException.ROUTINE_NOT_FOUND]);
    }
}
  • Contém a lógica para obter uma rotina pelo ID.
  • Obtém o usuário atualmente logado usando o ILoggedUser.
  • Obtém a rotina do repositório usando o IRoutineReadOnlyRepository.
  • Valida o usuário logado e a rotina usando o método Validate.
  • Mapeia a rotina para um ResponseRoutine usando o AutoMapper.
  • Retorna o ResponseRoutine.

Delete

IDeleteRoutineUseCase

Esta interface define um contrato para um caso de uso de exclusão de rotina.

namespace MyGeneralNotes.Application.UseCases.Routines.Delete;
public interface IDeleteRoutineUseCase
{
    Task Delete(long routineId);
}
  • Define um método Delete que aceita um routineId e retorna um Task.

DeleteRoutineUseCase

Esta classe implementa a interface IDeleteRoutineUseCase.

using MyGeneralNotes.Domain.Entities;
using MyGeneralNotes.Domain.Repositories;
using MyGeneralNotes.Domain.Repositories.Routine;
using MyGeneralNotes.Domain.Services.LoggedUser;
using MyGeneralNotes.Exceptions;
using MyGeneralNotes.Exceptions.ExceptionsBase;

namespace MyGeneralNotes.Application.UseCases.Routines.Delete;
public class DeleteRoutineUseCase(IRoutineReadOnlyRepository readOnlyRepository, IRoutineWriteOnlyRepository writeOnlyRepository, ILoggedUser logged, IUnitOfWork unitOfWork) : IDeleteRoutineUseCase
{
    private readonly IRoutineReadOnlyRepository _readOnlyRepository = readOnlyRepository;
    private readonly IRoutineWriteOnlyRepository _writeOnlyRepository = writeOnlyRepository;
    private readonly ILoggedUser _logged = logged;
    private readonly IUnitOfWork _unitOfWork = unitOfWork;

    public async Task Delete(long routineId)
    {
        var loggedUser = await _logged.User();

        var routine = await _readOnlyRepository.GetRoutine(routineId);

        Validate(loggedUser, routine);

        await _writeOnlyRepository.Delete(routineId);

        await _unitOfWork.Commit();
    }

    private static void Validate(Domain.Entities.User loggedUser, Routine? routine)
    {
        if (routine is null || routine.UserId != loggedUser.Id)
            throw new ErrorOnValidationException([MessagesException.ROUTINE_NOT_FOUND]);
    }
}
  • Contém a lógica para excluir uma rotina existente.
  • Obtém o usuário atualmente logado usando o ILoggedUser.
  • Obtém a rotina do repositório usando o IRoutineReadOnlyRepository.
  • Valida o usuário logado e a rotina usando o método Validate.
  • Exclui a rotina do repositório usando o IRoutineWriteOnlyRepository.
  • Confirma as alterações usando o IUnitOfWork.

Dashboard

IDashboardUseCase

Esta interface define um contrato para um caso de uso de obtenção de dashboard.

using MyGeneralNotes.Communication.Requests;
using MyGeneralNotes.Communication.Responses;

namespace MyGeneralNotes.Application.UseCases.Dashboard;
public interface IDashboardUseCase
{
    Task<ResponseDashboard> GetDashboard(RequestDashboard request);
}
  • Define um método GetDashboard que aceita um RequestDashboard e retorna um Task<ResponseDashboard>.

DashboardUseCase

Esta classe implementa a interface IDashboardUseCase.

using AutoMapper;
using MyGeneralNotes.Communication.Requests;
using MyGeneralNotes.Communication.Responses;
using MyGeneralNotes.Domain.Repositories.Routine;
using MyGeneralNotes.Domain.Services.LoggedUser;

namespace MyGeneralNotes.Application.UseCases.Dashboard;
public class DashboardUseCase(IMapper mapper, IRoutineReadOnlyRepository repositoy, ILoggedUser logged) : IDashboardUseCase
{
    private readonly IMapper _mapper = mapper;
    private readonly IRoutineReadOnlyRepository _repositoy = repositoy;
    private readonly ILoggedUser _logged = logged;

    public async Task<ResponseDashboard> GetDashboard(RequestDashboard request)
    {
        var loggedUser = await _logged.User();
        var routines = await _repositoy.GetAllUserRoutines(loggedUser.Id);

        return new ResponseDashboard
        {
            Routines = _mapper.Map<List<ResponseRoutinesDashboard>>(routines)
        };
    }
}
  • Contém a lógica para obter o dashboard de um usuário.
  • Obtém o usuário atualmente logado usando o ILoggedUser.
  • Obtém todas as rotinas do usuário do repositório usando o IRoutineReadOnlyRepository.
  • Mapeia as rotinas para uma lista de ResponseRoutine usando o AutoMapper.

DependencyInjectionExtension

using Microsoft.Extensions.DependencyInjection;
using MyGeneralNotes.Application.Services.AutoMapper;
using MyGeneralNotes.Application.UseCases.Dashboard;
using MyGeneralNotes.Application.UseCases.Login.DoLogin;
using MyGeneralNotes.Application.UseCases.Routines.Delete;
using MyGeneralNotes.Application.UseCases.Routines.GetById;
using MyGeneralNotes.Application.UseCases.Routines.Register;
using MyGeneralNotes.Application.UseCases.Routines.Update;
using MyGeneralNotes.Application.UseCases.User.ChangePassword;
using MyGeneralNotes.Application.UseCases.User.Profile;
using MyGeneralNotes.Application.UseCases.User.Register;
using MyGeneralNotes.Application.UseCases.User.Update;

namespace MyGeneralNotes.Application
{
    public static class DependencyInjectionExtension
    {
        public static void AddApplication(this IServiceCollection services)
        {
            AddAutoMapper(services);
            AddUseCases(services);
        }

        private static void AddAutoMapper(IServiceCollection services)
        {
            services.AddScoped(opt => new AutoMapper.MapperConfiguration(options =>
            {
                options.AddProfile(new MappingConfig());
            }).CreateMapper());
        }

        private static void AddUseCases(IServiceCollection services)
        {
            services.AddScoped<IRegisterUserUseCase, RegisterUserUseCase>();
            services.AddScoped<IDoLoginUseCase, DoLoginUseCase>();
            services.AddScoped<IGetUserProfileUseCase, GetUserProfileUseCase>();
            services.AddScoped<IUpdateUserUseCase, UpdateUserUseCase>();
            services.AddScoped<IChangePasswordUseCase, ChangePasswordUseCase>();

            services.AddScoped<IDashboardUseCase, DashboardUseCase>();

            services.AddScoped<IRegisterRoutineUseCase, RegisterRoutineUseCase>();
            services.AddScoped<IGetRoutineByIdUseCase, GetRoutineByIdUseCase>();
            services.AddScoped<IUpdateRoutineUseCase, UpdateRoutineUseCase>();
            services.AddScoped<IDeleteRoutineUseCase, DeleteRoutineUseCase>();
        }
    }
}

A classe DependencyInjectionExtension é responsável por configurar a injeção de dependência para essa camada de aplicação do seu projeto. Ela contém métodos para adicionar serviços ao container de injeção de dependência.

Métodos

  • AddApplication(this IServiceCollection services):

    • Este é um método de extensão para IServiceCollection. Ele chama os métodos AddAutoMapper e AddUseCases para adicionar as dependências necessárias para a camada de aplicação.
  • AddAutoMapper(IServiceCollection services):

    • Este método adiciona o AutoMapper ao container de injeção de dependência. O AutoMapper é uma biblioteca que ajuda a mapear um objeto para outro. Ele configura o AutoMapper para usar o perfil de mapeamento definido na classe MappingConfig.
  • AddUseCases(IServiceCollection services):

    • Este método adiciona todas as classes de caso de uso ao container de injeção de dependência. Cada caso de uso é registrado com o ciclo de vida Scoped, o que significa que uma instância será criada por solicitação.

Essas classes de caso de uso, validadores e configurações de mapeamento são os pilares fundamentais que sustentam a lógica central de nossa aplicação. Elas desempenham um papel crucial na manipulação eficaz dos dados, garantindo uma comunicação fluida entre os diversos componentes do sistema. Além disso, fornecem uma base sólida para o desenvolvimento, manutenção e expansão contínua do projeto.

Com uma estrutura bem definida e padrões consistentes, esses elementos simplificam não apenas o fluxo de trabalho dos desenvolvedores, mas também a compreensão e colaboração em equipe. Ao adotar essas práticas, estamos investindo na robustez e na adaptabilidade da aplicação, preparando-a para enfrentar os desafios futuros.

Próxima: MyGeneralNotes.API

⚠️ **GitHub.com Fallback** ⚠️