diff --git a/src/main/java/nextstep/qna/domain/Answer.java b/src/main/java/nextstep/qna/domain/Answer.java index cf681811e..afd908098 100644 --- a/src/main/java/nextstep/qna/domain/Answer.java +++ b/src/main/java/nextstep/qna/domain/Answer.java @@ -1,26 +1,19 @@ 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; - +public class Answer extends DeletableBaseEntity { private NsUser writer; private Question question; private String contents; - private boolean deleted = false; - - private LocalDateTime createdDate = LocalDateTime.now(); - - private LocalDateTime updatedDate; - public Answer() { } @@ -29,12 +22,12 @@ public Answer(NsUser writer, Question question, String contents) { } public Answer(Long id, NsUser writer, Question question, String contents) { - this.id = id; - if(writer == null) { + super(id); + if (writer == null) { throw new UnAuthorizedException(); } - if(question == null) { + if (question == null) { throw new NotFoundException(); } @@ -43,19 +36,6 @@ 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 boolean isOwner(NsUser writer) { return this.writer.equals(writer); } @@ -64,10 +44,6 @@ public NsUser getWriter() { return writer; } - public String getContents() { - return contents; - } - public void toQuestion(Question question) { this.question = question; } @@ -76,4 +52,19 @@ public void toQuestion(Question question) { public String toString() { return "Answer [id=" + getId() + ", writer=" + writer + ", contents=" + contents + "]"; } + + public void delete(NsUser loginUser) throws CannotDeleteException { + validateDeletableUser(loginUser); + delete(); + } + + private void validateDeletableUser(NsUser loginUser) throws CannotDeleteException { + if (!isOwner(loginUser)) { + throw new CannotDeleteException("다른 사람이 쓴 답변이 있어 삭제할 수 없습니다."); + } + } + + public DeleteHistory deleteHistory() { + return DeleteHistory.from(ContentType.ANSWER, getId(), getWriter(), LocalDateTime.now()); + } } 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..76bf9d1c9 --- /dev/null +++ b/src/main/java/nextstep/qna/domain/Answers.java @@ -0,0 +1,38 @@ +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 List answers; + + public Answers() { + this(new ArrayList<>()); + } + + public Answers(List answers) { + this.answers = new ArrayList<>(answers); + } + + public void add(Answer answer) { + answers.add(answer); + } + + public void deleteAll(NsUser loginUser) throws CannotDeleteException { + for (Answer answer : answers) { + answer.delete(loginUser); + } + } + + public List toDeleteHistories() { + List deleteHistories = new ArrayList<>(); + for (Answer answer : answers) { + deleteHistories.add(answer.deleteHistory()); + } + return deleteHistories; + } +} diff --git a/src/main/java/nextstep/qna/domain/DeletableBaseEntity.java b/src/main/java/nextstep/qna/domain/DeletableBaseEntity.java new file mode 100644 index 000000000..2ba69c907 --- /dev/null +++ b/src/main/java/nextstep/qna/domain/DeletableBaseEntity.java @@ -0,0 +1,32 @@ +package nextstep.qna.domain; + +import java.time.LocalDateTime; + +public abstract class DeletableBaseEntity { + + private Long id; + private boolean deleted = false; + + private LocalDateTime createdDate = LocalDateTime.now(); + + private LocalDateTime updatedDate; + + protected DeletableBaseEntity() { + } + + public DeletableBaseEntity(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + protected void delete() { + this.deleted = true; + } + + public boolean isDeleted() { + return deleted; + } +} diff --git a/src/main/java/nextstep/qna/domain/DeleteHistory.java b/src/main/java/nextstep/qna/domain/DeleteHistory.java index 43c37e5e5..5a15ecbda 100644 --- a/src/main/java/nextstep/qna/domain/DeleteHistory.java +++ b/src/main/java/nextstep/qna/domain/DeleteHistory.java @@ -19,13 +19,17 @@ public class DeleteHistory { public DeleteHistory() { } - public DeleteHistory(ContentType contentType, Long contentId, NsUser deletedBy, LocalDateTime createdDate) { + private DeleteHistory(ContentType contentType, Long contentId, NsUser deletedBy, LocalDateTime createdDate) { this.contentType = contentType; this.contentId = contentId; this.deletedBy = deletedBy; this.createdDate = createdDate; } + public static DeleteHistory from(ContentType contentType, Long contentId, NsUser deletedBy, LocalDateTime createdDate) { + return new DeleteHistory(contentType, contentId, deletedBy, LocalDateTime.now()); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/nextstep/qna/domain/Question.java b/src/main/java/nextstep/qna/domain/Question.java index b623c52c7..60ac5fc71 100644 --- a/src/main/java/nextstep/qna/domain/Question.java +++ b/src/main/java/nextstep/qna/domain/Question.java @@ -1,62 +1,27 @@ 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; - - private String title; - - private String contents; +public class Question extends DeletableBaseEntity { + private QuestionContent content; private NsUser writer; - private List answers = new ArrayList<>(); - - private boolean deleted = false; - - private LocalDateTime createdDate = LocalDateTime.now(); - - private LocalDateTime updatedDate; - - public Question() { - } + private Answers answers = new Answers(); public Question(NsUser writer, String title, String contents) { this(0L, writer, title, contents); } public Question(Long id, NsUser writer, String title, String contents) { - this.id = id; + super(id); this.writer = writer; - this.title = title; - this.contents = contents; - } - - 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; + this.content = new QuestionContent(title, contents); } public NsUser getWriter() { @@ -72,21 +37,27 @@ public boolean isOwner(NsUser loginUser) { return writer.equals(loginUser); } - public Question setDeleted(boolean deleted) { - this.deleted = deleted; - return this; + private void validateOwner(NsUser loginUser) throws CannotDeleteException { + if (!isOwner(loginUser)) { + throw new CannotDeleteException("질문을 삭제할 권한이 없습니다."); + } } - public boolean isDeleted() { - return deleted; + public DeleteHistory deleteHistory() { + return DeleteHistory.from(ContentType.QUESTION, getId(), writer, LocalDateTime.now()); } - public List getAnswers() { - return answers; + public void delete(NsUser loginUser) throws CannotDeleteException { + validateOwner(loginUser); + delete(); + + answers.deleteAll(loginUser); } - @Override - public String toString() { - return "Question [id=" + getId() + ", title=" + title + ", contents=" + contents + ", writer=" + writer + "]"; + public List toDeleteHistories() { + List deleteHistories = new ArrayList<>(); + deleteHistories.add(deleteHistory()); + deleteHistories.addAll(answers.toDeleteHistories()); + return deleteHistories; } } diff --git a/src/main/java/nextstep/qna/domain/QuestionContent.java b/src/main/java/nextstep/qna/domain/QuestionContent.java new file mode 100644 index 000000000..1d1be5187 --- /dev/null +++ b/src/main/java/nextstep/qna/domain/QuestionContent.java @@ -0,0 +1,11 @@ +package nextstep.qna.domain; + +public class QuestionContent { + private String title; + private String contents; + + public QuestionContent(String title, String contents) { + this.title = title; + this.contents = contents; + } +} diff --git a/src/main/java/nextstep/qna/service/QnAService.java b/src/main/java/nextstep/qna/service/QnAService.java index 5741c84d6..6e00b2574 100644 --- a/src/main/java/nextstep/qna/service/QnAService.java +++ b/src/main/java/nextstep/qna/service/QnAService.java @@ -8,7 +8,6 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -26,24 +25,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("질문을 삭제할 권한이 없습니다."); - } + question.delete(loginUser); - 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())); - } + List deleteHistories = question.toDeleteHistories(); deleteHistoryService.saveAll(deleteHistories); } } diff --git a/src/test/java/nextstep/qna/domain/AnswerTest.java b/src/test/java/nextstep/qna/domain/AnswerTest.java index 8e80ffb42..8b4a022fb 100644 --- a/src/test/java/nextstep/qna/domain/AnswerTest.java +++ b/src/test/java/nextstep/qna/domain/AnswerTest.java @@ -1,8 +1,43 @@ package nextstep.qna.domain; +import nextstep.qna.CannotDeleteException; +import nextstep.users.domain.NsUser; 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 delete_다른사람이_쓴_답변이_있으면_삭제불가() { + NsUser user = NsUserTest.JAVAJIGI; + Answer answer = AnswerTest.A2; + assertThatThrownBy(() -> answer.delete(user)) + .isInstanceOf(CannotDeleteException.class); + } + + @Test + void delete_성공() throws CannotDeleteException { + NsUser user = NsUserTest.JAVAJIGI; + Answer answer = AnswerTest.A1; + + answer.delete(user); + + assertThat(answer.isDeleted()).isTrue(); + } + + @Test + void deleteHistory_생성() { + Answer answer = AnswerTest.A1; + + DeleteHistory history = answer.deleteHistory(); + + assertThat(history).isEqualTo(DeleteHistory.from(ContentType.ANSWER, answer.getId(), answer.getWriter(), LocalDateTime.now())); + } } diff --git a/src/test/java/nextstep/qna/domain/QuestionTest.java b/src/test/java/nextstep/qna/domain/QuestionTest.java index 3b8782396..180715432 100644 --- a/src/test/java/nextstep/qna/domain/QuestionTest.java +++ b/src/test/java/nextstep/qna/domain/QuestionTest.java @@ -1,8 +1,38 @@ 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.*; 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 delete_성공() throws CannotDeleteException { + Question question = new Question(1L, NsUserTest.JAVAJIGI, "title1", "contents1"); + + question.delete(NsUserTest.JAVAJIGI); + } + + @Test + void delete_실패() { + Question question = new Question(1L, NsUserTest.JAVAJIGI, "title1", "contents1"); + + assertThatThrownBy(() -> question.delete(NsUserTest.SANJIGI)) + .isInstanceOf(CannotDeleteException.class); + } + + @Test + void deleteHistory() { + Question question = new Question(1L, NsUserTest.JAVAJIGI, "title1", "contents1"); + + DeleteHistory history = question.deleteHistory(); + + assertThat(history).isEqualTo(DeleteHistory.from(ContentType.QUESTION, question.getId(), question.getWriter(), LocalDateTime.now())); + } } diff --git a/src/test/java/nextstep/qna/service/QnaServiceTest.java b/src/test/java/nextstep/qna/service/QnaServiceTest.java index e1e943c23..218dd9027 100644 --- a/src/test/java/nextstep/qna/service/QnaServiceTest.java +++ b/src/test/java/nextstep/qna/service/QnaServiceTest.java @@ -83,8 +83,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())); + DeleteHistory.from(ContentType.QUESTION, question.getId(), question.getWriter(), LocalDateTime.now()), + DeleteHistory.from(ContentType.ANSWER, answer.getId(), answer.getWriter(), LocalDateTime.now())); verify(deleteHistoryService).saveAll(deleteHistories); } }