-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #30 from prgrms-web-devcourse-final-project/featur…
…e/read-share-board(WR9-25) Feature/read share board(wr9 25)
- Loading branch information
Showing
14 changed files
with
550 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
src/main/java/io/crops/warmletter/domain/share/controller/SharePostController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package io.crops.warmletter.domain.share.controller; | ||
|
||
import io.crops.warmletter.domain.share.dto.response.SharePostResponse; | ||
import io.crops.warmletter.domain.share.service.SharePostService; | ||
import io.crops.warmletter.global.response.PageResponse; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.data.domain.Sort; | ||
import org.springframework.data.web.PageableDefault; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.security.core.annotation.AuthenticationPrincipal; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
@RestController | ||
@RequestMapping("/api") | ||
@RequiredArgsConstructor | ||
public class SharePostController { | ||
|
||
private final SharePostService sharePostService; | ||
|
||
@GetMapping("/share-posts") | ||
// @PreAuthorize("hasRole('USER')") | ||
public ResponseEntity<PageResponse<SharePostResponse>> getAllPosts( | ||
@PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable | ||
// @AuthenticationPrincipal UserDetails userDetails | ||
) { | ||
return ResponseEntity.ok(new PageResponse<>(sharePostService.getAllPosts(pageable))); | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
src/main/java/io/crops/warmletter/domain/share/dto/response/SharePostResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package io.crops.warmletter.domain.share.dto.response; | ||
import io.crops.warmletter.domain.share.entity.SharePost; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
@Getter | ||
public class SharePostResponse { | ||
|
||
private Long shareProposalId; | ||
private String content; | ||
private boolean isActive; | ||
private LocalDateTime createdAt; | ||
|
||
public SharePostResponse(SharePost sharePost) { | ||
this.shareProposalId = sharePost.getShareProposalId(); | ||
this.content = sharePost.getContent(); | ||
this.isActive = sharePost.isActive(); | ||
this.createdAt = sharePost.getCreatedAt(); | ||
} | ||
|
||
} |
50 changes: 50 additions & 0 deletions
50
src/main/java/io/crops/warmletter/domain/share/entity/SharePost.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package io.crops.warmletter.domain.share.entity; | ||
|
||
import io.crops.warmletter.global.entity.BaseEntity; | ||
import io.crops.warmletter.global.entity.BaseTimeEntity; | ||
import jakarta.persistence.*; | ||
import lombok.AccessLevel; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import org.hibernate.annotations.CreationTimestamp; | ||
import org.hibernate.annotations.UpdateTimestamp; | ||
import org.springframework.data.annotation.CreatedDate; | ||
import org.springframework.data.annotation.LastModifiedDate; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
@Entity | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@Getter | ||
public class SharePost extends BaseEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@Column(nullable = false) | ||
private Long shareProposalId; | ||
|
||
private boolean isActive; | ||
|
||
@Column(nullable = false) | ||
private String content; | ||
|
||
@Builder | ||
public SharePost(Long shareProposalId, String title, String content,boolean isActive) { | ||
this.shareProposalId = shareProposalId; | ||
this.content = content; | ||
this.isActive = isActive; | ||
} | ||
|
||
// 비즈니스 로직 메서드 | ||
public void activate() { | ||
this.isActive = true; | ||
} | ||
|
||
public void deactivate() { | ||
this.isActive = false; | ||
} | ||
|
||
} |
32 changes: 32 additions & 0 deletions
32
src/main/java/io/crops/warmletter/domain/share/entity/SharePostLike.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package io.crops.warmletter.domain.share.entity; | ||
|
||
import io.crops.warmletter.global.entity.BaseEntity; | ||
import io.crops.warmletter.global.entity.BaseTimeEntity; | ||
import jakarta.persistence.*; | ||
import lombok.AccessLevel; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import org.springframework.data.annotation.CreatedDate; | ||
import org.springframework.data.annotation.LastModifiedDate; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
@Entity | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@Getter | ||
public class SharePostLike extends BaseEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@Column(nullable = false) | ||
private Long sharePostId; | ||
|
||
@Column(nullable = false) | ||
private Long memberId; | ||
|
||
private LocalDateTime createdAt; | ||
|
||
private LocalDateTime updatedAt; | ||
} |
38 changes: 38 additions & 0 deletions
38
src/main/java/io/crops/warmletter/domain/share/entity/ShareProposal.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package io.crops.warmletter.domain.share.entity; | ||
|
||
import io.crops.warmletter.domain.share.enums.ProposalStatus; | ||
import io.crops.warmletter.global.entity.BaseEntity; | ||
import jakarta.persistence.*; | ||
import lombok.AccessLevel; | ||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
@Entity | ||
@Getter | ||
@RequiredArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class ShareProposal extends BaseEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@Column(nullable = false) | ||
private Long requesterId; | ||
|
||
@Column(nullable = false) | ||
private Long recipientId; | ||
|
||
@Enumerated(EnumType.STRING) | ||
private ProposalStatus status; | ||
|
||
@Column(nullable = false) | ||
private String message; | ||
|
||
private LocalDateTime createdAt; | ||
|
||
private LocalDateTime updatedAt; | ||
|
||
|
||
} |
34 changes: 34 additions & 0 deletions
34
src/main/java/io/crops/warmletter/domain/share/entity/ShareProposalLetter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package io.crops.warmletter.domain.share.entity; | ||
|
||
import io.crops.warmletter.global.entity.BaseEntity; | ||
import jakarta.persistence.*; | ||
import lombok.AccessLevel; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
@Entity | ||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class ShareProposalLetter extends BaseEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@Column(nullable = false) | ||
private Long proposalId; | ||
|
||
@Column(nullable = false) | ||
private long letterId; | ||
|
||
@Column(nullable = false) | ||
private int displayOrder; | ||
|
||
private LocalDateTime createdAt; | ||
|
||
|
||
|
||
|
||
} |
6 changes: 6 additions & 0 deletions
6
src/main/java/io/crops/warmletter/domain/share/enums/ProposalStatus.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package io.crops.warmletter.domain.share.enums; | ||
|
||
public enum ProposalStatus { | ||
|
||
PENDING,APPROVED,REJECTED | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/io/crops/warmletter/domain/share/repository/ShareRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package io.crops.warmletter.domain.share.repository; | ||
|
||
import io.crops.warmletter.domain.share.entity.SharePost; | ||
import org.springframework.data.domain.Page; | ||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface ShareRepository extends JpaRepository<SharePost,Long> { | ||
|
||
Page<SharePost> findAllByIsActiveTrue(Pageable pageable); | ||
|
||
} |
29 changes: 29 additions & 0 deletions
29
src/main/java/io/crops/warmletter/domain/share/service/SharePostService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package io.crops.warmletter.domain.share.service; | ||
|
||
import io.crops.warmletter.domain.share.dto.response.SharePostResponse; | ||
import io.crops.warmletter.domain.share.entity.SharePost; | ||
import io.crops.warmletter.domain.share.repository.ShareRepository; | ||
import io.crops.warmletter.global.error.common.ErrorCode; | ||
import io.crops.warmletter.global.error.exception.BusinessException; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.data.domain.Page; | ||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class SharePostService { | ||
|
||
private final ShareRepository shareRepository; | ||
|
||
@Transactional(readOnly = true) | ||
public Page<SharePostResponse> getAllPosts(Pageable pageable) { | ||
// 0보다 작은 페이지를 요청한 경우 | ||
if (pageable.getPageNumber() < 0) { | ||
throw new BusinessException(ErrorCode.INVALID_PAGE_REQUEST); | ||
} | ||
Page<SharePost> sharePosts = shareRepository.findAllByIsActiveTrue(pageable); | ||
return sharePosts.map(SharePostResponse::new); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
src/test/java/io/crops/warmletter/domain/share/controller/SharePostControllerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package io.crops.warmletter.domain.share.controller; | ||
|
||
import io.crops.warmletter.domain.share.dto.response.SharePostResponse; | ||
import io.crops.warmletter.domain.share.entity.SharePost; | ||
import io.crops.warmletter.domain.share.service.SharePostService; | ||
import io.crops.warmletter.global.error.common.ErrorCode; | ||
import io.crops.warmletter.global.error.exception.BusinessException; | ||
import io.crops.warmletter.global.error.handler.GlobalExceptionHandler; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; | ||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; | ||
import org.springframework.data.domain.*; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.test.context.bean.override.mockito.MockitoBean; | ||
import org.springframework.test.web.servlet.MockMvc; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
import static org.hamcrest.Matchers.hasSize; | ||
import static org.mockito.ArgumentMatchers.any; | ||
import static org.mockito.Mockito.when; | ||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
|
||
@WebMvcTest({SharePostController.class, GlobalExceptionHandler.class}) | ||
@AutoConfigureMockMvc(addFilters = false) | ||
class SharePostControllerTest { | ||
|
||
@Autowired | ||
private MockMvc mockMvc; | ||
|
||
@MockitoBean | ||
private SharePostService sharePostService; | ||
|
||
|
||
private SharePostResponse sharePostResponse1; | ||
private SharePostResponse sharePostResponse2; | ||
@BeforeEach | ||
void createSharePost() { | ||
SharePost sharePost = new SharePost(1L, "게시글1", "to share my post",true); | ||
SharePost sharePost1 = new SharePost(2L, "게시글2", "to share my post1",true); | ||
sharePostResponse1 = new SharePostResponse(sharePost); | ||
sharePostResponse2 = new SharePostResponse(sharePost1); | ||
|
||
} | ||
|
||
@Test | ||
@DisplayName("페이징된 공유 게시글 반환 ") | ||
void getAllPosts() throws Exception { | ||
|
||
// given | ||
Pageable pageable = PageRequest.of(0, 10, Sort.by(Sort.Direction.ASC, "createdAt")); | ||
List<SharePostResponse> posts = List.of(sharePostResponse1, sharePostResponse2); | ||
Page<SharePostResponse> postPage = new PageImpl<>(posts, pageable, posts.size()); | ||
when(sharePostService.getAllPosts(any(Pageable.class))).thenReturn(postPage); | ||
|
||
//when | ||
mockMvc.perform(get("/api/share-posts") | ||
.contentType(MediaType.APPLICATION_JSON)) | ||
.andExpect(status().isOk()) | ||
.andExpect(jsonPath("$.content",hasSize(2))) | ||
.andExpect(jsonPath("$.content[0].content").value("to share my post")) | ||
.andExpect(jsonPath("$.content[1].content").value("to share my post1")) | ||
.andExpect(jsonPath("$.currentPage").value(1)) | ||
.andExpect(jsonPath("$.totalElements").value(2)) | ||
.andExpect(jsonPath("$.size").value(10)) | ||
.andDo(print()); | ||
} | ||
|
||
@Test | ||
@DisplayName("페이지 파라미터에 따라서 해당 페이지 반환 ") | ||
void getAllPosts_ReturnsSpecificPage() throws Exception { | ||
// given | ||
Pageable pageable = PageRequest.of(1, 10, Sort.by(Sort.Direction.DESC, "createdAt")); | ||
Page<SharePostResponse> emptyPage = new PageImpl<>(Collections.emptyList(), pageable, 20); | ||
|
||
when(sharePostService.getAllPosts(any(Pageable.class))).thenReturn(emptyPage); | ||
|
||
// when & then | ||
mockMvc.perform(get("/api/share-posts") | ||
.param("page", "1") | ||
.contentType(MediaType.APPLICATION_JSON)) | ||
.andExpect(status().isOk()) | ||
.andExpect(jsonPath("$.content").isArray()) | ||
.andExpect(jsonPath("$.currentPage").value(2)) | ||
.andExpect(jsonPath("$.totalElements").value(20)) | ||
.andDo(print()); | ||
} | ||
|
||
@Test | ||
@DisplayName("음수 페이지 요청시 예외 발생") | ||
void getAllPosts_ThrowsException_WhenPageNumberIsNegative() throws Exception { | ||
// given | ||
when(sharePostService.getAllPosts(any(Pageable.class))) | ||
.thenThrow(new BusinessException(ErrorCode.INVALID_PAGE_REQUEST)); | ||
|
||
// when & then | ||
mockMvc.perform(get("/api/share-posts") | ||
.param("page", "-1") | ||
.contentType(MediaType.APPLICATION_JSON)) | ||
.andExpect(status().isBadRequest()) | ||
.andExpect(jsonPath("$.code").value(ErrorCode.INVALID_PAGE_REQUEST.getCode())) | ||
.andExpect(jsonPath("$.message").value(ErrorCode.INVALID_PAGE_REQUEST.getMessage())) | ||
.andDo(print()); | ||
} | ||
|
||
} |
Oops, something went wrong.