diff --git a/module-api/src/main/java/com/mile/controller/moim/MoimController.java b/module-api/src/main/java/com/mile/controller/moim/MoimController.java index b339d155..81d5f937 100644 --- a/module-api/src/main/java/com/mile/controller/moim/MoimController.java +++ b/module-api/src/main/java/com/mile/controller/moim/MoimController.java @@ -10,6 +10,7 @@ import com.mile.moim.service.dto.MoimCuriousPostListResponse; import com.mile.moim.service.dto.MoimInfoOwnerResponse; import com.mile.moim.service.dto.MoimInfoResponse; +import com.mile.moim.service.dto.MoimTopicInfoListResponse; import com.mile.moim.service.dto.MoimNameConflictCheckResponse; import com.mile.moim.service.dto.MoimInvitationInfoResponse; import com.mile.moim.service.dto.MoimInfoModifyRequest; @@ -174,6 +175,15 @@ public SuccessResponse getTemporaryPost( return SuccessResponse.of(SuccessMessage.IS_TEMPORARY_POST_EXIST_GET_SUCCESS, moimService.getTemporaryPost(moimId, principalHandler.getUserIdFromPrincipal())); } + @Override + @GetMapping("/{moimId}/admin/topicList") + public ResponseEntity> getMoimTopicList( + @MoimIdPathVariable final Long moimId, + @RequestParam final int page, + @PathVariable("moimId") final String moimUrl + ) { + return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.MOIM_TOPIC_LIST_GET_SUCCESS, moimService.getMoimTopicList(moimId, principalHandler.getUserIdFromPrincipal(), page))); + } @Override @PutMapping("/{moimId}/info") diff --git a/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java b/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java index b5591082..0d4e9010 100644 --- a/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java +++ b/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java @@ -7,6 +7,8 @@ import com.mile.moim.service.dto.MoimCuriousPostListResponse; import com.mile.moim.service.dto.MoimInfoOwnerResponse; import com.mile.moim.service.dto.MoimInfoResponse; +import com.mile.moim.service.dto.MoimTopicInfoListResponse; +import com.mile.moim.service.dto.MoimNameConflictCheckResponse; import com.mile.moim.service.dto.MoimInvitationInfoResponse; import com.mile.moim.service.dto.MoimNameConflictCheckResponse; import com.mile.moim.service.dto.MoimInfoModifyRequest; @@ -214,6 +216,21 @@ ResponseEntity joinMoim( @PathVariable("moimId") final String moimUrl ); + @Operation(summary = "관리자 페이지 글감 조회") + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "글감 리스트 조회가 완료되었습니다."), + @ApiResponse(responseCode = "404", description = "해당 모임은 존재하지 않습니다."), + @ApiResponse(responseCode = "403", description = "사용자는 해당 모임의 모임장이 아닙니다."), + @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))) + } + ) + ResponseEntity> getMoimTopicList( + @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long moimId, + final int page, + @PathVariable("moimId") final String moimUrl + ); @Operation(summary = "관리자 페이지 모임 정보 수정") diff --git a/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java b/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java index 32cbd86e..afe7130b 100644 --- a/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java +++ b/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java @@ -67,6 +67,7 @@ public enum ErrorMessage { Forbidden */ COMMENT_ACCESS_ERROR(HttpStatus.FORBIDDEN.value(), "해당 사용자는 댓글에 접근 권한이 없습니다."), + OWNER_AUTHENTICATE_ERROR(HttpStatus.FORBIDDEN.value(), "사용자는 해당 모임의 모임장이 아닙니다."), /* Method Not Supported */ diff --git a/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java b/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java index 3488bb4e..1bc8737c 100644 --- a/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java +++ b/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java @@ -35,6 +35,7 @@ public enum SuccessMessage { IS_TEMPORARY_POST_EXIST_GET_SUCCESS(HttpStatus.OK.value(), "임시저장 글 존재 여부 조회가 완료되었습니다."), MOIM_INVITE_INFO_GET_SUCCESS(HttpStatus.OK.value(), "모임의 초대 정보 조회가 완료되었습니다."), IS_CONFLICT_WRITER_NAME_GET_SUCCESS(HttpStatus.OK.value(), "댓글 중복 여부가 조회되었습니다."), + MOIM_TOPIC_LIST_GET_SUCCESS(HttpStatus.OK.value(), "글감 리스트 조회가 완료되었습니다."), TOPIC_PUT_SUCCESS(HttpStatus.OK.value(), "글감 수정이 완료되었습니다."), TOPIC_DETAIL_GET_SUCCESS(HttpStatus.OK.value(), "글감 상세 정보 조회가 완료되었습니다."), MOIM_INFORMATION_PUT_SUCCESS(HttpStatus.OK.value(), "모임 정보 수정이 완료되었습니다."), diff --git a/module-domain/src/main/java/com/mile/moim/service/MoimService.java b/module-domain/src/main/java/com/mile/moim/service/MoimService.java index 3d4360e4..2e9367d3 100644 --- a/module-domain/src/main/java/com/mile/moim/service/MoimService.java +++ b/module-domain/src/main/java/com/mile/moim/service/MoimService.java @@ -12,6 +12,7 @@ import com.mile.moim.service.dto.MoimInfoModifyRequest; import com.mile.moim.service.dto.MoimInfoOwnerResponse; import com.mile.moim.service.dto.MoimInfoResponse; +import com.mile.moim.service.dto.MoimTopicInfoListResponse; import com.mile.moim.service.dto.MoimNameConflictCheckResponse; import com.mile.moim.service.dto.MoimInvitationInfoResponse; import com.mile.moim.service.dto.MoimTopicResponse; @@ -34,6 +35,8 @@ import com.mile.utils.SecureUrlUtil; import com.mile.writername.domain.WriterName; import com.mile.writername.service.WriterNameService; +import com.mile.moim.service.dto.PopularWriterListResponse; +import java.util.stream.Collectors; import com.mile.writername.service.dto.WriterNameInfoResponse; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -178,6 +181,26 @@ public TemporaryPostExistResponse getTemporaryPost( return TemporaryPostExistResponse.of(!secureUrlUtil.decodeUrl(postId).equals(0L), postId); } + public MoimTopicInfoListResponse getMoimTopicList( + final Long moimId, + final Long userId, + final int page + ) { + getAuthenticateOwnerOfMoim(moimId, userId); + return topicService.getTopicListFromMoim(moimId, page); + } + + private void getAuthenticateOwnerOfMoim( + final Long moimId, + final Long userId + ) { + Long writerNameId = writerNameService.getWriterNameIdByMoimIdAndUserId(moimId, userId); + Moim moim = findById(moimId); + if (!moim.getOwner().getId().equals(writerNameId)) { + throw new ForbiddenException(ErrorMessage.OWNER_AUTHENTICATE_ERROR); + } + } + @Transactional public void modifyMoimInforation( final Long moimId, diff --git a/module-domain/src/main/java/com/mile/moim/service/dto/MoimTopicInfoListResponse.java b/module-domain/src/main/java/com/mile/moim/service/dto/MoimTopicInfoListResponse.java new file mode 100644 index 00000000..1003ab33 --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/service/dto/MoimTopicInfoListResponse.java @@ -0,0 +1,21 @@ +package com.mile.moim.service.dto; + +import java.util.List; + +public record MoimTopicInfoListResponse( + int pageNumber, + Long topicCount, + List topics +) { + public static MoimTopicInfoListResponse of ( + final int pageNumber, + final Long topicCount, + final List moimTopicInfoResponses + ) { + return new MoimTopicInfoListResponse( + pageNumber, + topicCount, + moimTopicInfoResponses + ); + } +} diff --git a/module-domain/src/main/java/com/mile/moim/service/dto/MoimTopicInfoResponse.java b/module-domain/src/main/java/com/mile/moim/service/dto/MoimTopicInfoResponse.java new file mode 100644 index 00000000..23725ff4 --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/service/dto/MoimTopicInfoResponse.java @@ -0,0 +1,24 @@ +package com.mile.moim.service.dto; + +import com.mile.topic.domain.Topic; +import com.mile.utils.DateUtil; + +public record MoimTopicInfoResponse( + String topicId, + String topicName, + String topicTag, + String topicDescription, + String createdAt +) { + public static MoimTopicInfoResponse of( + final Topic topic + ) { + return new MoimTopicInfoResponse( + topic.getIdUrl(), + topic.getContent(), + topic.getKeyword(), + topic.getDescription(), + DateUtil.getStringDateOfLocalDate(topic.getCreatedAt()) + ); + } +} diff --git a/module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java b/module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java index 6da99fd6..410dacb4 100644 --- a/module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java +++ b/module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java @@ -1,5 +1,6 @@ package com.mile.topic.repository; - +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import com.mile.topic.domain.Topic; import org.springframework.data.jpa.repository.JpaRepository; @@ -8,4 +9,6 @@ public interface TopicRepository extends JpaRepository, TopicRepositoryCustom { List findByMoimId(final Long moimId); + Page findByMoimIdOrderByCreatedAtDesc(Long moimId, Pageable pageable); + Long countByMoimId(final Long moimId); } diff --git a/module-domain/src/main/java/com/mile/topic/service/TopicService.java b/module-domain/src/main/java/com/mile/topic/service/TopicService.java index 98fa2c99..546acd56 100644 --- a/module-domain/src/main/java/com/mile/topic/service/TopicService.java +++ b/module-domain/src/main/java/com/mile/topic/service/TopicService.java @@ -6,6 +6,8 @@ import com.mile.exception.model.ForbiddenException; import com.mile.exception.model.NotFoundException; import com.mile.moim.domain.Moim; +import com.mile.moim.service.dto.MoimTopicInfoListResponse; +import com.mile.moim.service.dto.MoimTopicInfoResponse; import com.mile.moim.service.dto.TopicCreateRequest; import com.mile.post.service.PostGetService; import com.mile.post.service.dto.PostListResponse; @@ -23,6 +25,9 @@ import com.mile.utils.SecureUrlUtil; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; import org.springframework.stereotype.Service; @@ -34,6 +39,8 @@ @RequiredArgsConstructor public class TopicService { + private static final int TOPIC_PER_PAGE_SIZE = 4; + private final TopicRepository topicRepository; private final CommentService commentService; private final UserService userService; @@ -141,6 +148,38 @@ public PostListInTopicResponse getPostListByTopic( postGetService.findByTopic(topic).stream().map(p -> PostListResponse.of(p, commentService.findCommentCountByPost(p))).collect(Collectors.toList())); } + public MoimTopicInfoListResponse getTopicListFromMoim( + final Long moimId, + final int page + ) { + + PageRequest pageRequest = PageRequest.of(page-1, TOPIC_PER_PAGE_SIZE, Sort.by(Sort.Direction.DESC, "createdAt")); + Page topicPage = topicRepository.findByMoimIdOrderByCreatedAtDesc(moimId, pageRequest); + + isContentsEmpty(topicPage.getContent()); + + return getTopicResponsesFromPage(topicPage, moimId); + } + + public MoimTopicInfoListResponse getTopicResponsesFromPage(Page topicPage, final Long moimId) { + List infoResponses = topicPage.getContent() + .stream() + .map(MoimTopicInfoResponse::of) + .collect(Collectors.toList()); + + return MoimTopicInfoListResponse.of( + topicPage.getTotalPages(), + getNumberOfTopicFromMoim(moimId), + infoResponses + ); + } + + public Long getNumberOfTopicFromMoim( + final Long moimId + ) { + return topicRepository.countByMoimId(moimId); + } + public TopicDetailResponse getTopicDetail( final Long userId, final Long topicId