diff --git a/src/TaxBaik.Application/DTOs/Validators.cs b/src/TaxBaik.Application/DTOs/Validators.cs index bcaac74..1f88560 100644 --- a/src/TaxBaik.Application/DTOs/Validators.cs +++ b/src/TaxBaik.Application/DTOs/Validators.cs @@ -53,3 +53,13 @@ public sealed class CreateClientDtoValidator : AbstractValidator x.Memo).MaximumLength(ValidationRules.MemoMaxLength); } } + +public sealed class FaqValidator : AbstractValidator +{ + public FaqValidator() + { + RuleFor(x => x.Question).NotEmpty().MaximumLength(300); + RuleFor(x => x.Answer).NotEmpty().MinimumLength(10).MaximumLength(5000); + RuleFor(x => x.Category).MaximumLength(50); + } +} diff --git a/src/TaxBaik.Application/Services/AnnouncementService.cs b/src/TaxBaik.Application/Services/AnnouncementService.cs index 7c10b0a..8615a98 100644 --- a/src/TaxBaik.Application/Services/AnnouncementService.cs +++ b/src/TaxBaik.Application/Services/AnnouncementService.cs @@ -1,10 +1,11 @@ namespace TaxBaik.Application.Services; +using FluentValidation; using TaxBaik.Application.DTOs; using TaxBaik.Domain.Entities; using TaxBaik.Domain.Interfaces; -public class AnnouncementService(IAnnouncementRepository repository) +public class AnnouncementService(IAnnouncementRepository repository, IValidator validator) { public Task> GetActiveAsync(CancellationToken ct = default) => repository.GetActiveAsync(ct); @@ -17,12 +18,14 @@ public class AnnouncementService(IAnnouncementRepository repository) public Task CreateAsync(AnnouncementDto dto, CancellationToken ct = default) { + validator.ValidateAndThrow(dto); var entity = MapToEntity(dto); return repository.CreateAsync(entity, ct); } public Task UpdateAsync(AnnouncementDto dto, CancellationToken ct = default) { + validator.ValidateAndThrow(dto); var entity = MapToEntity(dto); return repository.UpdateAsync(entity, ct); } diff --git a/src/TaxBaik.Application/Services/FaqService.cs b/src/TaxBaik.Application/Services/FaqService.cs index c071bbd..c1bdc53 100644 --- a/src/TaxBaik.Application/Services/FaqService.cs +++ b/src/TaxBaik.Application/Services/FaqService.cs @@ -1,9 +1,10 @@ namespace TaxBaik.Application.Services; +using FluentValidation; using TaxBaik.Domain.Entities; using TaxBaik.Domain.Interfaces; -public class FaqService(IFaqRepository repository) +public class FaqService(IFaqRepository repository, IValidator validator) { public static readonly string[] Categories = ["기장세금신고", "부동산", "증여상속", "기타"]; @@ -19,24 +20,17 @@ public class FaqService(IFaqRepository repository) public async Task CreateAsync(Faq faq, CancellationToken ct = default) { - Validate(faq); + validator.ValidateAndThrow(faq); return await repository.CreateAsync(faq, ct); } public async Task UpdateAsync(Faq faq, CancellationToken ct = default) { - Validate(faq); + validator.ValidateAndThrow(faq); await repository.UpdateAsync(faq, ct); } public async Task DeleteAsync(int id, CancellationToken ct = default) => await repository.DeleteAsync(id, ct); - private static void Validate(Faq faq) - { - if (string.IsNullOrWhiteSpace(faq.Question)) - throw new ValidationException("질문을 입력하세요."); - if (string.IsNullOrWhiteSpace(faq.Answer)) - throw new ValidationException("답변을 입력하세요."); - } } diff --git a/src/TaxBaik.Web/Endpoints/Announcement/AnnouncementValidators.cs b/src/TaxBaik.Web/Endpoints/Announcement/AnnouncementValidators.cs new file mode 100644 index 0000000..eb15e73 --- /dev/null +++ b/src/TaxBaik.Web/Endpoints/Announcement/AnnouncementValidators.cs @@ -0,0 +1,19 @@ +namespace TaxBaik.Web.Endpoints.Announcement; + +using FluentValidation; +using TaxBaik.Application.DTOs; + +public sealed class AnnouncementDtoValidator : AbstractValidator +{ + public AnnouncementDtoValidator() + { + RuleFor(x => x.Title) + .NotEmpty().WithMessage("제목을 입력하세요.") + .MaximumLength(ValidationRules.TitleMaxLength).WithMessage("제목은 최대 100자까지 입력 가능합니다."); + + RuleFor(x => x.Content).MaximumLength(2000).WithMessage("상세 내용은 최대 2000자까지 입력 가능합니다."); + RuleFor(x => x.DisplayType) + .NotEmpty().WithMessage("표시 유형을 선택하세요.") + .MaximumLength(20).WithMessage("표시 유형은 최대 20자까지 입력 가능합니다."); + } +} diff --git a/src/TaxBaik.Web/Endpoints/Faq/FaqValidators.cs b/src/TaxBaik.Web/Endpoints/Faq/FaqValidators.cs new file mode 100644 index 0000000..a3303a9 --- /dev/null +++ b/src/TaxBaik.Web/Endpoints/Faq/FaqValidators.cs @@ -0,0 +1,23 @@ +namespace TaxBaik.Web.Endpoints.Faq; + +using FluentValidation; + +public sealed class CreateFaqRequestValidator : AbstractValidator +{ + public CreateFaqRequestValidator() + { + RuleFor(x => x.Question).NotEmpty().MaximumLength(300); + RuleFor(x => x.Answer).NotEmpty().MinimumLength(10).MaximumLength(5000); + RuleFor(x => x.Category).MaximumLength(50); + } +} + +public sealed class UpdateFaqRequestValidator : AbstractValidator +{ + public UpdateFaqRequestValidator() + { + RuleFor(x => x.Question).NotEmpty().MaximumLength(300); + RuleFor(x => x.Answer).NotEmpty().MinimumLength(10).MaximumLength(5000); + RuleFor(x => x.Category).MaximumLength(50); + } +} diff --git a/src/TaxBaik.Web/Program.cs b/src/TaxBaik.Web/Program.cs index eade602..98f5492 100644 --- a/src/TaxBaik.Web/Program.cs +++ b/src/TaxBaik.Web/Program.cs @@ -359,6 +359,7 @@ builder.Services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All)); builder.Services.AddInfrastructure(); builder.Services.AddApplication(); builder.Services.AddValidatorsFromAssemblyContaining(); +builder.Services.AddValidatorsFromAssemblyContaining(); builder.Services.AddScoped(); builder.Services.AddScoped();