Skip to content

Commit

Permalink
Merge branch 'feature/get-user-profile' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
raffreitas committed Dec 18, 2024
2 parents 616384f + 7083ce5 commit 203e02e
Show file tree
Hide file tree
Showing 13 changed files with 197 additions and 2 deletions.
12 changes: 12 additions & 0 deletions src/MyRecipes.API/Controllers/UserController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using MyRecipes.API.Attributes;
using MyRecipes.Application.UseCases.User.Profile;
using MyRecipes.Application.UseCases.User.Register;
using MyRecipes.Communication.Requests;
using MyRecipes.Communication.Responses;
Expand All @@ -17,4 +19,14 @@ public async Task<IActionResult> Register([FromServices] IRegisterUserUseCase us

return Created(string.Empty, result);
}

[HttpGet]
[AuthenticatedUser]
[ProducesResponseType<ResponseUserProfileJson>(StatusCodes.Status200OK)]
public async Task<IActionResult> GetUserProfile([FromServices] IGetUserProfileUseCase userCase)
{
var result = await userCase.Execute();

return Ok(result);
}
}
2 changes: 2 additions & 0 deletions src/MyRecipes.Application/DependencyInjectionExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using MyRecipes.Application.Services.AutoMapper;
using MyRecipes.Application.Services.Cryptography;
using MyRecipes.Application.UseCases.Login.DoLogin;
using MyRecipes.Application.UseCases.User.Profile;
using MyRecipes.Application.UseCases.User.Register;

namespace MyRecipes.Application;
Expand All @@ -28,6 +29,7 @@ private static void AddUseCases(IServiceCollection services)
{
services.AddScoped<IRegisterUserUseCase, RegisterUserUseCase>();
services.AddScoped<IDoLoginUseCase, DoLoginUseCase>();
services.AddScoped<IGetUserProfileUseCase, GetUserProfileUseCase>();
}

private static void AddPasswordEncripter(IServiceCollection services, IConfiguration configuration)
Expand Down
7 changes: 7 additions & 0 deletions src/MyRecipes.Application/Services/AutoMapper/AutoMapping.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using AutoMapper;
using MyRecipes.Communication.Requests;
using MyRecipes.Communication.Responses;

namespace MyRecipes.Application.Services.AutoMapper;

Expand All @@ -8,11 +9,17 @@ public class AutoMapping : Profile
public AutoMapping()
{
RequestToDomain();
DomainToResponse();
}

private void RequestToDomain()
{
CreateMap<RequestRegisterUserJson, Domain.Entities.User>()
.ForMember(destination => destination.Password, option => option.Ignore());
}

