mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-07-16 17:47:22 +00:00
Auth and Emails land together since Auth's registration/resend flows need Emails to exist first. Service.Auth's four services (Register, Login, Confirmation, Token) collapse into MediatR commands/queries in Features.Auth; TokenService stays as a slice-internal service since multiple handlers call it. Auth no longer references Emails directly — it sends SendRegistrationEmailCommand/SendResendConfirmationEmailCommand (defined in Shared.Application) which Features.Emails handles, so neither slice has a project reference on the other. Service.Emails' IEmailService becomes Features.Emails' IEmailDispatcher, simplified to take (firstName, email, token) instead of a full UserAccount since that's all it ever used. API.Specs' TestApiFactory/MockEmailService are updated to swap in the relocated interface. Also deletes Infrastructure.Repository now that Breweries, UserManagement, and Auth have all moved their repos out of it, and replaces the two now-dead docker-compose test services (repository.tests, service.auth.tests, both pointing at deleted Dockerfiles) with a single unit.tests service that runs every Features.*.Tests project via Dockerfile.tests.
69 lines
2.5 KiB
C#
69 lines
2.5 KiB
C#
using FluentValidation;
|
|
|
|
namespace Features.Auth.Commands.RegisterUser;
|
|
|
|
/// <summary>
|
|
/// Validates <see cref="RegisterUserCommand"/> instances before they are processed.
|
|
/// </summary>
|
|
public class RegisterUserValidator : AbstractValidator<RegisterUserCommand>
|
|
{
|
|
/// <summary>
|
|
/// Configures validation rules for username format and length, first/last name length, email format and
|
|
/// length, minimum age based on date of birth, and password strength requirements.
|
|
/// </summary>
|
|
public RegisterUserValidator()
|
|
{
|
|
RuleFor(x => x.Username)
|
|
.NotEmpty()
|
|
.WithMessage("Username is required")
|
|
.Length(3, 64)
|
|
.WithMessage("Username must be between 3 and 64 characters")
|
|
.Matches("^[a-zA-Z0-9._-]+$")
|
|
.WithMessage(
|
|
"Username can only contain letters, numbers, dots, underscores, and hyphens"
|
|
);
|
|
|
|
RuleFor(x => x.FirstName)
|
|
.NotEmpty()
|
|
.WithMessage("First name is required")
|
|
.MaximumLength(128)
|
|
.WithMessage("First name cannot exceed 128 characters");
|
|
|
|
RuleFor(x => x.LastName)
|
|
.NotEmpty()
|
|
.WithMessage("Last name is required")
|
|
.MaximumLength(128)
|
|
.WithMessage("Last name cannot exceed 128 characters");
|
|
|
|
RuleFor(x => x.Email)
|
|
.NotEmpty()
|
|
.WithMessage("Email is required")
|
|
.EmailAddress()
|
|
.WithMessage("Invalid email format")
|
|
.MaximumLength(128)
|
|
.WithMessage("Email cannot exceed 128 characters");
|
|
|
|
RuleFor(x => x.DateOfBirth)
|
|
.NotEmpty()
|
|
.WithMessage("Date of birth is required")
|
|
.LessThan(DateTime.Today.AddYears(-19))
|
|
.WithMessage("You must be at least 19 years old to register");
|
|
|
|
RuleFor(x => x.Password)
|
|
.NotEmpty()
|
|
.WithMessage("Password is required")
|
|
.MinimumLength(8)
|
|
.WithMessage("Password must be at least 8 characters")
|
|
.Matches("[A-Z]")
|
|
.WithMessage("Password must contain at least one uppercase letter")
|
|
.Matches("[a-z]")
|
|
.WithMessage("Password must contain at least one lowercase letter")
|
|
.Matches("[0-9]")
|
|
.WithMessage("Password must contain at least one number")
|
|
.Matches("[^a-zA-Z0-9]")
|
|
.WithMessage(
|
|
"Password must contain at least one special character"
|
|
);
|
|
}
|
|
}
|