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

[BE] issue120: 스터디 리뷰 작성 #140

Merged
merged 26 commits into from
Jul 29, 2022
Merged

Conversation

sc0116
Copy link
Collaborator

@sc0116 sc0116 commented Jul 27, 2022

요약

스터디 리뷰 작성 기능

세부사항

  • 내가 참여한 스터디에 대해서만 후기를 작성할 수 있다.
  • 내가 참여하지 않은 스터디에 후기를 작성 시 에러를 응답한다.

close #120

@sc0116 sc0116 self-assigned this Jul 27, 2022
@sc0116 sc0116 added 🚀 feature New feature or request 🖥 backend New backend feature labels Jul 27, 2022
@sc0116 sc0116 requested review from jaejae-yoo, tco0427 and verus-j July 27, 2022 04:28
Copy link
Collaborator

@tco0427 tco0427 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

구현 굿굿!!
빠트린 final 키워드와 같이 꼼꼼하게 체크해주신 것 같아 좋았습니다!😃
몇가지 궁금한 점들 포함하여 코멘트 남겼어요!

Comment on lines 25 to 27
if (request.getMethod().equals("POST") && validatePath(request)) {
String token = AuthenticationExtractor.extract(request);
validateToken(token);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 스터디 생성 뿐 아니라 리뷰 작성에 대해서도 토큰이 필요해지면서 변경이 필요해졌군요..!!
그린론 코드에서는 내 스터디 조회 시에도 토큰일 필요하게 되어 변경이 발생하더라구요!

흠..🤔

    @Override
    public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) {
        if (isPreflight(request)) {
            return true;
        }

        final String token = AuthenticationExtractor.extract(request);

        if (token != null) {
            validateToken(token);
            
            request.setAttribute("payload", tokenProvider.getPayload(token));
        }

        return true;
    }

    private void validateToken(String token) {
        if (!tokenProvider.validateToken(token)) {
            throw new UnauthorizedException("유효하지 않은 토큰입니다.");
        }
    }

이와 같이 토큰이 있는 경우 즉 토큰이 포함된 요청인 경우에 토큰의 유효성을 검사하는 방향으로 수정하면 어떨까요??
기존의 코드는 새로운 토큰을 동반한 요청의 경우 계속해서 case가 추가되어 코드가 변경되어야할 것 같아요 ㅠ.ㅠ

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이것도 정말 좋은데 이렇게 되면 토큰이 필요없는 전체 목록 조회같은 기능에 유효하지 않은 토큰이 포함된다면 예외가 나지 않을까요? 원래같으면 토큰이 필요없는 비회원도 목록을 볼 수 있을텐데..!

