Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ [Feat]: 레크레이션 리뷰 작성 API 구현 #39

Merged
merged 3 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
@Getter
@AllArgsConstructor
public enum SuccessStatus implements BaseCode {
_OK(HttpStatus.OK, "COMMON200", "성공입니다.");
_OK(HttpStatus.OK, "COMMON200", "성공입니다."),
_CREATED(HttpStatus.CREATED, "COMMON201", "요청 성공 및 리소스 생성됨");

private final HttpStatus httpStatus;
private final String code;
private final String message;
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/com/avab/avab/controller/RecreationController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,36 @@

import java.util.List;

import jakarta.validation.Valid;

import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.avab.avab.apiPayload.BaseResponse;
import com.avab.avab.apiPayload.code.status.SuccessStatus;
import com.avab.avab.converter.RecreationConverter;
import com.avab.avab.domain.Recreation;
import com.avab.avab.domain.RecreationReview;
import com.avab.avab.domain.User;
import com.avab.avab.domain.enums.Age;
import com.avab.avab.domain.enums.Gender;
import com.avab.avab.domain.enums.Keyword;
import com.avab.avab.domain.enums.Place;
import com.avab.avab.dto.reqeust.RecreationRequestDTO.PostRecreationReviewDTO;
import com.avab.avab.dto.response.RecreationResponseDTO.DescriptionDTO;
import com.avab.avab.dto.response.RecreationResponseDTO.FavoriteDTO;
import com.avab.avab.dto.response.RecreationResponseDTO.PopularRecreationListDTO;
import com.avab.avab.dto.response.RecreationResponseDTO.RecreationPreviewListDTO;
import com.avab.avab.dto.response.RecreationResponseDTO.RecreationReviewCreatedDTO;
import com.avab.avab.security.handler.annotation.AuthUser;
import com.avab.avab.service.RecreationService;
import com.avab.avab.validation.annotation.ExistRecreation;
Expand Down Expand Up @@ -113,4 +120,19 @@ public BaseResponse<FavoriteDTO> toggleFavoriteRecreation(

return BaseResponse.onSuccess(RecreationConverter.toFavoriteDTO(isFavorite));
}

@Operation(summary = "레크레이션 리뷰 작성 API", description = "레크레이션에 리뷰를 작성합니다.")
@ApiResponses({@ApiResponse(responseCode = "COMMON201", description = "리뷰 생성 성공")})
@Parameter(name = "user", hidden = true)
@PostMapping("/{recreationId}/reviews")
@ResponseStatus(code = HttpStatus.CREATED)
public BaseResponse<RecreationReviewCreatedDTO> postRecreationReviewDTO(
@AuthUser User user,
@PathVariable("recreationId") @ExistRecreation Long recreationId,
@Valid @RequestBody PostRecreationReviewDTO request) {
RecreationReview review = recreationService.createReview(user, recreationId, request);

return BaseResponse.of(
SuccessStatus._CREATED, RecreationConverter.toRecreationReviewCreatedDTO(review));
}
}
17 changes: 17 additions & 0 deletions src/main/java/com/avab/avab/converter/RecreationConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,21 @@
import com.avab.avab.domain.RecreationHashtag;
import com.avab.avab.domain.RecreationKeyword;
import com.avab.avab.domain.RecreationPreparation;
import com.avab.avab.domain.RecreationReview;
import com.avab.avab.domain.RecreationWay;
import com.avab.avab.domain.User;
import com.avab.avab.domain.enums.Age;
import com.avab.avab.domain.enums.Gender;
import com.avab.avab.domain.enums.Keyword;
import com.avab.avab.domain.mapping.RecreationFavorite;
import com.avab.avab.domain.mapping.RecreationRecreationKeyword;
import com.avab.avab.dto.reqeust.RecreationRequestDTO.PostRecreationReviewDTO;
import com.avab.avab.dto.response.RecreationResponseDTO.DescriptionDTO;
import com.avab.avab.dto.response.RecreationResponseDTO.FavoriteDTO;
import com.avab.avab.dto.response.RecreationResponseDTO.PopularRecreationListDTO;
import com.avab.avab.dto.response.RecreationResponseDTO.RecreationPreviewDTO;
import com.avab.avab.dto.response.RecreationResponseDTO.RecreationPreviewListDTO;
import com.avab.avab.dto.response.RecreationResponseDTO.RecreationReviewCreatedDTO;
import com.avab.avab.dto.response.RecreationResponseDTO.WayDTO;

