From bbb68d9715c518e308b887ca1113472333756715 Mon Sep 17 00:00:00 2001 From: aaahyunseo Date: Sun, 18 Aug 2024 05:11:05 +0900 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20Board=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=EC=97=90=20Interest=20=EC=97=B0=EA=B4=80=EA=B4=80?= =?UTF-8?q?=EA=B3=84=20=EC=84=A4=EC=A0=95=20-=20#64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/swcompetitionproject/entity/Board.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/example/swcompetitionproject/entity/Board.java b/src/main/java/com/example/swcompetitionproject/entity/Board.java index a31ab08..cc3d92d 100644 --- a/src/main/java/com/example/swcompetitionproject/entity/Board.java +++ b/src/main/java/com/example/swcompetitionproject/entity/Board.java @@ -40,6 +40,9 @@ public class Board extends BaseEntity { @Setter private List boardCategories; + @OneToMany(mappedBy = "board", cascade = CascadeType.ALL, orphanRemoval = true) + private List interests; + public Board setContent(String content){ this.content = content; return this; From abae43fdc601cb5e15389b351bdf986aac79f467 Mon Sep 17 00:00:00 2001 From: aaahyunseo Date: Sun, 18 Aug 2024 05:11:28 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20BoardController=20=EA=B2=8C?= =?UTF-8?q?=EC=8B=9C=EA=B8=80=20=EA=B4=80=EC=8B=AC=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20-=20#64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/BoardController.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/main/java/com/example/swcompetitionproject/controller/BoardController.java b/src/main/java/com/example/swcompetitionproject/controller/BoardController.java index 01737ac..663cbe9 100644 --- a/src/main/java/com/example/swcompetitionproject/controller/BoardController.java +++ b/src/main/java/com/example/swcompetitionproject/controller/BoardController.java @@ -64,5 +64,26 @@ public ResponseEntity> deleteBoard(@RequestParam(value = "dorm boardService.deleteBoard(dormitory, boardId, user); return new ResponseEntity<>(ResponseDto.res(HttpStatus.OK, "게시글 삭제 완료"), HttpStatus.OK); } + + // 게시글 좋아요 등록 + @PostMapping("/{boardId}/like") + public ResponseEntity> likeBoard(@AuthenticatedUser User user, @PathVariable UUID boardId) { + boardService.likeBoard(user, boardId); + return new ResponseEntity<>(ResponseDto.res(HttpStatus.OK, "게시글 좋아요 등록 완료"), HttpStatus.OK); + } + + // 게시글 좋아요 삭제 + @DeleteMapping("/{boardId}/like") + public ResponseEntity> unlikeBoard(@AuthenticatedUser User user, @PathVariable UUID boardId) { + boardService.unlikeBoard(user, boardId); + return new ResponseEntity<>(ResponseDto.res(HttpStatus.OK, "게시글 좋아요 삭제 완료"), HttpStatus.OK); + } + + // 사용자가 좋아요를 누른 게시글 목록 조회 + @GetMapping("/likes") + public ResponseEntity> getLikedBoards(@AuthenticatedUser User user) { + BoardListData interestListData = boardService.getLikedBoards(user); + return new ResponseEntity<>(ResponseDto.res(HttpStatus.OK, "좋아요한 게시글 목록 조회 완료", interestListData), HttpStatus.OK); + } } From e41bdbbecfb6c232285de3b1fb67a6585f457228 Mon Sep 17 00:00:00 2001 From: aaahyunseo Date: Sun, 18 Aug 2024 05:15:16 +0900 Subject: [PATCH 03/11] =?UTF-8?q?feat:=20BoardService=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EA=B4=80=EC=8B=AC=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20-=20#64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/BoardService.java | 48 +++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/swcompetitionproject/service/BoardService.java b/src/main/java/com/example/swcompetitionproject/service/BoardService.java index dd8d4d7..354d88e 100644 --- a/src/main/java/com/example/swcompetitionproject/service/BoardService.java +++ b/src/main/java/com/example/swcompetitionproject/service/BoardService.java @@ -4,15 +4,13 @@ import com.example.swcompetitionproject.dto.request.board.UpdateBoardDto; import com.example.swcompetitionproject.dto.response.board.BoardData; import com.example.swcompetitionproject.dto.response.board.BoardListData; -import com.example.swcompetitionproject.entity.Board; -import com.example.swcompetitionproject.entity.BoardCategory; -import com.example.swcompetitionproject.entity.DormitoryType; -import com.example.swcompetitionproject.entity.User; +import com.example.swcompetitionproject.entity.*; import com.example.swcompetitionproject.exception.ErrorCode; import com.example.swcompetitionproject.exception.ForbiddenException; import com.example.swcompetitionproject.exception.NotFoundException; import com.example.swcompetitionproject.exception.UnauthorizedException; import com.example.swcompetitionproject.repository.BoardRepository; +import com.example.swcompetitionproject.repository.InterestRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -26,6 +24,7 @@ public class BoardService { private final BoardRepository boardRepository; private final ChattingService chattingService; + private final InterestRepository interestRepository; /** * 게시글 전체 조회 @@ -114,6 +113,47 @@ public void deleteBoard(String dormitory, UUID boardId, User user) { chattingService.deleteRoom(board); } + /** + * 게시글 좋아요 등록 + **/ + @Transactional + public void likeBoard(User user, UUID boardId) { + Board board = boardRepository.findById(boardId) + .orElseThrow(() -> new NotFoundException(ErrorCode.BOARD_NOT_FOUND)); + //이미 좋아요를 누른 게시물 + if (interestRepository.existsByUserAndBoard(user, board)) { + throw new UnauthorizedException(ErrorCode.ALREADY_LIKED); + } + + Interest like = Interest.builder() + .user(user) + .board(board) + .build(); + interestRepository.save(like); + } + + /** + * 게시글 좋아요 삭제 + **/ + @Transactional + public void unlikeBoard(User user, UUID boardId) { + Board board = boardRepository.findById(boardId) + .orElseThrow(() -> new NotFoundException(ErrorCode.BOARD_NOT_FOUND)); + Interest like = interestRepository.findByUserAndBoard(user, board) + .orElseThrow(() -> new NotFoundException(ErrorCode.LIKE_NOT_FOUND)); + + interestRepository.delete(like); + } + + /** + * 관심 게시글 조회 + **/ + @Transactional + public BoardListData getLikedBoards(User user) { + List likedBoards = interestRepository.findBoardsByUser(user); + return BoardListData.from(likedBoards); + } + /** * 접근 유저의 게시글 권한 확인 **/ From 43b55e78436f00077ee6b3fb64801d98b9b1f2bd Mon Sep 17 00:00:00 2001 From: aaahyunseo Date: Sun, 18 Aug 2024 05:15:39 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20ErrorCode=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80=20-=20#64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/swcompetitionproject/exception/ErrorCode.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/example/swcompetitionproject/exception/ErrorCode.java b/src/main/java/com/example/swcompetitionproject/exception/ErrorCode.java index 94b605f..0a09a5e 100644 --- a/src/main/java/com/example/swcompetitionproject/exception/ErrorCode.java +++ b/src/main/java/com/example/swcompetitionproject/exception/ErrorCode.java @@ -14,6 +14,7 @@ public enum ErrorCode { INVALID_DORMITORY("4012", "유효하지 않은 기숙사입니다."), INVALID_GENDER("4013", "유효하지 않은 성별입니다."), ROOM_FULL("4014", "채팅방 인원이 가득찼습니다."), + ALREADY_LIKED("4015","이미 좋아요를 눌렀습니다."), //ForbiddenException NO_ACCESS("4030", "접근 권한이 없습니다."), @@ -25,6 +26,7 @@ public enum ErrorCode { ROOM_NOT_FOUND("4042", "방을 찾을 수 없습니다."), BOARD_NOT_FOUND("4043", "게시글을 찾을 수 없습니다."), CATEGORY_NOT_FOUND("4044", "카테고리를 찾을 수 없습니다"), + LIKE_NOT_FOUND("4045","좋아요를 찾을 수 없습니다."), //ConflictException From eec4fa5f6848b424c585a706b4a19b8dbfd1fcfd Mon Sep 17 00:00:00 2001 From: aaahyunseo Date: Sun, 18 Aug 2024 05:15:58 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20Interest=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=EC=B6=94=EA=B0=80=20-=20#64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../swcompetitionproject/entity/Interest.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/com/example/swcompetitionproject/entity/Interest.java diff --git a/src/main/java/com/example/swcompetitionproject/entity/Interest.java b/src/main/java/com/example/swcompetitionproject/entity/Interest.java new file mode 100644 index 0000000..b520361 --- /dev/null +++ b/src/main/java/com/example/swcompetitionproject/entity/Interest.java @@ -0,0 +1,23 @@ +package com.example.swcompetitionproject.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Table(name = "interests") +public class Interest extends BaseEntity{ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "board_id") + private Board board; +} From 65d22ecf9a0731c366abd88f62642b21674f1ef8 Mon Sep 17 00:00:00 2001 From: aaahyunseo Date: Sun, 18 Aug 2024 05:16:13 +0900 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20InterestRepository=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20-=20#64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/InterestRepository.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/com/example/swcompetitionproject/repository/InterestRepository.java diff --git a/src/main/java/com/example/swcompetitionproject/repository/InterestRepository.java b/src/main/java/com/example/swcompetitionproject/repository/InterestRepository.java new file mode 100644 index 0000000..1f6be84 --- /dev/null +++ b/src/main/java/com/example/swcompetitionproject/repository/InterestRepository.java @@ -0,0 +1,19 @@ +package com.example.swcompetitionproject.repository; + +import com.example.swcompetitionproject.entity.Board; +import com.example.swcompetitionproject.entity.Interest; +import com.example.swcompetitionproject.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public interface InterestRepository extends JpaRepository { + boolean existsByUserAndBoard(User user, Board board); + Optional findByUserAndBoard(User user, Board board); + @Query("SELECT i.board FROM Interest i WHERE i.user = :user") + List findBoardsByUser(@Param("user") User user); +} From c0a1d1cc79f39e91a913dfb3c1a6420e1390afad Mon Sep 17 00:00:00 2001 From: aaahyunseo Date: Sun, 18 Aug 2024 05:16:39 +0900 Subject: [PATCH 07/11] =?UTF-8?q?feat:=20User=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=EC=97=90=20interest=20=EC=97=B0=EA=B4=80=EA=B4=80?= =?UTF-8?q?=EA=B3=84=20=EC=B6=94=EA=B0=80=20-=20#64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/swcompetitionproject/entity/User.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/example/swcompetitionproject/entity/User.java b/src/main/java/com/example/swcompetitionproject/entity/User.java index 57db5e6..1b307c9 100644 --- a/src/main/java/com/example/swcompetitionproject/entity/User.java +++ b/src/main/java/com/example/swcompetitionproject/entity/User.java @@ -41,6 +41,9 @@ public class User extends BaseEntity { @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) private List userRooms; + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + private List interests; + public User setName(String name){ this.name = name; return this; From fd9eccee621b914d39633bc37883370759589fb8 Mon Sep 17 00:00:00 2001 From: aaahyunseo Date: Sun, 18 Aug 2024 05:38:47 +0900 Subject: [PATCH 08/11] =?UTF-8?q?feat:=20BoardController=20=EA=B2=8C?= =?UTF-8?q?=EC=8B=9C=EA=B8=80=20=EC=A0=84=EC=B2=B4=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=8B=9C=20=EA=B4=80=EC=8B=AC=EA=B8=80=20=EC=97=AC=EB=B6=80=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20-=20#64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../swcompetitionproject/controller/BoardController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/swcompetitionproject/controller/BoardController.java b/src/main/java/com/example/swcompetitionproject/controller/BoardController.java index 663cbe9..5e56a05 100644 --- a/src/main/java/com/example/swcompetitionproject/controller/BoardController.java +++ b/src/main/java/com/example/swcompetitionproject/controller/BoardController.java @@ -25,7 +25,7 @@ public class BoardController { //게시글 전체 조회 @GetMapping public ResponseEntity> getBoardList(@AuthenticatedUser User user, @RequestParam(value = "dormitory") String dormitory) { - BoardListData boardListData = boardService.getBoardList(dormitory); + BoardListData boardListData = boardService.getBoardList(user, dormitory); return new ResponseEntity<>(ResponseDto.res(HttpStatus.OK, "게시글 목록 조회 완료", boardListData), HttpStatus.OK); } From 903f755de86bf747b3efc14af5c05d2ca9b5ce04 Mon Sep 17 00:00:00 2001 From: aaahyunseo Date: Sun, 18 Aug 2024 05:39:20 +0900 Subject: [PATCH 09/11] =?UTF-8?q?feat:=20BoardDetailResponseDto=20?= =?UTF-8?q?=EA=B4=80=EC=8B=AC=EA=B8=80=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20-=20#64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/board/BoardDetailResponseDto.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/swcompetitionproject/dto/response/board/BoardDetailResponseDto.java b/src/main/java/com/example/swcompetitionproject/dto/response/board/BoardDetailResponseDto.java index b259788..f7a3982 100644 --- a/src/main/java/com/example/swcompetitionproject/dto/response/board/BoardDetailResponseDto.java +++ b/src/main/java/com/example/swcompetitionproject/dto/response/board/BoardDetailResponseDto.java @@ -20,9 +20,10 @@ public class BoardDetailResponseDto { private int current; private int total; private GenderType gender; + private boolean like; private String createdAt; - public static BoardDetailResponseDto from(Board board){ + public static BoardDetailResponseDto of(Boolean isLike, Board board){ return BoardDetailResponseDto.builder() .id(board.getId()) .title(board.getTitle()) @@ -33,6 +34,7 @@ public static BoardDetailResponseDto from(Board board){ .current(board.getChattingRoom().getMemberCount()) .total(board.getTotal()) .gender(board.getUser().getGender()) + .like(isLike) .createdAt(board.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))) .build(); } From 757aa9621fcc28f35cab3bab71560caa0ccd1bfe Mon Sep 17 00:00:00 2001 From: aaahyunseo Date: Sun, 18 Aug 2024 05:39:44 +0900 Subject: [PATCH 10/11] =?UTF-8?q?feat:=20BoardListData=20=EA=B4=80?= =?UTF-8?q?=EC=8B=AC=EA=B8=80=20=EC=A1=B0=ED=9A=8C=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20-=20#64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/board/BoardListData.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/swcompetitionproject/dto/response/board/BoardListData.java b/src/main/java/com/example/swcompetitionproject/dto/response/board/BoardListData.java index 50763c4..5ee83b5 100644 --- a/src/main/java/com/example/swcompetitionproject/dto/response/board/BoardListData.java +++ b/src/main/java/com/example/swcompetitionproject/dto/response/board/BoardListData.java @@ -1,6 +1,8 @@ package com.example.swcompetitionproject.dto.response.board; import com.example.swcompetitionproject.entity.Board; +import com.example.swcompetitionproject.entity.User; +import com.example.swcompetitionproject.repository.InterestRepository; import lombok.Builder; import lombok.Getter; @@ -12,11 +14,23 @@ public class BoardListData { private List boardDtoList; + public static BoardListData of(List boards, User user, InterestRepository interestRepository) { + return BoardListData.builder() + .boardDtoList( + boards.stream() + .map(board -> { + boolean isLiked = interestRepository.existsByUserAndBoard(user, board); + return BoardDetailResponseDto.of(isLiked, board); + }) + .collect(Collectors.toList())) + .build(); + } + public static BoardListData from(List boards) { return BoardListData.builder() .boardDtoList( boards.stream() - .map(BoardDetailResponseDto::from) + .map(board -> BoardDetailResponseDto.of(true, board)) .collect(Collectors.toList())) .build(); } From acf0921c6258804f615588bf98a2a996007e7fe7 Mon Sep 17 00:00:00 2001 From: aaahyunseo Date: Sun, 18 Aug 2024 05:40:09 +0900 Subject: [PATCH 11/11] =?UTF-8?q?feat:=20BoardService=20=EA=B4=80=EC=8B=AC?= =?UTF-8?q?=EA=B8=80=20=EB=B0=98=ED=99=98=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20-=20#64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/swcompetitionproject/service/BoardService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/swcompetitionproject/service/BoardService.java b/src/main/java/com/example/swcompetitionproject/service/BoardService.java index 354d88e..7fa660e 100644 --- a/src/main/java/com/example/swcompetitionproject/service/BoardService.java +++ b/src/main/java/com/example/swcompetitionproject/service/BoardService.java @@ -30,10 +30,10 @@ public class BoardService { * 게시글 전체 조회 **/ @Transactional - public BoardListData getBoardList(String dormitory) { + public BoardListData getBoardList(User user, String dormitory) { DormitoryType dormitoryType = dormitoryNameValidate(dormitory); List boards = boardRepository.findAllByDormitoryOrderByCreatedAtDesc(dormitoryType); - return BoardListData.from(boards); + return BoardListData.of(boards, user, interestRepository); } /**