Comment on lines 23 to 29
@ExceptionHandler
public ResponseEntity<Void> handleUnauthorized(final UnauthorizedException e) {
@ExceptionHandler({
UnauthorizedException.class
})
public ResponseEntity<Void> handleUnauthorized(final Exception e) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 이와같이 변경한 이유가 무엇일까요??

현재 잡는 예외가 하나라서 @ExceptionHandler(UnauthorizedException.class)와 같이 해도 좋을 것 같아요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존에는 여러 개를 받고 있어서 일단은 { }로 감쌌는데 병합하면서 수정하겠슴당

Comment on lines 33 to 35
@ExceptionHandler({
NotFoundException.class
})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도!!

Comment on lines -26 to +27
public List<MemberData> findMembersByStudyId(Long studyId) {
String sql = "SELECT github_id, username, image_url, profile_url "
public List<MemberData> findMembersByStudyId(final Long studyId) {
final String sql = "SELECT github_id, username, image_url, profile_url "
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굿굿!!👍

Comment on lines 34 to 39
final String sql = "SELECT EXISTS "
+ "( "
+ "SELECT * "
+ "FROM member JOIN study_member ON member.id = study_member.member_id "
+ "WHERE study_member.study_id = ? AND study_member.member_id = ? "
+ ")";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

서브쿼리를 사용하셨군요..!! inner 쿼리에 * 대신 id 정도만 조회해봐도 동일한 결과가 나올 것 같아요!

@Column(nullable = false)
private String content;

@CreatedDate
@Column(nullable = false)
@Column(nullable = false, updatable = false)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updatable false 굿!!

Comment on lines 54 to 57

public static Review of(final AssociatedStudy associatedStudy, final Member member, final String content) {
return new Review(associatedStudy, member, content);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

음..🤔 생성자 체이닝이 아닌 정적 팩토리 메소드로 하신 이유가 있을까요??

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이미 아래에 생성자가 있어서 정적 팩토리 메서드를 만들 이유가 없어 보입니다.

Comment on lines +51 to -57
final LocalDateTime createdAt = LocalDateTime.now();
validatePeriod(period, createdAt);

this.id = id;
this.details = details;
this.participants = participants;
this.period = period;
this.createdAt = LocalDateTime.now();
this.createdAt = createdAt;
this.attachedTags = attachedTags;

validatePeriod(period);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 기존의 코드에서 변경한 이유가 있을까요?? 짱구의 생각이 궁금합니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

검증 로직이 위에 있어야 한다는 생각에서 변경하게 되었습니다! 검증 메소드에서 사용하는 now()와 실제 createAt에 넣어줄 now()를 동일하게 하기 위해 검증 전 선언했습니당

public class StudyNotFoundException extends RuntimeException {
import com.woowacourse.moamoa.common.exception.NotFoundException;

public class StudyNotFoundException extends NotFoundException {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아하..! 이렇게 상속의 용도로 NotFoundException을 만드신 거군요..!!
음..🤔 좋은 것 같은데요...??

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵! NotFound 뿐만 아니라 BadRequest나 Unauthorized 관련 예외 클래스를 각각 만들면 controller advice에 계속 추가해줘야 하는 번거로움 때문에 한번 더 묶어봤습니당

Comment on lines 18 to 20
@DisplayName("스터디 시작 전에 후기를 작성하면 400 에러를 반환한다.")
@Test
void writeable() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굿!!

Copy link
Collaborator

@jaejae-yoo jaejae-yoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

짱구 구현하느라 고생하셨어요! 코멘트 확인 부탁드려요 ~

@@ -35,14 +38,43 @@ public class Review {
@JoinColumn(name = "member_id")
private Member member;

// @Embedded
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주석 제거해주시면 좋을 것 같아요 ~

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 여기 병합 후 바꿀 예정이라 남겨두었어요


public class InvalidReviewException extends BadRequestException {

private static final String message = "스터디 시작 전 후기를 작성할 수 없습니다.";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

상수 컨벤션 대문자면 좋을 것 같아요 !

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요거 바로 수정할게욤

.andExpect(status().isBadRequest());
}

@DisplayName("필수 데이터인 후기 내용이 없는 경우 400을 반환한다.")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위의 테스트와 차이가 있는지 궁금해요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아마 ""와 null인데 DisplayName이 중복되었군요

@@ -35,14 +38,43 @@ public class Review {
@JoinColumn(name = "member_id")
private Member member;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

연관 매핑을 사용한 이유가 있나요??
아래 주석처럼 Embedded로 memberId를 가진 Reviewer로 써도 될꺼 같아요

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어 이거 병합하고 수정하자고 합의된거 아니었나욤..?

Comment on lines 54 to 57

public static Review of(final AssociatedStudy associatedStudy, final Member member, final String content) {
return new Review(associatedStudy, member, content);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이미 아래에 생성자가 있어서 정적 팩토리 메서드를 만들 이유가 없어 보입니다.

Comment on lines 72 to 79
public void writeable(final Study study) {
final LocalDate createdDate = this.createdDate.toLocalDate();
final LocalDate studyStartDate = study.getPeriod().getStartDate();

if (createdDate.isBefore(studyStartDate)) {
throw new InvalidReviewException();
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review에 두지 말고 Service 계층에 두는건 어떨까요?

Comment on lines 69 to 73
private void checkParticipate(final Long studyId, final Long memberId) {
if (!memberDao.existsByStudyIdAndMemberId(studyId, memberId)) {
throw new NotParticipatedMemberException();
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checkParticipate는 어떤걸 체크하는지에 대한 의미를 전혀 전달하지 못하는것 같아요...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

조금 더 명확하게 수정했습니다

@@ -18,6 +27,9 @@
public class ReviewService {

private final ReviewRepository reviewRepository;
private final MemberRepository memberRepository;
private final StudyRepository studyRepository;
private final MemberDao memberDao;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReviewService에 Repository와 Dao 두가지를 사용하고 있는데 사용하는 용도가 서로 달라 분리시키는게 좋아 보입니다.
Repository는 명령을 위해 DB에서 데이터를 조회해 객체로 매핑하는 용도이고, Dao는 조회를 위해 DB에서 데이터를 조회해 DTO로 변환해 전달하는 용도입니다. 이 부분을 별도의 Service 클래스를 두어 분리시켜두는게 좋을 것 같습니다.

Comment on lines 69 to 73
private void checkParticipate(final Long studyId, final Long memberId) {
if (!memberDao.existsByStudyIdAndMemberId(studyId, memberId)) {
throw new NotParticipatedMemberException();
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 데이터를 외부로 전달하기 위한 조회가 아닌 명령을 위해서 DB를 조회하기 때문에, Repository에서 확인하는게 좋아보입니다.

}

final AssociatedStudy associatedStudy = new AssociatedStudy(studyId);
final Review review = writeReviewRequest.toReview(associatedStudy, member);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new로 할지 toReview로 할지 고민중

.orElseThrow(InvalidMemberException::new);
final Participant participant = new Participant(member.getId());

if (!study.isParticipant(participant)) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isParticipated 로 수정하는게 좋을 것 같음

@@ -56,7 +57,7 @@ public class AcceptanceTest {
private MockRestServiceServer mockServer;

@BeforeEach
void setUp() {
protected void setUp() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AcceptanceTest의 setUp()을 setRestAssuredPort() 로 바꿔주는 게 좋을듯
(BeforeEach의 순서를 정할 수 있는지 알아보기)

void writeReviewByNonParticipateStudy() {
final WriteReviewRequest writeReviewRequest = new WriteReviewRequest("후기 내용입니다.");
final String jwtToken = getBearerTokenBySignInOrUp(
new GithubProfileResponse(2L, "jjanga", "https://image", "github.com"));
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jjanga버리기

@MockBean
private ReviewService reviewService;

@DisplayName("필수 데이터인 후기 내용이 비어있는 경우 400을 반환한다.")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

설명을 공백과 null로 구분하는게 좋을듯

Copy link
Collaborator

@tco0427 tco0427 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추가적인 피드백 반영까지 고생하셨습니다!!
Approve 해도 될 것 같습니다!👍

@@ -24,7 +24,7 @@ public void saveOrUpdate(final Member member) {

public MemberData searchBy(final Long githubId) {
final Member member = memberRepository.findByGithubId(githubId)
.orElseThrow(InvalidMemberException::new);
.orElseThrow(MemberNotFoundException::new);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

명확해서 좋아요 👍


assertThat(participants.contains(participant)).isTrue();
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EOF만 확인 부탁드려요 ~

@sc0116 sc0116 merged commit cdeb842 into develop Jul 29, 2022
@verus-j verus-j deleted the feat/120-write-review branch July 29, 2022 07:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🖥 backend New backend feature 🚀 feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants