forked from woowacourse-teams/2023-baton
-
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.
서포터 피드백 등록 API 구현 (woowacourse-teams#186)
* feat: Description VO 구현 * feat: SupporterFeedback 엔티티 구현 * chore: Feedback 관련 패키지 변경 * refactor: SupporterFeedback Entity 에 nullable 추가 * feat: Runner 에 equals&hashcode 추가 * feat: SupporterFeedback 등록 API 구현 * refactor: FeedbackBusinessException 내부 클래스 삭제 * test: 안 쓰는 인스턴스 변수 로컬 변수로 변경 * test: SupporterFeedback 관련 Fixture 구현 * test: RestAssuredTest 컨벤션에 맞게 변경 * refactor: FeedbackService 에 Transaction 추가 * refactor: FeedbackService Runner 찾는 과정 삭제 * refactor: 로그인 기능 추가에 따른 @AuthRunner 사용하도록 변경 * refactor: RunnerPost 와 SupporterFeedback 과의 관계를 OneToOne 으로 변경
- Loading branch information
1 parent
571db35
commit 5ffa7aa
Showing
26 changed files
with
797 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
100 changes: 100 additions & 0 deletions
100
backend/baton/src/main/java/touch/baton/domain/feedback/SupporterFeedback.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,100 @@ | ||
package touch.baton.domain.feedback; | ||
|
||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Embedded; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.Enumerated; | ||
import jakarta.persistence.ForeignKey; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.JoinColumn; | ||
import jakarta.persistence.ManyToOne; | ||
import jakarta.persistence.OneToOne; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import touch.baton.domain.common.BaseEntity; | ||
import touch.baton.domain.feedback.exception.SupporterFeedbackException; | ||
import touch.baton.domain.feedback.vo.Description; | ||
import touch.baton.domain.feedback.vo.ReviewType; | ||
import touch.baton.domain.runner.Runner; | ||
import touch.baton.domain.runnerpost.RunnerPost; | ||
import touch.baton.domain.supporter.Supporter; | ||
|
||
import java.util.Objects; | ||
|
||
import static jakarta.persistence.EnumType.STRING; | ||
import static jakarta.persistence.FetchType.LAZY; | ||
import static jakarta.persistence.GenerationType.IDENTITY; | ||
import static lombok.AccessLevel.PROTECTED; | ||
|
||
@Getter | ||
@NoArgsConstructor(access = PROTECTED) | ||
@Entity | ||
public class SupporterFeedback extends BaseEntity { | ||
|
||
@GeneratedValue(strategy = IDENTITY) | ||
@Id | ||
private Long id; | ||
|
||
@Enumerated(STRING) | ||
@Column(nullable = false) | ||
private ReviewType reviewType; | ||
|
||
@Embedded | ||
private Description description; | ||
|
||
@ManyToOne(fetch = LAZY) | ||
@JoinColumn(name = "supporter_id", nullable = false, foreignKey = @ForeignKey(name = "fk_supporter_feed_back_to_supporter")) | ||
private Supporter supporter; | ||
|
||
@ManyToOne(fetch = LAZY) | ||
@JoinColumn(name = "runner_id", nullable = false, foreignKey = @ForeignKey(name = "fk_supporter_feed_back_to_runner")) | ||
private Runner runner; | ||
|
||
@OneToOne(fetch = LAZY) | ||
@JoinColumn(name = "runner_post_id", nullable = false, foreignKey = @ForeignKey(name = "fk_supporter_feed_back_to_runner_post")) | ||
private RunnerPost runnerPost; | ||
|
||
@Builder | ||
private SupporterFeedback(final ReviewType reviewType, final Description description, final Supporter supporter, final Runner runner, final RunnerPost runnerPost) { | ||
this(null, reviewType, description, supporter, runner, runnerPost); | ||
} | ||
|
||
private SupporterFeedback(final Long id, final ReviewType reviewType, final Description description, final Supporter supporter, final Runner runner, final RunnerPost runnerPost) { | ||
validateNotNull(reviewType, description, supporter, runner, runnerPost); | ||
this.id = id; | ||
this.reviewType = reviewType; | ||
this.description = description; | ||
this.supporter = supporter; | ||
this.runner = runner; | ||
this.runnerPost = runnerPost; | ||
} | ||
|
||
private void validateNotNull(final ReviewType reviewType, | ||
final Description description, | ||
final Supporter supporter, | ||
final Runner runner, | ||
final RunnerPost runnerPost | ||
) { | ||
if (Objects.isNull(reviewType)) { | ||
throw new SupporterFeedbackException("SupporterFeedback 의 reviewType 은 null 일 수 없습니다."); | ||
} | ||
|
||
if (Objects.isNull(description)) { | ||
throw new SupporterFeedbackException("SupporterFeedback 의 description 은 null 일 수 없습니다."); | ||
} | ||
|
||
if (Objects.isNull(supporter)) { | ||
throw new SupporterFeedbackException("SupporterFeedback 의 supporter 는 null 일 수 없습니다."); | ||
} | ||
|
||
if (Objects.isNull(runner)) { | ||
throw new SupporterFeedbackException("SupporterFeedback 의 runner 는 null 일 수 없습니다."); | ||
} | ||
|
||
if (Objects.isNull(runnerPost)) { | ||
throw new SupporterFeedbackException("SupporterFeedback 의 runnerPost 는 null 일 수 없습니다."); | ||
} | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
backend/baton/src/main/java/touch/baton/domain/feedback/controller/FeedbackController.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,40 @@ | ||
package touch.baton.domain.feedback.controller; | ||
|
||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
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.util.UriComponentsBuilder; | ||
import touch.baton.domain.feedback.service.FeedbackService; | ||
import touch.baton.domain.feedback.service.SupporterFeedBackCreateRequest; | ||
import touch.baton.domain.oauth.controller.resolver.AuthRunnerPrincipal; | ||
import touch.baton.domain.runner.Runner; | ||
import touch.baton.domain.runner.service.RunnerService; | ||
|
||
import java.net.URI; | ||
|
||
@RequiredArgsConstructor | ||
@RequestMapping("/api/v1/feedback") | ||
@RestController | ||
public class FeedbackController { | ||
|
||
private final FeedbackService feedbackService; | ||
private final RunnerService runnerService; | ||
|
||
@PostMapping("/supporter") | ||
public ResponseEntity<Void> createSupporterFeedback(@AuthRunnerPrincipal final Runner runner, | ||
@Valid @RequestBody final SupporterFeedBackCreateRequest request | ||
) { | ||
final Long savedId = feedbackService.createSupporterFeedback(runner, request); | ||
|
||
final URI redirectUri = UriComponentsBuilder.fromPath("/api/v1/feedback/supporter") | ||
.path("/{id}") | ||
.buildAndExpand(savedId) | ||
.toUri(); | ||
return ResponseEntity.created(redirectUri).build(); | ||
} | ||
|
||
} |
10 changes: 10 additions & 0 deletions
10
.../baton/src/main/java/touch/baton/domain/feedback/exception/FeedbackBusinessException.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,10 @@ | ||
package touch.baton.domain.feedback.exception; | ||
|
||
import touch.baton.domain.common.exception.BusinessException; | ||
|
||
public class FeedbackBusinessException extends BusinessException { | ||
|
||
public FeedbackBusinessException(final String message) { | ||
super(message); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
...baton/src/main/java/touch/baton/domain/feedback/exception/SupporterFeedbackException.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,10 @@ | ||
package touch.baton.domain.feedback.exception; | ||
|
||
import touch.baton.domain.common.exception.DomainException; | ||
|
||
public class SupporterFeedbackException extends DomainException { | ||
|
||
public SupporterFeedbackException(final String message) { | ||
super(message); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
...ton/src/main/java/touch/baton/domain/feedback/repository/SupporterFeedbackRepository.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,7 @@ | ||
package touch.baton.domain.feedback.repository; | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import touch.baton.domain.feedback.SupporterFeedback; | ||
|
||
public interface SupporterFeedbackRepository extends JpaRepository<SupporterFeedback, Long> { | ||
} |
54 changes: 54 additions & 0 deletions
54
backend/baton/src/main/java/touch/baton/domain/feedback/service/FeedbackService.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,54 @@ | ||
package touch.baton.domain.feedback.service; | ||
|
||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import touch.baton.domain.feedback.SupporterFeedback; | ||
import touch.baton.domain.feedback.exception.FeedbackBusinessException; | ||
import touch.baton.domain.feedback.repository.SupporterFeedbackRepository; | ||
import touch.baton.domain.feedback.vo.Description; | ||
import touch.baton.domain.feedback.vo.ReviewType; | ||
import touch.baton.domain.runner.Runner; | ||
import touch.baton.domain.runnerpost.RunnerPost; | ||
import touch.baton.domain.runnerpost.repository.RunnerPostRepository; | ||
import touch.baton.domain.supporter.Supporter; | ||
import touch.baton.domain.supporter.repository.SupporterRepository; | ||
|
||
@RequiredArgsConstructor | ||
@Transactional(readOnly = true) | ||
@Service | ||
public class FeedbackService { | ||
|
||
private static final String DELIMITER = "|"; | ||
|
||
private final SupporterFeedbackRepository supporterFeedbackRepository; | ||
private final RunnerPostRepository runnerPostRepository; | ||
private final SupporterRepository supporterRepository; | ||
|
||
@Transactional | ||
public Long createSupporterFeedback(final Runner runner, final SupporterFeedBackCreateRequest request) { | ||
final Supporter foundSupporter = supporterRepository.findById(request.supporterId()) | ||
.orElseThrow(() -> new FeedbackBusinessException("서포터를 찾을 수 없습니다.")); | ||
final RunnerPost foundRunnerPost = runnerPostRepository.findById(request.runnerPostId()) | ||
.orElseThrow(() -> new FeedbackBusinessException("러너 게시글을 찾을 수 없습니다.")); | ||
|
||
if (foundRunnerPost.isNotOwner(runner)) { | ||
throw new FeedbackBusinessException("리뷰 글을 작성한 주인만 글을 작성할 수 있습니다."); | ||
} | ||
|
||
if (foundRunnerPost.isDifferentSupporter(foundSupporter)) { | ||
throw new FeedbackBusinessException("리뷰를 작성한 서포터에 대해서만 피드백을 작성할 수 있습니다."); | ||
} | ||
|
||
final SupporterFeedback supporterFeedback = SupporterFeedback.builder() | ||
.reviewType(ReviewType.valueOf(request.reviewType())) | ||
.description(new Description(String.join(DELIMITER, request.descriptions()))) | ||
.runner(runner) | ||
.supporter(foundSupporter) | ||
.runnerPost(foundRunnerPost) | ||
.build(); | ||
|
||
return supporterFeedbackRepository.save(supporterFeedback).getId(); | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
...ton/src/main/java/touch/baton/domain/feedback/service/SupporterFeedBackCreateRequest.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,16 @@ | ||
package touch.baton.domain.feedback.service; | ||
|
||
import touch.baton.domain.common.exception.ClientErrorCode; | ||
import touch.baton.domain.common.exception.validator.ValidNotNull; | ||
|
||
import java.util.List; | ||
|
||
public record SupporterFeedBackCreateRequest(@ValidNotNull(clientErrorCode = ClientErrorCode.REVIEW_TYPE_IS_NULL) | ||
String reviewType, | ||
List<String> descriptions, | ||
@ValidNotNull(clientErrorCode = ClientErrorCode.SUPPORTER_ID_IS_NULL) | ||
Long supporterId, | ||
@ValidNotNull(clientErrorCode = ClientErrorCode.RUNNER_ID_IS_NULL) | ||
Long runnerPostId | ||
) { | ||
} |
32 changes: 32 additions & 0 deletions
32
backend/baton/src/main/java/touch/baton/domain/feedback/vo/Description.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 touch.baton.domain.feedback.vo; | ||
|
||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Embeddable; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
import java.util.Objects; | ||
|
||
import static lombok.AccessLevel.PROTECTED; | ||
|
||
@EqualsAndHashCode | ||
@Getter | ||
@NoArgsConstructor(access = PROTECTED) | ||
@Embeddable | ||
public class Description { | ||
|
||
@Column(name = "description", nullable = true, columnDefinition = "TEXT") | ||
private String value; | ||
|
||
public Description(final String value) { | ||
validateNotNull(value); | ||
this.value = value; | ||
} | ||
|
||
private void validateNotNull(final String value) { | ||
if (Objects.isNull(value)) { | ||
throw new IllegalArgumentException("Description 객체 내부에 value 는 null 일 수 없습니다."); | ||
} | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
backend/baton/src/main/java/touch/baton/domain/feedback/vo/ReviewType.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 touch.baton.domain.feedback.vo; | ||
|
||
public enum ReviewType { | ||
|
||
GREAT, GOOD, BAD | ||
} |
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
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
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
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
22 changes: 22 additions & 0 deletions
22
backend/baton/src/test/java/touch/baton/assure/common/HttpStatusAndLocationHeader.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,22 @@ | ||
package touch.baton.assure.common; | ||
|
||
import org.springframework.http.HttpStatus; | ||
|
||
public class HttpStatusAndLocationHeader { | ||
|
||
private final HttpStatus httpStatus; | ||
private final String location; | ||
|
||
public HttpStatusAndLocationHeader(final HttpStatus httpStatus, final String location) { | ||
this.httpStatus = httpStatus; | ||
this.location = location; | ||
} | ||
|
||
public HttpStatus getHttpStatus() { | ||
return httpStatus; | ||
} | ||
|
||
public String getLocation() { | ||
return location; | ||
} | ||
} |
Oops, something went wrong.