private void DomainToResponse()
{
CreateMap<Domain.Entities.User, ResponseUserProfileJson>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using AutoMapper;
using MyRecipes.Communication.Responses;
using MyRecipes.Domain.Services.LoggedUser;

namespace MyRecipes.Application.UseCases.User.Profile;
internal class GetUserProfileUseCase : IGetUserProfileUseCase
{
private readonly ILoggedUser _loggedUser;
private readonly IMapper _mapper;

public GetUserProfileUseCase(ILoggedUser loggedUser, IMapper mapper)
{
_loggedUser = loggedUser;
_mapper = mapper;
}

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

return _mapper.Map<ResponseUserProfileJson>(user);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using MyRecipes.Communication.Responses;

namespace MyRecipes.Application.UseCases.User.Profile;
public interface IGetUserProfileUseCase
{
public Task<ResponseUserProfileJson> Execute();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace MyRecipes.Communication.Responses;
public class ResponseUserProfileJson
{
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
}
3 changes: 2 additions & 1 deletion tests/CommonTestsUtilities/Entities/UserBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public static (User user, string password) Build()
.RuleFor(user => user.Id, () => 1)
.RuleFor(user => user.Name, f => f.Person.FirstName)
.RuleFor(user => user.Email, (f, user) => f.Internet.Email(user.Name))
.RuleFor(user => user.Password, f => passwordEncripter.Encrypt(password));
.RuleFor(user => user.UserIdentifier, _ => Guid.NewGuid())
.RuleFor(user => user.Password, _ => passwordEncripter.Encrypt(password));

return (user, password);
}
Expand Down
16 changes: 16 additions & 0 deletions tests/CommonTestsUtilities/LoggedUser/LoggedUserBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Moq;
using MyRecipes.Domain.Entities;
using MyRecipes.Domain.Services.LoggedUser;

namespace CommonTestsUtilities.LoggedUser;
public class LoggedUserBuilder
{
public static ILoggedUser Build(User user)
{
var mock = new Mock<ILoggedUser>();

mock.Setup(x => x.User()).ReturnsAsync(user);

return mock.Object;
}
}
31 changes: 31 additions & 0 deletions tests/UseCases.Tests/User/Profile/GetUserProfileUseCaseTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using CommonTestsUtilities.Entities;
using CommonTestsUtilities.LoggedUser;
using CommonTestsUtilities.Mapper;
using FluentAssertions;
using MyRecipes.Application.UseCases.User.Profile;

namespace UseCases.Tests.User.Profile;
public class GetUserProfileUseCaseTest
{
[Fact]
public async Task Success()
{
var (user, _) = UserBuilder.Build();

var useCase = CreateUseCase(user);

var response = await useCase.Execute();

response.Should().NotBeNull();
response.Name.Should().Be(user.Name);
response.Email.Should().Be(user.Email);
}

private static GetUserProfileUseCase CreateUseCase(MyRecipes.Domain.Entities.User user)
{
var mapper = MapperBuilder.Build();
var loggedUser = LoggedUserBuilder.Build(user);

return new GetUserProfileUseCase(loggedUser, mapper);
}
}
1 change: 1 addition & 0 deletions tests/WebApi.Tests/CustomWebApplicationFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ protected override void ConfigureWebHost(IWebHostBuilder builder)
public string GetName() => _user.Name;
public string GetEmail() => _user.Email;
public string GetPassword() => _password;
public Guid GetUserIdentifier() => _user.UserIdentifier;

private void StartDatabase(MyRecipesDbContext dbContext)
{
Expand Down
20 changes: 19 additions & 1 deletion tests/WebApi.Tests/MyRecipesClassFixture.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Net.Http.Json;
using System.Net.Http.Headers;
using System.Net.Http.Json;

namespace WebApi.Tests;

Expand All @@ -14,11 +15,28 @@ protected async Task<HttpResponseMessage> DoPost<T>(string method, T request, st
return await _httpClient.PostAsJsonAsync(method, request);
}

protected async Task<HttpResponseMessage> DoGet(string method, string token = "", string culture = "en")
{
ChangeRequestCulture(culture);
AuthorizeRequest(token);

return await _httpClient.GetAsync(method);
}

private void ChangeRequestCulture(string culture)
{
if (_httpClient.DefaultRequestHeaders.Contains("Accept-Language"))
_httpClient.DefaultRequestHeaders.Remove("Accept-Language");

_httpClient.DefaultRequestHeaders.Add("Accept-Language", culture);
}

private void AuthorizeRequest(string token)
{
if (string.IsNullOrWhiteSpace(token))
return;

_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

}
}
33 changes: 33 additions & 0 deletions tests/WebApi.Tests/User/Profile/GetUserProfileInvalidTokenTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using CommonTestsUtilities.Tokens;
using FluentAssertions;
using System.Net;

namespace WebApi.Tests.User.Profile;
public class GetUserProfileInvalidTokenTest : MyRecipesClassFixture
{
private readonly string _method = "users";

public GetUserProfileInvalidTokenTest(CustomWebApplicationFactory factory) : base(factory) { }

[Fact]
public async Task Error_Token_Invalid()
{
var response = await DoGet(_method, "invalidToken");
response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
}

[Fact]
public async Task Error_Without_Token()
{
var response = await DoGet(_method, string.Empty);
response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
}

[Fact]
public async Task Error_Token_With_User_NotFound()
{
var token = JwtTokenGeneratorBuilder.Build().Generate(Guid.NewGuid());
var response = await DoGet(_method, token);
response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
}
}
38 changes: 38 additions & 0 deletions tests/WebApi.Tests/User/Profile/GetUserProfileTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using CommonTestsUtilities.Tokens;
using FluentAssertions;
using System.Net;
using System.Text.Json;

namespace WebApi.Tests.User.Profile;
public class GetUserProfileTest : MyRecipesClassFixture
{
private readonly string _method = "users";

private readonly string _name;
private readonly string _email;
private readonly Guid _userIdentifier;

public GetUserProfileTest(CustomWebApplicationFactory factory) : base(factory)
{
_name = factory.GetName();
_email = factory.GetEmail();
_userIdentifier = factory.GetUserIdentifier();
}

[Fact]
public async Task Success()
{
var token = JwtTokenGeneratorBuilder.Build().Generate(_userIdentifier);

var response = await DoGet(_method, token);

response.StatusCode.Should().Be(HttpStatusCode.OK);

using var responseBody = await response.Content.ReadAsStreamAsync();

var responseData = await JsonDocument.ParseAsync(responseBody);

responseData.RootElement.GetProperty("name").GetString().Should().NotBeNullOrWhiteSpace().And.Be(_name);
responseData.RootElement.GetProperty("email").GetString().Should().NotBeNullOrWhiteSpace().And.Be(_email);
}
}

0 comments on commit 203e02e

Please sign in to comment.