Skip to content

Commit

Permalink
fix(quetzalcoatl): configure testing environment for ci pipeline
Browse files Browse the repository at this point in the history
  • Loading branch information
WarriorsSami committed Jun 20, 2024
1 parent 3dfaabc commit 4488b68
Show file tree
Hide file tree
Showing 40 changed files with 425 additions and 427 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/quetzalcoatl-auth-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ jobs:
cd quetzalcoatl-auth
dotnet build --no-restore
- name: Test
run: dotnet test "quetzalcoatl-auth/Tests.Integration/Tests.Integration.csproj"
run: dotnet test -e ASPNETCORE_ENVIRONMENT=Testing "quetzalcoatl-auth/Tests.Integration/Tests.Integration.csproj"
3 changes: 2 additions & 1 deletion quetzalcoatl-auth/.env.template
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
ASPNETCORE_ENVIRONMENT=Development
ASPNETCORE_ENVIRONMENT=Testing
ASPNETCORE_URLS=http://+:5210
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false

JwtConfig__SecretKey="z7F+ut_aphaxeja0&ba*p9spew!4fe0rAFRO5HestitIKOv5nistlz3b=+edu1aP"
JwtConfig__JwtAccessTokenLifeTime="0:01:00:00.0"
Expand Down
54 changes: 22 additions & 32 deletions quetzalcoatl-auth/Api/Features/Auth/Login/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,39 +47,29 @@ public override async Task HandleAsync(LoginUserRequest req, CancellationToken c
}
);

HttpContext
.Response
.Cookies
.Append(
CookieAuthenticationDefaults.CookiePrefix + "AccessToken",
tokenResponse.AccessToken,
new CookieOptions
{
HttpOnly = true,
SameSite = SameSiteMode.None,
Secure = true,
Expires = DateTimeOffset
.UtcNow
.AddTicks(_jwtConfig.JwtAccessTokenLifetime.Ticks)
}
);
HttpContext.Response.Cookies.Append(
CookieAuthenticationDefaults.CookiePrefix + "AccessToken",
tokenResponse.AccessToken,
new CookieOptions
{
HttpOnly = true,
SameSite = SameSiteMode.None,
Secure = true,
Expires = DateTimeOffset.UtcNow.AddTicks(_jwtConfig.JwtAccessTokenLifetime.Ticks)
}
);

HttpContext
.Response
.Cookies
.Append(
CookieAuthenticationDefaults.CookiePrefix + "RefreshToken",
tokenResponse.RefreshToken,
new CookieOptions
{
HttpOnly = true,
SameSite = SameSiteMode.None,
Secure = true,
Expires = DateTimeOffset
.UtcNow
.AddTicks(_jwtConfig.JwtRefreshTokenLifetime.Ticks)
}
);
HttpContext.Response.Cookies.Append(
CookieAuthenticationDefaults.CookiePrefix + "RefreshToken",
tokenResponse.RefreshToken,
new CookieOptions
{
HttpOnly = true,
SameSite = SameSiteMode.None,
Secure = true,
Expires = DateTimeOffset.UtcNow.AddTicks(_jwtConfig.JwtRefreshTokenLifetime.Ticks)
}
);

await SendOkAsync(
response: new UserTokenResponse
Expand Down
14 changes: 5 additions & 9 deletions quetzalcoatl-auth/Api/Features/Auth/RefreshToken/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,12 @@ public override async Task PersistTokenAsync(UserTokenResponse response)

public override async Task RefreshRequestValidationAsync(UserTokenRequest req)
{
_logger.LogInformation(
"Validating the refresh token for user {UserId}",
req.UserId
);
_logger.LogInformation("Validating the refresh token for user {UserId}", req.UserId);

var storedRefreshToken = await _tokenRepository.GetRefreshTokenAsync(
rt =>
rt.Token == Guid.Parse(req.RefreshToken)
&& rt.UserId == Guid.Parse(req.UserId)
&& rt.ExpiryDate > DateTime.UtcNow
var storedRefreshToken = await _tokenRepository.GetRefreshTokenAsync(rt =>
rt.Token == Guid.Parse(req.RefreshToken)
&& rt.UserId == Guid.Parse(req.UserId)
&& rt.ExpiryDate > DateTime.UtcNow
);

if (storedRefreshToken is null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ public UserTokenResponseToRefreshTokenEntityProfile()
.ForMember(dest => dest.ExpiryDate, opt => opt.MapFrom(src => src.RefreshExpiry))
.ForMember(dest => dest.CreationDate, opt => opt.MapFrom(_ => DateTime.UtcNow));
}
}
}
54 changes: 22 additions & 32 deletions quetzalcoatl-auth/Api/Features/Auth/Register/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,39 +46,29 @@ public override async Task HandleAsync(RegisterUserRequest req, CancellationToke
}
);

