diff --git a/src/main/java/nextstep/qna/domain/Answer.java b/src/main/java/nextstep/qna/domain/Answer.java index cf681811e7..93d97a80a5 100644 --- a/src/main/java/nextstep/qna/domain/Answer.java +++ b/src/main/java/nextstep/qna/domain/Answer.java @@ -1,26 +1,17 @@ package nextstep.qna.domain; +import nextstep.qna.CannotDeleteException; import nextstep.qna.NotFoundException; import nextstep.qna.UnAuthorizedException; import nextstep.users.domain.NsUser; import java.time.LocalDateTime; -public class Answer { - private Long id; - - private NsUser writer; - +public class Answer extends BaseEntity { private Question question; - + private NsUser writer; private String contents; - private boolean deleted = false; - - private LocalDateTime createdDate = LocalDateTime.now(); - - private LocalDateTime updatedDate; - public Answer() { } @@ -29,7 +20,7 @@ public Answer(NsUser writer, Question question, String contents) { } public Answer(Long id, NsUser writer, Question question, String contents) { - this.id = id; + super(id); if(writer == null) { throw new UnAuthorizedException(); } @@ -43,17 +34,9 @@ public Answer(Long id, NsUser writer, Question question, String contents) { this.contents = contents; } - public Long getId() { - return id; - } - - public Answer setDeleted(boolean deleted) { - this.deleted = deleted; - return this; - } - - public boolean isDeleted() { - return deleted; + public void delete(NsUser loginUser) throws CannotDeleteException { + validateDeletableBy(loginUser); + markAsDeleted(); } public boolean isOwner(NsUser writer) { @@ -61,17 +44,22 @@ public boolean isOwner(NsUser writer) { } public NsUser getWriter() { - return writer; - } - - public String getContents() { - return contents; + return this.writer; } public void toQuestion(Question question) { this.question = question; } + private void validateDeletableBy(NsUser loginUser) throws CannotDeleteException { + if (!isOwner(loginUser)) { + throw new CannotDeleteException("다른 사람이 쓴 답변이 있어 삭제할 수 없습니다."); + } + } + public DeleteHistory createDeleteHistory() { + return new DeleteHistory(ContentType.ANSWER, getId(), getWriter(), LocalDateTime.now()); + } + @Override public String toString() { return "Answer [id=" + getId() + ", writer=" + writer + ", contents=" + contents + "]"; 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 0000000000..a445dd3cef --- /dev/null +++ b/src/main/java/nextstep/qna/domain/Answers.java @@ -0,0 +1,48 @@ +package nextstep.qna.domain; + +import nextstep.qna.CannotDeleteException; +import nextstep.users.domain.NsUser; + +import java.util.ArrayList; +import java.util.List; + +public class Answers { + private final List answers; + + public Answers() { + this(new ArrayList<>()); + } + + public Answers(Answer answer) { + this(List.of(answer)); + } + + public Answers(List answers) { + this.answers = answers; + } + + + public List getAnswers() { + return this.answers; + } + + public void add(Answer answer) { + this.answers.add(answer); + } + + public void delete(NsUser loginUser) throws CannotDeleteException { + for (Answer answer : answers) { + answer.delete(loginUser); + } + } + + public List createDeleteHistories() { + List deleteHistories = new ArrayList<>(); + + for (Answer answer : answers) { + deleteHistories.add(answer.createDeleteHistory()); + } + + return deleteHistories; + } +} diff --git a/src/main/java/nextstep/qna/domain/BaseEntity.java b/src/main/java/nextstep/qna/domain/BaseEntity.java new file mode 100644 index 0000000000..6ca0168e24 --- /dev/null +++ b/src/main/java/nextstep/qna/domain/BaseEntity.java @@ -0,0 +1,31 @@ +package nextstep.qna.domain; + +import java.time.LocalDateTime; + +public abstract class BaseEntity { + private Long id; + + private LocalDateTime createdDate = LocalDateTime.now(); + + private LocalDateTime updatedDate; + + private boolean deleted = false; + + public BaseEntity() {} + + public BaseEntity(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + protected void markAsDeleted() { + this.deleted = true; + } + + public boolean isDeleted() { + return deleted; + } +} diff --git a/src/main/java/nextstep/qna/domain/PostContent.java b/src/main/java/nextstep/qna/domain/PostContent.java new file mode 100644 index 0000000000..6df462c9ca --- /dev/null +++ b/src/main/java/nextstep/qna/domain/PostContent.java @@ -0,0 +1,23 @@ +package nextstep.qna.domain; + +import nextstep.users.domain.NsUser; + +public class PostContent { + private final NsUser writer; + private final String title; + private final String contents; + + public PostContent(NsUser writer, String title, String contents) { + this.writer = writer; + this.title = title; + this.contents = contents; + } + + public NsUser getWriter() { + return this.writer; + } + + public boolean isOwner(NsUser loginUser) { + return writer.equals(loginUser); + } +} diff --git a/src/main/java/nextstep/qna/domain/Question.java b/src/main/java/nextstep/qna/domain/Question.java index b623c52c76..40de23cddc 100644 --- a/src/main/java/nextstep/qna/domain/Question.java +++ b/src/main/java/nextstep/qna/domain/Question.java @@ -1,66 +1,34 @@ package nextstep.qna.domain; +import nextstep.qna.CannotDeleteException; import nextstep.users.domain.NsUser; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; -public class Question { - private Long id; +public class Question extends BaseEntity { + private PostContent postContent; - private String title; - - private String contents; - - private NsUser writer; - - private List answers = new ArrayList<>(); - - private boolean deleted = false; - - private LocalDateTime createdDate = LocalDateTime.now(); - - private LocalDateTime updatedDate; + private Answers answers = new Answers(); public Question() { } public Question(NsUser writer, String title, String contents) { - this(0L, writer, title, contents); + this(0L, new PostContent(writer, title, contents)); } public Question(Long id, NsUser writer, String title, String contents) { - this.id = id; - this.writer = writer; - this.title = title; - this.contents = contents; - } - - public Long getId() { - return id; - } - - public String getTitle() { - return title; + this(id, new PostContent(writer, title, contents)); } - - 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 Question(Long id, PostContent postContent) { + super(id); + this.postContent = postContent; } public NsUser getWriter() { - return writer; + return postContent.getWriter(); } public void addAnswer(Answer answer) { @@ -69,24 +37,45 @@ public void addAnswer(Answer answer) { } public boolean isOwner(NsUser loginUser) { - return writer.equals(loginUser); + return postContent.isOwner(loginUser); } - public Question setDeleted(boolean deleted) { - this.deleted = deleted; - return this; + public void markAsDeleted(NsUser loginUser) throws CannotDeleteException { + validateDeletableBy(loginUser); + markAsDeleted(); } - public boolean isDeleted() { - return deleted; + public void delete(NsUser loginUser) throws CannotDeleteException { + this.markAsDeleted(loginUser); + answers.delete(loginUser); + } + + public List createDeleteHistories() { + List histories = new ArrayList<>(); + + histories.add(new DeleteHistory( + ContentType.QUESTION, + getId(), + getWriter(), + LocalDateTime.now() + )); + + histories.addAll(answers.createDeleteHistories()); + + return histories; } - public List getAnswers() { - return answers; + public void validateDeletableBy(NsUser loginUser) throws CannotDeleteException { + if (!isOwner(loginUser)) { + throw new CannotDeleteException("질문을 삭제할 권한이 없습니다."); + } } @Override public String toString() { - return "Question [id=" + getId() + ", title=" + title + ", contents=" + contents + ", writer=" + writer + "]"; + return "Question{" + + "postContent=" + postContent + + ", answers=" + answers + + '}'; } } diff --git a/src/main/java/nextstep/qna/service/QnAService.java b/src/main/java/nextstep/qna/service/QnAService.java index 5741c84d65..6bed774c65 100644 --- a/src/main/java/nextstep/qna/service/QnAService.java +++ b/src/main/java/nextstep/qna/service/QnAService.java @@ -8,8 +8,6 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.util.ArrayList; import java.util.List; @Service("qnaService") @@ -26,24 +24,9 @@ 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.delete(loginUser); + + deleteHistoryService.saveAll(question.createDeleteHistories()); } -} +} \ No newline at end of file diff --git a/src/test/java/nextstep/qna/domain/AnswerTest.java b/src/test/java/nextstep/qna/domain/AnswerTest.java index 8e80ffb429..da73246e36 100644 --- a/src/test/java/nextstep/qna/domain/AnswerTest.java +++ b/src/test/java/nextstep/qna/domain/AnswerTest.java @@ -1,8 +1,36 @@ package nextstep.qna.domain; +import nextstep.qna.CannotDeleteException; import nextstep.users.domain.NsUserTest; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; 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 다른_사람이_쓴_답변이_있어_삭제할_수_없음() { + assertThatThrownBy(()-> + A1.delete(NsUserTest.SANJIGI) + ).isInstanceOf(CannotDeleteException.class) + .hasMessageContaining("다른 사람이 쓴 답변이 있어 삭제할 수 없습니다."); + } + + @Test + void 답변_삭제_성공() throws CannotDeleteException { + A1.delete(NsUserTest.JAVAJIGI); + + assertThat(A1.isDeleted()).isTrue(); + } + + @Test + void 삭제한_히스토리_생성() { + assertThat(A1.createDeleteHistory()) + .isEqualTo(new DeleteHistory(ContentType.ANSWER, A1.getId(), A1.getWriter(), LocalDateTime.now())); + } } diff --git a/src/test/java/nextstep/qna/domain/AnswersTest.java b/src/test/java/nextstep/qna/domain/AnswersTest.java new file mode 100644 index 0000000000..2ef1f895c9 --- /dev/null +++ b/src/test/java/nextstep/qna/domain/AnswersTest.java @@ -0,0 +1,14 @@ +package nextstep.qna.domain; + +import nextstep.users.domain.NsUserTest; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +public class AnswersTest { + @Test + void create() { + Answers answers = new Answers(new Answer(11L, NsUserTest.JAVAJIGI, QuestionTest.Q1, "Answers Contents1")); + + Assertions.assertThat(answers.getAnswers()).hasSize(1); + } +} diff --git a/src/test/java/nextstep/qna/domain/QuestionTest.java b/src/test/java/nextstep/qna/domain/QuestionTest.java index 3b87823963..8179985c3d 100644 --- a/src/test/java/nextstep/qna/domain/QuestionTest.java +++ b/src/test/java/nextstep/qna/domain/QuestionTest.java @@ -1,8 +1,36 @@ 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.*; 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 삭제할_수_없는_유저일_때() { + assertThatThrownBy(()-> + Q1.delete(NsUserTest.SANJIGI) + ).isInstanceOf(CannotDeleteException.class) + .hasMessageContaining("질문을 삭제할 권한이 없습니다."); + + } + + @Test + void 질문_삭제_성공() throws CannotDeleteException { + Q1.addAnswer(AnswerTest.A1); + Q1.delete(NsUserTest.JAVAJIGI); + + assertThat(Q1.isDeleted()).isTrue(); + } + + @Test + void 삭제_히스토리_생성() { + Q1.addAnswer(AnswerTest.A1); + + assertThat(Q1.createDeleteHistories()).hasSize(2); + } }