Skip to content

Commit

Permalink
Merge pull request #94 from Team-GAJI/feature/#85-study-likes-bookmar…
Browse files Browse the repository at this point in the history
…ks/GAJI-114

✨ [feature] #85 - 스터디 모집 게시글 좋아요, 북마크 API
  • Loading branch information
spenshark authored Aug 16, 2024
2 parents 69418c7 + f9dbce3 commit 21ad8c2
Show file tree
Hide file tree
Showing 11 changed files with 225 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
@AllArgsConstructor
public enum RecruitErrorStatus implements BaseErrorCodeInterface {
_RECRUIT_POST_NOT_FOUND(HttpStatus.BAD_REQUEST, "RECRUIT_4001", "모집 게시글을 찾을 수 없습니다."),

_ROOM_ALREADY_LIKE(HttpStatus.BAD_REQUEST, "LIKE_4001", "이미 좋아요 된 게시글 입니다."),
_ROOM_ALREADY_NO_LIKE(HttpStatus.BAD_REQUEST, "LIKE_4002", "이미 좋아요 취소된 게시글 입니다."),

_ROOM_ALREADY_BOOKMARK(HttpStatus.BAD_REQUEST, "BOOKMARK_4001", "이미 북마크 된 게시글 입니다."),
_ROOM_ALREADY_NO_BOOKMARK(HttpStatus.BAD_REQUEST, "BOOKMARK_4002", "이미 북마크 취소된 게시글 입니다."),
;

private final HttpStatus httpStatus;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import gaji.service.domain.common.entity.Category;
import gaji.service.domain.common.entity.SelectCategory;
import gaji.service.domain.enums.CategoryEnum;
import gaji.service.domain.recruit.entity.RecruitPostBookmark;
import gaji.service.domain.recruit.entity.RecruitPostLikes;
import gaji.service.domain.user.entity.User;
import gaji.service.domain.enums.Role;
import gaji.service.domain.recruit.entity.StudyComment;
Expand All @@ -13,9 +15,7 @@
import gaji.service.domain.studyMate.entity.StudyMate;
import gaji.service.global.converter.DateConverter;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -115,6 +115,32 @@ public static RecruitResponseDTO.CommentListDTO toCommentListDTO(int commentCoun
.build();
}

public static RecruitPostLikes toRecruitPostLikes(User user, Room room) {
return RecruitPostLikes.builder()
.user(user)
.room(room)
.build();
}

public static RecruitResponseDTO.StudyLikesIdDTO toStudyLikesIdDTO(RecruitPostLikes likes) {
return RecruitResponseDTO.StudyLikesIdDTO.builder()
.studyLikesId(likes.getId())
.build();
}

public static RecruitPostBookmark toRecruitPostBookmark(User user, Room room) {
return RecruitPostBookmark.builder()
.user(user)
.room(room)
.build();
}

public static RecruitResponseDTO.StudyBookmarkIdDTO toStudyBookmarkIdDTO(RecruitPostBookmark bookmark) {
return RecruitResponseDTO.StudyBookmarkIdDTO.builder()
.studyBookmarkId(bookmark.getId())
.build();
}

public static RecruitResponseDTO.PreviewDTO toPreviewDTO(Room room) {
return RecruitResponseDTO.PreviewDTO.builder()
.imageUrl(room.getThumbnailUrl())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import gaji.service.domain.user.entity.User;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

Expand All @@ -23,5 +24,9 @@ public class RecruitPostBookmark {
@JoinColumn(name = "room_id")
private Room room;


@Builder
public RecruitPostBookmark(User user, Room room) {
this.user = user;
this.room = room;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import gaji.service.domain.user.entity.User;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

Expand All @@ -24,4 +25,9 @@ public class RecruitPostLikes {
@JoinColumn(name = "room_id")
private Room room;

@Builder
public RecruitPostLikes(User user, Room room) {
this.user = user;
this.room = room;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package gaji.service.domain.recruit.repository;

import gaji.service.domain.recruit.entity.RecruitPostBookmark;
import gaji.service.domain.recruit.entity.RecruitPostLikes;
import gaji.service.domain.room.entity.Room;
import gaji.service.domain.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface RecruitPostBookmarkRepository extends JpaRepository<RecruitPostBookmark, Long> {
boolean existsByUserAndRoom(User user, Room room);

void deleteByUserAndRoom(User user, Room room);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package gaji.service.domain.recruit.repository;

import gaji.service.domain.recruit.entity.RecruitPostLikes;
import gaji.service.domain.room.entity.Room;
import gaji.service.domain.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface RecruitPostLikesRepository extends JpaRepository<RecruitPostLikes, Long> {
boolean existsByUserAndRoom(User user, Room room);

void deleteByUserAndRoom(User user, Room room);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,12 @@
public interface RecruitCommandService {

RecruitResponseDTO.CreateRoomDTO createRoom(RecruitRequestDTO.CreateRoomDTO request, Long userId);

RecruitResponseDTO.StudyLikesIdDTO likeStudy(Long userId, Long roomId);

void unLikeStudy(Long userId, Long roomId);

RecruitResponseDTO.StudyBookmarkIdDTO bookmarkStudy(Long userId, Long roomId);

void unBookmarkStudy(Long userId, Long roomId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,25 @@
import gaji.service.domain.common.repository.CategoryRepository;
import gaji.service.domain.enums.CategoryEnum;
import gaji.service.domain.enums.PostTypeEnum;
import gaji.service.domain.recruit.code.RecruitErrorStatus;
import gaji.service.domain.recruit.converter.RecruitConverter;
import gaji.service.domain.recruit.entity.RecruitPostBookmark;
import gaji.service.domain.recruit.entity.RecruitPostLikes;
import gaji.service.domain.recruit.repository.RecruitPostBookmarkRepository;
import gaji.service.domain.recruit.repository.RecruitPostLikesRepository;
import gaji.service.domain.common.repository.SelectCategoryRepository;
import gaji.service.domain.recruit.web.dto.RecruitRequestDTO;
import gaji.service.domain.recruit.web.dto.RecruitResponseDTO;
import gaji.service.domain.room.entity.Material;
import gaji.service.domain.room.entity.Room;
import gaji.service.domain.room.service.MaterialCommandService;
import gaji.service.domain.room.service.RoomCommandService;
import gaji.service.domain.room.service.RoomQueryService;
import gaji.service.domain.studyMate.entity.StudyMate;
import gaji.service.domain.studyMate.repository.StudyMateRepository;
import gaji.service.domain.user.entity.User;
import gaji.service.domain.user.service.UserQueryService;
import gaji.service.global.exception.RestApiException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -30,10 +37,13 @@ public class RecruitCommandServiceImpl implements RecruitCommandService {

private final RoomCommandService roomCommandService;
private final UserQueryService userQueryService;
private final RoomQueryService roomQueryService;
private final SelectCategoryRepository selectCategoryRepository;
private final CategoryRepository categoryRepository;
private final StudyMateRepository studyMateRepository;
private final MaterialCommandService materialCommandService;
private final RecruitPostLikesRepository recruitPostLikesRepository;
private final RecruitPostBookmarkRepository recruitPostBookmarkRepository;

private static final String DEFAULT_THUMBNAIL_URL = "https://gaji-bucket.s3.ap-northeast-2.amazonaws.com/study/gaji.png";

Expand Down Expand Up @@ -104,4 +114,63 @@ private String generateInviteCode() {

return code.toString();
}

@Override
@Transactional
public RecruitResponseDTO.StudyLikesIdDTO likeStudy(Long userId, Long roomId) {
User user = userQueryService.findUserById(userId);
Room room = roomQueryService.findRoomById(roomId);

if (recruitPostLikesRepository.existsByUserAndRoom(user, room)) {
throw new RestApiException(RecruitErrorStatus._ROOM_ALREADY_LIKE);
}

RecruitPostLikes studyLikes = recruitPostLikesRepository.save(RecruitConverter.toRecruitPostLikes(user, room));
room.increaseLike();

return RecruitConverter.toStudyLikesIdDTO(studyLikes);
}

@Override
@Transactional
public void unLikeStudy(Long userId, Long roomId) {
User user = userQueryService.findUserById(userId);
Room room = roomQueryService.findRoomById(roomId);

if (!recruitPostLikesRepository.existsByUserAndRoom(user, room)) {
throw new RestApiException(RecruitErrorStatus._ROOM_ALREADY_NO_LIKE);
}

recruitPostLikesRepository.deleteByUserAndRoom(user, room);
room.decreaseLike();
}

@Override
@Transactional
public RecruitResponseDTO.StudyBookmarkIdDTO bookmarkStudy(Long userId, Long roomId) {
User user = userQueryService.findUserById(userId);
Room room = roomQueryService.findRoomById(roomId);

if (recruitPostBookmarkRepository.existsByUserAndRoom(user, room)) {
throw new RestApiException(RecruitErrorStatus._ROOM_ALREADY_BOOKMARK);
}

RecruitPostBookmark studyBookmark = recruitPostBookmarkRepository.save(RecruitConverter.toRecruitPostBookmark(user, room));
room.increaseBookmark();

return RecruitConverter.toStudyBookmarkIdDTO(studyBookmark);
}

@Override
@Transactional
public void unBookmarkStudy(Long userId, Long roomId) {
User user = userQueryService.findUserById(userId);
Room room = roomQueryService.findRoomById(roomId);

if (!recruitPostBookmarkRepository.existsByUserAndRoom(user, room)) {
throw new RestApiException(RecruitErrorStatus._ROOM_ALREADY_NO_BOOKMARK);
}
recruitPostBookmarkRepository.deleteByUserAndRoom(user, room);
room.decreaseBookmark();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ public class RecruitController {

@PostMapping("")
@Operation(summary = "스터디 모집 게시글 생성 API", description = "스터디 모집 게시글을 생성하는 API입니다.")
public BaseResponse<RecruitResponseDTO.CreateRoomDTO> createRoom(@RequestBody @Valid RecruitRequestDTO.CreateRoomDTO request, @RequestHeader("Authorization") String authorizationHeader) {
public BaseResponse<RecruitResponseDTO.CreateRoomDTO> createRoom(
@RequestBody @Valid RecruitRequestDTO.CreateRoomDTO request,
@RequestHeader("Authorization") String authorizationHeader) {
Long userId = tokenProviderService.getUserIdFromToken(authorizationHeader);
RecruitResponseDTO.CreateRoomDTO responseDTO = recruitCommandService.createRoom(request, userId);
return BaseResponse.onSuccess(responseDTO);
Expand All @@ -49,6 +51,46 @@ public BaseResponse<RecruitResponseDTO.CommentListDTO> getCommentList(@PathVaria
return BaseResponse.onSuccess(responseDTO);
}

@PostMapping("/{roomId}/likes")
@Operation(summary = "스터디 모집 게시글 좋아요 API", description = "스터디 모집 게시글 좋아요 누르는 API입니다.")
public BaseResponse<RecruitResponseDTO.StudyLikesIdDTO> likeStudy(
@RequestHeader("Authorization") String authorizationHeader,
@PathVariable @Min(value = 1, message = "roomId는 1 이상 이어야 합니다.") Long roomId) {
Long userId = tokenProviderService.getUserIdFromToken(authorizationHeader);
RecruitResponseDTO.StudyLikesIdDTO responseDTO = recruitCommandService.likeStudy(userId, roomId);
return BaseResponse.onSuccess(responseDTO);
}

@DeleteMapping("/{roomId}/likes")
@Operation(summary = "스터디 모집 게시글 좋아요 취소 API", description = "스터디 모집 게시글 좋아요 취소하는 API 입니다.")
public BaseResponse unLikeStudy(
@RequestHeader("Authorization") String authorizationHeader,
@PathVariable @Min(value = 1, message = "roomId는 1 이상 이어야 합니다.") Long roomId) {
Long userId = tokenProviderService.getUserIdFromToken(authorizationHeader);
recruitCommandService.unLikeStudy(userId, roomId);
return BaseResponse.onSuccess(null);
}

@PostMapping("/{roomId}/bookmarks")
@Operation(summary = "스터디 모집 게시글 북마크 API", description = "스터디 모집 게시글 북마크 누르는 API입니다.")
public BaseResponse<RecruitResponseDTO.StudyBookmarkIdDTO> bookmarkStudy(
@RequestHeader("Authorization") String authorizationHeader,
@PathVariable @Min(value = 1, message = "roomId는 1 이상 이어야 합니다.") Long roomId) {
Long userId = tokenProviderService.getUserIdFromToken(authorizationHeader);
RecruitResponseDTO.StudyBookmarkIdDTO responseDTO = recruitCommandService.bookmarkStudy(userId, roomId);
return BaseResponse.onSuccess(responseDTO);
}

@DeleteMapping("/{roomId}/bookmarks")
@Operation(summary = "스터디 모집 게시글 북마크 취소 API", description = "스터디 모집 게시글 북마크 취소하는 API 입니다.")
public BaseResponse unBookmarkStudy(
@RequestHeader("Authorization") String authorizationHeader,
@PathVariable @Min(value = 1, message = "roomId는 1 이상 이어야 합니다.") Long roomId) {
Long userId = tokenProviderService.getUserIdFromToken(authorizationHeader);
recruitCommandService.unBookmarkStudy(userId, roomId);
return BaseResponse.onSuccess(null);
}

@GetMapping("/preview")
@Operation(summary = "스터디 모집 게시글 미리보기 목록 조회 API", description = "모집 게시글 목록을 조회하는 API 입니다.")
public BaseResponse<RecruitResponseDTO.PreviewListDTO> getPreviewList(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,24 @@ public static class CommentResponseDTO {
public static class CommentListDTO {
int commentCount;
List<CommentResponseDTO> commentList;

}

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class StudyLikesIdDTO {
Long studyLikesId;
}

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class StudyBookmarkIdDTO {
Long studyBookmarkId;

}

@Builder
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/gaji/service/domain/room/entity/Room.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,20 @@ public void prePersist() {
this.bookmarks = 0;
this.recruitPostTypeEnum = RecruitPostTypeEnum.RECRUITING;
}

public void increaseLike() {
this.likes++;
}

public void decreaseLike() {
this.likes--;
}

public void increaseBookmark() {
this.bookmarks++;
}

public void decreaseBookmark() {
this.bookmarks--;
}
}

0 comments on commit 21ad8c2

Please sign in to comment.