HttpContext
.Response
.Cookies
.Append(
CookieAuthenticationDefaults.CookiePrefix + "AccessToken",
tokenResponse.AccessToken,
new CookieOptions
{
HttpOnly = true,
SameSite = SameSiteMode.None,
Secure = true,
Expires = DateTimeOffset
.UtcNow
.AddTicks(_jwtConfig.JwtAccessTokenLifetime.Ticks)
}
);
HttpContext.Response.Cookies.Append(
CookieAuthenticationDefaults.CookiePrefix + "AccessToken",
tokenResponse.AccessToken,
new CookieOptions
{
HttpOnly = true,
SameSite = SameSiteMode.None,
Secure = true,
Expires = DateTimeOffset.UtcNow.AddTicks(_jwtConfig.JwtAccessTokenLifetime.Ticks)
}
);

HttpContext
.Response
.Cookies
.Append(
CookieAuthenticationDefaults.CookiePrefix + "RefreshToken",
tokenResponse.RefreshToken,
new CookieOptions
{
HttpOnly = true,
SameSite = SameSiteMode.None,
Secure = true,
Expires = DateTimeOffset
.UtcNow
.AddTicks(_jwtConfig.JwtRefreshTokenLifetime.Ticks)
}
);
HttpContext.Response.Cookies.Append(
CookieAuthenticationDefaults.CookiePrefix + "RefreshToken",
tokenResponse.RefreshToken,
new CookieOptions
{
HttpOnly = true,
SameSite = SameSiteMode.None,
Secure = true,
Expires = DateTimeOffset.UtcNow.AddTicks(_jwtConfig.JwtRefreshTokenLifetime.Ticks)
}
);

await SendCreatedAtAsync(
endpointName: $"/api/users/{user.Id}",
Expand Down
23 changes: 17 additions & 6 deletions quetzalcoatl-auth/Api/Features/Auth/Register/Validators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ public Validator()
.NotEmpty()
.WithMessage("Username is required")
.MinimumLength(ApplicationUserConsts.UsernameMinLength)
.WithMessage($"Username must be at least {ApplicationUserConsts.UsernameMinLength} characters long");
.WithMessage(
$"Username must be at least {ApplicationUserConsts.UsernameMinLength} characters long"
);

RuleFor(x => x.Email)
.NotEmpty()
Expand All @@ -20,22 +22,30 @@ public Validator()
.NotEmpty()
.WithMessage("Password is required")
.MinimumLength(ApplicationUserConsts.PasswordMinLength)
.WithMessage($"Password must be at least {ApplicationUserConsts.PasswordMinLength} characters long")
.WithMessage(
$"Password must be at least {ApplicationUserConsts.PasswordMinLength} characters long"
)
.MaximumLength(ApplicationUserConsts.PasswordMaxLength)
.WithMessage($"Password must be at most {ApplicationUserConsts.PasswordMaxLength} characters long")
.WithMessage(
$"Password must be at most {ApplicationUserConsts.PasswordMaxLength} characters long"
)
.Matches(ApplicationUserConsts.PasswordRegex)
.WithMessage(
"Password must contain at least one uppercase letter, one lowercase letter, one number and one special character"
);

RuleFor(x => x.Fullname)
.MaximumLength(ApplicationUserConsts.FullnameMaxLength)
.WithMessage($"Fullname must be at most {ApplicationUserConsts.FullnameMaxLength} characters long")
.WithMessage(
$"Fullname must be at most {ApplicationUserConsts.FullnameMaxLength} characters long"
)
.When(x => !string.IsNullOrWhiteSpace(x.Fullname));

RuleFor(x => x.Bio)
.MaximumLength(ApplicationUserConsts.BioMaxLength)
.WithMessage($"Bio must be at most {ApplicationUserConsts.BioMaxLength} characters long")
.WithMessage(
$"Bio must be at most {ApplicationUserConsts.BioMaxLength} characters long"
)
.When(x => !string.IsNullOrWhiteSpace(x.Bio));

RuleFor(x => x.ProfilePicture)
Expand All @@ -47,7 +57,8 @@ public Validator()
.When(x => x.ProfilePicture is not null);
}

private static bool IsAllowedSize(long length) => length <= ApplicationUserConsts.ProfilePictureMaxLength;
private static bool IsAllowedSize(long length) =>
length <= ApplicationUserConsts.ProfilePictureMaxLength;

