From d453802c901f49fa98b972fc59ad52094b1c3860 Mon Sep 17 00:00:00 2001 From: Jiyun Date: Sun, 10 Nov 2024 16:10:32 +0900 Subject: [PATCH] #74 Feat: create likes and viewing post functions --- .../apipayload/code/status/ErrorStatus.java | 1 + .../controller/PostController.java | 23 ++++++-- .../converter/PostConverter.java | 34 +++++++++++- .../KahluaProject/domain/post/Post.java | 10 ++++ .../KahluaProject/domain/post/PostLikes.java | 31 +++++++++++ .../dto/post/request/PostCreateRequest.java | 4 ++ .../dto/post/response/PostGetResponse.java | 39 ++++++++++++++ .../post/response/PostImageGetResponse.java | 16 ++++++ .../repository/post/PostLikesRepository.java | 14 +++++ .../repository/{ => post}/PostRepository.java | 6 ++- .../KahluaProject/service/PostService.java | 54 +++++++++++++++++-- 11 files changed, 220 insertions(+), 12 deletions(-) create mode 100644 src/main/java/kahlua/KahluaProject/domain/post/PostLikes.java create mode 100644 src/main/java/kahlua/KahluaProject/dto/post/response/PostGetResponse.java create mode 100644 src/main/java/kahlua/KahluaProject/dto/post/response/PostImageGetResponse.java create mode 100644 src/main/java/kahlua/KahluaProject/repository/post/PostLikesRepository.java rename src/main/java/kahlua/KahluaProject/repository/{ => post}/PostRepository.java (61%) diff --git a/src/main/java/kahlua/KahluaProject/apipayload/code/status/ErrorStatus.java b/src/main/java/kahlua/KahluaProject/apipayload/code/status/ErrorStatus.java index 3259845..8a9ae44 100644 --- a/src/main/java/kahlua/KahluaProject/apipayload/code/status/ErrorStatus.java +++ b/src/main/java/kahlua/KahluaProject/apipayload/code/status/ErrorStatus.java @@ -44,6 +44,7 @@ public enum ErrorStatus implements BaseCode { WEBSOCKET_SESSION_UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "WEBSOCKET SESSION UNAUTHORIZED", "웹소켓 연결에 실패했습니다."), //게시판 에러 + POST_NOT_FOUND(HttpStatus.NOT_FOUND, "POST_NOT_FOUND", "존재하지 않는 게시글입니다."), IMAGE_NOT_UPLOAD(HttpStatus.BAD_REQUEST, "IMAGE_NOT_UPLOAD", "이미지 업로드 개수를 초과하였습니다."); private final HttpStatus httpStatus; diff --git a/src/main/java/kahlua/KahluaProject/controller/PostController.java b/src/main/java/kahlua/KahluaProject/controller/PostController.java index 9910201..0b98cb8 100644 --- a/src/main/java/kahlua/KahluaProject/controller/PostController.java +++ b/src/main/java/kahlua/KahluaProject/controller/PostController.java @@ -5,14 +5,14 @@ import kahlua.KahluaProject.apipayload.ApiResponse; import kahlua.KahluaProject.dto.post.request.PostCreateRequest; import kahlua.KahluaProject.dto.post.response.PostCreateResponse; +import kahlua.KahluaProject.dto.post.response.PostGetResponse; import kahlua.KahluaProject.security.AuthDetails; import kahlua.KahluaProject.service.PostService; +import kahlua.KahluaProject.service.TicketService; import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @Tag(name = "게시판", description = "게시판 관련 API") @@ -23,12 +23,25 @@ public class PostController { private final PostService postService; - @PostMapping("notice/create") + @PostMapping("/notice/create") @Operation(summary = "공지사항 작성", description = "창립제, 악기 구비 등 깔루아 전체 공지 내용을 작성합니다.") public ApiResponse createPost(@RequestBody PostCreateRequest postCreateRequest, @AuthenticationPrincipal AuthDetails authDetails) { PostCreateResponse postCreateResponse = postService.createPost(postCreateRequest, authDetails.user()); return ApiResponse.onSuccess(postCreateResponse); } + @PostMapping("/{post_id}/create_like") + @Operation(summary = "좋아요 생성/삭제", description = "게시글을 좋아요 생성/삭제를 진행합니다.") + public ResponseEntity cratePostLike(@PathVariable("post_id") Long post_id, @AuthenticationPrincipal AuthDetails authDetails) { + boolean result = postService.createPostLike(authDetails.user(), post_id); + if (result == true) return ResponseEntity.ok().body(ApiResponse.onSuccess("like_create")); + else return ResponseEntity.ok().body(ApiResponse.onSuccess("like_delete")); + } + @GetMapping("/notice/{post_id}/detail") + @Operation(summary = "공지사항 내용 조회", description = "공지 내용을 조회합니다.") + public ApiResponse viewPost(@PathVariable("post_id") Long post_id, @AuthenticationPrincipal AuthDetails authDetails) { + PostGetResponse postGetResponse = postService.viewPost(post_id, authDetails.user()); + return ApiResponse.onSuccess(postGetResponse); + } } diff --git a/src/main/java/kahlua/KahluaProject/converter/PostConverter.java b/src/main/java/kahlua/KahluaProject/converter/PostConverter.java index cf1fd51..9702267 100644 --- a/src/main/java/kahlua/KahluaProject/converter/PostConverter.java +++ b/src/main/java/kahlua/KahluaProject/converter/PostConverter.java @@ -2,11 +2,14 @@ import kahlua.KahluaProject.domain.post.Post; import kahlua.KahluaProject.domain.post.PostImage; +import kahlua.KahluaProject.domain.post.PostLikes; import kahlua.KahluaProject.domain.user.User; import kahlua.KahluaProject.dto.post.request.PostCreateRequest; import kahlua.KahluaProject.dto.post.request.PostImageCreateRequest; import kahlua.KahluaProject.dto.post.response.PostCreateResponse; +import kahlua.KahluaProject.dto.post.response.PostGetResponse; import kahlua.KahluaProject.dto.post.response.PostImageCreateResponse; +import kahlua.KahluaProject.dto.post.response.PostImageGetResponse; import java.util.Collections; import java.util.List; @@ -15,10 +18,18 @@ public class PostConverter { - public static Post toPost(PostCreateRequest postCreateRequest) { + public static Post toPost(PostCreateRequest postCreateRequest, User user) { return Post.builder() .title(postCreateRequest.getTitle()) .content(postCreateRequest.getContent()) + .user(user) + .build(); + } + + public static PostLikes toPostLikes(Post post, User user) { + return PostLikes.builder() + .post(post) + .user(user) .build(); } @@ -56,4 +67,25 @@ public static List toPostImageCreateResponse(List getImageUrls = post.getImageUrls().stream() + .map(postImage2 -> PostImageGetResponse.builder() + .id(postImage2.getId()) + .url(postImage2.getUrl()) + .build()) + .collect(Collectors.toList()); + + return PostGetResponse.builder() + .id(post.getId()) + .title(post.getTitle()) + .content(post.getContent()) + .writer(post.getUser().getName()) + .likes(post.getLikes()) + .imageUrls(getImageUrls) + .created_at(post.getCreatedAt()) + .created_at(post.getUpdatedAt()) + .build(); + } } diff --git a/src/main/java/kahlua/KahluaProject/domain/post/Post.java b/src/main/java/kahlua/KahluaProject/domain/post/Post.java index ef93af9..88f52af 100644 --- a/src/main/java/kahlua/KahluaProject/domain/post/Post.java +++ b/src/main/java/kahlua/KahluaProject/domain/post/Post.java @@ -48,4 +48,14 @@ public void addImage(PostImage postImage) { postImage = new PostImage(postImage.getUrl(), this); ImageUrls.add(postImage); } + + public void increaseLikes() { + this.likes++; + } + + public void decreaseLikes() { + if (this.likes > 0) { + this.likes--; + } + } } diff --git a/src/main/java/kahlua/KahluaProject/domain/post/PostLikes.java b/src/main/java/kahlua/KahluaProject/domain/post/PostLikes.java new file mode 100644 index 0000000..cf4f19d --- /dev/null +++ b/src/main/java/kahlua/KahluaProject/domain/post/PostLikes.java @@ -0,0 +1,31 @@ +package kahlua.KahluaProject.domain.post; + +import jakarta.persistence.*; +import kahlua.KahluaProject.domain.BaseEntity; +import kahlua.KahluaProject.domain.user.User; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Builder +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "postLikes") +public class PostLikes extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="like_id") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "post_id") + private Post post; +} diff --git a/src/main/java/kahlua/KahluaProject/dto/post/request/PostCreateRequest.java b/src/main/java/kahlua/KahluaProject/dto/post/request/PostCreateRequest.java index db1f0ff..0b1791b 100644 --- a/src/main/java/kahlua/KahluaProject/dto/post/request/PostCreateRequest.java +++ b/src/main/java/kahlua/KahluaProject/dto/post/request/PostCreateRequest.java @@ -1,6 +1,7 @@ package kahlua.KahluaProject.dto.post.request; import io.swagger.v3.oas.annotations.media.Schema; +import kahlua.KahluaProject.domain.user.User; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -18,6 +19,9 @@ public class PostCreateRequest { @Schema(description = "게시글 내용", example = "안녕하세요 깔루아 기장입니다. 감사합니다.") private String content; + @Schema(description = "게시글 작성자", example = "관리자") + private User user; + @Schema(description = "게시글 사진 리스트", example = "https://bucketname.s3.region.amazonaws.com/image1.jpg") private List imageUrls; } diff --git a/src/main/java/kahlua/KahluaProject/dto/post/response/PostGetResponse.java b/src/main/java/kahlua/KahluaProject/dto/post/response/PostGetResponse.java new file mode 100644 index 0000000..a32a67c --- /dev/null +++ b/src/main/java/kahlua/KahluaProject/dto/post/response/PostGetResponse.java @@ -0,0 +1,39 @@ +package kahlua.KahluaProject.dto.post.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; + +import java.time.LocalDateTime; +import java.util.List; + +@Getter +@Builder +public class PostGetResponse { + + @Schema(description = "아이디(번호)", example = "1") + private Long id; + + @Schema(description = "게시글 제목", example = "2024년 9월 정기공연") + private String title; + + @Schema(description = "게시글 내용", example = "안녕하세요 깔루아 기장입니다. 감사합니다.") + private String content; + + @Schema(description = "게시글 작성자", example = "관리자") + private String writer; + + @Schema(description = "게시글 좋아요 수", example = "13") + private int likes; + + //게시글 댓글 수 + + @Schema(description = "게시글 사진 리스트", example = "https://bucketname.s3.region.amazonaws.com/image1.jpg") + private List imageUrls; + + @Schema(description = "작성한 날짜", example = "2024-08-01T00:00:00") + private LocalDateTime created_at; + + @Schema(description = "수정한 날짜", example = "2024-08-10T00:00:00") + private LocalDateTime updated_at; +} diff --git a/src/main/java/kahlua/KahluaProject/dto/post/response/PostImageGetResponse.java b/src/main/java/kahlua/KahluaProject/dto/post/response/PostImageGetResponse.java new file mode 100644 index 0000000..7e0b70d --- /dev/null +++ b/src/main/java/kahlua/KahluaProject/dto/post/response/PostImageGetResponse.java @@ -0,0 +1,16 @@ +package kahlua.KahluaProject.dto.post.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class PostImageGetResponse { + + @Schema(description = "id") + private Long id; + + @Schema(description = "image url") + private String url; +} diff --git a/src/main/java/kahlua/KahluaProject/repository/post/PostLikesRepository.java b/src/main/java/kahlua/KahluaProject/repository/post/PostLikesRepository.java new file mode 100644 index 0000000..c1bede5 --- /dev/null +++ b/src/main/java/kahlua/KahluaProject/repository/post/PostLikesRepository.java @@ -0,0 +1,14 @@ +package kahlua.KahluaProject.repository.post; + +import kahlua.KahluaProject.domain.post.Post; +import kahlua.KahluaProject.domain.post.PostLikes; +import kahlua.KahluaProject.domain.user.User; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface PostLikesRepository extends JpaRepository { + +// boolean existsByPostAndUser(Post); + Optional findByPostAndUser(Post post, User user); +} diff --git a/src/main/java/kahlua/KahluaProject/repository/PostRepository.java b/src/main/java/kahlua/KahluaProject/repository/post/PostRepository.java similarity index 61% rename from src/main/java/kahlua/KahluaProject/repository/PostRepository.java rename to src/main/java/kahlua/KahluaProject/repository/post/PostRepository.java index e47367a..643de68 100644 --- a/src/main/java/kahlua/KahluaProject/repository/PostRepository.java +++ b/src/main/java/kahlua/KahluaProject/repository/post/PostRepository.java @@ -1,7 +1,11 @@ -package kahlua.KahluaProject.repository; +package kahlua.KahluaProject.repository.post; import kahlua.KahluaProject.domain.post.Post; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface PostRepository extends JpaRepository { + + Optional findById(Long id); } diff --git a/src/main/java/kahlua/KahluaProject/service/PostService.java b/src/main/java/kahlua/KahluaProject/service/PostService.java index 6bc3793..29d065d 100644 --- a/src/main/java/kahlua/KahluaProject/service/PostService.java +++ b/src/main/java/kahlua/KahluaProject/service/PostService.java @@ -4,23 +4,24 @@ import kahlua.KahluaProject.converter.PostConverter; import kahlua.KahluaProject.domain.post.Post; import kahlua.KahluaProject.domain.post.PostImage; +import kahlua.KahluaProject.domain.post.PostLikes; import kahlua.KahluaProject.domain.user.User; import kahlua.KahluaProject.domain.user.UserType; import kahlua.KahluaProject.dto.post.request.PostCreateRequest; -import kahlua.KahluaProject.dto.post.request.PostImageCreateRequest; import kahlua.KahluaProject.dto.post.response.PostCreateResponse; +import kahlua.KahluaProject.dto.post.response.PostGetResponse; import kahlua.KahluaProject.dto.post.response.PostImageCreateResponse; import kahlua.KahluaProject.exception.GeneralException; import kahlua.KahluaProject.repository.PostImageRepository; -import kahlua.KahluaProject.repository.PostRepository; +import kahlua.KahluaProject.repository.UserRepository; +import kahlua.KahluaProject.repository.post.PostLikesRepository; +import kahlua.KahluaProject.repository.post.PostRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Collections; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -28,6 +29,7 @@ public class PostService { private final PostRepository postRepository; private final PostImageRepository postImageRepository; + private final PostLikesRepository postLikesRepository; @Transactional public PostCreateResponse createPost(PostCreateRequest postCreateRequest, User user) { @@ -37,7 +39,7 @@ public PostCreateResponse createPost(PostCreateRequest postCreateRequest, User u throw new GeneralException(ErrorStatus.UNAUTHORIZED); } - Post post = PostConverter.toPost(postCreateRequest); + Post post = PostConverter.toPost(postCreateRequest, user); postRepository.save(post); List imageUrls = PostConverter.toPostImage(postCreateRequest.getImageUrls(), post); @@ -50,4 +52,46 @@ public PostCreateResponse createPost(PostCreateRequest postCreateRequest, User u return postCreateResponse; } + + @Transactional + public boolean createPostLike(User user, Long post_id) { + + // 선택한 게시글이 존재하는 지 확인 + Post existingPost = postRepository.findById(post_id) + .orElseThrow(() -> new GeneralException(ErrorStatus.POST_NOT_FOUND)); + + // 사용자가 좋아요를 눌렀는지 확인 + Optional existingLike = postLikesRepository.findByPostAndUser(existingPost, user); + + if (existingLike.isPresent()) { + postLikesRepository.delete(existingLike.get()); + System.out.println("like"+existingLike.get()); + + existingPost.decreaseLikes(); + postRepository.save(existingPost); + return false; // 좋아요 취소 + } else { + PostLikes newLike = PostConverter.toPostLikes(existingPost, user); + postLikesRepository.save(newLike); + + existingPost.increaseLikes(); + postRepository.save(existingPost); + return true; // 좋아요 생성 + } + } + + @Transactional + public PostGetResponse viewPost(Long post_id, User user) { + + // 공지사항 조회의 경우 kahlua 혹은 ADMIN인지 확인 + if(user.getUserType() != UserType.KAHLUA && user.getUserType() != UserType.ADMIN){ + throw new GeneralException(ErrorStatus.UNAUTHORIZED); + } + + // 선택한 게시글이 존재하는 지 확인 + Post existingPost = postRepository.findById(post_id) + .orElseThrow(() -> new GeneralException(ErrorStatus.POST_NOT_FOUND)); + + return PostConverter.toPostGetResponse(existingPost); + } }