-
Notifications
You must be signed in to change notification settings - Fork 4
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
Q&A 기능 추가 #526
Q&A 기능 추가 #526
Changes from 23 commits
dc709f1
df75dd7
73a4b19
26078dd
4b7fb84
e14af04
d81ff04
e0e6e8e
0d5f85f
ab415a0
f54d0a9
59fb738
4224840
29076c3
97aa6ea
12c6e3d
7cfcd3a
0146a4e
68c9497
3559bcd
66b18d6
e35adcb
636d934
1d7e896
1611cff
98ac03b
544ad4c
493260b
ea5df21
410426b
082d7d5
e33718c
ce53640
5866b56
0dba066
a1b178a
4da8433
16e2029
7c50d90
ae7751b
4912784
5a5896f
ec7fdca
0f0d3e9
1771054
026d62d
c06b726
7d27cca
ef8a11d
a929963
091bb9a
8d7c84a
3a20334
14f1477
2370238
c49fac1
e726017
f35b69f
7ad8437
5285c0c
e820761
b99d36c
624edc3
e79559b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.ddang.ddang.qna.application.exception; | ||
|
||
public class AnswerNotFoundException extends IllegalArgumentException { | ||
|
||
public AnswerNotFoundException(final String message) { | ||
super(message); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,6 +1,7 @@ | ||||||||||||||
package com.ddang.ddang.qna.domain; | ||||||||||||||
|
||||||||||||||
import com.ddang.ddang.common.entity.BaseCreateTimeEntity; | ||||||||||||||
import com.ddang.ddang.user.domain.User; | ||||||||||||||
import jakarta.persistence.Column; | ||||||||||||||
import jakarta.persistence.Entity; | ||||||||||||||
import jakarta.persistence.FetchType; | ||||||||||||||
|
@@ -20,9 +21,11 @@ | |||||||||||||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||||||||||||||
@Getter | ||||||||||||||
@EqualsAndHashCode(of = "id", callSuper = false) | ||||||||||||||
@ToString(of = {"id", "content"}) | ||||||||||||||
@ToString(of = {"id", "content", "deleted"}) | ||||||||||||||
public class Answer extends BaseCreateTimeEntity { | ||||||||||||||
|
||||||||||||||
private static final boolean DELETED_STATUS = true; | ||||||||||||||
|
||||||||||||||
@Id | ||||||||||||||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||||||||||||||
private Long id; | ||||||||||||||
|
@@ -34,11 +37,26 @@ public class Answer extends BaseCreateTimeEntity { | |||||||||||||
@Column(columnDefinition = "text") | ||||||||||||||
private String content; | ||||||||||||||
|
||||||||||||||
@Column(name = "is_deleted") | ||||||||||||||
private boolean deleted = false; | ||||||||||||||
|
||||||||||||||
public Answer(final String content) { | ||||||||||||||
this.content = content; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
public void initQuestion(final Question question) { | ||||||||||||||
this.question = question; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
public boolean isWriter(final User user) { | ||||||||||||||
return question.getAuction().isOwner(user); | ||||||||||||||
} | ||||||||||||||
Comment on lines
+51
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 필수isWriter() 테스트코드가 없네요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아이구.. 감사합니다 🙇♀️ |
||||||||||||||
|
||||||||||||||
public void delete() { | ||||||||||||||
deleted = DELETED_STATUS; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
public User getWriter() { | ||||||||||||||
return question.getWriter(); | ||||||||||||||
} | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 필수Answer의 writer는 auction의 seller가 되지 않을까요?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 헉... 정말 큰일 날 뻔 헀네요. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 필수추가된 메서드들에 대한 테스트코드가 없는 것 같아요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 확인감사합니다. 추가해두었습니다! |
||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,9 +23,11 @@ | |
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@Getter | ||
@EqualsAndHashCode(of = "id", callSuper = false) | ||
@ToString(of = {"id", "content"}) | ||
@ToString(of = {"id", "content", "deleted"}) | ||
public class Question extends BaseCreateTimeEntity { | ||
|
||
private static final boolean DELETED_STATUS = true; | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
@@ -44,6 +46,9 @@ public class Question extends BaseCreateTimeEntity { | |
@OneToOne(mappedBy = "question") | ||
private Answer answer; | ||
|
||
@Column(name = "is_deleted") | ||
private boolean deleted = false; | ||
|
||
public Question(final Auction auction, final User writer, final String content) { | ||
this.auction = auction; | ||
this.writer = writer; | ||
|
@@ -58,4 +63,12 @@ public void addAnswer(final Answer answer) { | |
public boolean isAnsweringAllowed(final User user) { | ||
return auction.isOwner(user); | ||
} | ||
|
||
public boolean isWriter(final User user) { | ||
return writer.equals(user); | ||
} | ||
|
||
public void delete() { | ||
deleted = DELETED_STATUS; | ||
} | ||
Comment on lines
+71
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 질문Question을 삭제해도 Answer는 그대로 남아있는 건가요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저도 해당 부분을 고민하다 Anwer의 경우 가져오는 방법이 Question을 통해서밖에 없어 굳이 삭제처리를 않았습니다.
Comment on lines
+67
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 필수여기도 새로 추가된 메서드들에 대한 테스트코드가 없습니다! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 자코코.. 생각보다 관대하군요..?ㅎㅎ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 필수isDelete() 테스트만 있고. delete() 테스트는 없는 것 같아요! |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,15 @@ | ||
package com.ddang.ddang.qna.infrastructure; | ||
|
||
import com.ddang.ddang.qna.domain.Answer; | ||
import org.springframework.data.jpa.repository.EntityGraph; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import java.util.Optional; | ||
|
||
public interface JpaAnswerRepository extends JpaRepository<Answer, Long> { | ||
|
||
boolean existsByQuestionId(Long questionId); | ||
|
||
@EntityGraph(attributePaths = {"question", "question.auction", "question.auction.seller"}) | ||
Optional<Answer> findByIdAndDeletedIsFalse(Long answerId); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 필수바로 아래 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 추가했습니다. 감사합니다! |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package com.ddang.ddang.report.application; | ||
|
||
import com.ddang.ddang.qna.application.exception.AnswerNotFoundException; | ||
import com.ddang.ddang.qna.domain.Answer; | ||
import com.ddang.ddang.qna.infrastructure.JpaAnswerRepository; | ||
import com.ddang.ddang.report.application.dto.CreateAnswerReportDto; | ||
import com.ddang.ddang.report.application.dto.ReadAnswerReportDto; | ||
import com.ddang.ddang.report.application.exception.InvalidAnswererReportException; | ||
import com.ddang.ddang.report.domain.AnswerReport; | ||
import com.ddang.ddang.report.infrastructure.persistence.JpaAnswerReportRepository; | ||
import com.ddang.ddang.user.application.exception.UserNotFoundException; | ||
import com.ddang.ddang.user.domain.User; | ||
import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.List; | ||
|
||
@Service | ||
@Transactional(readOnly = true) | ||
@RequiredArgsConstructor | ||
public class AnswerReportService { | ||
|
||
private final JpaAnswerRepository answerRepository; | ||
private final JpaUserRepository userRepository; | ||
private final JpaAnswerReportRepository answerReportRepository; | ||
|
||
@Transactional | ||
public Long create(final CreateAnswerReportDto answerReportDto) { | ||
final Answer answer = answerRepository.findByIdAndDeletedIsFalse(answerReportDto.answerId()) | ||
.orElseThrow(() -> | ||
new AnswerNotFoundException("해당 답변을 찾을 수 없습니다.") | ||
); | ||
final User reporter = userRepository.findByIdAndDeletedIsFalse(answerReportDto.reporterId()) | ||
.orElseThrow(() -> new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); | ||
checkInvalidAnswerReport(reporter, answer); | ||
|
||
final AnswerReport answerReport = answerReportDto.toEntity(answer, reporter); | ||
|
||
return answerReportRepository.save(answerReport) | ||
.getId(); | ||
} | ||
|
||
private void checkInvalidAnswerReport(final User reporter, final Answer answer) { | ||
if (answer.isWriter(reporter)) { | ||
throw new InvalidAnswererReportException("본인 답변입니다."); | ||
} | ||
if (answerReportRepository.existsByIdAndReporterId(answer.getId(), reporter.getId())) { | ||
throw new InvalidAnswererReportException("이미 신고한 답변입니다."); | ||
} | ||
} | ||
|
||
public List<ReadAnswerReportDto> readAll() { | ||
final List<AnswerReport> answerReports = answerReportRepository.findAllByOrderByIdAsc(); | ||
|
||
return answerReports.stream() | ||
.map(ReadAnswerReportDto::from) | ||
.toList(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
칭찬
헉 이럴수가.. 리뷰 빼먹었었네요.. 칭찬해요!