diff --git a/src/main/java/keeper/project/homepage/ctf/dto/CtfChallengeAdminDto.java b/src/main/java/keeper/project/homepage/ctf/dto/CtfChallengeAdminDto.java index 52633748..29b7aeba 100644 --- a/src/main/java/keeper/project/homepage/ctf/dto/CtfChallengeAdminDto.java +++ b/src/main/java/keeper/project/homepage/ctf/dto/CtfChallengeAdminDto.java @@ -1,12 +1,13 @@ package keeper.project.homepage.ctf.dto; +import static java.util.stream.Collectors.toList; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty.Access; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import java.time.LocalDateTime; import java.util.ArrayList; -import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity; import keeper.project.homepage.ctf.entity.CtfChallengeEntity; import keeper.project.homepage.ctf.entity.CtfChallengeTypeEntity; import keeper.project.homepage.ctf.entity.CtfContestEntity; @@ -38,12 +39,12 @@ public class CtfChallengeAdminDto extends CtfChallengeDto { private CtfDynamicChallengeInfoDto dynamicInfo; public CtfChallengeEntity toEntity(CtfContestEntity contest, CtfChallengeTypeEntity type, - CtfChallengeCategoryEntity category, FileEntity fileEntity, MemberEntity creator) { + FileEntity fileEntity, MemberEntity creator) { return CtfChallengeEntity.builder() .name(title) .description(content) .ctfContestEntity(contest) - .ctfChallengeCategoryEntity(category) + .ctfChallengeHasCtfChallengeCategoryList(new ArrayList<>()) .ctfChallengeTypeEntity(type) .isSolvable(isSolvable) .registerTime(LocalDateTime.now()) @@ -56,8 +57,6 @@ public CtfChallengeEntity toEntity(CtfContestEntity contest, CtfChallengeTypeEnt } public static CtfChallengeAdminDto toDto(CtfChallengeEntity challenge, Long solvedTeamCount) { - CtfChallengeCategoryDto category = CtfChallengeCategoryDto.toDto( - challenge.getCtfChallengeCategoryEntity()); CtfChallengeTypeDto type = CtfChallengeTypeDto.toDto( challenge.getCtfChallengeTypeEntity()); FileDto file = FileDto.toDto( @@ -70,7 +69,9 @@ public static CtfChallengeAdminDto toDto(CtfChallengeEntity challenge, Long solv .title(challenge.getName()) .content(challenge.getDescription()) .contestId(challenge.getCtfContestEntity().getId()) - .category(category) + .categories(challenge.getCtfChallengeHasCtfChallengeCategoryList().stream() + .map(CtfChallengeCategoryDto::toDto) + .collect(toList())) .type(type) .flag(getVirtualTeamFlag(challenge).getContent()) .isSolvable(challenge.getIsSolvable()) diff --git a/src/main/java/keeper/project/homepage/ctf/dto/CtfChallengeCategoryDto.java b/src/main/java/keeper/project/homepage/ctf/dto/CtfChallengeCategoryDto.java index 0f3a06e5..c087f6be 100644 --- a/src/main/java/keeper/project/homepage/ctf/dto/CtfChallengeCategoryDto.java +++ b/src/main/java/keeper/project/homepage/ctf/dto/CtfChallengeCategoryDto.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty.Access; import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity; +import keeper.project.homepage.ctf.entity.CtfChallengeHasCtfChallengeCategoryEntity; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -24,10 +25,24 @@ public class CtfChallengeCategoryDto { @JsonProperty(access = Access.READ_ONLY) private String name; + public static CtfChallengeCategoryEntity toEntity(CtfChallengeCategoryDto ctfChallengeCategoryDto){ + return CtfChallengeCategoryEntity.builder() + .id(ctfChallengeCategoryDto.getId()) + .name(ctfChallengeCategoryDto.getName()) + .build(); + } + public static CtfChallengeCategoryDto toDto(CtfChallengeCategoryEntity ctfChallengeCategoryEntity) { return CtfChallengeCategoryDto.builder() .id(ctfChallengeCategoryEntity.getId()) .name(ctfChallengeCategoryEntity.getName()) .build(); } + + public static CtfChallengeCategoryDto toDto(CtfChallengeHasCtfChallengeCategoryEntity ctfChallengeHasCtfChallengeCategoryEntity) { + return CtfChallengeCategoryDto.builder() + .id(ctfChallengeHasCtfChallengeCategoryEntity.getCategory().getId()) + .name(ctfChallengeHasCtfChallengeCategoryEntity.getCategory().getName()) + .build(); + } } diff --git a/src/main/java/keeper/project/homepage/ctf/dto/CtfChallengeDto.java b/src/main/java/keeper/project/homepage/ctf/dto/CtfChallengeDto.java index 410273db..29392815 100644 --- a/src/main/java/keeper/project/homepage/ctf/dto/CtfChallengeDto.java +++ b/src/main/java/keeper/project/homepage/ctf/dto/CtfChallengeDto.java @@ -1,7 +1,8 @@ package keeper.project.homepage.ctf.dto; +import static java.util.stream.Collectors.toList; + import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty.Access; import keeper.project.homepage.ctf.entity.CtfChallengeEntity; @@ -32,8 +33,6 @@ public class CtfChallengeDto extends CtfCommonChallengeDto { public static CtfChallengeDto toDto(CtfChallengeEntity challenge, Long solvedTeamCount, Boolean isSolved, CtfFlagEntity ctfFlagEntity) { - CtfChallengeCategoryDto category = CtfChallengeCategoryDto.toDto( - challenge.getCtfChallengeCategoryEntity()); FileDto file = FileDto.toDto(challenge.getFileEntity()); return CtfChallengeDto.builder() @@ -41,7 +40,10 @@ public static CtfChallengeDto toDto(CtfChallengeEntity challenge, Long solvedTea .title(challenge.getName()) .content(challenge.getDescription()) .contestId(challenge.getCtfContestEntity().getId()) - .category(category) + .categories(challenge.getCtfChallengeHasCtfChallengeCategoryList() + .stream() + .map(CtfChallengeCategoryDto::toDto) + .collect(toList())) .creatorName(challenge.getCreator().getNickName()) .score(challenge.getScore()) .solvedTeamCount(solvedTeamCount) diff --git a/src/main/java/keeper/project/homepage/ctf/dto/CtfCommonChallengeDto.java b/src/main/java/keeper/project/homepage/ctf/dto/CtfCommonChallengeDto.java index f69da1d1..41665309 100644 --- a/src/main/java/keeper/project/homepage/ctf/dto/CtfCommonChallengeDto.java +++ b/src/main/java/keeper/project/homepage/ctf/dto/CtfCommonChallengeDto.java @@ -1,10 +1,13 @@ package keeper.project.homepage.ctf.dto; +import static java.util.stream.Collectors.toList; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty.Access; import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.annotation.Nulls; import java.time.LocalDateTime; +import java.util.List; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import keeper.project.homepage.ctf.entity.CtfChallengeEntity; @@ -28,7 +31,7 @@ public class CtfCommonChallengeDto { protected String title; protected Long score; - protected CtfChallengeCategoryDto category; + protected List categories; protected Long contestId; @Max(MAX_SUBMIT_COUNT) @Min(MIN_SUBMIT_COUNT) @@ -48,14 +51,15 @@ public class CtfCommonChallengeDto { public static CtfCommonChallengeDto toDto(CtfChallengeEntity challenge, Boolean isSolved, CtfFlagEntity ctfFlagEntity) { - CtfChallengeCategoryDto category = CtfChallengeCategoryDto.toDto( - challenge.getCtfChallengeCategoryEntity()); return CtfCommonChallengeDto.builder() .challengeId(challenge.getId()) .title(challenge.getName()) .contestId(challenge.getCtfContestEntity().getId()) - .category(category) + .categories(challenge.getCtfChallengeHasCtfChallengeCategoryList() + .stream() + .map(CtfChallengeCategoryDto::toDto) + .collect(toList())) .score(challenge.getScore()) .isSolved(isSolved) .remainedSubmitCount(ctfFlagEntity.getRemainedSubmitCount()) diff --git a/src/main/java/keeper/project/homepage/ctf/entity/CtfChallengeEntity.java b/src/main/java/keeper/project/homepage/ctf/entity/CtfChallengeEntity.java index ce29bab4..873dcc6b 100644 --- a/src/main/java/keeper/project/homepage/ctf/entity/CtfChallengeEntity.java +++ b/src/main/java/keeper/project/homepage/ctf/entity/CtfChallengeEntity.java @@ -57,9 +57,9 @@ public class CtfChallengeEntity { @JoinColumn(name = "type_id", nullable = false) CtfChallengeTypeEntity ctfChallengeTypeEntity; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "category_id", nullable = false) - CtfChallengeCategoryEntity ctfChallengeCategoryEntity; + @Builder.Default + @OneToMany(mappedBy = "challenge", cascade = CascadeType.REMOVE) + List ctfChallengeHasCtfChallengeCategoryList = new ArrayList<>(); @Column(nullable = false) @Setter @@ -90,4 +90,8 @@ public class CtfChallengeEntity { @PrimaryKeyJoinColumn @Setter CtfDynamicChallengeInfoEntity dynamicChallengeInfoEntity; + + public void addCtfChallengeHasCtfChallengeCategory(CtfChallengeHasCtfChallengeCategoryEntity ctfChallengeHasCtfChallengeCategoryEntity) { + this.getCtfChallengeHasCtfChallengeCategoryList().add(ctfChallengeHasCtfChallengeCategoryEntity); + } } diff --git a/src/main/java/keeper/project/homepage/ctf/entity/CtfChallengeHasCtfChallengeCategoryEntity.java b/src/main/java/keeper/project/homepage/ctf/entity/CtfChallengeHasCtfChallengeCategoryEntity.java new file mode 100644 index 00000000..740b5609 --- /dev/null +++ b/src/main/java/keeper/project/homepage/ctf/entity/CtfChallengeHasCtfChallengeCategoryEntity.java @@ -0,0 +1,35 @@ +package keeper.project.homepage.ctf.entity; + +import java.io.Serializable; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Builder +@Entity +@Getter +@NoArgsConstructor +@AllArgsConstructor +@IdClass(CtfChallengeHasCtfChallengeCategoryEntityPK.class) // 정의한 idclass 주입 +@Table(name = "ctf_challenge_has_ctf_challenge_category") +public class CtfChallengeHasCtfChallengeCategoryEntity implements Serializable { + + @Id + @ManyToOne(targetEntity = CtfChallengeEntity.class, fetch = FetchType.LAZY) + @JoinColumn(name = "ctf_challenge_id") + private CtfChallengeEntity challenge; + + @Id + @ManyToOne(targetEntity = CtfChallengeCategoryEntity.class, fetch = FetchType.LAZY) + @JoinColumn(name = "ctf_challenge_category_id") + private CtfChallengeCategoryEntity category; + +} diff --git a/src/main/java/keeper/project/homepage/ctf/entity/CtfChallengeHasCtfChallengeCategoryEntityPK.java b/src/main/java/keeper/project/homepage/ctf/entity/CtfChallengeHasCtfChallengeCategoryEntityPK.java new file mode 100644 index 00000000..e80faa8e --- /dev/null +++ b/src/main/java/keeper/project/homepage/ctf/entity/CtfChallengeHasCtfChallengeCategoryEntityPK.java @@ -0,0 +1,19 @@ +package keeper.project.homepage.ctf.entity; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CtfChallengeHasCtfChallengeCategoryEntityPK implements Serializable { + + private Long challenge; + private Long category; +} diff --git a/src/main/java/keeper/project/homepage/ctf/repository/CtfChallengeHasCtfChallengeCategoryRepository.java b/src/main/java/keeper/project/homepage/ctf/repository/CtfChallengeHasCtfChallengeCategoryRepository.java new file mode 100644 index 00000000..0ebf9988 --- /dev/null +++ b/src/main/java/keeper/project/homepage/ctf/repository/CtfChallengeHasCtfChallengeCategoryRepository.java @@ -0,0 +1,10 @@ +package keeper.project.homepage.ctf.repository; + +import keeper.project.homepage.ctf.entity.CtfChallengeHasCtfChallengeCategoryEntity; +import keeper.project.homepage.ctf.entity.CtfChallengeHasCtfChallengeCategoryEntityPK; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface CtfChallengeHasCtfChallengeCategoryRepository extends + JpaRepository { + +} diff --git a/src/main/java/keeper/project/homepage/ctf/service/CtfAdminService.java b/src/main/java/keeper/project/homepage/ctf/service/CtfAdminService.java index 99207bad..8d7ef33b 100644 --- a/src/main/java/keeper/project/homepage/ctf/service/CtfAdminService.java +++ b/src/main/java/keeper/project/homepage/ctf/service/CtfAdminService.java @@ -8,12 +8,14 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; import keeper.project.homepage.ctf.dto.CtfChallengeAdminDto; +import keeper.project.homepage.ctf.dto.CtfChallengeCategoryDto; import keeper.project.homepage.ctf.dto.CtfContestAdminDto; import keeper.project.homepage.ctf.dto.CtfDynamicChallengeInfoDto; import keeper.project.homepage.ctf.dto.CtfProbMakerDto; import keeper.project.homepage.ctf.dto.CtfSubmitLogDto; import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity; import keeper.project.homepage.ctf.entity.CtfChallengeEntity; +import keeper.project.homepage.ctf.entity.CtfChallengeHasCtfChallengeCategoryEntity; import keeper.project.homepage.ctf.entity.CtfChallengeTypeEntity; import keeper.project.homepage.ctf.entity.CtfContestEntity; import keeper.project.homepage.ctf.entity.CtfDynamicChallengeInfoEntity; @@ -24,6 +26,7 @@ import keeper.project.homepage.ctf.exception.CustomCtfChallengeNotFoundException; import keeper.project.homepage.ctf.exception.CustomCtfTypeNotFoundException; import keeper.project.homepage.ctf.repository.CtfChallengeCategoryRepository; +import keeper.project.homepage.ctf.repository.CtfChallengeHasCtfChallengeCategoryRepository; import keeper.project.homepage.ctf.repository.CtfChallengeRepository; import keeper.project.homepage.ctf.repository.CtfChallengeTypeRepository; import keeper.project.homepage.ctf.repository.CtfContestRepository; @@ -63,6 +66,8 @@ public class CtfAdminService { private final CtfContestRepository ctfContestRepository; private final CtfTeamRepository ctfTeamRepository; private final CtfChallengeCategoryRepository ctfChallengeCategoryRepository; + + private final CtfChallengeHasCtfChallengeCategoryRepository ctfChallengeHasCtfChallengeCategoryRepository; private final CtfSubmitLogRepository ctfSubmitLogRepository; private final CtfChallengeTypeRepository ctfChallengeTypeRepository; private final CtfChallengeRepository challengeRepository; @@ -111,6 +116,8 @@ public CtfProbMakerDto designateProbMaker(CtfProbMakerDto probMakerDto) { @Transactional public CtfChallengeAdminDto createChallenge(CtfChallengeAdminDto challengeAdminDto) { CtfChallengeEntity newChallenge = createChallengeEntity(challengeAdminDto); + + setChallengeCategory(newChallenge, challengeAdminDto); if (ctfUtilService.isTypeDynamic(newChallenge)) { trySetDynamicInfoInChallenge(newChallenge, challengeAdminDto); } @@ -317,14 +324,32 @@ private Long getCtfId(CtfChallengeEntity challenge) { private CtfChallengeEntity createChallengeEntityWithFileEntity( CtfChallengeAdminDto challengeAdminDto, FileEntity fileEntity) { CtfContestEntity contest = getCtfContestEntity(challengeAdminDto.getContestId()); - CtfChallengeCategoryEntity category = getCategoryEntity(challengeAdminDto); + CtfChallengeTypeEntity type = getTypeEntity(challengeAdminDto); MemberEntity creator = authService.getMemberEntityWithJWT(); + CtfChallengeEntity challenge = challengeAdminDto - .toEntity(contest, type, category, fileEntity, creator); + .toEntity(contest, type, fileEntity, creator); + return challengeRepository.save(challenge); } + private void setChallengeCategory(CtfChallengeEntity challenge, + CtfChallengeAdminDto challengeAdminDto) { + List ctfChallengeCategoryEntityList = challengeAdminDto.getCategories() + .stream() + .map(CtfChallengeCategoryDto::toEntity).toList(); + + for (CtfChallengeCategoryEntity ctfChallengeCategory : ctfChallengeCategoryEntityList) { + challenge.addCtfChallengeHasCtfChallengeCategory(ctfChallengeHasCtfChallengeCategoryRepository + .save(CtfChallengeHasCtfChallengeCategoryEntity + .builder() + .challenge(challenge) + .category(ctfChallengeCategory) + .build())); + } + } + private CtfChallengeEntity createChallengeEntity(CtfChallengeAdminDto challengeAdminDto) { return createChallengeEntityWithFileEntity(challengeAdminDto, null); } @@ -335,9 +360,10 @@ private CtfChallengeTypeEntity getTypeEntity(CtfChallengeAdminDto challengeAdmin .orElseThrow(CustomCtfTypeNotFoundException::new); } - private CtfChallengeCategoryEntity getCategoryEntity(CtfChallengeAdminDto challengeAdminDto) { + private CtfChallengeCategoryEntity getCategoryEntity( + CtfChallengeCategoryDto ctfChallengeCategoryDto) { return ctfChallengeCategoryRepository - .findById(challengeAdminDto.getCategory().getId()) + .findById(ctfChallengeCategoryDto.getId()) .orElseThrow(CustomCtfCategoryNotFoundException::new); } diff --git a/src/test/java/keeper/project/homepage/ctf/controller/CtfAdminControllerTest.java b/src/test/java/keeper/project/homepage/ctf/controller/CtfAdminControllerTest.java index 5fe187aa..1cff6449 100644 --- a/src/test/java/keeper/project/homepage/ctf/controller/CtfAdminControllerTest.java +++ b/src/test/java/keeper/project/homepage/ctf/controller/CtfAdminControllerTest.java @@ -32,12 +32,15 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.util.ArrayList; +import java.util.List; import keeper.project.homepage.ctf.dto.CtfChallengeAdminDto; import keeper.project.homepage.ctf.dto.CtfChallengeCategoryDto; import keeper.project.homepage.ctf.dto.CtfChallengeTypeDto; import keeper.project.homepage.ctf.dto.CtfContestAdminDto; import keeper.project.homepage.ctf.dto.CtfDynamicChallengeInfoDto; import keeper.project.homepage.ctf.dto.CtfProbMakerDto; +import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory; import keeper.project.homepage.ctf.entity.CtfChallengeEntity; import keeper.project.homepage.ctf.entity.CtfContestEntity; import keeper.project.homepage.ctf.entity.CtfFlagEntity; @@ -267,8 +270,10 @@ private boolean isDisqualifyProbMakerRole(MemberEntity probMaker, MemberJobEntit @Test @DisplayName("출제자 권한으로 문제 생성 - 성공") public void createProblemSuccess() throws Exception { - CtfChallengeCategoryDto category = CtfChallengeCategoryDto.toDto( - ctfChallengeCategoryRepository.getById(FORENSIC.getId())); + List categories = new ArrayList<>(); + categories.add(FORENSIC); + categories.add(MISC); + CtfChallengeTypeDto type = CtfChallengeTypeDto.toDto( ctfChallengeTypeRepository.getById(DYNAMIC.getId())); MemberEntity creator = generateMemberEntity(출제자, 정회원, 일반회원); @@ -288,7 +293,7 @@ public void createProblemSuccess() throws Exception { Long score = 1234L; String flag = "flag{keeper}"; CtfChallengeAdminDto challenge = generateCtfChallengeAdminDto(35L, - category, type, creator, title, content, isSolvable, score, flag, dynamicInfo); + categories, type, creator, title, content, isSolvable, score, flag, dynamicInfo); mockMvc.perform(post("/v1/admin/ctf/prob") .header("Authorization", creatorToken) @@ -301,7 +306,8 @@ public void createProblemSuccess() throws Exception { .andExpect(jsonPath("$.data.title").value(title)) .andExpect(jsonPath("$.data.content").value(content)) .andExpect(jsonPath("$.data.contestId").value(contestEntity.getId())) - .andExpect(jsonPath("$.data.category.id").value(category.getId())) + .andExpect(jsonPath("$.data.categories[0].id").value(categories.get(0).getId())) + .andExpect(jsonPath("$.data.categories[1].id").value(categories.get(1).getId())) .andExpect(jsonPath("$.data.type.id").value(type.getId())) .andExpect(jsonPath("$.data.isSolvable").value(isSolvable)) .andExpect(jsonPath("$.data.creatorName").value(creator.getNickName())) @@ -314,7 +320,7 @@ public void createProblemSuccess() throws Exception { fieldWithPath("title").description("문제 제목"), fieldWithPath("content").description("문제 내용"), fieldWithPath("contestId").description("문제가 등록 될 CTF id"), - fieldWithPath("category.id").description("문제 카테고리 Id"), + fieldWithPath("categories[].id").description("문제 카테고리 Id"), fieldWithPath("type.id").description("문제 Type Id"), fieldWithPath("isSolvable").description("현재 풀 수 있는 지 여부"), fieldWithPath("score").description( @@ -343,8 +349,10 @@ public void createProblemSuccess() throws Exception { @Test @DisplayName("회장 권한으로 STANDARD 문제 생성 - 성공") public void createStandardProblemSuccess() throws Exception { - CtfChallengeCategoryDto category = CtfChallengeCategoryDto.toDto( - ctfChallengeCategoryRepository.getById(FORENSIC.getId())); + + List categories = new ArrayList<>(); + categories.add(FORENSIC); + CtfChallengeTypeDto type = CtfChallengeTypeDto.toDto( ctfChallengeTypeRepository.getById(STANDARD.getId())); MemberEntity creator = generateMemberEntity(출제자, 정회원, 일반회원); @@ -357,7 +365,7 @@ public void createStandardProblemSuccess() throws Exception { Long score = 1234L; String flag = "flag{keeper}"; CtfChallengeAdminDto challenge = generateCtfChallengeAdminDto(35L, - category, type, creator, title, content, isSolvable, score, flag); + categories, type, creator, title, content, isSolvable, score, flag); createChallengeControllerTest(challenge) .andExpect(status().isOk()) @@ -366,7 +374,7 @@ public void createStandardProblemSuccess() throws Exception { .andExpect(jsonPath("$.data.title").value(title)) .andExpect(jsonPath("$.data.content").value(content)) .andExpect(jsonPath("$.data.contestId").value(contestEntity.getId())) - .andExpect(jsonPath("$.data.category.id").value(category.getId())) + .andExpect(jsonPath("$.data.categories[0].id").value(categories.get(0).getId())) .andExpect(jsonPath("$.data.type.id").value(type.getId())) .andExpect(jsonPath("$.data.isSolvable").value(isSolvable)) .andExpect(jsonPath("$.data.creatorName").value(adminEntity.getNickName())) @@ -377,8 +385,9 @@ public void createStandardProblemSuccess() throws Exception { @Test @DisplayName("문제 생성 시 maxSubmitCount를 넣지 않을 경우 default value가 들어가야 한다.") public void createProblem_maxSubmitCount_defaultValue() throws Exception { - CtfChallengeCategoryDto category = CtfChallengeCategoryDto.toDto( - ctfChallengeCategoryRepository.getById(FORENSIC.getId())); + List categories = new ArrayList<>(); + categories.add(FORENSIC); + CtfChallengeTypeDto type = CtfChallengeTypeDto.toDto( ctfChallengeTypeRepository.getById(STANDARD.getId())); MemberEntity creator = generateMemberEntity(출제자, 정회원, 일반회원); @@ -392,7 +401,7 @@ public void createProblem_maxSubmitCount_defaultValue() throws Exception { String flag = "flag{keeper}"; CtfChallengeAdminDto challenge = generateCtfChallengeAdminDto( - null, category, type, creator, title, content, isSolvable, score, flag); + null, categories, type, creator, title, content, isSolvable, score, flag); createChallengeControllerTest(challenge) .andExpect(status().isOk()) @@ -401,7 +410,7 @@ public void createProblem_maxSubmitCount_defaultValue() throws Exception { .andExpect(jsonPath("$.data.title").value(title)) .andExpect(jsonPath("$.data.content").value(content)) .andExpect(jsonPath("$.data.contestId").value(contestEntity.getId())) - .andExpect(jsonPath("$.data.category.id").value(category.getId())) + .andExpect(jsonPath("$.data.categories[0].id").value(categories.get(0).getId())) .andExpect(jsonPath("$.data.type.id").value(type.getId())) .andExpect(jsonPath("$.data.isSolvable").value(isSolvable)) .andExpect(jsonPath("$.data.creatorName").value(adminEntity.getNickName())) @@ -423,8 +432,10 @@ private ResultActions createChallengeControllerTest(CtfChallengeAdminDto challen @ValueSource(longs = {-10, 0, 1, 3, 15, 45, 50, 51, 123, Integer.MAX_VALUE}) @DisplayName("회장 권한으로 STANDARD 문제 생성 - 성공") public void createProblem_maxSubmitCount_validValue(long maxSubmitCount) throws Exception { - CtfChallengeCategoryDto category = CtfChallengeCategoryDto.toDto( - ctfChallengeCategoryRepository.getById(FORENSIC.getId())); + + List categories = new ArrayList<>(); + categories.add(FORENSIC); + CtfChallengeTypeDto type = CtfChallengeTypeDto.toDto( ctfChallengeTypeRepository.getById(STANDARD.getId())); MemberEntity creator = generateMemberEntity(출제자, 정회원, 일반회원); @@ -437,7 +448,7 @@ public void createProblem_maxSubmitCount_validValue(long maxSubmitCount) throws Long score = 1234L; String flag = "flag{keeper}"; CtfChallengeAdminDto challenge = generateCtfChallengeAdminDto( - maxSubmitCount, category, type, creator, title, content, isSolvable, score, flag); + maxSubmitCount, categories, type, creator, title, content, isSolvable, score, flag); if (MIN_SUBMIT_COUNT <= maxSubmitCount && maxSubmitCount <= MAX_SUBMIT_COUNT) { createChallengeControllerTest(challenge) @@ -447,7 +458,7 @@ public void createProblem_maxSubmitCount_validValue(long maxSubmitCount) throws .andExpect(jsonPath("$.data.title").value(title)) .andExpect(jsonPath("$.data.content").value(content)) .andExpect(jsonPath("$.data.contestId").value(contestEntity.getId())) - .andExpect(jsonPath("$.data.category.id").value(category.getId())) + .andExpect(jsonPath("$.data.categories[0].id").value(categories.get(0).getId())) .andExpect(jsonPath("$.data.type.id").value(type.getId())) .andExpect(jsonPath("$.data.isSolvable").value(isSolvable)) .andExpect(jsonPath("$.data.creatorName").value(adminEntity.getNickName())) @@ -463,21 +474,30 @@ public void createProblem_maxSubmitCount_validValue(long maxSubmitCount) throws } private CtfChallengeAdminDto generateCtfChallengeAdminDto(Long maxSubmitCount, - CtfChallengeCategoryDto category, CtfChallengeTypeDto type, MemberEntity creator, + List categories, CtfChallengeTypeDto type, MemberEntity creator, String title, String content, Boolean isSolvable, Long score, String flag) { return generateCtfChallengeAdminDto( - maxSubmitCount, category, type, creator, title, content, isSolvable, score, flag, null); + maxSubmitCount, categories, type, creator, title, content, isSolvable, score, flag, null); } private CtfChallengeAdminDto generateCtfChallengeAdminDto(Long maxSubmitCount, - CtfChallengeCategoryDto category, CtfChallengeTypeDto type, MemberEntity creator, + List categories, CtfChallengeTypeDto type, MemberEntity creator, String title, String content, Boolean isSolvable, Long score, String flag, CtfDynamicChallengeInfoDto dynamicInfo) { + + List categoryDtos = categories + .stream() + .map(ctfChallengeCategory -> CtfChallengeCategoryDto + .builder() + .id(ctfChallengeCategory.getId()) + .name(ctfChallengeCategory.getName()).build()) + .toList(); + CtfChallengeAdminDto challenge = CtfChallengeAdminDto.builder() .title(title) .content(content) .contestId(contestEntity.getId()) - .category(category) + .categories(categoryDtos) .type(type) .isSolvable(isSolvable) .creatorName(creator.getNickName()) @@ -495,8 +515,12 @@ public void fileRegistrationInProblemSuccess() throws Exception { MockMultipartFile file = new MockMultipartFile("file", "image.png", "image/png", "<>".getBytes()); Long score = 1234L; + + List categories = new ArrayList<>(); + categories.add(FORENSIC); + CtfChallengeEntity challenge = generateCtfChallenge( - contestEntity, DYNAMIC, FORENSIC, score, true); + contestEntity, DYNAMIC, categories, score, true); mockMvc.perform(multipart("/v1/admin/ctf/prob/file") .file(file) .param("challengeId", String.valueOf(challenge.getId())) @@ -523,13 +547,14 @@ public void fileRegistrationInProblemSuccess() throws Exception { @Test @DisplayName("문제 오픈 - 성공") public void openProblemSuccess() throws Exception { - + List categories = new ArrayList<>(); + categories.add(FORENSIC); MemberEntity creator = generateMemberEntity(출제자, 정회원, 일반회원); Long teamScore = 0L; Long score = 1234L; CtfTeamEntity team = generateCtfTeam(contestEntity, creator, teamScore); CtfChallengeEntity challenge = generateCtfChallenge( - contestEntity, STANDARD, MISC, score, false); + contestEntity, STANDARD, categories, score, false); generateCtfFlag(team, challenge, false); mockMvc.perform(patch("/v1/admin/ctf/prob/{pid}/open", challenge.getId()) @@ -557,13 +582,14 @@ public void openProblemSuccess() throws Exception { @Test @DisplayName("문제 닫기 - 성공") public void closeProblemSuccess() throws Exception { - MemberEntity creator = generateMemberEntity(출제자, 정회원, 일반회원); Long teamScore = 0L; Long score = 1234L; CtfTeamEntity team = generateCtfTeam(contestEntity, creator, teamScore); + List categories = new ArrayList<>(); + categories.add(MISC); CtfChallengeEntity challenge = generateCtfChallenge( - contestEntity, STANDARD, MISC, score, false); + contestEntity, STANDARD, categories, score, false); generateCtfFlag(team, challenge, false); mockMvc.perform(patch("/v1/admin/ctf/prob/{pid}/close", challenge.getId()) @@ -596,7 +622,9 @@ public void deleteProblemSuccess() throws Exception { Long teamScore = 0L; Long score = 1234L; CtfTeamEntity team = generateCtfTeam(contestEntity, creator, teamScore); - CtfChallengeEntity challenge = generateCtfChallenge(contestEntity, STANDARD, MISC, score, true); + List categories = new ArrayList<>(); + categories.add(MISC); + CtfChallengeEntity challenge = generateCtfChallenge(contestEntity, STANDARD, categories, score, true); generateCtfFlag(team, challenge, false); // when @@ -634,8 +662,12 @@ public void deleteStandardProblemScoreRollbackSuccess() throws Exception { Long teamScore = 0L; Long score = 1234L; CtfTeamEntity team = generateCtfTeam(contestEntity, creator, teamScore); + + List categories = new ArrayList<>(); + categories.add(MISC); + CtfChallengeEntity challenge = generateCtfChallenge( - contestEntity, STANDARD, MISC, score, true); + contestEntity, STANDARD, categories, score, true); CtfFlagEntity flag = generateCtfFlag(team, challenge, false); // when @@ -672,8 +704,12 @@ public void deleteDynamicProblemScoreRollbackSuccess() throws Exception { Long teamScore = 0L; Long score = 1234L; CtfTeamEntity team = generateCtfTeam(contestEntity, creator, teamScore); + + List categories = new ArrayList<>(); + categories.add(MISC); + CtfChallengeEntity challenge = generateCtfChallenge(contestEntity, - DYNAMIC, MISC, score, true); + DYNAMIC, categories, score, true); Long maxScore = 2000L; Long minScore = 100L; generateDynamicChallengeInfo(challenge, maxScore, minScore); @@ -736,20 +772,28 @@ public void getProblemListSuccess() throws Exception { Long teamScore = 0L; Long score = 1234L; CtfTeamEntity team = generateCtfTeam(contestEntity, creator, teamScore); - CtfChallengeEntity challenge = generateCtfChallenge( - contestEntity, STANDARD, MISC, score, false); + + List categories1 = new ArrayList<>(); + categories1.add(MISC); + + CtfChallengeEntity challenge1 = generateCtfChallenge( + contestEntity, STANDARD, categories1, score, false); + + List categories2 = new ArrayList<>(); + categories2.add(FORENSIC); + CtfChallengeEntity challenge2 = generateCtfChallenge( - contestEntity, DYNAMIC, FORENSIC, score, false); + contestEntity, DYNAMIC, categories2, score, false); generateDynamicChallengeInfo(challenge2, 1000L, 100L); generateCtfFlag(team, challenge2, false); - generateCtfFlag(team, challenge, false); + generateCtfFlag(team, challenge1, false); // when MockMultipartFile file = new MockMultipartFile("file", "image.png", "image/png", "<>".getBytes()); mockMvc.perform(multipart("/v1/admin/ctf/prob/file") .file(file) - .param("challengeId", String.valueOf(challenge.getId())) + .param("challengeId", String.valueOf(challenge1.getId())) .param("page", "0") .param("size", "10") .header("Authorization", adminToken) @@ -783,10 +827,16 @@ public void getSubmitLogListSuccess() throws Exception { Long teamScore = 0L; Long score = 1234L; CtfTeamEntity team = generateCtfTeam(contestEntity, creator, teamScore); + List categories1 = new ArrayList<>(); + categories1.add(MISC); + CtfChallengeEntity challenge = generateCtfChallenge( - contestEntity, STANDARD, MISC, score, false); + contestEntity, STANDARD, categories1, score, false); + + List categories2 = new ArrayList<>(); + categories2.add(FORENSIC); CtfChallengeEntity challenge2 = generateCtfChallenge( - contestEntity, DYNAMIC, FORENSIC, score, false); + contestEntity, DYNAMIC, categories2, score, false); generateDynamicChallengeInfo(challenge2, 1000L, 100L); generateCtfFlag(team, challenge2, false); generateCtfFlag(team, challenge, false); diff --git a/src/test/java/keeper/project/homepage/ctf/controller/CtfChallengeControllerTest.java b/src/test/java/keeper/project/homepage/ctf/controller/CtfChallengeControllerTest.java index bad60c13..09839e52 100644 --- a/src/test/java/keeper/project/homepage/ctf/controller/CtfChallengeControllerTest.java +++ b/src/test/java/keeper/project/homepage/ctf/controller/CtfChallengeControllerTest.java @@ -19,6 +19,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity; +import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory; import keeper.project.homepage.ctf.entity.CtfChallengeEntity; import keeper.project.homepage.ctf.entity.CtfContestEntity; import keeper.project.homepage.ctf.entity.CtfFlagEntity; @@ -54,13 +58,14 @@ public void getProblemListSuccess() throws Exception { CtfContestEntity contest = generateCtfContest(adminEntity, true); Long score = 1000L; - + List categories = new ArrayList<>(); + categories.add(MISC); CtfChallengeEntity dynamicChallenge = generateCtfChallenge( - contest, DYNAMIC, FORENSIC, score, true); + contest, DYNAMIC, categories, score, true); CtfChallengeEntity standardChallenge = generateCtfChallenge( - contest, STANDARD, MISC, score, true); + contest, STANDARD, categories, score, true); CtfChallengeEntity notSolvable = generateCtfChallenge( - contest, DYNAMIC, WEB, score, false); + contest, DYNAMIC, categories, score, false); CtfTeamEntity team = generateCtfTeam(contest, userEntity, 0L); @@ -79,8 +84,8 @@ public void getProblemListSuccess() throws Exception { .andExpect(jsonPath("$.list[0].content").doesNotExist()) .andExpect(jsonPath("$.list[0].contestId") .value(dynamicChallenge.getCtfContestEntity().getId())) - .andExpect(jsonPath("$.list[0].category.id") - .value(dynamicChallenge.getCtfChallengeCategoryEntity().getId())) + .andExpect(jsonPath("$.list[0].categories[0].id") + .value(categories.get(0).getId())) .andExpect(jsonPath("$.list[0].type.id").doesNotExist()) .andExpect(jsonPath("$.list[0].isSolvable").doesNotExist()) .andExpect(jsonPath("$.list[0].score").value(dynamicChallenge.getScore())) @@ -91,8 +96,8 @@ public void getProblemListSuccess() throws Exception { .andExpect(jsonPath("$.list[1].content").doesNotExist()) .andExpect(jsonPath("$.list[1].contestId") .value(standardChallenge.getCtfContestEntity().getId())) - .andExpect(jsonPath("$.list[1].category.id") - .value(standardChallenge.getCtfChallengeCategoryEntity().getId())) + .andExpect(jsonPath("$.list[1].categories[0].id") + .value(categories.get(0).getId())) .andExpect(jsonPath("$.list[1].type.id").doesNotExist()) .andExpect(jsonPath("$.list[1].isSolvable").doesNotExist()) .andExpect(jsonPath("$.list[1].score").value(standardChallenge.getScore())) @@ -116,11 +121,14 @@ public void getProblemListSuccess_lastTryTimeNullable() throws Exception { CtfContestEntity contest = generateCtfContest(adminEntity, true); Long score = 1000L; + List categories = new ArrayList<>(); + + categories.add(FORENSIC); CtfChallengeEntity dynamicChallenge = generateCtfChallenge( - contest, DYNAMIC, FORENSIC, score, true); + contest, DYNAMIC, categories, score, true); CtfChallengeEntity standardChallenge = generateCtfChallenge( - contest, STANDARD, MISC, score, true); + contest, STANDARD, categories, score, true); CtfTeamEntity team = generateCtfTeam(contest, userEntity, 0L); @@ -148,8 +156,11 @@ public void checkFlagSuccess() throws Exception { Long maxScore = 1234L; Long minScore = 567L; + List categories = new ArrayList<>(); + categories.add(FORENSIC); + CtfChallengeEntity dynamicChallenge = generateCtfChallenge( - contest, DYNAMIC, FORENSIC, score, true); + contest, DYNAMIC, categories, score, true); generateDynamicChallengeInfo(dynamicChallenge, maxScore, minScore); CtfTeamEntity team = generateCtfTeam(contest, userEntity, 0L); @@ -193,9 +204,10 @@ public void checkFlagFailedByNotEnoughSubmitCount() throws Exception { Long score = 1000L; Long maxScore = 1234L; Long minScore = 567L; - + List categories = new ArrayList<>(); + categories.add(FORENSIC); CtfChallengeEntity dynamicChallenge = generateCtfChallenge( - contest, DYNAMIC, FORENSIC, score, true); + contest, DYNAMIC, categories, score, true); generateDynamicChallengeInfo(dynamicChallenge, maxScore, minScore); CtfTeamEntity team = generateCtfTeam(contest, userEntity, 0L); CtfFlagEntity flag = generateCtfFlag(team, dynamicChallenge, false, 0L); @@ -220,9 +232,10 @@ public void getProblemDetailSuccess() throws Exception { CtfContestEntity contest = generateCtfContest(adminEntity, true); Long score = 1000L; - + List categories = new ArrayList<>(); + categories.add(FORENSIC); CtfChallengeEntity dynamicChallenge = generateCtfChallenge( - contest, DYNAMIC, FORENSIC, score, true); + contest, DYNAMIC, categories, score, true); generateFileInChallenge(dynamicChallenge); CtfTeamEntity team = generateCtfTeam(contest, userEntity, 0L); @@ -239,8 +252,8 @@ public void getProblemDetailSuccess() throws Exception { .andExpect(jsonPath("$.data.content").value(dynamicChallenge.getDescription())) .andExpect(jsonPath("$.data.contestId") .value(dynamicChallenge.getCtfContestEntity().getId())) - .andExpect(jsonPath("$.data.category.id") - .value(dynamicChallenge.getCtfChallengeCategoryEntity().getId())) + .andExpect(jsonPath("$.data.categories[0].id") + .value(categories.get(0).getId())) .andExpect(jsonPath("$.data.type.id").doesNotExist()) .andExpect(jsonPath("$.data.isSolvable").doesNotExist()) .andExpect( diff --git a/src/test/java/keeper/project/homepage/ctf/controller/CtfSpringTestHelper.java b/src/test/java/keeper/project/homepage/ctf/controller/CtfSpringTestHelper.java index cfd5adff..4bececce 100644 --- a/src/test/java/keeper/project/homepage/ctf/controller/CtfSpringTestHelper.java +++ b/src/test/java/keeper/project/homepage/ctf/controller/CtfSpringTestHelper.java @@ -1,5 +1,6 @@ package keeper.project.homepage.ctf.controller; +import static java.util.stream.Collectors.toList; import static keeper.project.homepage.ctf.service.CtfChallengeService.RETRY_SECONDS; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath; @@ -13,6 +14,7 @@ import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity; import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory; import keeper.project.homepage.ctf.entity.CtfChallengeEntity; +import keeper.project.homepage.ctf.entity.CtfChallengeHasCtfChallengeCategoryEntity; import keeper.project.homepage.ctf.entity.CtfChallengeTypeEntity; import keeper.project.homepage.ctf.entity.CtfChallengeTypeEntity.CtfChallengeType; import keeper.project.homepage.ctf.entity.CtfContestEntity; @@ -22,6 +24,7 @@ import keeper.project.homepage.ctf.entity.CtfTeamEntity; import keeper.project.homepage.ctf.entity.CtfTeamHasMemberEntity; import keeper.project.homepage.ctf.repository.CtfChallengeCategoryRepository; +import keeper.project.homepage.ctf.repository.CtfChallengeHasCtfChallengeCategoryRepository; import keeper.project.homepage.ctf.repository.CtfChallengeRepository; import keeper.project.homepage.ctf.repository.CtfChallengeTypeRepository; import keeper.project.homepage.ctf.repository.CtfContestRepository; @@ -42,6 +45,9 @@ public class CtfSpringTestHelper extends ApiControllerTestHelper { @Autowired protected CtfChallengeCategoryRepository ctfChallengeCategoryRepository; + @Autowired + protected CtfChallengeHasCtfChallengeCategoryRepository ctfChallengeHasCtfChallengeCategoryRepository; + @Autowired protected CtfChallengeTypeRepository ctfChallengeTypeRepository; @@ -182,14 +188,13 @@ protected CtfTeamEntity generateCtfTeam(CtfContestEntity ctfContestEntity, Membe protected CtfChallengeEntity generateCtfChallenge( CtfContestEntity ctfContestEntity, CtfChallengeType ctfChallengeType, - CtfChallengeCategory ctfChallengeCategory, + List category, Long score, boolean isSolvable) { final long epochTime = System.nanoTime(); CtfChallengeTypeEntity ctfChallengeTypeEntity = ctfChallengeTypeRepository.getById( ctfChallengeType.getId()); - CtfChallengeCategoryEntity ctfChallengeCategoryEntity = ctfChallengeCategoryRepository.getById( - ctfChallengeCategory.getId()); + CtfChallengeEntity entity = CtfChallengeEntity.builder() .name("name_" + epochTime) .description("desc_" + epochTime) @@ -197,13 +202,32 @@ protected CtfChallengeEntity generateCtfChallenge( .creator(memberRepository.getById(1L)) // Virtual Member .isSolvable(isSolvable) .ctfChallengeTypeEntity(ctfChallengeTypeEntity) - .ctfChallengeCategoryEntity(ctfChallengeCategoryEntity) + .ctfChallengeHasCtfChallengeCategoryList(new ArrayList<>()) .score(score) .ctfContestEntity(ctfContestEntity) .ctfFlagEntity(new ArrayList<>()) .maxSubmitCount(100L) .build(); ctfChallengeRepository.save(entity); + + List ctfChallengeCategoryEntityList = category + .stream() + .map(ctfChallengeCategory -> CtfChallengeCategoryEntity + .builder() + .id(ctfChallengeCategory.getId()) + .name(ctfChallengeCategory.getName()) + .build()) + .toList(); + + for (CtfChallengeCategoryEntity ctfChallengeCategory : ctfChallengeCategoryEntityList) { + CtfChallengeHasCtfChallengeCategoryEntity save = ctfChallengeHasCtfChallengeCategoryRepository.save( + CtfChallengeHasCtfChallengeCategoryEntity.builder() + .challenge(entity) + .category(ctfChallengeCategory) + .build()); + entity.getCtfChallengeHasCtfChallengeCategoryList().add(save); + } + return entity; } @@ -284,8 +308,8 @@ protected List generateChallengeCommonDtoResponseFields(Respons commonFields.addAll(Arrays.asList( fieldWithPath(prefix + ".challengeId").description("해당 문제의 Id"), fieldWithPath(prefix + ".title").description("문제 제목"), - fieldWithPath(prefix + ".category.id").description("문제가 속한 카테고리의 id"), - fieldWithPath(prefix + ".category.name").description("문제가 속한 카테고리의 이름"), + fieldWithPath(prefix + ".categories[].id").description("문제가 속한 카테고리의 id"), + fieldWithPath(prefix + ".categories[].name").description("문제가 속한 카테고리의 이름"), fieldWithPath(prefix + ".score").description("문제의 점수"), fieldWithPath(prefix + ".isSolved").description("내가 풀었는 지"), fieldWithPath(prefix + ".maxSubmitCount").description("최대 제출 횟수"), @@ -315,8 +339,8 @@ protected List generateChallengeAdminDtoResponseFields(Response fieldWithPath(prefix + ".challengeId").description("해당 문제의 Id"), fieldWithPath(prefix + ".title").description("문제 제목"), fieldWithPath(prefix + ".content").description("문제 설명"), - fieldWithPath(prefix + ".category.id").description("문제가 속한 카테고리의 id"), - fieldWithPath(prefix + ".category.name").description("문제가 속한 카테고리의 이름"), + fieldWithPath(prefix + ".categories[].id").description("문제가 속한 카테고리의 id"), + fieldWithPath(prefix + ".categories[].name").description("문제가 속한 카테고리의 이름"), fieldWithPath(prefix + ".type.id").description("문제가 속한 타입의 id"), fieldWithPath(prefix + ".type.name").description("문제가 속한 타입의 이름"), fieldWithPath(prefix + ".flag").description("문제에 설정 된 flag (현재는 모든 팀이 동일한 flag를 가집니다."), @@ -370,8 +394,8 @@ protected List generateChallengeDtoResponseFields(ResponseType fieldWithPath(prefix + ".challengeId").description("해당 문제의 Id"), fieldWithPath(prefix + ".title").description("문제 제목"), fieldWithPath(prefix + ".content").description("문제 설명"), - fieldWithPath(prefix + ".category.id").description("문제가 속한 카테고리의 id"), - fieldWithPath(prefix + ".category.name").description("문제가 속한 카테고리의 이름"), + fieldWithPath(prefix + ".categories[].id").description("문제가 속한 카테고리의 id"), + fieldWithPath(prefix + ".categories[].name").description("문제가 속한 카테고리의 이름"), fieldWithPath(prefix + ".score").description("문제의 점수"), fieldWithPath(prefix + ".creatorName").description("문제 생성자 이름"), fieldWithPath(prefix + ".contestId").description("문제의 대회 Id"), @@ -548,7 +572,8 @@ protected List generateTeamDetailDtoResponseFields(ResponseType fieldWithPath(prefix + ".creatorId").description("team 생성자 Id"), fieldWithPath(prefix + ".contestId").description("team이 속한 contest Id"), subsectionWithPath(prefix + ".teamMembers").description("team에 속한 팀원 정보"), - subsectionWithPath(prefix + ".solvedChallengeList").description("team이 푼 문제들 정보 (푼 문제이므로 남은 제출 횟수가 0으로 표기되어 나갑니다.)") + subsectionWithPath(prefix + ".solvedChallengeList").description( + "team이 푼 문제들 정보 (푼 문제이므로 남은 제출 횟수가 0으로 표기되어 나갑니다.)") )); commonFields.addAll(generateTeamDtoResponseFields(type, success, code, msg)); if (addDescriptors.length > 0) { diff --git a/src/test/java/keeper/project/homepage/ctf/controller/CtfTeamControllerTest.java b/src/test/java/keeper/project/homepage/ctf/controller/CtfTeamControllerTest.java index cbe7e733..e6a71227 100644 --- a/src/test/java/keeper/project/homepage/ctf/controller/CtfTeamControllerTest.java +++ b/src/test/java/keeper/project/homepage/ctf/controller/CtfTeamControllerTest.java @@ -1,5 +1,6 @@ package keeper.project.homepage.ctf.controller; +import static keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory.FORENSIC; import static keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory.MISC; import static keeper.project.homepage.ctf.entity.CtfChallengeTypeEntity.CtfChallengeType.STANDARD; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; @@ -17,7 +18,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import keeper.project.homepage.ctf.controller.CtfSpringTestHelper; +import java.util.ArrayList; +import java.util.List; +import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory; import keeper.project.homepage.ctf.entity.CtfChallengeEntity; import keeper.project.homepage.ctf.entity.CtfContestEntity; import keeper.project.homepage.ctf.entity.CtfTeamEntity; @@ -189,8 +192,9 @@ void getTeamDetail() throws Exception { .build(); ctfTeamHasMemberRepository.save(teamHasMemberEntity); team.getCtfTeamHasMemberEntityList().add(teamHasMemberEntity); - - CtfChallengeEntity challenge = generateCtfChallenge(contestEntity, STANDARD, MISC, 1234L, + List categories = new ArrayList<>(); + categories.add(MISC); + CtfChallengeEntity challenge = generateCtfChallenge(contestEntity, STANDARD, categories, 1234L, false); generateCtfFlag(team, challenge, true); diff --git a/src/test/java/keeper/project/homepage/ctf/repository/CtfChallengeRepositoryTest.java b/src/test/java/keeper/project/homepage/ctf/repository/CtfChallengeRepositoryTest.java index bd903705..31d42685 100644 --- a/src/test/java/keeper/project/homepage/ctf/repository/CtfChallengeRepositoryTest.java +++ b/src/test/java/keeper/project/homepage/ctf/repository/CtfChallengeRepositoryTest.java @@ -27,8 +27,6 @@ public void saveChallengeList() { boolean isSolvable = true; CtfChallengeTypeEntity ctfChallengeTypeEntity = ctfChallengeTypeRepository.getById( STANDARD.getId()); - CtfChallengeCategoryEntity ctfChallengeCategoryEntity = ctfChallengeCategoryRepository.getById( - SYSTEM.getId()); Long score = 1000L; CtfContestEntity contest = generateCtfContest(member); @@ -40,7 +38,7 @@ public void saveChallengeList() { .creator(member) // Virtual Member .isSolvable(isSolvable) .ctfChallengeTypeEntity(ctfChallengeTypeEntity) - .ctfChallengeCategoryEntity(ctfChallengeCategoryEntity) + .ctfChallengeHasCtfChallengeCategoryList(new ArrayList<>()) .score(score) .ctfContestEntity(contest) .ctfFlagEntity(new ArrayList<>()) @@ -55,7 +53,6 @@ public void saveChallengeList() { assertThat(findChallenge.getCreator()).isEqualTo(member); assertThat(findChallenge.getIsSolvable()).isEqualTo(isSolvable); assertThat(findChallenge.getCtfChallengeTypeEntity()).isEqualTo(ctfChallengeTypeEntity); - assertThat(findChallenge.getCtfChallengeCategoryEntity()).isEqualTo(ctfChallengeCategoryEntity); assertThat(findChallenge.getScore()).isEqualTo(score); assertThat(findChallenge.getCtfContestEntity()).isEqualTo(contest); } @@ -71,8 +68,6 @@ public void saveLargeDescriptionChallengeList() { boolean isSolvable = true; CtfChallengeTypeEntity ctfChallengeTypeEntity = ctfChallengeTypeRepository.getById( STANDARD.getId()); - CtfChallengeCategoryEntity ctfChallengeCategoryEntity = ctfChallengeCategoryRepository.getById( - SYSTEM.getId()); Long score = 1000L; CtfContestEntity contest = generateCtfContest(member); @@ -84,7 +79,7 @@ public void saveLargeDescriptionChallengeList() { .creator(member) // Virtual Member .isSolvable(isSolvable) .ctfChallengeTypeEntity(ctfChallengeTypeEntity) - .ctfChallengeCategoryEntity(ctfChallengeCategoryEntity) + .ctfChallengeHasCtfChallengeCategoryList(new ArrayList<>()) .score(score) .ctfContestEntity(contest) .ctfFlagEntity(new ArrayList<>()) @@ -99,7 +94,6 @@ public void saveLargeDescriptionChallengeList() { assertThat(findChallenge.getCreator()).isEqualTo(member); assertThat(findChallenge.getIsSolvable()).isEqualTo(isSolvable); assertThat(findChallenge.getCtfChallengeTypeEntity()).isEqualTo(ctfChallengeTypeEntity); - assertThat(findChallenge.getCtfChallengeCategoryEntity()).isEqualTo(ctfChallengeCategoryEntity); assertThat(findChallenge.getScore()).isEqualTo(score); assertThat(findChallenge.getCtfContestEntity()).isEqualTo(contest); } diff --git a/src/test/java/keeper/project/homepage/ctf/repository/CtfFlagRepositoryTest.java b/src/test/java/keeper/project/homepage/ctf/repository/CtfFlagRepositoryTest.java index 64bc1ada..aff43d89 100644 --- a/src/test/java/keeper/project/homepage/ctf/repository/CtfFlagRepositoryTest.java +++ b/src/test/java/keeper/project/homepage/ctf/repository/CtfFlagRepositoryTest.java @@ -6,7 +6,12 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity; +import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory; import keeper.project.homepage.ctf.entity.CtfChallengeEntity; +import keeper.project.homepage.ctf.entity.CtfChallengeHasCtfChallengeCategoryEntity; import keeper.project.homepage.ctf.entity.CtfContestEntity; import keeper.project.homepage.ctf.entity.CtfFlagEntity; import keeper.project.homepage.ctf.entity.CtfTeamEntity; @@ -30,7 +35,8 @@ private CtfFlagEntity generateFlag(long remainedSubmitCount) { MemberEntity member = memberRepository.getById(1L); CtfContestEntity contest = generateCtfContest(member); CtfTeamEntity ctfTeam = generateCtfTeam(contest, member, 0L); - CtfChallengeEntity ctfChallenge = generateCtfChallenge(contest, STANDARD, MISC, 1000L); + + CtfChallengeEntity ctfChallenge = generateCtfChallenge(contest, STANDARD, 1000L); return CtfFlagEntity.builder() .content(content) .ctfTeamEntity(ctfTeam) diff --git a/src/test/java/keeper/project/homepage/ctf/repository/CtfSubmitLogRepositoryTest.java b/src/test/java/keeper/project/homepage/ctf/repository/CtfSubmitLogRepositoryTest.java index e6e78277..3d7e9414 100644 --- a/src/test/java/keeper/project/homepage/ctf/repository/CtfSubmitLogRepositoryTest.java +++ b/src/test/java/keeper/project/homepage/ctf/repository/CtfSubmitLogRepositoryTest.java @@ -5,6 +5,8 @@ import static org.assertj.core.api.Assertions.assertThat; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory; import keeper.project.homepage.ctf.entity.CtfChallengeEntity; import keeper.project.homepage.ctf.entity.CtfContestEntity; @@ -26,7 +28,8 @@ void testContest() { MemberEntity member = memberRepository.getById(1L); CtfContestEntity contest = generateCtfContest(member); CtfTeamEntity ctfTeam = generateCtfTeam(contest, member, 0L); - CtfChallengeEntity ctfChallenge = generateCtfChallenge(contest, STANDARD, MISC, 1000L); + + CtfChallengeEntity ctfChallenge = generateCtfChallenge(contest, STANDARD, 1000L); // when CtfSubmitLogEntity submitLog = CtfSubmitLogEntity.builder() diff --git a/src/test/java/keeper/project/homepage/ctf/repository/CtfTestHelper.java b/src/test/java/keeper/project/homepage/ctf/repository/CtfTestHelper.java index 50d8d4c0..fadfdf81 100644 --- a/src/test/java/keeper/project/homepage/ctf/repository/CtfTestHelper.java +++ b/src/test/java/keeper/project/homepage/ctf/repository/CtfTestHelper.java @@ -3,6 +3,8 @@ import static java.time.LocalDateTime.now; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity; import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory; import keeper.project.homepage.ctf.entity.CtfChallengeEntity; @@ -111,13 +113,12 @@ protected CtfTeamEntity generateCtfTeam(CtfContestEntity ctfContestEntity, Membe protected CtfChallengeEntity generateCtfChallenge( CtfContestEntity ctfContestEntity, CtfChallengeType ctfChallengeType, - CtfChallengeCategory ctfChallengeCategory, Long score) { final long epochTime = System.nanoTime(); CtfChallengeTypeEntity ctfChallengeTypeEntity = ctfChallengeTypeRepository.getById( ctfChallengeType.getId()); - CtfChallengeCategoryEntity ctfChallengeCategoryEntity = ctfChallengeCategoryRepository.getById( - ctfChallengeCategory.getId()); + + CtfChallengeEntity entity = CtfChallengeEntity.builder() .name("name_" + epochTime) .description("desc_" + epochTime) @@ -125,11 +126,12 @@ protected CtfChallengeEntity generateCtfChallenge( .creator(memberRepository.getById(1L)) // Virtual Member .isSolvable(false) .ctfChallengeTypeEntity(ctfChallengeTypeEntity) - .ctfChallengeCategoryEntity(ctfChallengeCategoryEntity) + .ctfChallengeHasCtfChallengeCategoryList(new ArrayList<>()) .score(score) .ctfContestEntity(ctfContestEntity) .maxSubmitCount(123L) .build(); + ctfChallengeRepository.save(entity); return entity; } diff --git a/src/test/java/keeper/project/homepage/ctf/service/CtfAdminServiceTest.java b/src/test/java/keeper/project/homepage/ctf/service/CtfAdminServiceTest.java index 49c39f6f..f921d745 100644 --- a/src/test/java/keeper/project/homepage/ctf/service/CtfAdminServiceTest.java +++ b/src/test/java/keeper/project/homepage/ctf/service/CtfAdminServiceTest.java @@ -4,12 +4,14 @@ import static keeper.project.homepage.ApiControllerTestHelper.MemberJobName.회장; import static keeper.project.homepage.ApiControllerTestHelper.MemberRankName.일반회원; import static keeper.project.homepage.ApiControllerTestHelper.MemberTypeName.정회원; +import static keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory.FORENSIC; import static keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory.WEB; import static keeper.project.homepage.ctf.entity.CtfChallengeTypeEntity.CtfChallengeType.DYNAMIC; import static keeper.project.homepage.ctf.entity.CtfChallengeTypeEntity.CtfChallengeType.STANDARD; import static org.assertj.core.api.Assertions.assertThat; import java.nio.file.AccessDeniedException; +import java.util.ArrayList; import java.util.List; import java.util.UUID; import javax.persistence.EntityManager; @@ -20,6 +22,7 @@ import keeper.project.homepage.ctf.dto.CtfDynamicChallengeInfoDto; import keeper.project.homepage.ctf.dto.CtfFlagDto; import keeper.project.homepage.ctf.dto.CtfTeamDetailDto; +import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory; import keeper.project.homepage.ctf.entity.CtfContestEntity; import keeper.project.homepage.ctf.entity.CtfFlagEntity; import keeper.project.homepage.member.entity.MemberEntity; @@ -65,9 +68,12 @@ private static void setAuthentication(MemberEntity contestCreator, MemberJobName } @Test - @DisplayName("문제 생성 테스트") + @DisplayName("문제 생성 테스트 - 카테고리 1개") void createChallenge() { - CtfChallengeAdminDto result = createStandardChallenge(1234L, "flag", "content", "title", 123L); + List categories = new ArrayList<>(); + categories.add(WEB); + CtfChallengeAdminDto result = createStandardChallenge(1234L, "flag", "content", "title", + categories, 123L); CtfFlagEntity flag = ctfFlagRepository.findByCtfChallengeEntityIdAndCtfTeamEntityId( result.getChallengeId(), CtfUtilService.VIRTUAL_TEAM_ID).orElseThrow(); @@ -79,19 +85,58 @@ void createChallenge() { assertThat(result.getContent()).isEqualTo("content"); assertThat(result.getTitle()).isEqualTo("title"); assertThat(result.getScore()).isEqualTo(1234L); - assertThat(result.getCategory().getId()).isEqualTo(getWebCategory().getId()); + assertThat(result.getCategories().get(0).getId()).isEqualTo(categories.get(0).getId()); + assertThat(result.getCategories().size()).isEqualTo(1); assertThat(result.getContestId()).isEqualTo(ctfContestEntity.getId()); assertThat(flag.getRemainedSubmitCount()).isEqualTo(123L); assertThat(flag.getIsCorrect()).isEqualTo(false); } - private CtfChallengeAdminDto createStandardChallenge(long score) { - return createStandardChallenge(score, getRandomUUID(), getRandomUUID(), getRandomUUID(), 15L); + @Test + @DisplayName("문제 생성 테스트 - 카테고리 2개이상") + void createChallengeHasManyCategory() { + List categories = new ArrayList<>(); + categories.add(WEB); + categories.add(FORENSIC); + CtfChallengeAdminDto result = createStandardChallenge(1234L, "flag", "content", "title", + categories, 123L); + CtfFlagEntity flag = ctfFlagRepository.findByCtfChallengeEntityIdAndCtfTeamEntityId( + result.getChallengeId(), CtfUtilService.VIRTUAL_TEAM_ID).orElseThrow(); + + assertThat(result.getFlag()).isEqualTo("flag"); + assertThat(result.getRemainedSubmitCount()).isEqualTo(123L); + assertThat(result.getType().getId()).isEqualTo(getStandardType().getId()); + assertThat(result.getDynamicInfo().getMaxScore()).isNull(); + assertThat(result.getDynamicInfo().getMinScore()).isNull(); + assertThat(result.getContent()).isEqualTo("content"); + assertThat(result.getTitle()).isEqualTo("title"); + assertThat(result.getScore()).isEqualTo(1234L); + assertThat(result.getCategories().get(0).getId()).isEqualTo(categories.get(0).getId()); + assertThat(result.getCategories().get(1).getId()).isEqualTo(categories.get(1).getId()); + assertThat(result.getCategories().size()).isEqualTo(2); + assertThat(result.getContestId()).isEqualTo(ctfContestEntity.getId()); + assertThat(flag.getRemainedSubmitCount()).isEqualTo(123L); + assertThat(flag.getIsCorrect()).isEqualTo(false); + } + + private CtfChallengeAdminDto createStandardChallenge(long score, + List categories) { + return createStandardChallenge(score, getRandomUUID(), getRandomUUID(), getRandomUUID(), + categories, 15L); } private CtfChallengeAdminDto createStandardChallenge(long score, String flag, String content, - String title, long maxSubmitCount) { + String title, List categories, long maxSubmitCount) { setAuthentication(contestCreator, 회장); + + List categoryDtos = categories + .stream() + .map(ctfChallengeCategory -> CtfChallengeCategoryDto + .builder() + .id(ctfChallengeCategory.getId()) + .name(ctfChallengeCategory.getName()).build()) + .toList(); + CtfChallengeAdminDto challengeAdminDto = CtfChallengeAdminDto.builder() .isSolvable(true) .flag(flag) @@ -100,7 +145,7 @@ private CtfChallengeAdminDto createStandardChallenge(long score, String flag, St .content(content) .title(title) .score(score) - .category(getWebCategory()) + .categories(categoryDtos) .contestId(ctfContestEntity.getId()) .maxSubmitCount(maxSubmitCount) .build(); @@ -116,6 +161,18 @@ private CtfChallengeAdminDto createDynamicChallenge(CtfDynamicChallengeInfoDto d private CtfChallengeAdminDto createDynamicChallenge(CtfDynamicChallengeInfoDto dynamicScore, String flag, String content, String title, long maxSubmitCount) { setAuthentication(contestCreator, 회장); + + List categories = new ArrayList<>(); + categories.add(WEB); + + List categoryDtos = categories + .stream() + .map(ctfChallengeCategory -> CtfChallengeCategoryDto + .builder() + .id(ctfChallengeCategory.getId()) + .name(ctfChallengeCategory.getName()).build()) + .toList(); + CtfChallengeAdminDto challengeAdminDto = CtfChallengeAdminDto.builder() .isSolvable(true) .flag(flag) @@ -124,7 +181,7 @@ private CtfChallengeAdminDto createDynamicChallenge(CtfDynamicChallengeInfoDto d .content(content) .title(title) .score(0L) - .category(getWebCategory()) + .categories(categoryDtos) .contestId(ctfContestEntity.getId()) .maxSubmitCount(maxSubmitCount) .build(); @@ -132,13 +189,6 @@ private CtfChallengeAdminDto createDynamicChallenge(CtfDynamicChallengeInfoDto d return ctfAdminService.createChallenge(challengeAdminDto); } - private static CtfChallengeCategoryDto getWebCategory() { - return CtfChallengeCategoryDto.builder() - .id(WEB.getId()) - .name(WEB.getName()) - .build(); - } - private static CtfChallengeTypeDto getStandardType() { return CtfChallengeTypeDto.builder() .id(STANDARD.getId()) @@ -156,9 +206,11 @@ private static CtfChallengeTypeDto getDynamicType() { @Test @DisplayName("[시나리오1] STANDRAD 문제 삭제 시 점수 반영 제대로 되는지 테스트") void deleteProblem_scenario1() { - CtfChallengeAdminDto challenge1 = createStandardChallenge(100L); - CtfChallengeAdminDto challenge2 = createStandardChallenge(200L); - CtfChallengeAdminDto challenge3 = createStandardChallenge(400L); + List categories = new ArrayList<>(); + categories.add(WEB); + CtfChallengeAdminDto challenge1 = createStandardChallenge(100L, categories); + CtfChallengeAdminDto challenge2 = createStandardChallenge(200L, categories); + CtfChallengeAdminDto challenge3 = createStandardChallenge(400L, categories); MemberEntity user1 = generateMemberEntity(회원, 정회원, 일반회원); CtfTeamDetailDto team1 = createCtfTeam(user1); // 1번, 2번 문제 해결 @@ -192,7 +244,7 @@ void deleteProblem_scenario1() { assertThat(ctfTeamRepository.getById(team2.getId()).getScore()).isEqualTo(400L); assertThat(ctfTeamRepository.getById(team3.getId()).getScore()).isEqualTo(400L); - CtfChallengeAdminDto challenge4 = createStandardChallenge(800L); + CtfChallengeAdminDto challenge4 = createStandardChallenge(800L, categories); assertThat(solveChallenge(challenge4, user1)).isTrue(); assertThat(solveChallenge(challenge4, user2)).isTrue(); diff --git a/src/test/java/keeper/project/homepage/ctf/service/CtfChallengeServiceTest.java b/src/test/java/keeper/project/homepage/ctf/service/CtfChallengeServiceTest.java index 400db93e..cbd3a296 100644 --- a/src/test/java/keeper/project/homepage/ctf/service/CtfChallengeServiceTest.java +++ b/src/test/java/keeper/project/homepage/ctf/service/CtfChallengeServiceTest.java @@ -13,9 +13,12 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; import keeper.project.homepage.ctf.controller.CtfSpringTestHelper; import keeper.project.homepage.ctf.dto.CtfFlagDto; +import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity; +import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory; import keeper.project.homepage.ctf.entity.CtfChallengeEntity; import keeper.project.homepage.ctf.entity.CtfContestEntity; import keeper.project.homepage.ctf.entity.CtfFlagEntity; @@ -50,7 +53,9 @@ void setCtfChallenge() { Long score = 1000L; Long maxScore = 1234L; Long minScore = 567L; - dynamicChallenge = generateCtfChallenge(contest, DYNAMIC, FORENSIC, score, true); + List categories = new ArrayList<>(); + categories.add(FORENSIC); + dynamicChallenge = generateCtfChallenge(contest, DYNAMIC, categories, score, true); generateDynamicChallengeInfo(dynamicChallenge, maxScore, minScore); teamEntity = generateCtfTeam(contest, userEntity, 0L); setAuthentication(userEntity, "ROLE_회원"); diff --git a/src/test/java/keeper/project/homepage/ctf/service/CtfServiceTest.java b/src/test/java/keeper/project/homepage/ctf/service/CtfServiceTest.java index f4652d0d..8cfd094f 100644 --- a/src/test/java/keeper/project/homepage/ctf/service/CtfServiceTest.java +++ b/src/test/java/keeper/project/homepage/ctf/service/CtfServiceTest.java @@ -7,6 +7,7 @@ import static keeper.project.homepage.ctf.entity.CtfChallengeTypeEntity.CtfChallengeType.STANDARD; import static org.assertj.core.api.Assertions.assertThat; +import java.util.ArrayList; import java.util.List; import keeper.project.homepage.ctf.controller.CtfSpringTestHelper; import keeper.project.homepage.ctf.dto.CtfChallengeAdminDto; @@ -14,6 +15,7 @@ import keeper.project.homepage.ctf.dto.CtfChallengeTypeDto; import keeper.project.homepage.ctf.dto.CtfFlagDto; import keeper.project.homepage.ctf.dto.CtfTeamDetailDto; +import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory; import keeper.project.homepage.ctf.entity.CtfContestEntity; import keeper.project.homepage.ctf.entity.CtfFlagEntity; import keeper.project.homepage.ctf.entity.CtfSubmitLogEntity; @@ -155,6 +157,14 @@ private CtfChallengeAdminDto createChallenge(Long contestId, MemberEntity member new UsernamePasswordAuthenticationToken(member.getId(), member.getPassword(), List.of(new SimpleGrantedAuthority("ROLE_회원")))); final long epochTime = System.nanoTime(); + + List categories = new ArrayList<>(); + categories.add(MISC); + + List categoryDtos = categories.stream().map( + ctfChallengeCategory -> CtfChallengeCategoryDto.builder().id(ctfChallengeCategory.getId()) + .name(ctfChallengeCategory.getName()).build()).toList(); + CtfChallengeAdminDto createChallenge = CtfChallengeAdminDto.builder() .title("TITLE_" + epochTime) .content("CONTENT_" + epochTime) @@ -165,9 +175,7 @@ private CtfChallengeAdminDto createChallenge(Long contestId, MemberEntity member .type(CtfChallengeTypeDto.builder() .id(STANDARD.getId()) .build()) - .category(CtfChallengeCategoryDto.builder() - .id(MISC.getId()) - .build()) + .categories(categoryDtos) .maxSubmitCount(100L) .build(); return ctfAdminService.createChallenge(createChallenge); diff --git a/src/test/java/keeper/project/homepage/ctf/service/CtfTeamServiceTest.java b/src/test/java/keeper/project/homepage/ctf/service/CtfTeamServiceTest.java index ff8a1185..0be2d65f 100644 --- a/src/test/java/keeper/project/homepage/ctf/service/CtfTeamServiceTest.java +++ b/src/test/java/keeper/project/homepage/ctf/service/CtfTeamServiceTest.java @@ -4,12 +4,14 @@ import static keeper.project.homepage.ctf.entity.CtfChallengeTypeEntity.CtfChallengeType.STANDARD; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; import keeper.project.homepage.ctf.controller.CtfSpringTestHelper; import keeper.project.homepage.ctf.dto.CtfChallengeAdminDto; import keeper.project.homepage.ctf.dto.CtfChallengeCategoryDto; import keeper.project.homepage.ctf.dto.CtfChallengeTypeDto; import keeper.project.homepage.ctf.dto.CtfTeamDetailDto; +import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory; import keeper.project.homepage.ctf.entity.CtfContestEntity; import keeper.project.homepage.member.entity.MemberEntity; import org.assertj.core.api.Assertions; @@ -174,14 +176,24 @@ void leaveTeam() { String testFlag = "testFlag"; Long testScore = 1234L; + List categories = new ArrayList<>(); + categories.add(SYSTEM); + + List categoryDtos = categories + .stream() + .map(ctfChallengeCategory -> CtfChallengeCategoryDto + .builder() + .id(ctfChallengeCategory.getId()) + .name(ctfChallengeCategory.getName()).build()) + .toList(); + CtfChallengeAdminDto createChallengeInfo = CtfChallengeAdminDto.builder() .content(testContent) .contestId(contest.getId()) .flag(testFlag) .isSolvable(true) .type(CtfChallengeTypeDto.builder().id(STANDARD.getId()).build()) - .category( - CtfChallengeCategoryDto.builder().id(SYSTEM.getId()).build()) + .categories(categoryDtos) .title(testTitle) .score(testScore) .maxSubmitCount(123L) diff --git a/src/test/java/keeper/project/homepage/util/service/CtfUtilServiceTest.java b/src/test/java/keeper/project/homepage/util/service/CtfUtilServiceTest.java index 3ebf3770..11f2fb64 100644 --- a/src/test/java/keeper/project/homepage/util/service/CtfUtilServiceTest.java +++ b/src/test/java/keeper/project/homepage/util/service/CtfUtilServiceTest.java @@ -10,6 +10,9 @@ import java.util.List; import java.util.stream.IntStream; import keeper.project.homepage.ctf.controller.CtfSpringTestHelper; +import keeper.project.homepage.ctf.dto.CtfChallengeCategoryDto; +import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity; +import keeper.project.homepage.ctf.entity.CtfChallengeCategoryEntity.CtfChallengeCategory; import keeper.project.homepage.ctf.entity.CtfChallengeEntity; import keeper.project.homepage.ctf.entity.CtfContestEntity; import keeper.project.homepage.ctf.entity.CtfFlagEntity; @@ -55,8 +58,10 @@ void setUp() { validTeamList.add(generateCtfTeam(validCtf, generateMemberEntity(회원, 정회원, 일반회원), 0L))); validChallengeList = new ArrayList<>(); + List categories = new ArrayList<>(); + categories.add(FORENSIC); IntStream.range(0, VALID_CHALLENGE_COUNT).forEach(n -> { - CtfChallengeEntity challenge = generateCtfChallenge(validCtf, DYNAMIC, FORENSIC, 0L, true); + CtfChallengeEntity challenge = generateCtfChallenge(validCtf, DYNAMIC, categories, 0L, true); generateDynamicChallengeInfo(challenge, 1000L, 100L); validChallengeList.add(challenge); });