diff --git a/README.md b/README.md index 498506166..44bb102aa 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,9 @@ * 모든 피드백을 완료하면 다음 단계를 도전하고 앞의 과정을 반복한다. ## 온라인 코드 리뷰 과정 -* [텍스트와 이미지로 살펴보는 온라인 코드 리뷰 과정](https://github.com/next-step/nextstep-docs/tree/master/codereview) \ No newline at end of file +* [텍스트와 이미지로 살펴보는 온라인 코드 리뷰 과정](https://github.com/next-step/nextstep-docs/tree/master/codereview) + +# todo +- [] Question 에 삭제 상태 변경 추가 +- [] Answer에 삭제 상태 변경 추가 +- [] Answer 일급컬렉션 추가 diff --git a/src/main/java/nextstep/qna/domain/Answer.java b/src/main/java/nextstep/qna/domain/Answer.java index cf681811e..7df698136 100644 --- a/src/main/java/nextstep/qna/domain/Answer.java +++ b/src/main/java/nextstep/qna/domain/Answer.java @@ -7,39 +7,34 @@ import java.time.LocalDateTime; public class Answer { + private Long id; private NsUser writer; - private Question question; - private String contents; - private boolean deleted = false; + private boolean deleted; - private LocalDateTime createdDate = LocalDateTime.now(); + private LocalDateTime createdDate; private LocalDateTime updatedDate; - public Answer() { - } - public Answer(NsUser writer, Question question, String contents) { this(null, writer, question, contents); } public Answer(Long id, NsUser writer, Question question, String contents) { this.id = id; - if(writer == null) { + if (writer == null) { throw new UnAuthorizedException(); } - if(question == null) { + if (question == null) { throw new NotFoundException(); } this.writer = writer; - this.question = question; this.contents = contents; } @@ -47,11 +42,6 @@ public Long getId() { return id; } - public Answer setDeleted(boolean deleted) { - this.deleted = deleted; - return this; - } - public boolean isDeleted() { return deleted; } @@ -64,16 +54,12 @@ public NsUser getWriter() { return writer; } - public String getContents() { - return contents; - } - - public void toQuestion(Question question) { - this.question = question; - } - @Override public String toString() { return "Answer [id=" + getId() + ", writer=" + writer + ", contents=" + contents + "]"; } + + public void delete() { + deleted = true; + } } diff --git a/src/main/java/nextstep/qna/domain/Answers.java b/src/main/java/nextstep/qna/domain/Answers.java new file mode 100644 index 000000000..860790be9 --- /dev/null +++ b/src/main/java/nextstep/qna/domain/Answers.java @@ -0,0 +1,36 @@ +package nextstep.qna.domain; + +import java.time.LocalDateTime; +import java.util.*; + +import nextstep.users.domain.NsUser; + +public class Answers { + + private List answers; + + public Answers(List answers) { + this.answers = answers; + } + + public void add(Answer answer) { + answers.add(answer); + } + + public boolean isContainOtherOwner(NsUser loginUser) { + return answers.stream() + .anyMatch(answer -> !answer.isOwner(loginUser)); + } + + public void delete() { + answers.forEach(answer -> answer.delete()); + } + + public List getDeleteHistory() { + List deleteHistories = new ArrayList<>(); + for (Answer answer : answers) { + deleteHistories.add(new DeleteHistory(ContentType.ANSWER, answer.getId(), answer.getWriter(), LocalDateTime.now())); + } + return deleteHistories; + } +} diff --git a/src/main/java/nextstep/qna/domain/Question.java b/src/main/java/nextstep/qna/domain/Question.java index b623c52c7..b3c3467b3 100644 --- a/src/main/java/nextstep/qna/domain/Question.java +++ b/src/main/java/nextstep/qna/domain/Question.java @@ -1,5 +1,6 @@ package nextstep.qna.domain; +import nextstep.qna.CannotDeleteException; import nextstep.users.domain.NsUser; import java.time.LocalDateTime; @@ -15,56 +16,40 @@ public class Question { private NsUser writer; - private List answers = new ArrayList<>(); + private Answers answers; - private boolean deleted = false; + private boolean deleted; private LocalDateTime createdDate = LocalDateTime.now(); private LocalDateTime updatedDate; - public Question() { - } - public Question(NsUser writer, String title, String contents) { this(0L, writer, title, contents); } public Question(Long id, NsUser writer, String title, String contents) { + this(0L, writer, title, contents, new Answers(new ArrayList<>()), false); + } + + public Question(Long id, NsUser writer, String title, String contents, Answers answers, boolean deleted) { this.id = id; this.writer = writer; this.title = title; this.contents = contents; + this.answers = answers; + this.deleted = deleted; } public Long getId() { return id; } - public String getTitle() { - return title; - } - - public Question setTitle(String title) { - this.title = title; - return this; - } - - public String getContents() { - return contents; - } - - public Question setContents(String contents) { - this.contents = contents; - return this; - } - public NsUser getWriter() { return writer; } public void addAnswer(Answer answer) { - answer.toQuestion(this); answers.add(answer); } @@ -72,21 +57,44 @@ public boolean isOwner(NsUser loginUser) { return writer.equals(loginUser); } - public Question setDeleted(boolean deleted) { - this.deleted = deleted; - return this; - } - public boolean isDeleted() { return deleted; } - public List getAnswers() { - return answers; - } - @Override public String toString() { return "Question [id=" + getId() + ", title=" + title + ", contents=" + contents + ", writer=" + writer + "]"; } + + public void deleteBy(NsUser loginUser) throws CannotDeleteException{ + validDeleteAuth(loginUser); + validOtherUserAnswer(loginUser); + deleted = true; + answers.delete(); + } + + private void validOtherUserAnswer(NsUser loginUser) throws CannotDeleteException { + if (answers.isContainOtherOwner(loginUser)) { + throw new CannotDeleteException("다른 사람이 쓴 답변이 있어 삭제할 수 없습니다."); + } + } + + private void validDeleteAuth(NsUser loginUser) throws CannotDeleteException { + if (!this.isOwner(loginUser)) { + throw new CannotDeleteException("질문을 삭제할 권한이 없습니다."); + } + } + + public List getDeleteHistory() { + List deleteHistories = new ArrayList<>(); + if (!this.deleted) { + return deleteHistories; + } + + deleteHistories.add(new DeleteHistory(ContentType.QUESTION, id, writer, LocalDateTime.now())); + deleteHistories.addAll(answers.getDeleteHistory()); + return deleteHistories; + } + + } diff --git a/src/main/java/nextstep/qna/service/QnAService.java b/src/main/java/nextstep/qna/service/QnAService.java index 5741c84d6..457dfa173 100644 --- a/src/main/java/nextstep/qna/service/QnAService.java +++ b/src/main/java/nextstep/qna/service/QnAService.java @@ -14,6 +14,7 @@ @Service("qnaService") public class QnAService { + @Resource(name = "questionRepository") private QuestionRepository questionRepository; @@ -26,24 +27,7 @@ public class QnAService { @Transactional public void deleteQuestion(NsUser loginUser, long questionId) throws CannotDeleteException { Question question = questionRepository.findById(questionId).orElseThrow(NotFoundException::new); - if (!question.isOwner(loginUser)) { - throw new CannotDeleteException("질문을 삭제할 권한이 없습니다."); - } - - List answers = question.getAnswers(); - for (Answer answer : answers) { - if (!answer.isOwner(loginUser)) { - throw new CannotDeleteException("다른 사람이 쓴 답변이 있어 삭제할 수 없습니다."); - } - } - - List deleteHistories = new ArrayList<>(); - question.setDeleted(true); - deleteHistories.add(new DeleteHistory(ContentType.QUESTION, questionId, question.getWriter(), LocalDateTime.now())); - for (Answer answer : answers) { - answer.setDeleted(true); - deleteHistories.add(new DeleteHistory(ContentType.ANSWER, answer.getId(), answer.getWriter(), LocalDateTime.now())); - } - deleteHistoryService.saveAll(deleteHistories); + question.deleteBy(loginUser); + deleteHistoryService.saveAll(question.getDeleteHistory()); } } diff --git a/src/main/java/nextstep/users/domain/NsUser.java b/src/main/java/nextstep/users/domain/NsUser.java index 62ec5138c..187b0ee57 100755 --- a/src/main/java/nextstep/users/domain/NsUser.java +++ b/src/main/java/nextstep/users/domain/NsUser.java @@ -6,6 +6,7 @@ import java.util.Objects; public class NsUser { + public static final GuestNsUser GUEST_USER = new GuestNsUser(); private Long id; @@ -110,7 +111,7 @@ public boolean equalsNameAndEmail(NsUser target) { } return name.equals(target.name) && - email.equals(target.email); + email.equals(target.email); } public boolean isGuestUser() { @@ -118,6 +119,7 @@ public boolean isGuestUser() { } private static class GuestNsUser extends NsUser { + @Override public boolean isGuestUser() { return true; @@ -127,12 +129,12 @@ public boolean isGuestUser() { @Override public String toString() { return "NsUser{" + - "id=" + id + - ", userId='" + userId + '\'' + - ", name='" + name + '\'' + - ", email='" + email + '\'' + - ", createdAt=" + createdAt + - ", updatedAt=" + updatedAt + - '}'; + "id=" + id + + ", userId='" + userId + '\'' + + ", name='" + name + '\'' + + ", email='" + email + '\'' + + ", createdAt=" + createdAt + + ", updatedAt=" + updatedAt + + '}'; } } diff --git a/src/test/java/nextstep/qna/domain/AnswerTest.java b/src/test/java/nextstep/qna/domain/AnswerTest.java index 8e80ffb42..99dc14ae3 100644 --- a/src/test/java/nextstep/qna/domain/AnswerTest.java +++ b/src/test/java/nextstep/qna/domain/AnswerTest.java @@ -1,8 +1,19 @@ package nextstep.qna.domain; +import nextstep.qna.CannotDeleteException; import nextstep.users.domain.NsUserTest; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; public class AnswerTest { + public static final Answer A1 = new Answer(NsUserTest.JAVAJIGI, QuestionTest.Q1, "Answers Contents1"); public static final Answer A2 = new Answer(NsUserTest.SANJIGI, QuestionTest.Q1, "Answers Contents2"); + + @Test + void 삭제_테스트() throws CannotDeleteException { + A1.delete(); + assertThat(A1.isDeleted()).isEqualTo(true); + } } diff --git a/src/test/java/nextstep/qna/domain/QuestionTest.java b/src/test/java/nextstep/qna/domain/QuestionTest.java index 3b8782396..3e31d80fe 100644 --- a/src/test/java/nextstep/qna/domain/QuestionTest.java +++ b/src/test/java/nextstep/qna/domain/QuestionTest.java @@ -1,8 +1,19 @@ package nextstep.qna.domain; +import nextstep.qna.CannotDeleteException; import nextstep.users.domain.NsUserTest; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; public class QuestionTest { + public static final Question Q1 = new Question(NsUserTest.JAVAJIGI, "title1", "contents1"); public static final Question Q2 = new Question(NsUserTest.SANJIGI, "title2", "contents2"); + + @Test + void 삭제_테스트() throws CannotDeleteException { + Q1.deleteBy(NsUserTest.JAVAJIGI); + assertThat(Q1.isDeleted()).isEqualTo(true); + } } diff --git a/src/test/java/nextstep/qna/service/QnaServiceTest.java b/src/test/java/nextstep/qna/service/QnaServiceTest.java index e1e943c23..53c7fd0c3 100644 --- a/src/test/java/nextstep/qna/service/QnaServiceTest.java +++ b/src/test/java/nextstep/qna/service/QnaServiceTest.java @@ -22,6 +22,7 @@ @ExtendWith(MockitoExtension.class) public class QnaServiceTest { + @Mock private QuestionRepository questionRepository; @@ -83,8 +84,8 @@ public void setUp() throws Exception { private void verifyDeleteHistories() { List deleteHistories = Arrays.asList( - new DeleteHistory(ContentType.QUESTION, question.getId(), question.getWriter(), LocalDateTime.now()), - new DeleteHistory(ContentType.ANSWER, answer.getId(), answer.getWriter(), LocalDateTime.now())); + new DeleteHistory(ContentType.QUESTION, question.getId(), question.getWriter(), LocalDateTime.now()), + new DeleteHistory(ContentType.ANSWER, answer.getId(), answer.getWriter(), LocalDateTime.now())); verify(deleteHistoryService).saveAll(deleteHistories); } }