diff --git a/resource-server/src/main/java/com/inhabas/api/domain/budget/domain/BudgetSupportApplication.java b/resource-server/src/main/java/com/inhabas/api/domain/budget/domain/BudgetSupportApplication.java index 972c8715..b0a4b2b2 100644 --- a/resource-server/src/main/java/com/inhabas/api/domain/budget/domain/BudgetSupportApplication.java +++ b/resource-server/src/main/java/com/inhabas/api/domain/budget/domain/BudgetSupportApplication.java @@ -62,6 +62,9 @@ public class BudgetSupportApplication extends BaseBoard { @Column(name = "DATE_CHECKED", columnDefinition = "DATETIME(0)") private LocalDateTime dateChecked; + @Column(name = "DATE_DEPOSITED", columnDefinition = "DATETIME(0)") + private LocalDateTime dateDeposited; + public String getDetails() { return details.getValue(); } @@ -151,6 +154,7 @@ public void reject(String reason, Member memberInCharge) { public void complete(Member memberInCharge) { if (this.isApproved()) { this.status = RequestStatus.COMPLETED; + this.dateDeposited = LocalDateTime.now(); this.memberInCharge = memberInCharge; } else { throw new StatusNotFollowProceduresException(); diff --git a/resource-server/src/main/java/com/inhabas/api/domain/comment/domain/Comment.java b/resource-server/src/main/java/com/inhabas/api/domain/comment/domain/Comment.java index 0a2202cf..d73110d7 100644 --- a/resource-server/src/main/java/com/inhabas/api/domain/comment/domain/Comment.java +++ b/resource-server/src/main/java/com/inhabas/api/domain/comment/domain/Comment.java @@ -8,6 +8,7 @@ import javax.persistence.*; import lombok.AccessLevel; +import lombok.Builder; import lombok.NoArgsConstructor; import org.springframework.data.jpa.domain.support.AuditingEntityListener; @@ -51,7 +52,7 @@ public class Comment extends BaseEntity { private Boolean isDeleted = false; /* constructor */ - + @Builder public Comment(String content, Member writer, BaseBoard parentBoard) { this.content = new Content(content); this.writtenBy(writer); diff --git a/resource-server/src/main/java/com/inhabas/api/domain/menu/domain/Menu.java b/resource-server/src/main/java/com/inhabas/api/domain/menu/domain/Menu.java index 2c296bfc..87ff7c8d 100644 --- a/resource-server/src/main/java/com/inhabas/api/domain/menu/domain/Menu.java +++ b/resource-server/src/main/java/com/inhabas/api/domain/menu/domain/Menu.java @@ -45,7 +45,7 @@ public class Menu extends BaseEntity { @Embedded private MenuName name; @Enumerated(EnumType.STRING) - @Column(name = "TYPE", length = 20, nullable = false) + @Column(name = "TYPE", length = 50, nullable = false) private MenuType type; @Embedded private Description description; diff --git a/resource-server/src/main/java/com/inhabas/api/domain/myInfo/dto/MyBoardDto.java b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/dto/MyBoardDto.java new file mode 100644 index 00000000..edd0a2df --- /dev/null +++ b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/dto/MyBoardDto.java @@ -0,0 +1,43 @@ +package com.inhabas.api.domain.myInfo.dto; + +import java.time.LocalDateTime; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; + +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; + +@NoArgsConstructor +@Getter +public class MyBoardDto { + + // 게시글 id + @NotNull @Positive private Long id; + + @NotNull private Integer menuId; + + @NotNull private String menuName; + + @NotBlank private String title; + + @NotNull + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + @Schema(type = "string", example = "2024-11-01T00:00:00") + private LocalDateTime dateCreated; + + @Builder + public MyBoardDto( + Long id, Integer menuId, String menuName, String title, LocalDateTime dateCreated) { + this.id = id; + this.menuId = menuId; + this.menuName = menuName; + this.title = title; + this.dateCreated = dateCreated; + } +} diff --git a/resource-server/src/main/java/com/inhabas/api/domain/myInfo/dto/MyBudgetSupportApplicationDto.java b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/dto/MyBudgetSupportApplicationDto.java new file mode 100644 index 00000000..19092743 --- /dev/null +++ b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/dto/MyBudgetSupportApplicationDto.java @@ -0,0 +1,54 @@ +package com.inhabas.api.domain.myInfo.dto; + +import java.time.LocalDateTime; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.inhabas.api.auth.domain.oauth2.member.domain.valueObject.RequestStatus; +import io.swagger.v3.oas.annotations.media.Schema; + +@Getter +@NoArgsConstructor +public class MyBudgetSupportApplicationDto { + + @NotNull private Long id; + + @NotNull private RequestStatus status; + + @NotBlank private String title; + + @NotNull + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + @Schema(type = "string", example = "2024-11-01T00:00:00") + private LocalDateTime dateCreated; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + @Schema(type = "string", example = "2024-11-01T00:00:00") + private LocalDateTime dateChecked; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + @Schema(type = "string", example = "2024-11-01T00:00:00") + private LocalDateTime dateDeposited; + + @Builder + public MyBudgetSupportApplicationDto( + Long id, + RequestStatus status, + String title, + LocalDateTime dateCreated, + LocalDateTime dateChecked, + LocalDateTime dateDeposited) { + this.id = id; + this.status = status; + this.title = title; + this.dateCreated = dateCreated; + this.dateChecked = dateChecked; + this.dateDeposited = dateDeposited; + } +} diff --git a/resource-server/src/main/java/com/inhabas/api/domain/myInfo/dto/MyCommentDto.java b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/dto/MyCommentDto.java new file mode 100644 index 00000000..3187c5d5 --- /dev/null +++ b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/dto/MyCommentDto.java @@ -0,0 +1,46 @@ +package com.inhabas.api.domain.myInfo.dto; + +import java.time.LocalDateTime; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; + +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; + +@NoArgsConstructor +@Getter +public class MyCommentDto { + + // ParentsBoard의 게시판 id + @NotNull @Positive private Long id; + + // ParentsBoard의 menuId + @NotNull private Integer menuId; + + // ParentsBoard의 메뉴 이름 + @NotNull private String menuName; + + // 댓글의 내용 + @NotBlank private String content; + + @NotNull + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + @Schema(type = "string", example = "2024-11-01T00:00:00") + private LocalDateTime dateCreated; + + @Builder + public MyCommentDto( + Long id, Integer menuId, String menuName, String content, LocalDateTime dateCreated) { + this.id = id; + this.menuId = menuId; + this.menuName = menuName; + this.content = content; + this.dateCreated = dateCreated; + } +} diff --git a/resource-server/src/main/java/com/inhabas/api/domain/myInfo/repository/MyInfoRepository.java b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/repository/MyInfoRepository.java new file mode 100644 index 00000000..843dee09 --- /dev/null +++ b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/repository/MyInfoRepository.java @@ -0,0 +1,8 @@ +package com.inhabas.api.domain.myInfo.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.inhabas.api.domain.normalBoard.domain.NormalBoard; + +public interface MyInfoRepository + extends JpaRepository, MyInfoRepositoryCustom {} diff --git a/resource-server/src/main/java/com/inhabas/api/domain/myInfo/repository/MyInfoRepositoryCustom.java b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/repository/MyInfoRepositoryCustom.java new file mode 100644 index 00000000..49699cc7 --- /dev/null +++ b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/repository/MyInfoRepositoryCustom.java @@ -0,0 +1,16 @@ +package com.inhabas.api.domain.myInfo.repository; + +import java.util.List; + +import com.inhabas.api.domain.myInfo.dto.MyBoardDto; +import com.inhabas.api.domain.myInfo.dto.MyBudgetSupportApplicationDto; +import com.inhabas.api.domain.myInfo.dto.MyCommentDto; + +public interface MyInfoRepositoryCustom { + + List findAllBoardsByMemberId(Long memberId); + + List findAllCommentsByMemberId(Long memberId); + + List findAllBudgetSupportApplicationsByMemberId(Long memberId); +} diff --git a/resource-server/src/main/java/com/inhabas/api/domain/myInfo/repository/MyInfoRepositoryImpl.java b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/repository/MyInfoRepositoryImpl.java new file mode 100644 index 00000000..2001907e --- /dev/null +++ b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/repository/MyInfoRepositoryImpl.java @@ -0,0 +1,87 @@ +package com.inhabas.api.domain.myInfo.repository; + +import static com.inhabas.api.domain.board.domain.QBaseBoard.baseBoard; +import static com.inhabas.api.domain.budget.domain.QBudgetSupportApplication.budgetSupportApplication; +import static com.inhabas.api.domain.comment.domain.QComment.comment; + +import java.util.List; +import java.util.stream.Collectors; + +import lombok.RequiredArgsConstructor; + +import com.inhabas.api.domain.budget.domain.BudgetSupportApplication; +import com.inhabas.api.domain.comment.domain.Comment; +import com.inhabas.api.domain.myInfo.dto.MyBoardDto; +import com.inhabas.api.domain.myInfo.dto.MyBudgetSupportApplicationDto; +import com.inhabas.api.domain.myInfo.dto.MyCommentDto; +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQueryFactory; + +@RequiredArgsConstructor +public class MyInfoRepositoryImpl implements MyInfoRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + @Override + public List findAllBoardsByMemberId(Long memberId) { + return queryFactory + .select( + Projections.constructor( + MyBoardDto.class, + baseBoard.id, + baseBoard.menu.id, + baseBoard.menu.name.value, + baseBoard.title.value, + baseBoard.dateCreated)) + .from(baseBoard) + .where( + baseBoard + .writer + .id + .eq(memberId) + // budgetSupportApplication은 예산신청 조회가 따로 있으므로, 게시판 조회 범주에서 제외 + .and(baseBoard.instanceOf(BudgetSupportApplication.class).not())) + .orderBy(baseBoard.dateCreated.desc()) + .fetch(); + } + + @Override + public List findAllCommentsByMemberId(Long memberId) { + List comments = + queryFactory + .selectFrom(comment) + .where(comment.writer.id.eq(memberId)) + .orderBy(comment.dateCreated.desc()) + .fetch(); + + return comments.stream() + .map( + comment -> + new MyCommentDto( + comment.getParentBoard().getId(), + comment.getParentBoard().getMenu().getId(), + comment.getParentBoard().getMenu().getName(), + comment.getContent(), + comment.getDateCreated())) + .collect(Collectors.toList()); + } + + @Override + public List findAllBudgetSupportApplicationsByMemberId( + Long memberId) { + return queryFactory + .select( + Projections.constructor( + MyBudgetSupportApplicationDto.class, + budgetSupportApplication.id, + budgetSupportApplication.status, + budgetSupportApplication.title.value, + budgetSupportApplication.dateCreated, + budgetSupportApplication.dateChecked, + budgetSupportApplication.dateDeposited)) + .from(budgetSupportApplication) + .where(budgetSupportApplication.applicant.id.eq(memberId)) + .orderBy(budgetSupportApplication.dateCreated.desc()) + .fetch(); + } +} diff --git a/resource-server/src/main/java/com/inhabas/api/domain/myInfo/usecase/MyInfoService.java b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/usecase/MyInfoService.java new file mode 100644 index 00000000..41e4f259 --- /dev/null +++ b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/usecase/MyInfoService.java @@ -0,0 +1,15 @@ +package com.inhabas.api.domain.myInfo.usecase; + +import java.util.List; + +import com.inhabas.api.domain.myInfo.dto.MyBoardDto; +import com.inhabas.api.domain.myInfo.dto.MyBudgetSupportApplicationDto; +import com.inhabas.api.domain.myInfo.dto.MyCommentDto; + +public interface MyInfoService { + List getMyBoards(Long memberId); + + List getMyComments(Long memberId); + + List getMyBudgetSupportApplications(Long memberId); +} diff --git a/resource-server/src/main/java/com/inhabas/api/domain/myInfo/usecase/MyInfoServiceImpl.java b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/usecase/MyInfoServiceImpl.java new file mode 100644 index 00000000..b3144cf2 --- /dev/null +++ b/resource-server/src/main/java/com/inhabas/api/domain/myInfo/usecase/MyInfoServiceImpl.java @@ -0,0 +1,60 @@ +package com.inhabas.api.domain.myInfo.usecase; + +import java.util.ArrayList; +import java.util.List; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.inhabas.api.domain.myInfo.dto.MyBoardDto; +import com.inhabas.api.domain.myInfo.dto.MyBudgetSupportApplicationDto; +import com.inhabas.api.domain.myInfo.dto.MyCommentDto; +import com.inhabas.api.domain.myInfo.repository.MyInfoRepository; + +@Service +@Slf4j +@RequiredArgsConstructor +public class MyInfoServiceImpl implements MyInfoService { + + private final MyInfoRepository myInfoRepository; + + // 현재 로그인한 유저의 모든 게시글을 불러온다. + @Override + @Transactional(readOnly = true) + public List getMyBoards(Long memberId) { + + List myBoardDtoList = new ArrayList<>(); + + myBoardDtoList.addAll(myInfoRepository.findAllBoardsByMemberId(memberId)); + + return myBoardDtoList; + } + + // 현재 로그인한 유저의 모든 댓글을 불러온다. + @Override + @Transactional(readOnly = true) + public List getMyComments(Long memberId) { + + List myCommentDtoList = new ArrayList<>(); + + myCommentDtoList.addAll(myInfoRepository.findAllCommentsByMemberId(memberId)); + + return myCommentDtoList; + } + + // 현재 로그인한 유저의 모든 예산 신청 내역을 불러온다. + @Override + @Transactional(readOnly = true) + public List getMyBudgetSupportApplications(Long memberId) { + + List budgetSupportApplicationDtoList = new ArrayList<>(); + + budgetSupportApplicationDtoList.addAll( + myInfoRepository.findAllBudgetSupportApplicationsByMemberId(memberId)); + + return budgetSupportApplicationDtoList; + } +} diff --git a/resource-server/src/main/java/com/inhabas/api/web/MyProfileController.java b/resource-server/src/main/java/com/inhabas/api/web/MyInfoController.java similarity index 71% rename from resource-server/src/main/java/com/inhabas/api/web/MyProfileController.java rename to resource-server/src/main/java/com/inhabas/api/web/MyInfoController.java index 75a87cd7..c21a65bf 100644 --- a/resource-server/src/main/java/com/inhabas/api/web/MyProfileController.java +++ b/resource-server/src/main/java/com/inhabas/api/web/MyInfoController.java @@ -18,6 +18,10 @@ import com.inhabas.api.auth.domain.error.ErrorResponse; import com.inhabas.api.auth.domain.oauth2.member.dto.*; import com.inhabas.api.domain.member.usecase.MemberProfileService; +import com.inhabas.api.domain.myInfo.dto.MyBoardDto; +import com.inhabas.api.domain.myInfo.dto.MyBudgetSupportApplicationDto; +import com.inhabas.api.domain.myInfo.dto.MyCommentDto; +import com.inhabas.api.domain.myInfo.usecase.MyInfoService; import com.inhabas.api.global.dto.PageInfoDto; import com.inhabas.api.global.dto.PagedResponseDto; import com.inhabas.api.global.util.PageUtil; @@ -35,9 +39,10 @@ @RestController @Tag(name = "내 정보 관리", description = "마이 페이지 기능") @RequiredArgsConstructor -public class MyProfileController { +public class MyInfoController { private final MemberProfileService memberProfileService; + private final MyInfoService myInfoService; @Operation(summary = "내 정보 조회", description = "사용자 자신의 정보만 조회 가능") @ApiResponses( @@ -225,6 +230,94 @@ public ResponseEntity handleMyInfoRequest( return ResponseEntity.noContent().build(); } - // [모임, 글, 댓글, 예산신청 조회] 추후 개발 예정 + @Operation(summary = "내가 쓴 게시글 목록 조회") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + content = {@Content(schema = @Schema(implementation = MyBoardDto.class))}), + }) + @GetMapping("/myInfo/boards") + public ResponseEntity> getBoardList( + @Parameter(description = "페이지", example = "0") + @RequestParam(name = "page", defaultValue = "0") + int page, + @Parameter(description = "페이지당 개수", example = "10") + @RequestParam(name = "size", defaultValue = "10") + int size, + @Authenticated Long memberId) { + + Pageable pageable = PageRequest.of(page, size); + List allDtoList = myInfoService.getMyBoards(memberId); + List pagedDtoList = PageUtil.getPagedDtoList(pageable, allDtoList); + + PageImpl myBoardsDtoPage = + new PageImpl<>(pagedDtoList, pageable, allDtoList.size()); + PageInfoDto pageInfoDto = new PageInfoDto(myBoardsDtoPage); + + return ResponseEntity.ok(new PagedResponseDto<>(pageInfoDto, pagedDtoList)); + } + + @Operation(summary = "내가 쓴 댓글 목록 조회") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + content = {@Content(schema = @Schema(implementation = MyCommentDto.class))}), + }) + @GetMapping("/myInfo/comments") + public ResponseEntity> getCommentsList( + @Parameter(description = "페이지", example = "0") + @RequestParam(name = "page", defaultValue = "0") + int page, + @Parameter(description = "페이지당 개수", example = "10") + @RequestParam(name = "size", defaultValue = "10") + int size, + @Authenticated Long memberId) { + + Pageable pageable = PageRequest.of(page, size); + List allDtoList = myInfoService.getMyComments(memberId); + List pagedDtoList = PageUtil.getPagedDtoList(pageable, allDtoList); + + PageImpl myCommentsDtoPage = + new PageImpl<>(pagedDtoList, pageable, allDtoList.size()); + PageInfoDto pageInfoDto = new PageInfoDto(myCommentsDtoPage); + + return ResponseEntity.ok(new PagedResponseDto<>(pageInfoDto, pagedDtoList)); + } + + @Operation(summary = "내가 쓴 예산지원신청 목록 조회") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + content = { + @Content(schema = @Schema(implementation = MyBudgetSupportApplicationDto.class)) + }), + }) + @GetMapping("/myInfo/supports") + public ResponseEntity> + getBudgetSupportApplicationsList( + @Parameter(description = "페이지", example = "0") + @RequestParam(name = "page", defaultValue = "0") + int page, + @Parameter(description = "페이지당 개수", example = "10") + @RequestParam(name = "size", defaultValue = "10") + int size, + @Authenticated Long memberId) { + + Pageable pageable = PageRequest.of(page, size); + List allDtoList = + myInfoService.getMyBudgetSupportApplications(memberId); + List pagedDtoList = + PageUtil.getPagedDtoList(pageable, allDtoList); + + PageImpl myBudgetSupportApplicationDtoPage = + new PageImpl<>(pagedDtoList, pageable, allDtoList.size()); + PageInfoDto pageInfoDto = new PageInfoDto(myBudgetSupportApplicationDtoPage); + + return ResponseEntity.ok(new PagedResponseDto<>(pageInfoDto, pagedDtoList)); + } + // [모임, 강의 조회] 추후 개발 예정 } diff --git a/resource-server/src/test/java/com/inhabas/api/domain/myInfo/domain/MyBoardExampleTest.java b/resource-server/src/test/java/com/inhabas/api/domain/myInfo/domain/MyBoardExampleTest.java new file mode 100644 index 00000000..cd639d0d --- /dev/null +++ b/resource-server/src/test/java/com/inhabas/api/domain/myInfo/domain/MyBoardExampleTest.java @@ -0,0 +1,3 @@ +package com.inhabas.api.domain.myInfo.domain; + +public class MyBoardExampleTest {} diff --git a/resource-server/src/test/java/com/inhabas/api/domain/myInfo/dto/MyBoardDtoTest.java b/resource-server/src/test/java/com/inhabas/api/domain/myInfo/dto/MyBoardDtoTest.java new file mode 100644 index 00000000..31092ce0 --- /dev/null +++ b/resource-server/src/test/java/com/inhabas/api/domain/myInfo/dto/MyBoardDtoTest.java @@ -0,0 +1,73 @@ +package com.inhabas.api.domain.myInfo.dto; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDateTime; +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; + +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 MyBoardDtoTest { + + 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("MyBoardDto 객체를 정상적으로 생성한다.") + @Test + public void MyBoardsDto_is_OK() { + // given + MyBoardDto myBoardDto = + MyBoardDto.builder() + .id(1L) + .menuId(16) + .menuName("알파 테스터") + .title("title") + .dateCreated(LocalDateTime.now()) + .build(); + + // when + Set> violations = validator.validate(myBoardDto); + + // then + assertThat(violations).isEmpty(); + } + + @DisplayName("MyBoardDto menuName 필드가 null 이면 validation 실패") + @Test + public void MenuName_is_null() { + // given + MyBoardDto myBoardDto = + MyBoardDto.builder() + .id(1L) + .menuId(16) + .menuName(null) + .title("title") + .dateCreated(LocalDateTime.now()) + .build(); + + // when + Set> violations = validator.validate(myBoardDto); + + // then + assertThat(violations).hasSize(1); + } +} diff --git a/resource-server/src/test/java/com/inhabas/api/domain/myInfo/dto/MyBudgetSupportApplicationsTest.java b/resource-server/src/test/java/com/inhabas/api/domain/myInfo/dto/MyBudgetSupportApplicationsTest.java new file mode 100644 index 00000000..d55b6254 --- /dev/null +++ b/resource-server/src/test/java/com/inhabas/api/domain/myInfo/dto/MyBudgetSupportApplicationsTest.java @@ -0,0 +1,79 @@ +package com.inhabas.api.domain.myInfo.dto; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDateTime; +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; + +import com.inhabas.api.auth.domain.oauth2.member.domain.valueObject.RequestStatus; + +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 MyBudgetSupportApplicationsTest { + + 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("MyBudgetSupportApplicationsDto 객체를 정상적으로 생성한다.") + @Test + public void MyBoardsDto_is_OK() { + // given + MyBudgetSupportApplicationDto myBudgetSupportApplicationDto = + MyBudgetSupportApplicationDto.builder() + .id(1L) + .status(RequestStatus.COMPLETED) + .title("예산신청 제목") + .dateCreated(LocalDateTime.now()) + .dateChecked(LocalDateTime.now()) + .dateDeposited(LocalDateTime.now()) + .build(); + + // when + Set> violations = + validator.validate(myBudgetSupportApplicationDto); + + // then + assertThat(violations).isEmpty(); + } + + @DisplayName("MyBudgetSupportApplicationsDto status 필드가 null 이면 validation 실패") + @Test + public void MenuName_is_null() { + // given + MyBudgetSupportApplicationDto myBudgetSupportApplicationDto = + MyBudgetSupportApplicationDto.builder() + .id(1L) + .status(null) + .title("예산신청 제목") + .dateCreated(LocalDateTime.now()) + .dateChecked(LocalDateTime.now()) + .dateDeposited(LocalDateTime.now()) + .build(); + + // when + Set> violations = + validator.validate(myBudgetSupportApplicationDto); + + // then + assertThat(violations).hasSize(1); + } +} diff --git a/resource-server/src/test/java/com/inhabas/api/domain/myInfo/dto/MyCommentDtoTest.java b/resource-server/src/test/java/com/inhabas/api/domain/myInfo/dto/MyCommentDtoTest.java new file mode 100644 index 00000000..700ca4f8 --- /dev/null +++ b/resource-server/src/test/java/com/inhabas/api/domain/myInfo/dto/MyCommentDtoTest.java @@ -0,0 +1,73 @@ +package com.inhabas.api.domain.myInfo.dto; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDateTime; +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; + +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 MyCommentDtoTest { + + 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("MyCommentDto 객체를 정상적으로 생성한다.") + @Test + public void MyCommentsDto_is_OK() { + // given + MyCommentDto myCommentDto = + MyCommentDto.builder() + .id(1L) + .menuId(16) + .menuName("알파 테스터") + .content("댓글 내용") + .dateCreated(LocalDateTime.now()) + .build(); + + // when + Set> violations = validator.validate(myCommentDto); + + // then + assertThat(violations).isEmpty(); + } + + @DisplayName("MyCommentDto content 필드가 blank 이면 validation 실패") + @Test + public void Content_is_blank() { + // given + MyCommentDto myCommentDto = + MyCommentDto.builder() + .id(1L) + .menuId(16) + .menuName("알파 테스터") + .content("") + .dateCreated(LocalDateTime.now()) + .build(); + + // when + Set> violations = validator.validate(myCommentDto); + + // then + assertThat(violations).hasSize(1); + } +} diff --git a/resource-server/src/test/java/com/inhabas/api/domain/myInfo/repository/MyInfoRepositoryTest.java b/resource-server/src/test/java/com/inhabas/api/domain/myInfo/repository/MyInfoRepositoryTest.java new file mode 100644 index 00000000..eae8ff04 --- /dev/null +++ b/resource-server/src/test/java/com/inhabas/api/domain/myInfo/repository/MyInfoRepositoryTest.java @@ -0,0 +1,139 @@ +package com.inhabas.api.domain.myInfo.repository; + +import static com.inhabas.api.domain.member.domain.entity.MemberTest.basicMember1; +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDateTime; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.transaction.annotation.Transactional; + +import com.inhabas.api.auth.domain.oauth2.member.domain.entity.Member; +import com.inhabas.api.auth.domain.oauth2.member.domain.valueObject.RequestStatus; +import com.inhabas.api.domain.budget.domain.BudgetSupportApplication; +import com.inhabas.api.domain.budget.repository.BudgetApplicationRepository; +import com.inhabas.api.domain.comment.domain.Comment; +import com.inhabas.api.domain.comment.repository.CommentRepository; +import com.inhabas.api.domain.menu.domain.Menu; +import com.inhabas.api.domain.menu.domain.MenuGroup; +import com.inhabas.api.domain.menu.domain.valueObject.MenuType; +import com.inhabas.api.domain.myInfo.dto.MyBoardDto; +import com.inhabas.api.domain.myInfo.dto.MyBudgetSupportApplicationDto; +import com.inhabas.api.domain.myInfo.dto.MyCommentDto; +import com.inhabas.api.domain.normalBoard.domain.NormalBoard; +import com.inhabas.api.domain.normalBoard.domain.NormalBoardExampleTest; +import com.inhabas.api.domain.normalBoard.repository.NormalBoardRepository; +import com.inhabas.testAnnotataion.DefaultDataJpaTest; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DefaultDataJpaTest +public class MyInfoRepositoryTest { + + @Autowired MyInfoRepository myInfoRepository; + @Autowired NormalBoardRepository normalBoardRepository; + @Autowired CommentRepository commentRepository; + @Autowired BudgetApplicationRepository budgetApplicationRepository; + @Autowired TestEntityManager em; + + private Member writer; + + @Transactional + @BeforeEach + public void setUp() { + writer = em.persist(basicMember1()); + + MenuGroup normalBoardMenuGroup = em.persist(new MenuGroup("게시판")); + Menu noticeBoardMenu = + em.persist( + Menu.builder() + .menuGroup(normalBoardMenuGroup) + .priority(1) + .type(MenuType.NORMAL_NOTICE) + .name("공지사항") + .description("부원이 알아야 할 내용을 게시합니다.") + .build()); + + NormalBoard noticeBoard1 = + NormalBoardExampleTest.getBoard1(noticeBoardMenu).writtenBy(writer, NormalBoard.class); + NormalBoard noticeBoard2 = + NormalBoardExampleTest.getBoard2(noticeBoardMenu).writtenBy(writer, NormalBoard.class); + normalBoardRepository.save(noticeBoard1); + normalBoardRepository.save(noticeBoard2); + + Comment comment1 = + Comment.builder().content("내가 쓴 댓글").writer(writer).parentBoard(noticeBoard1).build(); + Comment reply1 = + Comment.builder() + .content("내가 쓴 대댓글") + .writer(writer) + .parentBoard(noticeBoard1) + .build() + .replyTo(comment1); + commentRepository.save(comment1); + commentRepository.save(reply1); + + MenuGroup budgetBoardMenuGroup = em.persist(new MenuGroup("회계")); + Menu budgetMenu = + em.persist( + Menu.builder() + .menuGroup(budgetBoardMenuGroup) + .priority(1) + .type(MenuType.BUDGET_SUPPORT) + .name("예산지원신청") + .description("예산 지원을 신청하는 게시판입니다.") + .build()); + + BudgetSupportApplication application = + BudgetSupportApplication.builder() + .applicant(writer) + .account("123-123-123") + .title("title") + .dateUsed(LocalDateTime.now()) + .details("details") + .menu(budgetMenu) + .outcome(10000) + .status(RequestStatus.PENDING) + .build() + .writtenBy(writer, BudgetSupportApplication.class); + budgetApplicationRepository.save(application); + } + + @DisplayName("내가 작성한 글 목록을 내 정보에서 조회한다.") + @Transactional(readOnly = true) + @Test + public void findAllBoardsByMemberId() { + List myBoards = myInfoRepository.findAllBoardsByMemberId(writer.getId()); + + assertThat(myBoards).hasSize(2); + assertThat(myBoards.get(0).getTitle()).isEqualTo("이건 공지1"); + assertThat(myBoards.get(1).getTitle()).isEqualTo("이건 공지2"); + } + + @DisplayName("내가 작성한 댓글 목록을 내 정보에서 조회한다.") + @Transactional(readOnly = true) + @Test + public void findAllCommentsByMemberId() { + List myComments = myInfoRepository.findAllCommentsByMemberId(writer.getId()); + + assertThat(myComments).hasSize(2); + // 이 부분은 실제 내용으로 교체 필요 + assertThat(myComments.get(0).getContent()).isEqualTo("내가 쓴 댓글"); + assertThat(myComments.get(1).getContent()).isEqualTo("내가 쓴 대댓글"); + } + + @DisplayName("내가 작성한 예산지원신청 목록을 내 정보에서 조회한다.") + @Transactional(readOnly = true) + @Test + public void findAllBudgetSupportApplicationsByMemberId() { + List myBudgetSupportApplications = + myInfoRepository.findAllBudgetSupportApplicationsByMemberId(writer.getId()); + + assertThat(myBudgetSupportApplications).hasSize(1); + assertThat(myBudgetSupportApplications.get(0).getTitle()).isEqualTo("title"); + } +} diff --git a/resource-server/src/test/java/com/inhabas/api/domain/myInfo/usecase/MyInfoServiceImplTest.java b/resource-server/src/test/java/com/inhabas/api/domain/myInfo/usecase/MyInfoServiceImplTest.java new file mode 100644 index 00000000..27b0f528 --- /dev/null +++ b/resource-server/src/test/java/com/inhabas/api/domain/myInfo/usecase/MyInfoServiceImplTest.java @@ -0,0 +1,75 @@ +package com.inhabas.api.domain.myInfo.usecase; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; + +import java.util.Collections; +import java.util.List; + +import org.springframework.transaction.annotation.Transactional; + +import com.inhabas.api.auth.domain.oauth2.member.domain.entity.Member; +import com.inhabas.api.domain.member.domain.entity.MemberTest; +import com.inhabas.api.domain.myInfo.dto.MyBoardDto; +import com.inhabas.api.domain.myInfo.dto.MyBudgetSupportApplicationDto; +import com.inhabas.api.domain.myInfo.dto.MyCommentDto; +import com.inhabas.api.domain.myInfo.repository.MyInfoRepository; +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 MyInfoServiceImplTest { + + @Mock private MyInfoRepository myInfoRepository; + + @InjectMocks private MyInfoServiceImpl myInfoService; + + @DisplayName("내가 쓴 게시글 목록을 조회한다.") + @Transactional(readOnly = true) + @Test + void getMyBoards() { + Member writer = MemberTest.basicMember1(); + given(myInfoRepository.findAllBoardsByMemberId(writer.getId())) + .willReturn(Collections.singletonList(new MyBoardDto())); + + List result = myInfoService.getMyBoards(writer.getId()); + + assertThat(result).isNotEmpty(); + verify(myInfoRepository).findAllBoardsByMemberId(writer.getId()); + } + + @DisplayName("내가 쓴 댓글 목록을 조회한다.") + @Transactional(readOnly = true) + @Test + void getMyComments() { + Member writer = MemberTest.basicMember1(); + given(myInfoRepository.findAllCommentsByMemberId(writer.getId())) + .willReturn(Collections.singletonList(new MyCommentDto())); + + List result = myInfoService.getMyComments(writer.getId()); + + assertThat(result).isNotEmpty(); + verify(myInfoRepository).findAllCommentsByMemberId(writer.getId()); + } + + @DisplayName("내가 쓴 예산지원 신청 목록을 조회한다.") + @Transactional(readOnly = true) + @Test + void getMyBudgetSupportApplications() { + Member writer = MemberTest.basicMember1(); + given(myInfoRepository.findAllBudgetSupportApplicationsByMemberId(writer.getId())) + .willReturn(Collections.singletonList(new MyBudgetSupportApplicationDto())); + + List result = + myInfoService.getMyBudgetSupportApplications(writer.getId()); + + assertThat(result).isNotEmpty(); + verify(myInfoRepository).findAllBudgetSupportApplicationsByMemberId(writer.getId()); + } +} diff --git a/resource-server/src/test/java/com/inhabas/api/web/MyProfileControllerTest.java b/resource-server/src/test/java/com/inhabas/api/web/MyInfoControllerTest.java similarity index 73% rename from resource-server/src/test/java/com/inhabas/api/web/MyProfileControllerTest.java rename to resource-server/src/test/java/com/inhabas/api/web/MyInfoControllerTest.java index 3bf0bd9a..0b4bbd86 100644 --- a/resource-server/src/test/java/com/inhabas/api/web/MyProfileControllerTest.java +++ b/resource-server/src/test/java/com/inhabas/api/web/MyInfoControllerTest.java @@ -28,16 +28,21 @@ import com.inhabas.api.auth.domain.oauth2.member.dto.*; import com.inhabas.api.domain.member.domain.entity.MemberTest; import com.inhabas.api.domain.member.usecase.MemberProfileService; +import com.inhabas.api.domain.myInfo.dto.MyBoardDto; +import com.inhabas.api.domain.myInfo.dto.MyBudgetSupportApplicationDto; +import com.inhabas.api.domain.myInfo.dto.MyCommentDto; +import com.inhabas.api.domain.myInfo.usecase.MyInfoService; import com.inhabas.testAnnotataion.NoSecureWebMvcTest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -@NoSecureWebMvcTest(MyProfileController.class) -class MyProfileControllerTest { +@NoSecureWebMvcTest(MyInfoController.class) +class MyInfoControllerTest { @Autowired private MockMvc mvc; @MockBean private MemberProfileService memberProfileService; + @MockBean private MyInfoService myInfoService; @Autowired private ObjectMapper objectMapper; private String jsonOf(Object o) throws JsonProcessingException { @@ -240,4 +245,87 @@ public void handleMyInfoRequestTest() throws Exception { .content(jsonOf(handleNameRequestDto))) .andExpect(status().isNoContent()); } + + @DisplayName("내가 작성한 게시글 목록을 조회 성공 200") + @Test + public void getMyBoardsTest() throws Exception { + // given + Member writer = MemberTest.basicMember1(); + MyBoardDto myBoardDto = + MyBoardDto.builder() + .id(1L) + .menuId(4) + .menuName("공지사항") + .title("이건 공지") + .dateCreated(LocalDateTime.now()) + .build(); + given(myInfoService.getMyBoards(writer.getId())).willReturn(List.of(myBoardDto)); + + // when + String response = + mvc.perform(get("/myInfo/boards")) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsString(StandardCharsets.UTF_8); + + // then + assertThat(response).contains(jsonOf(List.of(myBoardDto))); + } + + @DisplayName("내가 작성한 댓글 목록을 조회 성공 200") + @Test + public void getMyCommentsTest() throws Exception { + // given + Member writer = MemberTest.basicMember1(); + MyCommentDto myCommentDto = + MyCommentDto.builder() + .id(1L) + .menuId(1) + .menuName("자유게시판") + .content("댓글댓글") + .dateCreated(LocalDateTime.now()) + .build(); + given(myInfoService.getMyComments(writer.getId())).willReturn(List.of(myCommentDto)); + + // when + String response = + mvc.perform(get("/myInfo/comments")) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsString(StandardCharsets.UTF_8); + + // then + assertThat(response).contains(jsonOf(List.of(myCommentDto))); + } + + @DisplayName("내가 작성한 예산지원신청 목록을 조회 성공 200.") + @Test + public void getMyBudgetSupportApplicationsTest() throws Exception { + // given + Member writer = MemberTest.basicMember1(); + MyBudgetSupportApplicationDto myBudgetSupportApplicationDto = + MyBudgetSupportApplicationDto.builder() + .id(1L) + .status(RequestStatus.COMPLETED) + .title("1월 ec2 서버비용") + .dateCreated(LocalDateTime.now()) + .dateChecked(LocalDateTime.now()) + .dateDeposited(LocalDateTime.now()) + .build(); + given(myInfoService.getMyBudgetSupportApplications(writer.getId())) + .willReturn(List.of(myBudgetSupportApplicationDto)); + + // when + String response = + mvc.perform(get("/myInfo/supports")) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsString(StandardCharsets.UTF_8); + + // then + assertThat(response).contains(jsonOf(List.of(myBudgetSupportApplicationDto))); + } }