private static bool IsAllowedType(string contentType) =>
ApplicationUserConsts.AllowedProfilePictureTypes.Contains(contentType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static class SortUsersByExtensions
public static IEnumerable<UserDto> SortUsers(
this IEnumerable<UserDto> query,
SortUsersBy sortBy
)
)
{
return sortBy switch
{
Expand All @@ -39,7 +39,7 @@ SortUsersBy sortBy
public static IAsyncEnumerable<UserDto> SortUsers(
this IAsyncEnumerable<UserDto> query,
SortUsersBy sortBy
)
)
{
return sortBy switch
{
Expand All @@ -48,4 +48,4 @@ SortUsersBy sortBy
_ => query.OrderBy(user => user.Username),
};
}
}
}
8 changes: 4 additions & 4 deletions quetzalcoatl-auth/Api/Features/Core/JwtExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ out var validatedToken
private static bool IsJwtWithValidSecurityAlgorithm(SecurityToken validatedToken)
{
return (validatedToken is JwtSecurityToken jwtSecurityToken)
&& jwtSecurityToken
.Header
.Alg
.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase);
&& jwtSecurityToken.Header.Alg.Equals(
SecurityAlgorithms.HmacSha256,
StringComparison.InvariantCultureIgnoreCase
);
}
}
2 changes: 1 addition & 1 deletion quetzalcoatl-auth/Api/Features/Core/LinqExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ public static IAsyncEnumerable<T> Paginate<T>(IAsyncEnumerable<T> query, int pag
{
return query.Skip((page - 1) * pageSize).Take(pageSize);
}
}
}
3 changes: 1 addition & 2 deletions quetzalcoatl-auth/Api/Features/Users/Delete/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ public override async Task HandleAsync(DeleteUserRequest req, CancellationToken
if (!result.Succeeded)
{
var errors = result
.Errors
.Select(e => e.Description)
.Errors.Select(e => e.Description)
.Aggregate("Identity Errors: ", (a, b) => $"{a}, {b}");

_logger.LogWarning(
Expand Down
6 changes: 3 additions & 3 deletions quetzalcoatl-auth/Api/Features/Users/Get/Mappers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public ApplicationUserToGetUserResponseProfile()
.ForMember(
dest => dest.ProfilePictureId,
opt =>
opt.MapFrom<Guid?>(
src => src.ProfilePicture != null ? src.ProfilePicture!.Id : null
)
opt.MapFrom<Guid?>(src =>
src.ProfilePicture != null ? src.ProfilePicture!.Id : null
)
);
}
}
28 changes: 19 additions & 9 deletions quetzalcoatl-auth/Api/Features/Users/GetAll/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,37 @@ public override async Task HandleAsync(GetAllUsersRequest req, CancellationToken
{
_logger.LogInformation("Getting all users");

var users = _userManager.Users.AsAsyncEnumerable().SelectAwait(async user =>
{
var userDto = _mapper.Map<UserDto>(user);
userDto.Roles = await _userManager.GetRolesAsync(user);
return userDto;
}).AsAsyncEnumerable();

var users = _userManager
.Users.AsAsyncEnumerable()
.SelectAwait(async user =>
{
var userDto = _mapper.Map<UserDto>(user);
userDto.Roles = await _userManager.GetRolesAsync(user);
return userDto;
})
.AsAsyncEnumerable();

if (!string.IsNullOrWhiteSpace(req.Username))
{
users = users.Where(user => user.Username.Contains(req.Username));
}

var totalCount = await users.CountAsync(cancellationToken: ct);

if (req.SortBy is not null)
{
users = users.SortUsers(req.SortBy.Value);
}

users = LinqExtensions.Paginate(users, req.Page ?? 1, req.PageSize ?? 10);

await SendOkAsync(response: new GetAllUsersResponse { Users = users.ToEnumerable(), TotalCount = totalCount }, ct);
await SendOkAsync(
response: new GetAllUsersResponse
{
Users = users.ToEnumerable(),
TotalCount = totalCount
},
ct
);
}
}
6 changes: 3 additions & 3 deletions quetzalcoatl-auth/Api/Features/Users/GetAll/Mappers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public ApplicationUserToUserDtoProfile()
.ForMember(
dest => dest.ProfilePictureId,
opt =>
opt.MapFrom<Guid?>(
src => src.ProfilePicture != null ? src.ProfilePicture!.Id : null
)
opt.MapFrom<Guid?>(src =>
src.ProfilePicture != null ? src.ProfilePicture!.Id : null
)
);
}
}
Loading

0 comments on commit 4488b68

Please sign in to comment.