diff --git a/backend/src/main/java/codezap/category/dto/request/CreateCategoryRequest.java b/backend/src/main/java/codezap/category/dto/request/CreateCategoryRequest.java index 9587c9d04..3dacbb10d 100644 --- a/backend/src/main/java/codezap/category/dto/request/CreateCategoryRequest.java +++ b/backend/src/main/java/codezap/category/dto/request/CreateCategoryRequest.java @@ -10,7 +10,7 @@ public record CreateCategoryRequest( @Schema(description = "카테고리 이름", example = "Spring") @NotBlank(message = "카테고리 이름이 null 입니다.", groups = NotNullGroup.class) - @Size(max = 255, message = "카테고리 이름은 최대 255자까지 입력 가능합니다.", groups = SizeCheckGroup.class) + @Size(max = 15, message = "카테고리 이름은 최대 15자까지 입력 가능합니다.", groups = SizeCheckGroup.class) String name ) { } diff --git a/backend/src/main/java/codezap/global/validation/ByteLength.java b/backend/src/main/java/codezap/global/validation/ByteLength.java index 5b15f20b1..bbc3a1801 100644 --- a/backend/src/main/java/codezap/global/validation/ByteLength.java +++ b/backend/src/main/java/codezap/global/validation/ByteLength.java @@ -10,7 +10,7 @@ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) -@Constraint(validatedBy = ByteLengthValidator.class) +@Constraint(validatedBy = {ByteLengthValidator.class, GroupedByteLengthValidator.class}) public @interface ByteLength { String message(); diff --git a/backend/src/main/java/codezap/global/validation/GroupedByteLengthValidator.java b/backend/src/main/java/codezap/global/validation/GroupedByteLengthValidator.java new file mode 100644 index 000000000..92e9e31cb --- /dev/null +++ b/backend/src/main/java/codezap/global/validation/GroupedByteLengthValidator.java @@ -0,0 +1,30 @@ +package codezap.global.validation; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +public class GroupedByteLengthValidator implements ConstraintValidator> { + + private int max; + private int min; + + @Override + public void initialize(ByteLength constraintAnnotation) { + max = constraintAnnotation.max(); + min = constraintAnnotation.min(); + } + + @Override + public boolean isValid(List strings, ConstraintValidatorContext constraintValidatorContext) { + return strings.stream() + .allMatch(this::isValid); + } + + private boolean isValid(String target) { + int byteLength = target.getBytes(StandardCharsets.UTF_8).length; + return min <= byteLength && byteLength <= max; + } +} diff --git a/backend/src/main/java/codezap/template/dto/request/CreateTemplateRequest.java b/backend/src/main/java/codezap/template/dto/request/CreateTemplateRequest.java index 2da75905e..8d18cceab 100644 --- a/backend/src/main/java/codezap/template/dto/request/CreateTemplateRequest.java +++ b/backend/src/main/java/codezap/template/dto/request/CreateTemplateRequest.java @@ -40,10 +40,15 @@ public record CreateTemplateRequest( @Schema(description = "태그 목록") @NotNull(message = "태그 목록이 null 입니다.", groups = NotNullGroup.class) + @ByteLength(max = 30, message = "태그 명은 최대 30자까지 입력 가능합니다.", groups = SizeCheckGroup.class) + @Valid List tags ) implements ValidatedSourceCodesOrdinalRequest { + @Override public List extractSourceCodesOrdinal() { - return sourceCodes.stream().map(CreateSourceCodeRequest::ordinal).toList(); + return sourceCodes.stream() + .map(CreateSourceCodeRequest::ordinal) + .toList(); } } diff --git a/backend/src/test/java/codezap/category/controller/CategoryControllerTest.java b/backend/src/test/java/codezap/category/controller/CategoryControllerTest.java index 24f36b67c..cf12f97a0 100644 --- a/backend/src/test/java/codezap/category/controller/CategoryControllerTest.java +++ b/backend/src/test/java/codezap/category/controller/CategoryControllerTest.java @@ -76,7 +76,7 @@ void createCategoryFailWithNotLogin() throws Exception { @Test @DisplayName("카테고리 생성 실패: 카테고리 이름 길이 초과") - void createCategoryFailWithlongName() throws Exception { + void createCategoryFailWithLongName() throws Exception { CreateCategoryRequest createCategoryRequest = new CreateCategoryRequest("a".repeat(MAX_LENGTH + 1)); mvc.perform(post("/categories") @@ -84,7 +84,7 @@ void createCategoryFailWithlongName() throws Exception { .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(createCategoryRequest))) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.detail").value("카테고리 이름은 최대 255자까지 입력 가능합니다.")); + .andExpect(jsonPath("$.detail").value("카테고리 이름은 최대 15자까지 입력 가능합니다.")); } } diff --git a/backend/src/test/java/codezap/template/controller/TemplateControllerTest.java b/backend/src/test/java/codezap/template/controller/TemplateControllerTest.java index c7e75adba..ed5c5fa06 100644 --- a/backend/src/test/java/codezap/template/controller/TemplateControllerTest.java +++ b/backend/src/test/java/codezap/template/controller/TemplateControllerTest.java @@ -383,6 +383,28 @@ void createTemplateFailWithLongNullTags() throws Exception { .andExpect(jsonPath("$.detail").value("태그 목록이 null 입니다.")); } + @Test + @DisplayName("템플릿 생성 실패: 태그 목록에서 30자 초과인 태그 존재") + void createTemplateFailWithOverSizeTags() throws Exception { + String exceededTag = "a".repeat(31); + + CreateTemplateRequest templateRequest = new CreateTemplateRequest( + "title", + "description", + List.of(new CreateSourceCodeRequest("title", "sourceCode", 1)), + 1, + 1L, + List.of(exceededTag) + ); + + mvc.perform(post("/templates") + .cookie(cookie) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(templateRequest))) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.detail").value("태그 명은 최대 30자까지 입력 가능합니다.")); + } @ParameterizedTest @DisplayName("템플릿 생성 실패: 잘못된 소스 코드 순서 입력")