From 9747ad13549b833dd3b47c7910b616343f22896f Mon Sep 17 00:00:00 2001 From: skytin1004 Date: Thu, 22 Feb 2024 18:54:17 +0900 Subject: [PATCH] =?UTF-8?q?[feature/Inhabas#234]=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EB=A6=AC=ED=8E=99=ED=86=A0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/contest/domain/ContestBoard.java | 5 +- .../domain/valueObject/ContestType.java | 20 +- .../contest/dto/ContestBoardDetailDto.java | 6 +- .../contest/dto/SaveContestBoardDto.java | 7 +- .../ContestBoardRepositoryCustom.java | 6 +- .../ContestBoardRepositoryImpl.java | 50 ++++- .../contest/usecase/ContestBoardService.java | 10 +- .../usecase/ContestBoardServiceImpl.java | 122 +++++------ .../api/web/ContestBoardController.java | 136 ++++++------ .../contest/domain/ContestBoardTest.java | 85 ++++---- .../dto/ContestBoardDetailDtoTest.java | 97 +++++++++ .../contest/dto/SaveContestBoardDtoTest.java | 20 +- .../usecase/ContestBoardServiceImplTest.java | 204 ++++++++++++++++++ .../usecase/ContestBoardServiceTest.java | 184 ---------------- .../domain/menu/domain/MenuExampleTest.java | 4 + .../valueObject/MenuGroupExampleTest.java | 4 + 16 files changed, 566 insertions(+), 394 deletions(-) create mode 100644 resource-server/src/test/java/com/inhabas/api/domain/contest/dto/ContestBoardDetailDtoTest.java create mode 100644 resource-server/src/test/java/com/inhabas/api/domain/contest/usecase/ContestBoardServiceImplTest.java delete mode 100644 resource-server/src/test/java/com/inhabas/api/domain/contest/usecase/ContestBoardServiceTest.java diff --git a/resource-server/src/main/java/com/inhabas/api/domain/contest/domain/ContestBoard.java b/resource-server/src/main/java/com/inhabas/api/domain/contest/domain/ContestBoard.java index 2a1eeaaa..154df325 100644 --- a/resource-server/src/main/java/com/inhabas/api/domain/contest/domain/ContestBoard.java +++ b/resource-server/src/main/java/com/inhabas/api/domain/contest/domain/ContestBoard.java @@ -29,6 +29,7 @@ import com.inhabas.api.domain.contest.domain.valueObject.ContestType; import com.inhabas.api.domain.contest.domain.valueObject.Topic; import com.inhabas.api.domain.file.domain.BoardFile; +import com.inhabas.api.domain.menu.domain.Menu; @Entity @Table(name = "CONTEST_BOARD") @@ -71,7 +72,7 @@ public String getContent() { @Builder public ContestBoard( - ContestType contestType, + Menu menu, Long contestFieldId, String title, String content, @@ -80,7 +81,7 @@ public ContestBoard( LocalDate dateContestStart, LocalDate dateContestEnd) { - this.contestType = contestType; + super(title, menu); this.contestField = new ContestField(contestFieldId); this.title = new Title(title); this.content = new Content(content); diff --git a/resource-server/src/main/java/com/inhabas/api/domain/contest/domain/valueObject/ContestType.java b/resource-server/src/main/java/com/inhabas/api/domain/contest/domain/valueObject/ContestType.java index 43e827f5..ddd935de 100644 --- a/resource-server/src/main/java/com/inhabas/api/domain/contest/domain/valueObject/ContestType.java +++ b/resource-server/src/main/java/com/inhabas/api/domain/contest/domain/valueObject/ContestType.java @@ -1,6 +1,22 @@ package com.inhabas.api.domain.contest.domain.valueObject; public enum ContestType { - CONTEST, // 공모전 - ACTIVITY // 대외활동 + CONTEST("contest", 18), + ACTIVITY("activity", 19); + + private final String boardType; + private final int menuId; + + ContestType(String boardType, int menuId) { + this.boardType = boardType; + this.menuId = menuId; + } + + public String getBoardType() { + return boardType; + } + + public int getMenuId() { + return menuId; + } } diff --git a/resource-server/src/main/java/com/inhabas/api/domain/contest/dto/ContestBoardDetailDto.java b/resource-server/src/main/java/com/inhabas/api/domain/contest/dto/ContestBoardDetailDto.java index c3add923..33658e8f 100644 --- a/resource-server/src/main/java/com/inhabas/api/domain/contest/dto/ContestBoardDetailDto.java +++ b/resource-server/src/main/java/com/inhabas/api/domain/contest/dto/ContestBoardDetailDto.java @@ -23,7 +23,7 @@ public class ContestBoardDetailDto { @NotNull @Positive private Long id; - @NotNull private Long contestField; + @NotNull private Long contestFieldId; @NotBlank private String title; @@ -60,7 +60,7 @@ public class ContestBoardDetailDto { @Builder public ContestBoardDetailDto( Long id, - Long contestField, + Long contestFieldId, String title, String content, String writerName, @@ -74,7 +74,7 @@ public ContestBoardDetailDto( List images, List otherFiles) { this.id = id; - this.contestField = contestField; + this.contestFieldId = contestFieldId; this.title = title; this.content = content; this.writerName = writerName; diff --git a/resource-server/src/main/java/com/inhabas/api/domain/contest/dto/SaveContestBoardDto.java b/resource-server/src/main/java/com/inhabas/api/domain/contest/dto/SaveContestBoardDto.java index 6f6a6244..e977e824 100644 --- a/resource-server/src/main/java/com/inhabas/api/domain/contest/dto/SaveContestBoardDto.java +++ b/resource-server/src/main/java/com/inhabas/api/domain/contest/dto/SaveContestBoardDto.java @@ -8,24 +8,19 @@ import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; -import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.web.multipart.MultipartFile; -import com.inhabas.api.domain.contest.domain.valueObject.ContestType; import org.hibernate.validator.constraints.Length; // 공모전 게시판 글 업데이트 및 저장 @Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) +@NoArgsConstructor() public class SaveContestBoardDto { - @NotNull(message = "공모전 게시판 타입을 선택해주세요.") - private ContestType contestType; - @NotNull(message = "공모전 분야를 선택해주세요.") private Long contestFieldId; diff --git a/resource-server/src/main/java/com/inhabas/api/domain/contest/repository/ContestBoardRepositoryCustom.java b/resource-server/src/main/java/com/inhabas/api/domain/contest/repository/ContestBoardRepositoryCustom.java index 75c21d4f..3316526e 100644 --- a/resource-server/src/main/java/com/inhabas/api/domain/contest/repository/ContestBoardRepositoryCustom.java +++ b/resource-server/src/main/java/com/inhabas/api/domain/contest/repository/ContestBoardRepositoryCustom.java @@ -1,12 +1,16 @@ package com.inhabas.api.domain.contest.repository; import java.util.List; +import java.util.Optional; import com.inhabas.api.domain.contest.domain.ContestBoard; import com.inhabas.api.domain.contest.domain.valueObject.ContestType; +import com.inhabas.api.domain.contest.dto.ContestBoardDto; public interface ContestBoardRepositoryCustom { - List findAllByContestTypeAndFieldLike( + List findAllByTypeAndFieldAndSearch( ContestType contestType, Long contestFieldId, String search, String sortBy); + + public Optional findByTypeAndId(ContestType contestType, Long boardId); } diff --git a/resource-server/src/main/java/com/inhabas/api/domain/contest/repository/ContestBoardRepositoryImpl.java b/resource-server/src/main/java/com/inhabas/api/domain/contest/repository/ContestBoardRepositoryImpl.java index 68607e79..c7ad2703 100644 --- a/resource-server/src/main/java/com/inhabas/api/domain/contest/repository/ContestBoardRepositoryImpl.java +++ b/resource-server/src/main/java/com/inhabas/api/domain/contest/repository/ContestBoardRepositoryImpl.java @@ -1,15 +1,21 @@ package com.inhabas.api.domain.contest.repository; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.BiFunction; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import com.inhabas.api.domain.contest.domain.ContestBoard; import com.inhabas.api.domain.contest.domain.QContestBoard; import com.inhabas.api.domain.contest.domain.valueObject.ContestType; +import com.inhabas.api.domain.contest.dto.ContestBoardDto; +import com.inhabas.api.global.util.ClassifiedFiles; +import com.inhabas.api.global.util.ClassifyFiles; import com.querydsl.core.types.Order; import com.querydsl.core.types.OrderSpecifier; import com.querydsl.core.types.dsl.BooleanExpression; @@ -37,11 +43,11 @@ private OrderSpecifier getSortedColumn( } // 공모전 검색 및 필터링 기능 - public List findAllByContestTypeAndFieldLike( + public List findAllByTypeAndFieldAndSearch( ContestType contestType, Long contestFieldId, String search, String sortBy) { BooleanExpression target = - contestTypeEq(contestType) - .and(contestFieldEq(contestFieldId)) + eqContestType(contestType) + .and(eqContestField(contestFieldId)) .and( titleLike(search) .or(contentLike(search)) @@ -56,14 +62,46 @@ public List findAllByContestTypeAndFieldLike( query.orderBy(contestBoard.dateContestEnd.desc()); // 마감순: dateContestEnd 순으로 내림차순 정렬 } - return query.fetch(); + List boards = query.fetch(); + + return boards.stream() + .map( + board -> { + ClassifiedFiles classifiedFiles = + ClassifyFiles.classifyFiles(new ArrayList<>(board.getFiles())); + return ContestBoardDto.builder() + .id(board.getId()) + .contestFieldId(board.getContestField().getId()) + .title(board.getTitle()) + .topic(board.getTopic()) + .association(board.getAssociation()) + .dateContestStart(board.getDateContestStart()) + .dateContestEnd(board.getDateContestEnd()) + .thumbnail(classifiedFiles.getThumbnail()) + .build(); + }) + .collect(Collectors.toList()); } - private BooleanExpression contestTypeEq(ContestType contestType) { + @Override + public Optional findByTypeAndId(ContestType contestType, Long boardId) { + return Optional.ofNullable( + queryFactory + .selectFrom(contestBoard) + .where((eqContestType(contestType)).and(contestBoard.id.eq(boardId))) + .orderBy(contestBoard.dateCreated.desc()) + .fetchOne()); + } + + private BooleanExpression eqMemberId(Long memberId) { + return contestBoard.writer.id.eq(memberId); + } + + private BooleanExpression eqContestType(ContestType contestType) { return contestBoard.contestType.eq(contestType); } - private BooleanExpression contestFieldEq(Long contestFieldId) { + private BooleanExpression eqContestField(Long contestFieldId) { if (contestFieldId == null) { return null; } diff --git a/resource-server/src/main/java/com/inhabas/api/domain/contest/usecase/ContestBoardService.java b/resource-server/src/main/java/com/inhabas/api/domain/contest/usecase/ContestBoardService.java index b8b52edb..1a794c3b 100644 --- a/resource-server/src/main/java/com/inhabas/api/domain/contest/usecase/ContestBoardService.java +++ b/resource-server/src/main/java/com/inhabas/api/domain/contest/usecase/ContestBoardService.java @@ -9,15 +9,17 @@ public interface ContestBoardService { - List getContestBoardsByType( + List getContestBoards( ContestType contestType, Long contestFieldId, String search, String sortBy); Long writeContestBoard( - Long memberId, SaveContestBoardDto saveContestBoardDto, ContestType contestType); + Long memberId, ContestType contestType, SaveContestBoardDto saveContestBoardDto); - ContestBoardDetailDto getContestBoard(Long boardId); + // 공모전 게시판 단일조회 + ContestBoardDetailDto getContestBoard(ContestType contestType, Long boardId); - void updateContestBoard(Long boardId, SaveContestBoardDto saveContestBoardDto); + void updateContestBoard( + Long boardId, ContestType contestType, SaveContestBoardDto saveContestBoardDto); void deleteContestBoard(Long boardId); } diff --git a/resource-server/src/main/java/com/inhabas/api/domain/contest/usecase/ContestBoardServiceImpl.java b/resource-server/src/main/java/com/inhabas/api/domain/contest/usecase/ContestBoardServiceImpl.java index a7c5133a..783f25d8 100644 --- a/resource-server/src/main/java/com/inhabas/api/domain/contest/usecase/ContestBoardServiceImpl.java +++ b/resource-server/src/main/java/com/inhabas/api/domain/contest/usecase/ContestBoardServiceImpl.java @@ -1,10 +1,13 @@ package com.inhabas.api.domain.contest.usecase; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -14,7 +17,6 @@ import com.inhabas.api.auth.domain.oauth2.member.domain.exception.MemberNotFoundException; import com.inhabas.api.auth.domain.oauth2.member.repository.MemberRepository; import com.inhabas.api.domain.board.exception.S3UploadFailedException; -import com.inhabas.api.domain.board.usecase.BoardSecurityChecker; import com.inhabas.api.domain.contest.domain.ContestBoard; import com.inhabas.api.domain.contest.domain.valueObject.ContestType; import com.inhabas.api.domain.contest.dto.ContestBoardDetailDto; @@ -30,128 +32,106 @@ import com.inhabas.api.global.util.FileUtil; @Service +@Slf4j @Transactional @RequiredArgsConstructor public class ContestBoardServiceImpl implements ContestBoardService { private final ContestBoardRepository contestBoardRepository; - - private final BoardSecurityChecker boardSecurityChecker; - private final MemberRepository memberRepository; - private final MenuRepository menuRepository; - private final S3Service s3Service; - private static final String CONTEST_BOARD_MENU_NAME = "공모전 게시판"; - - private static final String DIR_NAME = "contest/"; - // 타입별 공모전 게시판 목록 조회 @Override - @Transactional(readOnly = true) - public List getContestBoardsByType( + public List getContestBoards( ContestType contestType, Long contestFieldId, String search, String sortBy) { if (search == null || search.trim().isEmpty()) { search = ""; } - List contestBoardList = - contestBoardRepository.findAllByContestTypeAndFieldLike( - contestType, contestFieldId, search, sortBy); - - return contestBoardList.stream() - .map( - contestBoard -> { - ClassifiedFiles classifiedFiles = - ClassifyFiles.classifyFiles(new ArrayList<>(contestBoard.getFiles())); - - return ContestBoardDto.builder() - .id(contestBoard.getId()) - .contestFieldId(contestBoard.getContestField().getId()) - .title(contestBoard.getTitle()) - .association(contestBoard.getAssociation()) - .topic(contestBoard.getTopic()) - .dateContestStart(contestBoard.getDateContestStart()) - .dateContestEnd(contestBoard.getDateContestEnd()) - .thumbnail(classifiedFiles.getThumbnail()) - .build(); - }) - .collect(Collectors.toList()); + List contestBoardList = new ArrayList<>(); + + contestBoardList.addAll( + contestBoardRepository.findAllByTypeAndFieldAndSearch( + contestType, contestFieldId, search, sortBy)); + return contestBoardList; + } + + // 공모전 게시판 단일조회 + @Override + public ContestBoardDetailDto getContestBoard(ContestType contestType, Long boardId) { + ContestBoard contestBoard = + contestBoardRepository + .findByTypeAndId(contestType, boardId) + .orElseThrow(NotFoundException::new); + + List files = + Optional.ofNullable(contestBoard.getFiles()).orElse(Collections.emptyList()); + ClassifiedFiles classifiedFiles = ClassifyFiles.classifyFiles(new ArrayList<>(files)); + + return ContestBoardDetailDto.builder() + .id(contestBoard.getId()) + .contestFieldId(contestBoard.getContestField().getId()) + .title(contestBoard.getTitle()) + .content(contestBoard.getContent()) + .writerName(contestBoard.getWriter().getName()) + .association(contestBoard.getAssociation()) + .topic(contestBoard.getTopic()) + .dateContestStart(contestBoard.getDateContestStart()) + .dateContestEnd(contestBoard.getDateContestEnd()) + .dateCreated(contestBoard.getDateCreated()) + .dateUpdated(contestBoard.getDateUpdated()) + .thumbnail(classifiedFiles.getThumbnail()) + .images(classifiedFiles.getImages()) + .otherFiles(classifiedFiles.getOtherFiles()) + .build(); } // contestType 별로 게시글 작성 @Override - @Transactional public Long writeContestBoard( - Long memberId, SaveContestBoardDto saveContestBoardDto, ContestType contestType) { + Long memberId, ContestType contestType, SaveContestBoardDto saveContestBoardDto) { Member writer = memberRepository.findById(memberId).orElseThrow(MemberNotFoundException::new); Menu menu = - menuRepository - .findByName_Value(CONTEST_BOARD_MENU_NAME) - .orElseThrow(NotFoundException::new); + menuRepository.findById(contestType.getMenuId()).orElseThrow(NotFoundException::new); ContestBoard contestBoard = ContestBoard.builder() + .menu(menu) + .contestFieldId(saveContestBoardDto.getContestFieldId()) .title(saveContestBoardDto.getTitle()) .content(saveContestBoardDto.getContent()) .association(saveContestBoardDto.getAssociation()) .topic(saveContestBoardDto.getTopic()) .dateContestStart(saveContestBoardDto.getDateContestStart()) .dateContestEnd(saveContestBoardDto.getDateContestEnd()) - .contestType(contestType) - .contestFieldId(saveContestBoardDto.getContestFieldId()) .build() .writtenBy(writer, ContestBoard.class); - return updateContestBoardFiles(saveContestBoardDto, contestBoard); - } - - // 공모전 게시판 단일조회 - @Override - @Transactional(readOnly = true) - public ContestBoardDetailDto getContestBoard(Long boardId) { - - ContestBoard contestBoard = - contestBoardRepository.findById(boardId).orElseThrow(NotFoundException::new); - - ClassifiedFiles classifiedFiles = - ClassifyFiles.classifyFiles(new ArrayList<>(contestBoard.getFiles())); - - return ContestBoardDetailDto.builder() - .id(contestBoard.getId()) - .title(contestBoard.getTitle()) - .content(contestBoard.getContent()) - .writerName(contestBoard.getWriter().getName()) - .dateCreated(contestBoard.getDateCreated()) - .dateUpdated(contestBoard.getDateUpdated()) - .thumbnail(classifiedFiles.getThumbnail()) - .images(classifiedFiles.getImages()) - .otherFiles(classifiedFiles.getOtherFiles()) - .build(); + return updateContestBoardFiles(saveContestBoardDto, contestType, contestBoard); } @Override - @Transactional - public void updateContestBoard(Long boardId, SaveContestBoardDto saveContestBoardDto) { + public void updateContestBoard( + Long boardId, ContestType contestType, SaveContestBoardDto saveContestBoardDto) { ContestBoard contestBoard = contestBoardRepository.findById(boardId).orElseThrow(NotFoundException::new); - updateContestBoardFiles(saveContestBoardDto, contestBoard); + updateContestBoardFiles(saveContestBoardDto, contestType, contestBoard); } @Override - @Transactional public void deleteContestBoard(Long boardId) { contestBoardRepository.deleteById(boardId); } private Long updateContestBoardFiles( - SaveContestBoardDto saveContestBoardDto, ContestBoard contestBoard) { + SaveContestBoardDto saveContestBoardDto, ContestType contestType, ContestBoard contestBoard) { + final String DIR_NAME = contestType.getBoardType() + "/"; List updateFiles = new ArrayList<>(); List urlListForDelete = new ArrayList<>(); diff --git a/resource-server/src/main/java/com/inhabas/api/web/ContestBoardController.java b/resource-server/src/main/java/com/inhabas/api/web/ContestBoardController.java index 58336839..01c4af20 100644 --- a/resource-server/src/main/java/com/inhabas/api/web/ContestBoardController.java +++ b/resource-server/src/main/java/com/inhabas/api/web/ContestBoardController.java @@ -23,6 +23,8 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import com.inhabas.api.auth.domain.error.ErrorResponse; +import com.inhabas.api.domain.board.dto.BoardCountDto; +import com.inhabas.api.domain.board.repository.BaseBoardRepository; import com.inhabas.api.domain.contest.domain.valueObject.ContestType; import com.inhabas.api.domain.contest.dto.ContestBoardDetailDto; import com.inhabas.api.domain.contest.dto.ContestBoardDto; @@ -48,8 +50,22 @@ public class ContestBoardController { private final ContestBoardService contestBoardService; + private final BaseBoardRepository baseBoardRepository; - @Operation(summary = "공모전 게시판 목록 조회", description = "공모전 게시판 목록 조회") + @Operation(summary = "게시판 종류 당 글 개수 조회") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + content = {@Content(schema = @Schema(implementation = BoardCountDto.class))}), + }) + @GetMapping("/contest/count") + @SecurityRequirements(value = {}) + public ResponseEntity> getBoardCount() { + return ResponseEntity.ok(baseBoardRepository.countRowsGroupByMenuName(2)); + } + + @Operation(summary = "공모전 게시글 목록 조회", description = "공모전 게시판 목록 조회") @ApiResponses( value = { @ApiResponse( @@ -79,8 +95,7 @@ public class ContestBoardController { @SecurityRequirements(value = {}) @GetMapping("/contest/{contestType}") @PreAuthorize( - // 공모전 게시판 MenuId : 18 - "@boardSecurityChecker.checkMenuAccess(18, T(com.inhabas.api.domain.board.usecase.BoardSecurityChecker).READ_BOARD_LIST)") + "@boardSecurityChecker.checkMenuAccess(#contestType.menuId, T(com.inhabas.api.domain.board.usecase.BoardSecurityChecker).READ_BOARD_LIST)") public ResponseEntity> getContestBoard( @PathVariable("contestType") ContestType contestType, @Parameter(description = "공모전 분야", example = "1") @@ -100,21 +115,24 @@ public ResponseEntity> getContestBoard( String sortBy) { Pageable pageable = PageRequest.of(page, size); - List allDtos = - contestBoardService.getContestBoardsByType(contestType, contestFieldId, search, sortBy); - List pagedDtos = PageUtil.getPagedDtoList(pageable, allDtos); + List allDtoList = + contestBoardService.getContestBoards(contestType, contestFieldId, search, sortBy); + List pagedDtoList = PageUtil.getPagedDtoList(pageable, allDtoList); PageImpl ContestBoardDtoPage = - new PageImpl<>(pagedDtos, pageable, allDtos.size()); + new PageImpl<>(pagedDtoList, pageable, allDtoList.size()); PageInfoDto pageInfoDto = new PageInfoDto(ContestBoardDtoPage); - return ResponseEntity.ok(new PagedResponseDto<>(pageInfoDto, pagedDtos)); + return ResponseEntity.ok(new PagedResponseDto<>(pageInfoDto, pagedDtoList)); } - @Operation(summary = "공모전 게시판 글 생성", description = "공모전 게시판 글 생성 (활동회원 이상)") + @Operation(summary = "공모전 게시글 단일 조회") + @GetMapping("/contest/{contestType}/{boardId}") + @PreAuthorize( + "@boardSecurityChecker.checkMenuAccess(#contestType.menuId, T(com.inhabas.api.domain.board.usecase.BoardSecurityChecker).READ_BOARD)") @ApiResponses( value = { - @ApiResponse(responseCode = "201", description = "'Location' 헤더에 생성된 리소스의 URI 가 포함됩니다."), + @ApiResponse(responseCode = "200"), @ApiResponse( responseCode = "400", description = "입력값이 없거나, 타입이 유효하지 않습니다.", @@ -136,12 +154,43 @@ public ResponseEntity> getContestBoard( value = "{\"status\": 404, \"code\": \"G004\", \"message\": \"데이터가 존재하지 않습니다.\"}"))) }) + public ResponseEntity getContestBoard( + @PathVariable Long boardId, @PathVariable ContestType contestType) { + + return ResponseEntity.ok(contestBoardService.getContestBoard(contestType, boardId)); + } + + @Operation(summary = "공모전 게시글 추가") @PostMapping(path = "/contest/{contestType}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @PreAuthorize( - "@boardSecurityChecker.checkMenuAccess(18, T(com.inhabas.api.domain.board.usecase.BoardSecurityChecker).CREATE_BOARD)") + "@boardSecurityChecker.checkMenuAccess(#contestType.menuId, T(com.inhabas.api.domain.board.usecase.BoardSecurityChecker).CREATE_BOARD)") + @ApiResponses( + value = { + @ApiResponse(responseCode = "201", description = "'Location' 헤더에 생성된 리소스의 URI 가 포함됩니다."), + @ApiResponse( + responseCode = "400", + description = "입력값이 없거나, 타입이 유효하지 않습니다.", + content = + @Content( + schema = @Schema(implementation = ErrorResponse.class), + examples = + @ExampleObject( + value = + "{\"status\": 400, \"code\": \"G003\", \"message\": \"입력값이 없거나, 타입이 유효하지 않습니다.\"}"))), + @ApiResponse( + responseCode = "404", + description = "데이터가 존재하지 않습니다.", + content = + @Content( + schema = @Schema(implementation = ErrorResponse.class), + examples = + @ExampleObject( + value = + "{\"status\": 404, \"code\": \"G004\", \"message\": \"데이터가 존재하지 않습니다.\"}"))) + }) public ResponseEntity writeContestBoard( @Authenticated Long memberId, - @PathVariable("contestType") ContestType contestType, + @PathVariable ContestType contestType, @RequestPart("contestFieldId") Long contestFieldId, @RequestPart("title") String title, @RequestPart("content") String content, @@ -161,10 +210,8 @@ public ResponseEntity writeContestBoard( dateContestStart, dateContestEnd, files); - - // PathVariable인 {contestType}에 따라 공모전 글 작성 페이지가 CONTEST와 EXTERNAL_ACTIVITY로 분류됨 Long newContestBoardId = - contestBoardService.writeContestBoard(memberId, saveContestBoardDto, contestType); + contestBoardService.writeContestBoard(memberId, contestType, saveContestBoardDto); // 뒤에 추가 URI 생성 URI location = @@ -176,44 +223,11 @@ public ResponseEntity writeContestBoard( return ResponseEntity.created(location).build(); } - @Operation(summary = "공모전 게시판 글 단일 조회", description = "공모전 게시판 글 단일 조회") - @ApiResponses( - value = { - @ApiResponse(responseCode = "200"), - @ApiResponse( - responseCode = "400", - description = "입력값이 없거나, 타입이 유효하지 않습니다.", - content = - @Content( - schema = @Schema(implementation = ErrorResponse.class), - examples = - @ExampleObject( - value = - "{\"status\": 400, \"code\": \"G003\", \"message\": \"입력값이 없거나, 타입이 유효하지 않습니다.\"}"))), - @ApiResponse( - responseCode = "404", - description = "데이터가 존재하지 않습니다.", - content = - @Content( - schema = @Schema(implementation = ErrorResponse.class), - examples = - @ExampleObject( - value = - "{\"status\": 404, \"code\": \"G004\", \"message\": \"데이터가 존재하지 않습니다.\"}"))) - }) - @SecurityRequirements(value = {}) - @GetMapping("/contest/{contestType}/{boardId}") - @PreAuthorize( - "@boardSecurityChecker.checkMenuAccess(18, T(com.inhabas.api.domain.board.usecase.BoardSecurityChecker).READ_BOARD)") - public ResponseEntity findContestBoard( - @PathVariable("contestType") ContestType contestType, @PathVariable Long boardId) { - - ContestBoardDetailDto contestBoardDetailDto = contestBoardService.getContestBoard(boardId); - - return ResponseEntity.ok(contestBoardDetailDto); - } - - @Operation(summary = "공모전 게시판 글 수정", description = "공모전 게시판 글 수정 (작성자, 회장만)") + @Operation(summary = "공모전 게시글 수정") + @PostMapping( + path = "/contest/{contestType}/{boardId}", + consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @PreAuthorize("@boardSecurityChecker.boardWriterOnly(#boardId) or hasRole('VICE_CHIEF')") @ApiResponses( value = { @ApiResponse(responseCode = "200"), @@ -238,13 +252,9 @@ public ResponseEntity findContestBoard( value = "{\"status\": 404, \"code\": \"G004\", \"message\": \"데이터가 존재하지 않습니다.\"}"))) }) - @PostMapping( - path = "/contest/{contestType}/{boardId}", - consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - @PreAuthorize("@boardSecurityChecker.boardWriterOnly(#boardId) or hasRole('VICE_CHIEF')") - public ResponseEntity updateContestBoard( + public ResponseEntity updateContestBoard( @Authenticated Long memberId, - @PathVariable("contestType") ContestType contestType, + @PathVariable ContestType contestType, @PathVariable Long boardId, @RequestPart("contestFieldId") Long contestFieldId, @RequestPart("title") String title, @@ -265,12 +275,14 @@ public ResponseEntity updateContestBoard( dateContestStart, dateContestEnd, files); - contestBoardService.updateContestBoard(boardId, saveContestBoardDto); + contestBoardService.updateContestBoard(boardId, contestType, saveContestBoardDto); return ResponseEntity.noContent().build(); } - @Operation(summary = "공모전 게시판 글 삭제", description = "공모전 게시판 글 삭제 (작성자, 회장만)") + @Operation(summary = "공모전 게시글 삭제") + @DeleteMapping("contest/{contestType}/{boardId}") + @PreAuthorize("@boardSecurityChecker.boardWriterOnly(#boardId) or hasRole('VICE_CHIEF')") @ApiResponses( value = { @ApiResponse(responseCode = "204"), @@ -295,8 +307,6 @@ public ResponseEntity updateContestBoard( value = "{\"status\": 404, \"code\": \"G004\", \"message\": \"데이터가 존재하지 않습니다.\"}"))) }) - @DeleteMapping("contest/{contestType}/{boardId}") - @PreAuthorize("@boardSecurityChecker.boardWriterOnly(#boardId) or hasRole('VICE_CHIEF')") public ResponseEntity deleteContestBoard( @Authenticated Long memberId, @PathVariable ContestType contestType, diff --git a/resource-server/src/test/java/com/inhabas/api/domain/contest/domain/ContestBoardTest.java b/resource-server/src/test/java/com/inhabas/api/domain/contest/domain/ContestBoardTest.java index 51244246..c66d81b4 100644 --- a/resource-server/src/test/java/com/inhabas/api/domain/contest/domain/ContestBoardTest.java +++ b/resource-server/src/test/java/com/inhabas/api/domain/contest/domain/ContestBoardTest.java @@ -1,14 +1,13 @@ package com.inhabas.api.domain.contest.domain; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; -import com.inhabas.api.domain.contest.domain.valueObject.ContestType; import com.inhabas.api.domain.file.domain.BoardFile; +import com.inhabas.api.domain.menu.domain.Menu; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -18,30 +17,27 @@ class ContestBoardTest { + @Mock private Menu menu; + + private ContestBoard contestBoard; + @Mock private ContestField contestField; @BeforeEach void setUp() { MockitoAnnotations.openMocks(this); - when(contestField.getId()).thenReturn(1L); - } - @Test - @DisplayName("올바른 ContestBoard를 생성한다.") - void createContestBoardTest() { - // Given + String title = "테스트 공모전"; + String content = "테스트 내용"; + String association = "테스트 협회"; + String topic = "테스트 주제"; LocalDate dateContestStart = LocalDate.of(2023, 1, 1); LocalDate dateContestEnd = LocalDate.of(2023, 12, 31); - var title = "테스트 공모전"; - var content = "테스트 내용"; - var association = "테스트 협회"; - var topic = "테스트 주제"; - // When - ContestBoard contestBoard = + contestBoard = ContestBoard.builder() - .contestType(ContestType.CONTEST) - .contestFieldId(contestField.getId()) + .menu(menu) + .contestFieldId(1L) .title(title) .content(content) .association(association) @@ -49,41 +45,24 @@ void createContestBoardTest() { .dateContestStart(dateContestStart) .dateContestEnd(dateContestEnd) .build(); - - // Then - assertThat(contestBoard.getContestType()).isEqualTo(ContestType.CONTEST); - assertThat(contestBoard.getContestField().getId()).isEqualTo(contestField.getId()); - assertThat(contestBoard.getTitle()).isEqualTo(title); - assertThat(contestBoard.getContent()).isEqualTo(content); - assertThat(contestBoard.getAssociation()).isEqualTo(association); - assertThat(contestBoard.getTopic()).isEqualTo(topic); - assertThat(contestBoard.getDateContestStart()).isEqualTo(dateContestStart); - assertThat(contestBoard.getDateContestEnd()).isEqualTo(dateContestEnd); } @Test - @DisplayName("ContestBoard에 첨부 파일을 추가한다.") - void addFilesToContestBoardTest() { - // Given - ContestBoard contestBoard = new ContestBoard(); - List files = new ArrayList<>(); - files.add(new BoardFile("file1.jpg", "url1", contestBoard)); - files.add(new BoardFile("file2.pdf", "url2", contestBoard)); - - // When - contestBoard.updateFiles(files); - + @DisplayName("올바른 ContestBoard를 생성한다.") + void createContestBoardTest() { // Then - assertThat(contestBoard.getFiles()).hasSize(2); - assertThat(contestBoard.getFiles().get(0).getName()).isEqualTo("file1.jpg"); - assertThat(contestBoard.getFiles().get(0).getUrl()).isEqualTo("url1"); - assertThat(contestBoard.getFiles().get(1).getName()).isEqualTo("file2.pdf"); - assertThat(contestBoard.getFiles().get(1).getUrl()).isEqualTo("url2"); + assertThat(contestBoard.getContestField().getId()).isEqualTo(1L); + assertThat(contestBoard.getTitle()).isEqualTo("테스트 공모전"); + assertThat(contestBoard.getContent()).isEqualTo("테스트 내용"); + assertThat(contestBoard.getAssociation()).isEqualTo("테스트 협회"); + assertThat(contestBoard.getTopic()).isEqualTo("테스트 주제"); + assertThat(contestBoard.getDateContestStart()).isEqualTo(LocalDate.of(2023, 1, 1)); + assertThat(contestBoard.getDateContestEnd()).isEqualTo(LocalDate.of(2023, 12, 31)); } @Test @DisplayName("ContestBoard 정보를 수정한다.") - void updateContestBoardInfoTest() { + void updateContestBoardTest() { // Given ContestBoard contestBoard = new ContestBoard(); Long newContestFieldId = 1L; @@ -113,4 +92,24 @@ void updateContestBoardInfoTest() { assertThat(contestBoard.getDateContestStart()).isEqualTo(newDateContestStart); assertThat(contestBoard.getDateContestEnd()).isEqualTo(newDateContestEnd); } + + @Test + @DisplayName("ContestBoard의 첨부 파일을 수정한다.") + void updateFilesTest() { + // Given + + List files = new ArrayList<>(); + files.add(new BoardFile("file1.jpg", "/url1", contestBoard)); + files.add(new BoardFile("file2.pdf", "/url2", contestBoard)); + + // When + contestBoard.updateFiles(files); + + // Then + assertThat(contestBoard.getFiles()).hasSize(2); + assertThat(contestBoard.getFiles().get(0).getName()).isEqualTo("file1.jpg"); + assertThat(contestBoard.getFiles().get(0).getUrl()).isEqualTo("/url1"); + assertThat(contestBoard.getFiles().get(1).getName()).isEqualTo("file2.pdf"); + assertThat(contestBoard.getFiles().get(1).getUrl()).isEqualTo("/url2"); + } } diff --git a/resource-server/src/test/java/com/inhabas/api/domain/contest/dto/ContestBoardDetailDtoTest.java b/resource-server/src/test/java/com/inhabas/api/domain/contest/dto/ContestBoardDetailDtoTest.java new file mode 100644 index 00000000..8dc9d2b1 --- /dev/null +++ b/resource-server/src/test/java/com/inhabas/api/domain/contest/dto/ContestBoardDetailDtoTest.java @@ -0,0 +1,97 @@ +package com.inhabas.api.domain.contest.dto; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; + +import com.inhabas.api.domain.file.dto.FileDownloadDto; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class ContestBoardDetailDtoTest { + + private static ValidatorFactory validatorFactory; + private static Validator validator; + + @BeforeAll + public static void init() { + validatorFactory = Validation.buildDefaultValidatorFactory(); + validator = validatorFactory.getValidator(); + } + + @AfterAll + public static void close() { + validatorFactory.close(); + } + + @DisplayName("ContestBoardDetailDto 객체를 정상적으로 생성한다.") + @Test + public void createContestBoardDetailDto() { + // given + ContestBoardDetailDto contestBoardDetailDto = + ContestBoardDetailDto.builder() + .id(1L) + .contestFieldId(1L) + .title("테스트 제목") + .content("테스트 내용") + .writerName("송민석") + .association("(주) 아이바스") + .topic("테스트 주제") + .dateContestStart(LocalDate.now()) + .dateContestEnd(LocalDate.now().plusDays(10)) + .dateCreated(LocalDateTime.now()) + .dateUpdated(LocalDateTime.now()) + .thumbnail(new FileDownloadDto("thumbnail.jpg", "thumbnailUrl")) + .images(new ArrayList<>()) + .otherFiles(new ArrayList<>()) + .build(); + + // when + Set> violations = + validator.validate(contestBoardDetailDto); + + // then + assertThat(violations).isEmpty(); + } + + @DisplayName("ContestBoardDetailDto title 필드가 null 이면 validation 실패") + @Test + public void nullTitleTest() { + // given + ContestBoardDetailDto contestBoardDetailDto = + ContestBoardDetailDto.builder() + .id(1L) + .contestFieldId(1L) + // title 필드 null + .content("테스트 내용") + .writerName("송민석") + .association("(주) 아이바스") + .topic("테스트 주제") + .dateContestStart(LocalDate.now()) + .dateContestEnd(LocalDate.now().plusDays(10)) + .dateCreated(LocalDateTime.now()) + .dateUpdated(LocalDateTime.now()) + .thumbnail(new FileDownloadDto("thumbnail.jpg", "thumbnailUrl")) + .images(new ArrayList<>()) + .otherFiles(new ArrayList<>()) + .build(); + + // when + Set> violations = + validator.validate(contestBoardDetailDto); + + // then + assertThat(violations).hasSize(1); + } +} diff --git a/resource-server/src/test/java/com/inhabas/api/domain/contest/dto/SaveContestBoardDtoTest.java b/resource-server/src/test/java/com/inhabas/api/domain/contest/dto/SaveContestBoardDtoTest.java index 5e88768a..93db9774 100644 --- a/resource-server/src/test/java/com/inhabas/api/domain/contest/dto/SaveContestBoardDtoTest.java +++ b/resource-server/src/test/java/com/inhabas/api/domain/contest/dto/SaveContestBoardDtoTest.java @@ -1,8 +1,5 @@ package com.inhabas.api.domain.contest.dto; -import static org.assertj.core.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.time.LocalDate; import java.util.ArrayList; import java.util.List; @@ -13,7 +10,12 @@ import javax.validation.Validator; import javax.validation.ValidatorFactory; -import org.junit.jupiter.api.*; +import org.assertj.core.api.Assertions; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; public class SaveContestBoardDtoTest { private static ValidatorFactory validatorFactory; @@ -45,7 +47,7 @@ public void FieldsAreNullError() { List errorMessage = new ArrayList<>(); violations.forEach(error -> errorMessage.add(error.getMessage())); - assertThat(errorMessage) + Assertions.assertThat(errorMessage) .contains( "제목을 입력하세요.", "본문을 입력하세요.", @@ -70,7 +72,7 @@ public void FieldsAreBlankedError() { List errorMessage = new ArrayList<>(); violations.forEach(error -> errorMessage.add(error.getMessage())); - assertThat(errorMessage) + Assertions.assertThat(errorMessage) .contains( "제목을 입력하세요.", "본문을 입력하세요.", @@ -103,8 +105,8 @@ public void InputsAreExceededError() { List errorMessage = new ArrayList<>(); violations.forEach(error -> errorMessage.add(error.getMessage())); - assertEquals(3, violations.size()); - assertThat(errorMessage) + Assertions.assertThat(violations).hasSize(3); + Assertions.assertThat(errorMessage) .containsOnly("제목은 최대 100자입니다.", "100자 이내로 작성해주세요.", "500자 이내로 작성해주세요."); } @@ -131,6 +133,6 @@ public void DeadlineIsOutdatedError() { List errorMessage = new ArrayList<>(); violations.forEach(error -> errorMessage.add(error.getMessage())); - assertThat(errorMessage).containsOnly("이미 모집기간이 종료된 공모전은 등록할 수 없습니다."); + Assertions.assertThat(errorMessage).containsOnly("이미 모집기간이 종료된 공모전은 등록할 수 없습니다."); } } diff --git a/resource-server/src/test/java/com/inhabas/api/domain/contest/usecase/ContestBoardServiceImplTest.java b/resource-server/src/test/java/com/inhabas/api/domain/contest/usecase/ContestBoardServiceImplTest.java new file mode 100644 index 00000000..df8707c8 --- /dev/null +++ b/resource-server/src/test/java/com/inhabas/api/domain/contest/usecase/ContestBoardServiceImplTest.java @@ -0,0 +1,204 @@ +package com.inhabas.api.domain.contest.usecase; + +import static com.inhabas.api.domain.contest.domain.valueObject.ContestType.ACTIVITY; +import static com.inhabas.api.domain.menu.domain.MenuExampleTest.getContestMenu; +import static com.inhabas.api.domain.menu.domain.valueObject.MenuGroupExampleTest.getContestMenuGroup; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.times; + +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; + +import org.springframework.test.util.ReflectionTestUtils; + +import com.inhabas.api.auth.domain.oauth2.member.domain.entity.Member; +import com.inhabas.api.auth.domain.oauth2.member.repository.MemberRepository; +import com.inhabas.api.domain.contest.domain.ContestBoard; +import com.inhabas.api.domain.contest.domain.valueObject.ContestType; +import com.inhabas.api.domain.contest.dto.ContestBoardDetailDto; +import com.inhabas.api.domain.contest.dto.ContestBoardDto; +import com.inhabas.api.domain.contest.dto.SaveContestBoardDto; +import com.inhabas.api.domain.contest.repository.ContestBoardRepository; +import com.inhabas.api.domain.file.dto.FileDownloadDto; +import com.inhabas.api.domain.file.usecase.S3Service; +import com.inhabas.api.domain.member.domain.entity.MemberTest; +import com.inhabas.api.domain.menu.domain.Menu; +import com.inhabas.api.domain.menu.repository.MenuRepository; +import org.assertj.core.api.Assertions; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(MockitoExtension.class) +public class ContestBoardServiceImplTest { + + @InjectMocks private ContestBoardServiceImpl contestBoardService; + + @Mock private ContestBoardRepository contestBoardRepository; + + @Mock private MemberRepository memberRepository; + + @Mock private MenuRepository menuRepository; + + @Mock private S3Service s3Service; + + @DisplayName("Contest board 게시글 목록을 조회한다.") + @Test + void getContestBoards() { + // given + ContestBoardDto contestBoardDto = + ContestBoardDto.builder() + .id(1L) + .contestFieldId(1L) + .title("테스트 제목") + .association("(주) 아이바스") + .topic("테스트 주제") + .dateContestStart(LocalDate.now()) + .dateContestEnd(LocalDate.now().plusDays(10)) + .thumbnail(new FileDownloadDto("thumbnail.jpg", "thumbnailUrl")) + .build(); + + given( + contestBoardRepository.findAllByTypeAndFieldAndSearch( + any(ContestType.class), anyLong(), anyString(), anyString())) + .willReturn(List.of(contestBoardDto)); + + // when + List result = contestBoardService.getContestBoards(ACTIVITY, 1L, "", "title"); + + // then + Assertions.assertThat(result).hasSize(1); + } + + @DisplayName("Contest board 게시글 단일 조회한다.") + @Test + void getContestBoard() { + // given + Member member = MemberTest.chiefMember(); + Menu menu = getContestMenu(getContestMenuGroup()); + + ContestBoard contestBoard = + ContestBoard.builder() + .menu(menu) + .contestFieldId(1L) + .title("테스트 제목") + .content("테스트 내용") + .association("(주) 아이바스") + .topic("테스트 주제") + .dateContestStart(LocalDate.now()) + .dateContestEnd(LocalDate.now().plusDays(10)) + .build() + .writtenBy(member, ContestBoard.class); + + given(contestBoardRepository.findByTypeAndId(any(), any())) + .willReturn(Optional.of(contestBoard)); + + // when + ContestBoardDetailDto dto = contestBoardService.getContestBoard(ACTIVITY, 1L); + + // then + assertThat(dto).isNotNull(); + assertThat(dto.getTitle()).isEqualTo("테스트 제목"); + assertThat(dto.getContent()).isEqualTo("테스트 내용"); + assertThat(dto.getAssociation()).isEqualTo("(주) 아이바스"); + assertThat(dto.getTopic()).isEqualTo("테스트 주제"); + assertThat(dto.getDateContestStart()).isEqualTo(LocalDate.now()); + assertThat(dto.getDateContestEnd()).isEqualTo(LocalDate.now().plusDays(10)); + } + + @DisplayName("Contest board 게시글을 작성한다.") + @Test + void writeContestBoard() { + // given + Member member = MemberTest.chiefMember(); + SaveContestBoardDto saveContestBoardDto = + SaveContestBoardDto.builder() + .contestFieldId(1L) + .title("테스트 제목") + .content("테스트 내용") + .association("(주) 아이바스") + .topic("테스트 주제") + .dateContestStart(LocalDate.now()) + .dateContestEnd(LocalDate.now().plusDays(10)) + .files(null) + .build(); + Menu menu = getContestMenu(getContestMenuGroup()); + ContestBoard contestBoard = + ContestBoard.builder() + .menu(menu) + .contestFieldId(1L) + .title("테스트 제목") + .content("테스트 내용") + .association("(주) 아이바스") + .topic("테스트 주제") + .dateContestStart(LocalDate.now()) + .dateContestEnd(LocalDate.now().plusDays(10)) + .build() + .writtenBy(member, ContestBoard.class); + + given(memberRepository.findById(any())).willReturn(Optional.of(member)); + given(contestBoardRepository.save(any())).willReturn(contestBoard); + given(menuRepository.findById(anyInt())).willReturn(Optional.of(menu)); + + // when + contestBoardService.writeContestBoard(1L, ACTIVITY, saveContestBoardDto); + // then + then(menuRepository).should(times(1)).findById(anyInt()); + then(contestBoardRepository).should(times(1)).save(any()); + } + + @DisplayName("Contest board 게시글을 수정한다.") + @Test + void updateContestBoard() { + // given + SaveContestBoardDto saveContestBoardDto = new SaveContestBoardDto(); + Menu menu = getContestMenu(getContestMenuGroup()); + ContestBoard contestBoard = + ContestBoard.builder() + .menu(menu) + .contestFieldId(1L) + .title("테스트 제목") + .content("테스트 내용") + .association("(주) 아이바스") + .topic("테스트 주제") + .dateContestStart(LocalDate.now()) + .dateContestEnd(LocalDate.now().plusDays(10)) + .build(); + ReflectionTestUtils.setField(contestBoard, "id", 1L); + + given(contestBoardRepository.findById(any())).willReturn(Optional.of(contestBoard)); + given(contestBoardRepository.save(any())).willReturn(contestBoard); + + // when + contestBoardService.updateContestBoard(contestBoard.getId(), ACTIVITY, saveContestBoardDto); + + // then + then(contestBoardRepository).should(times(1)).findById(any()); + then(contestBoardRepository).should(times(1)).save(any()); + } + + @DisplayName("Contest board 게시글을 삭제한다.") + @Test + void deleteContestBoard() { + // given + Long boardId = 1L; + doNothing().when(contestBoardRepository).deleteById(boardId); + // when + contestBoardService.deleteContestBoard(boardId); + + // then + then(contestBoardRepository).should(times(1)).deleteById(boardId); + } +} diff --git a/resource-server/src/test/java/com/inhabas/api/domain/contest/usecase/ContestBoardServiceTest.java b/resource-server/src/test/java/com/inhabas/api/domain/contest/usecase/ContestBoardServiceTest.java deleted file mode 100644 index 64f8e87e..00000000 --- a/resource-server/src/test/java/com/inhabas/api/domain/contest/usecase/ContestBoardServiceTest.java +++ /dev/null @@ -1,184 +0,0 @@ -package com.inhabas.api.domain.contest.usecase; - -import com.inhabas.api.domain.contest.repository.ContestBoardRepository; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -@ExtendWith(MockitoExtension.class) -public class ContestBoardServiceTest { - - @InjectMocks ContestBoardServiceImpl contestBoardService; - - @Mock ContestBoardRepository contestBoardRepository; - - @DisplayName("공모전 게시글을 성공적으로 생성한다.") - @Test - public void createContestBoard() { - // //given - // StudentId StudentId = new StudentId("12201863"); - // SaveContestBoardDto saveContestBoardDto = - // new SaveContestBoardDto("title", "content", "association", "topic", - // LocalDate.of(2022, 1, 1), LocalDate.of(2022, 1, 26)); - // ContestBoard contestBoard = - // new ContestBoard("title", "content", "association", "topic", - // LocalDate.of(2022, 1, 1), LocalDate.of(2022, 1, 26)); - // - // given(contestBoardRepository.save(any())).willReturn(contestBoard); - // - // // when - // Integer returnedId = contestBoardService.write(StudentId, saveContestBoardDto); - // - // // then - // then(contestBoardRepository).should(times(1)).save(any()); - } - - @DisplayName("공모전 게시판의 목록을 조회한다.") - @Test - public void getContestBoardList() { - // //given - // Pageable pageable = PageRequest.of(0, 10, Sort.Direction.DESC, "deadline"); - // - // ListContestBoardDto contestBoardDto1 = - // new ListContestBoardDto("title1", "contents1", LocalDate.of(2022, 1, 1), - // LocalDate.of(2022, 3, 4)); - // ListContestBoardDto contestBoardDto2 = - // new ListContestBoardDto("title2", "contents2", LocalDate.of(2022, 1, 1), - // LocalDate.of(2022, 5, 28)); - // ListContestBoardDto contestBoardDto3 = - // new ListContestBoardDto("title2", "contents2", LocalDate.of(2022, 1, 1), - // LocalDate.of(2022, 2, 20)); - // - // List results = new ArrayList<>(); - // results.add(contestBoardDto3); - // results.add(contestBoardDto1); - // results.add(contestBoardDto2); - // - // Page expectedContestBoardDto = new PageImpl<>(results, pageable, - // results.size()); - // - // given(contestBoardRepository.findAllByMenuId(any(), any())).willReturn( - // expectedContestBoardDto); - // - // //when - // Page returnedBoardList = contestBoardService.getBoardList( - // new MenuId(1), pageable); - // - // //then - // assertThat(returnedBoardList).isEqualTo(expectedContestBoardDto); - - } - - @DisplayName("공모전 게시글 단일 조회에 성공한다.") - @Test - public void getDetailBoard() { - // //given - // DetailContestBoardDto contestBoardDto = - // new DetailContestBoardDto(1, "mingyeom", "title", "content", - // "association", "topic", LocalDate.of(2022, 1, 1), - // LocalDate.of(2022, 1, 29), LocalDateTime.now(), null); - // - // given(contestBoardRepository.findDtoById(any())).willReturn(Optional.of(contestBoardDto)); - // - // // when - // contestBoardService.getBoard(1); - // - // // then - // then(contestBoardRepository).should(times(1)).findDtoById(any()); - } - - @DisplayName("공모전 게시글을 성공적으로 삭제한다.") - @Test - public void deleteContestBoard() { - // //given - // StudentId StudentId = new StudentId("12201863"); - // ContestBoard contestBoard = - // new ContestBoard("title", "content", "association", "topic", - // LocalDate.of(2022, 1, 1), LocalDate.of(2022, 1, 26)) - // .writtenBy(StudentId); - // - // given(contestBoardRepository.findById(anyInt())).willReturn(Optional.of(contestBoard)); - // doNothing().when(contestBoardRepository).deleteById(any()); - // - // // when - // contestBoardService.delete(StudentId, 1); - // - // // then - // then(contestBoardRepository).should(times(1)).deleteById(any()); - } - - // @DisplayName("공모전 게시글을 수정한다.") - // @Test - // public void updateContestBoard() { - // //given - // StudentId StudentId = new StudentId("12201863"); - // ContestBoard expectedContestBoard = - // new ContestBoard("title", "content", "association", "topic", - // LocalDate.of(2022, 1, 1), LocalDate.of(2022, 1, 26)) - // .writtenBy(StudentId); - // - // given(contestBoardRepository.save(any())).willReturn(expectedContestBoard); - // - // given(contestBoardRepository.findById(any())).willReturn(Optional.of(expectedContestBoard)); - // - // UpdateContestBoardDto updateContestBoardDto = new UpdateContestBoardDto(1, "수정된 제목", - // "수정된 내용", "수정된 협회기관명", "수정된 공모전 주제", LocalDate.of(2022, 1, 1), - // LocalDate.of(2022, 1, 26)); - // - // // when - // contestBoardService.update(StudentId, updateContestBoardDto); - // - // // then - // then(contestBoardRepository).should(times(1)).save(any()); - // } - - @DisplayName("작성자가 아니면 수정할 수 없다.") - @Test - public void failToModifyTest() { - // //given - // StudentId badUser = new StudentId("44444444"); - // StudentId originalWriter = new StudentId("12201863"); - // ContestBoard expectedContestBoard = - // new ContestBoard("title", "content", "association", "topic", - // LocalDate.of(2022, 1, 1), LocalDate.of(2022, 1, 26)) - // .writtenBy(originalWriter); - // - // given(contestBoardRepository.findById(any())).willReturn(Optional.of(expectedContestBoard)); - // - // UpdateContestBoardDto updateContestBoardDto = new UpdateContestBoardDto(1, "수정된 제목", - // "수정된 내용", "수정된 협회기관명", "수정된 공모전 주제", LocalDate.of(2022, 1, 1), - // LocalDate.of(2022, 1, 26)); - // - // // when - // Assertions.assertThrows(OnlyWriterModifiableException.class, - // ()->contestBoardService.update(badUser, updateContestBoardDto)); - // - // //then - // then(contestBoardRepository).should(times(0)).save(any()); - } - - @DisplayName("작성자가 아니면 삭제할 수 없다.") - @Test - public void failToDeleteTest() { - // //given - // StudentId badUser = new StudentId("44444444"); - // StudentId StudentId = new StudentId("12201863"); - // ContestBoard contestBoard = - // new ContestBoard("title", "content", "association", "topic", - // LocalDate.of(2022, 1, 1), LocalDate.of(2022, 1, 26)) - // .writtenBy(StudentId); - // - // given(contestBoardRepository.findById(anyInt())).willReturn(Optional.of(contestBoard)); - // - // // when - // Assertions.assertThrows(OnlyWriterModifiableException.class, - // ()->contestBoardService.delete(badUser, 1)); - // - // // then - // then(contestBoardRepository).should(times(0)).deleteById(any()); - } -} diff --git a/resource-server/src/test/java/com/inhabas/api/domain/menu/domain/MenuExampleTest.java b/resource-server/src/test/java/com/inhabas/api/domain/menu/domain/MenuExampleTest.java index 17a3daec..05031264 100644 --- a/resource-server/src/test/java/com/inhabas/api/domain/menu/domain/MenuExampleTest.java +++ b/resource-server/src/test/java/com/inhabas/api/domain/menu/domain/MenuExampleTest.java @@ -12,6 +12,10 @@ public static Menu getNormalNoticeMenu(MenuGroup menuGroup) { return new Menu(menuGroup, 1, MenuType.NORMAL_NOTICE, "공지 사항", "공지 사항 설명"); } + public static Menu getContestMenu(MenuGroup menuGroup) { + return new Menu(menuGroup, 1, MenuType.CONTEST, "공모전 게시판", "공모전 게시판 설명"); + } + public static Menu getMenu2(MenuGroup menuGroup) { return new Menu(menuGroup, 1, MenuType.STUDY, "강의", "강의 설명"); } diff --git a/resource-server/src/test/java/com/inhabas/api/domain/menu/domain/valueObject/MenuGroupExampleTest.java b/resource-server/src/test/java/com/inhabas/api/domain/menu/domain/valueObject/MenuGroupExampleTest.java index b427d696..0b112685 100644 --- a/resource-server/src/test/java/com/inhabas/api/domain/menu/domain/valueObject/MenuGroupExampleTest.java +++ b/resource-server/src/test/java/com/inhabas/api/domain/menu/domain/valueObject/MenuGroupExampleTest.java @@ -12,6 +12,10 @@ public static MenuGroup getNormalMenuGroup() { return new MenuGroup("게시판"); } + public static MenuGroup getContestMenuGroup() { + return new MenuGroup("공모전 게시판"); + } + public static MenuGroup getMenuGroup2() { return new MenuGroup("STUDY"); }