using Extrudex.API.DTOs.Filaments; using FluentValidation; namespace Extrudex.API.Validators; /// /// Validation rules for creating a Filament (Spool) via the /filaments route. /// Mirrors the domain rules enforced in the controller and ensures consistent /// validation regardless of the request pipeline entry point. /// public class CreateFilamentRequestValidator : AbstractValidator { public CreateFilamentRequestValidator() { RuleFor(x => x.MaterialBaseId) .NotEmpty().WithMessage("MaterialBaseId is required."); RuleFor(x => x.MaterialFinishId) .NotEmpty().WithMessage("MaterialFinishId is required."); RuleFor(x => x.Brand) .NotEmpty().WithMessage("Brand is required.") .MaximumLength(200).WithMessage("Brand must not exceed 200 characters."); RuleFor(x => x.ColorName) .NotEmpty().WithMessage("ColorName is required.") .MaximumLength(200).WithMessage("ColorName must not exceed 200 characters."); RuleFor(x => x.ColorHex) .NotEmpty().WithMessage("ColorHex is required.") .Matches(@"^#[0-9A-Fa-f]{6}$").WithMessage("ColorHex must be a valid hex color code (e.g., #FF0000)."); RuleFor(x => x.WeightTotalGrams) .GreaterThan(0).WithMessage("Total weight must be greater than zero."); RuleFor(x => x.WeightRemainingGrams) .GreaterThanOrEqualTo(0).WithMessage("Remaining weight must be non-negative."); RuleFor(x => x.WeightRemainingGrams) .LessThanOrEqualTo(x => x.WeightTotalGrams) .WithMessage("WeightRemainingGrams cannot exceed WeightTotalGrams."); RuleFor(x => x.FilamentDiameterMm) .GreaterThan(0).WithMessage("Filament diameter must be greater than zero."); RuleFor(x => x.SpoolSerial) .NotEmpty().WithMessage("SpoolSerial is required.") .MaximumLength(200).WithMessage("SpoolSerial must not exceed 200 characters."); When(x => x.PurchasePrice.HasValue, () => { RuleFor(x => x.PurchasePrice!.Value) .GreaterThanOrEqualTo(0).WithMessage("Purchase price must be non-negative."); }); } } /// /// Validation rules for updating a Filament (Spool) via the /filaments route. /// Enforces the same domain rules as creation, plus ensures the updated /// WeightRemainingGrams does not exceed the updated WeightTotalGrams. /// public class UpdateFilamentRequestValidator : AbstractValidator { public UpdateFilamentRequestValidator() { RuleFor(x => x.MaterialBaseId) .NotEmpty().WithMessage("MaterialBaseId is required."); RuleFor(x => x.MaterialFinishId) .NotEmpty().WithMessage("MaterialFinishId is required."); RuleFor(x => x.Brand) .NotEmpty().WithMessage("Brand is required.") .MaximumLength(200).WithMessage("Brand must not exceed 200 characters."); RuleFor(x => x.ColorName) .NotEmpty().WithMessage("ColorName is required.") .MaximumLength(200).WithMessage("ColorName must not exceed 200 characters."); RuleFor(x => x.ColorHex) .NotEmpty().WithMessage("ColorHex is required.") .Matches(@"^#[0-9A-Fa-f]{6}$").WithMessage("ColorHex must be a valid hex color code (e.g., #FF0000)."); RuleFor(x => x.WeightTotalGrams) .GreaterThan(0).WithMessage("Total weight must be greater than zero."); RuleFor(x => x.WeightRemainingGrams) .GreaterThanOrEqualTo(0).WithMessage("Remaining weight must be non-negative."); RuleFor(x => x.WeightRemainingGrams) .LessThanOrEqualTo(x => x.WeightTotalGrams) .WithMessage("WeightRemainingGrams cannot exceed WeightTotalGrams."); RuleFor(x => x.FilamentDiameterMm) .GreaterThan(0).WithMessage("Filament diameter must be greater than zero."); RuleFor(x => x.SpoolSerial) .NotEmpty().WithMessage("SpoolSerial is required.") .MaximumLength(200).WithMessage("SpoolSerial must not exceed 200 characters."); When(x => x.PurchasePrice.HasValue, () => { RuleFor(x => x.PurchasePrice!.Value) .GreaterThanOrEqualTo(0).WithMessage("Purchase price must be non-negative."); }); } }