public class RecreationConverter {
Expand Down Expand Up @@ -142,4 +145,18 @@ public static RecreationFavorite toRecreationFavorite(Recreation recreation, Use
public static FavoriteDTO toFavoriteDTO(Boolean isFavorite) {
return FavoriteDTO.builder().isFavorite(isFavorite).build();
}

public static RecreationReview toRecreationReview(
User user, Recreation recreation, PostRecreationReviewDTO request) {
return RecreationReview.builder()
.recreation(recreation)
.author(user)
.contents(request.getContents())
.stars(request.getStars())
.build();
}

public static RecreationReviewCreatedDTO toRecreationReviewCreatedDTO(RecreationReview review) {
return RecreationReviewCreatedDTO.builder().reviewId(review.getId()).build();
}
}
7 changes: 6 additions & 1 deletion src/main/java/com/avab/avab/domain/RecreationReview.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;

import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;

import com.avab.avab.domain.common.BaseEntity;
import com.avab.avab.domain.mapping.RecreationReviewRecommendation;

Expand All @@ -28,6 +31,8 @@
@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@DynamicUpdate
@DynamicInsert
public class RecreationReview extends BaseEntity {

@Id
Expand All @@ -36,7 +41,7 @@ public class RecreationReview extends BaseEntity {

private Integer stars;

@Column(length = 300)
@Column(length = 500)
private String contents;

private Integer goodCount;
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/com/avab/avab/dto/reqeust/RecreationRequestDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.avab.avab.dto.reqeust;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

import lombok.Getter;
import lombok.Setter;

public class RecreationRequestDTO {

@Getter
@Setter
public static class PostRecreationReviewDTO {

@Min(value = 0, message = "별점은 0점 이상이어야 합니다.")
@Max(value = 5, message = "별점은 5점 이하여야 합니다.")
@NotNull(message = "별점은 필수입니다.")
private Integer stars;

@Size(max = 500, message = "리뷰는 300자 이하여야 합니다.")
@NotEmpty(message = "리뷰 내용은 필수입니다.")
private String contents;
}
}
34 changes: 22 additions & 12 deletions src/main/java/com/avab/avab/dto/response/RecreationResponseDTO.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.avab.avab.domain.enums.Keyword;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -16,8 +17,8 @@ public class RecreationResponseDTO {

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public static class PopularRecreationListDTO {

List<Keyword> keywordList;
Expand All @@ -33,8 +34,8 @@ public static class PopularRecreationListDTO {

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public static class RecreationPreviewDTO {

Long id;
Expand All @@ -50,8 +51,8 @@ public static class RecreationPreviewDTO {

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public static class RecreationPreviewListDTO {

List<RecreationPreviewDTO> recreationList;
Expand All @@ -60,8 +61,8 @@ public static class RecreationPreviewListDTO {

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public static class DescriptionDTO {

Long recreationId;
Expand All @@ -77,8 +78,8 @@ public static class DescriptionDTO {

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public static class WayDTO {

String contents;
Expand All @@ -87,10 +88,19 @@ public static class WayDTO {

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public static class FavoriteDTO {

Boolean isFavorite;
}

@Builder
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public static class RecreationReviewCreatedDTO {

Long reviewId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.avab.avab.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.avab.avab.domain.RecreationReview;

public interface RecreationReviewRepository extends JpaRepository<RecreationReview, Long> {}
4 changes: 4 additions & 0 deletions src/main/java/com/avab/avab/service/RecreationService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import org.springframework.data.domain.Page;

import com.avab.avab.domain.Recreation;
import com.avab.avab.domain.RecreationReview;
import com.avab.avab.domain.User;
import com.avab.avab.domain.enums.Age;
import com.avab.avab.domain.enums.Gender;
import com.avab.avab.domain.enums.Keyword;
import com.avab.avab.domain.enums.Place;
import com.avab.avab.dto.reqeust.RecreationRequestDTO.PostRecreationReviewDTO;
import com.avab.avab.dto.response.RecreationResponseDTO.PopularRecreationListDTO;

public interface RecreationService {
Expand All @@ -30,4 +32,6 @@ Page<Recreation> searchRecreations(
Recreation getRecreationDescription(Long recreationId);

Boolean toggleFavoriteRecreation(Long recreationId, User user);

RecreationReview createReview(User user, Long recreationId, PostRecreationReviewDTO request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,18 @@
import com.avab.avab.apiPayload.exception.RecreationException;
import com.avab.avab.converter.RecreationConverter;
import com.avab.avab.domain.Recreation;
import com.avab.avab.domain.RecreationReview;
import com.avab.avab.domain.User;
import com.avab.avab.domain.enums.Age;
import com.avab.avab.domain.enums.Gender;
import com.avab.avab.domain.enums.Keyword;
import com.avab.avab.domain.enums.Place;
import com.avab.avab.domain.mapping.RecreationFavorite;
import com.avab.avab.dto.reqeust.RecreationRequestDTO.PostRecreationReviewDTO;
import com.avab.avab.dto.response.RecreationResponseDTO.PopularRecreationListDTO;
import com.avab.avab.repository.RecreationFavoriteRepository;
import com.avab.avab.repository.RecreationRepository;
import com.avab.avab.repository.RecreationReviewRepository;
import com.avab.avab.service.RecreationService;

import lombok.RequiredArgsConstructor;
Expand All @@ -31,6 +34,7 @@ public class RecreationServiceImpl implements RecreationService {

private final RecreationRepository recreationRepository;
private final RecreationFavoriteRepository recreationFavoriteRepository;
private final RecreationReviewRepository recreationReviewRepository;
private final Integer SEARCH_PAGE_SIZE = 9;

public List<PopularRecreationListDTO> getTop3RecreationsByViewCount() {
Expand Down Expand Up @@ -69,6 +73,19 @@ public Boolean toggleFavoriteRecreation(Long recreationId, User user) {
}
}

@Override
public RecreationReview createReview(
User user, Long recreationId, PostRecreationReviewDTO request) {
Recreation recreation =
recreationRepository
.findById(recreationId)
.orElseThrow(
() -> new RecreationException(ErrorStatus.RECREATION_NOT_FOUND));

RecreationReview review = RecreationConverter.toRecreationReview(user, recreation, request);
return recreationReviewRepository.save(review);
}

@Override
public Page<Recreation> searchRecreations(
User user,
Expand Down