diff --git a/build.gradle b/build.gradle index 74124c19..a4c3a8ab 100755 --- a/build.gradle +++ b/build.gradle @@ -34,4 +34,5 @@ dependencies { runtime('net.rakugakibox.spring.boot:logback-access-spring-boot-starter:2.7.1') testCompile('org.springframework.boot:spring-boot-starter-test') testCompile('org.assertj:assertj-core:3.10.0') + implementation 'org.projectlombok:lombok' } \ No newline at end of file diff --git a/src/main/java/codesquad/answer/Answer.java b/src/main/java/codesquad/answer/Answer.java index 394b1539..83882fa2 100644 --- a/src/main/java/codesquad/answer/Answer.java +++ b/src/main/java/codesquad/answer/Answer.java @@ -2,10 +2,14 @@ import codesquad.qua.Question; import codesquad.user.User; +import lombok.Getter; +import lombok.NoArgsConstructor; import javax.persistence.*; @Entity +@Getter +@NoArgsConstructor public class Answer { @Id @@ -16,54 +20,35 @@ public class Answer { @JoinColumn(foreignKey = @ForeignKey(name = "fk_answer_to_question")) private Question question; - private String writer; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(foreignKey = @ForeignKey(name = "fk_answer_to_user")) + private User writer; private String comment; - private boolean deletedFlag = false; + private boolean deletedFlag; - public boolean isDeletedFlag() { - return deletedFlag; + public Answer(Question question, User writer, String comment) { + this.question = question; + this.writer = writer; + this.comment = comment; + deletedFlag = false; } public void changeDeletedFlag() { deletedFlag = true; } - public String getWriter() { - return writer; - } - - public void setWriter(String writer) { - this.writer = writer; - } - - public Long getId() { - return id; - } - - public Question getQuestion() { - return question; - } - - public void setQuestion(Question question) { - this.question = question; - } - - public String getComment() { - return comment; - } - - public void setComment(String comment) { - this.comment = comment; - } - public void addQuestion(Question question) { question.getAnswers().add(this); this.question = question; } public boolean equalsWriter(User user) { - return writer.equals(user.getName()); + return writer.equals(user); + } + + public ResponseAnswerDto toResponseAnswerDto() { + return new ResponseAnswerDto(id, comment, question.getId(), writer.getName()); } } diff --git a/src/main/java/codesquad/answer/AnswerController.java b/src/main/java/codesquad/answer/AnswerController.java deleted file mode 100644 index aee0cd4c..00000000 --- a/src/main/java/codesquad/answer/AnswerController.java +++ /dev/null @@ -1,72 +0,0 @@ -package codesquad.answer; - -import codesquad.qua.Question; -import codesquad.qua.QuestionRepository; -import codesquad.user.User; -import codesquad.utils.SessionUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; - -import javax.servlet.http.HttpSession; -import java.util.NoSuchElementException; - -@Controller -public class AnswerController { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - @Autowired - private AnswerRepository answerRepository; - @Autowired - private QuestionRepository questionRepository; - - @PostMapping("/questions/{question-id}/answers") - public String create(@PathVariable("question-id") Long questionId, Answer answer, HttpSession session, Model model) { - Question question = questionRepository.findById(questionId) - .orElseThrow(NoSuchElementException::new); - - logger.info("답글 내용 : {}", answer.getComment()); - logger.info("답글 작성자 : {}", answer.getWriter()); - - User user = SessionUtil.getUserBySession(session); - - if (user == null) { - return "/login"; - } - - answer.setWriter(user.getName()); - answer.addQuestion(question); - - answerRepository.save(answer); - - return "redirect:/questions/" + questionId; - } - - @DeleteMapping("/questions/{question-id}/answers/{answer-id}") - @Transactional - public String remove(@PathVariable("question-id") Long questionId, - @PathVariable("answer-id") Long answerId, HttpSession session) { - User user = SessionUtil.getUserBySession(session); - - Answer answer = answerRepository.findById(answerId) - .orElseThrow(NoSuchElementException::new); - - if (user == null) { - return "/login"; - } - - if (!answer.equalsWriter(user)) { - return "user/login_failed"; - } - - answer.changeDeletedFlag(); - - return "redirect:/questions/" + questionId; - } -} diff --git a/src/main/java/codesquad/answer/AnswerRepository.java b/src/main/java/codesquad/answer/AnswerRepository.java index 6decc11b..0caac67f 100644 --- a/src/main/java/codesquad/answer/AnswerRepository.java +++ b/src/main/java/codesquad/answer/AnswerRepository.java @@ -1,6 +1,12 @@ package codesquad.answer; +import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface AnswerRepository extends JpaRepository { + + @EntityGraph(attributePaths = {"question"}) + Optional findQuestionFetchJoinById(Long id); } diff --git a/src/main/java/codesquad/answer/AnswerService.java b/src/main/java/codesquad/answer/AnswerService.java new file mode 100644 index 00000000..4e9c4468 --- /dev/null +++ b/src/main/java/codesquad/answer/AnswerService.java @@ -0,0 +1,62 @@ +package codesquad.answer; + +import codesquad.qua.Question; +import codesquad.qua.QuestionRepository; +import codesquad.response.Result; +import codesquad.user.User; +import codesquad.utils.SessionUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpSession; +import java.util.NoSuchElementException; + +@Service +@Slf4j +@RequiredArgsConstructor +public class AnswerService { + + private final AnswerRepository answerRepository; + private final QuestionRepository questionRepository; + + public Result create(long questionId, RequestAnswerDto requestAnswerDto, HttpSession session) { + log.info("comment = {}", requestAnswerDto.getComment()); + + User user = SessionUtil.getUserBySession(session); + + if (user == null) { + return Result.fail("로그인 하세요"); + } + + Question question = questionRepository.findById(questionId) + .orElseThrow(NoSuchElementException::new); + + Answer answer = new Answer(question, user, requestAnswerDto.getComment()); + answer.addQuestion(question); + answerRepository.save(answer); + + return Result.ok(answer.toResponseAnswerDto()); + } + + @Transactional + public Result remove(long questionId, long answerId, HttpSession session) { + User user = SessionUtil.getUserBySession(session); + + if (user == null) { + return Result.fail("로그인 하세요"); + } + + Answer answer = answerRepository.findQuestionFetchJoinById(answerId) + .orElseThrow(NoSuchElementException::new); + + if (!answer.equalsWriter(user)) { + return Result.fail("다른 사람 답글은 삭제 못해요"); + } + + answer.changeDeletedFlag(); + + return Result.ok(answer.toResponseAnswerDto()); + } +} \ No newline at end of file diff --git a/src/main/java/codesquad/answer/ApiAnswerController.java b/src/main/java/codesquad/answer/ApiAnswerController.java new file mode 100644 index 00000000..01584dda --- /dev/null +++ b/src/main/java/codesquad/answer/ApiAnswerController.java @@ -0,0 +1,27 @@ +package codesquad.answer; + +import codesquad.response.Result; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpSession; + +@RestController +@RequiredArgsConstructor +@Slf4j +public class ApiAnswerController { + + private final AnswerService answerService; + + @PostMapping("/questions/{question-id}/answers") + public Result create(@PathVariable("question-id") Long questionId, @RequestBody RequestAnswerDto requestAnswerDto, HttpSession session) { + return answerService.create(questionId, requestAnswerDto, session); + } + + @DeleteMapping("/questions/{question-id}/answers/{answer-id}") + public Result remove(@PathVariable("question-id") Long questionId, + @PathVariable("answer-id") Long answerId, HttpSession session) { + return answerService.remove(questionId, answerId, session); + } +} diff --git a/src/main/java/codesquad/answer/RequestAnswerDto.java b/src/main/java/codesquad/answer/RequestAnswerDto.java new file mode 100644 index 00000000..6ffd5d38 --- /dev/null +++ b/src/main/java/codesquad/answer/RequestAnswerDto.java @@ -0,0 +1,10 @@ +package codesquad.answer; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class RequestAnswerDto { + private String comment; +} diff --git a/src/main/java/codesquad/answer/ResponseAnswerDto.java b/src/main/java/codesquad/answer/ResponseAnswerDto.java new file mode 100644 index 00000000..9a9feb43 --- /dev/null +++ b/src/main/java/codesquad/answer/ResponseAnswerDto.java @@ -0,0 +1,16 @@ +package codesquad.answer; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +public class ResponseAnswerDto { + + private long id; + private String comment; + private long questionId; + private String writer; +} diff --git a/src/main/java/codesquad/exception/QuestionDeleteException.java b/src/main/java/codesquad/exception/QuestionDeleteException.java new file mode 100644 index 00000000..11c3b2fe --- /dev/null +++ b/src/main/java/codesquad/exception/QuestionDeleteException.java @@ -0,0 +1,11 @@ +package codesquad.exception; + +public class QuestionDeleteException extends RuntimeException { + + public QuestionDeleteException() { + } + + public QuestionDeleteException(String message) { + super(message); + } +} diff --git a/src/main/java/codesquad/exception/QuestionEditException.java b/src/main/java/codesquad/exception/QuestionEditException.java new file mode 100644 index 00000000..77411e46 --- /dev/null +++ b/src/main/java/codesquad/exception/QuestionEditException.java @@ -0,0 +1,11 @@ +package codesquad.exception; + +public class QuestionEditException extends RuntimeException { + + public QuestionEditException() { + } + + public QuestionEditException(String message) { + super(message); + } +} diff --git a/src/main/java/codesquad/qua/Question.java b/src/main/java/codesquad/qua/Question.java index d601206a..07ee65f3 100644 --- a/src/main/java/codesquad/qua/Question.java +++ b/src/main/java/codesquad/qua/Question.java @@ -2,12 +2,17 @@ import codesquad.answer.Answer; import codesquad.user.User; +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Getter; +import lombok.NoArgsConstructor; import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity +@NoArgsConstructor +@Getter public class Question { @Id @@ -22,52 +27,25 @@ public class Question { private String contents; - private boolean deletedFlag = false; + private boolean deletedFlag; @OneToMany(mappedBy = "question") - private List answers = new ArrayList<>(); - - public List getAnswers() { - return answers; + @JsonIgnore + private List answers; + + public Question(QuestionDto questionDto, User user) { + this.writer = user; + this.title = questionDto.getTitle(); + this.contents = questionDto.getContents(); + answers = new ArrayList<>(); + deletedFlag = false; } public void changeDeleteFlag() { deletedFlag = true; } - public boolean isDeletedFlag() { - return deletedFlag; - } - - public User getWriter() { - return writer; - } - - public void setWriter(User writer) { - this.writer = writer; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getContents() { - return contents; - } - - public void setContents(String contents) { - this.contents = contents; - } - - public Long getId() { - return id; - } - - public void update(Question question) { + public void update(QuestionDto question) { this.title = question.getTitle(); this.contents = question.getContents(); } @@ -79,4 +57,12 @@ public boolean equalsWriter(User user) { public boolean hasAnswers() { return answers.size() > 0; } + + public void deleteQuestion() { + changeDeleteFlag(); + + for (Answer answer : answers) { + answer.changeDeletedFlag(); + } + } } \ No newline at end of file diff --git a/src/main/java/codesquad/qua/QuestionController.java b/src/main/java/codesquad/qua/QuestionController.java index 31900344..26b2d491 100644 --- a/src/main/java/codesquad/qua/QuestionController.java +++ b/src/main/java/codesquad/qua/QuestionController.java @@ -1,35 +1,26 @@ package codesquad.qua; -import codesquad.answer.Answer; -import codesquad.answer.AnswerRepository; -import codesquad.user.User; -import codesquad.utils.SessionUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import codesquad.exception.QuestionDeleteException; +import codesquad.exception.QuestionEditException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpSession; -import java.util.NoSuchElementException; @Controller +@RequiredArgsConstructor +@Slf4j public class QuestionController { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - @Autowired - QuestionRepository questionRepository; - - @Autowired - AnswerRepository answerRepository; + private final QuestionService questionService; @GetMapping("/questions/form") public String createForm(HttpSession session) { - User user = SessionUtil.getUserBySession(session); - - if (user == null) { + if (!questionService.setCreateForm(session)) { return "/login"; } @@ -37,122 +28,62 @@ public String createForm(HttpSession session) { } @PostMapping("/questions") - public String create(Question question, HttpSession session) { - User user = SessionUtil.getUserBySession(session); - - if (user == null) { + public String createQuestion(QuestionDto questionDto, HttpSession session) { + if (!questionService.create(questionDto, session)) { return "/login"; } - question.setWriter(user); - questionRepository.save(question); - logger.info("user : {}", question.getWriter().getName()); return "redirect:/"; } @GetMapping("/") - public String list(Model model) { - model.addAttribute("question", questionRepository.findAll()); + public String showQuestionList(Model model) { + model.addAttribute("question", questionService.list()); return "qna/list"; } @GetMapping("/questions/{id}") - public String qnaInfo(Model model, @PathVariable("id") Long id) { - Question question = findQuestionById(id); - model.addAttribute("question", question); - model.addAttribute("count", countAnswers(question)); - + public String showQuestion(Model model, @PathVariable("id") Long id) { + model.addAttribute("question", questionService.findQuestionById(id)); + model.addAttribute("count", questionService.countAnswers(id)); return "qna/show"; } - @Transactional @PutMapping("/questions/{id}") - public String update(Question changedQuestion, @PathVariable("id") Long id, HttpSession session) { - User user = SessionUtil.getUserBySession(session); - Question savedQuestion = findQuestionById(id); - - if (user == null || !isQuestionMatchUser(user, savedQuestion)) { + public String updateQuestion(QuestionDto changedQuestion, @PathVariable("id") Long id, HttpSession session) { + try { + questionService.update(changedQuestion, id, session); + } catch (QuestionEditException showException) { return "qna/show_failed"; } - logger.info("user: {}", user.getName()); - logger.info("question: {}", savedQuestion.getWriter()); - - savedQuestion.update(changedQuestion); - return "redirect:/"; } @GetMapping("/questions/{id}/updateForm") public String updateForm(Model model, @PathVariable("id") Long id, HttpSession session) { - User user = SessionUtil.getUserBySession(session); - Question savedQuestion = findQuestionById(id); - - if (user == null || !isQuestionMatchUser(user, savedQuestion)) { + try { + questionService.setUpdateForm(id, session); + } catch (QuestionEditException showException) { return "qna/show_failed"; } - logger.info("user: {}", user.getName()); - logger.info("question: {}", savedQuestion.getWriter()); - - model.addAttribute("question", savedQuestion); + model.addAttribute("question", questionService.findQuestionById(id)); return "qna/updateForm"; } @DeleteMapping("/questions/{id}") - @Transactional - public String remove(@PathVariable("id") Long id, HttpSession session) { - User user = SessionUtil.getUserBySession(session); - Question savedQuestion = findQuestionById(id); - - logger.info("user: {}", user.getName()); - logger.info("question: {}", savedQuestion.getWriter()); + public String removeQuestion(@PathVariable("id") Long id, HttpSession session) { - if (user == null || !isQuestionMatchUser(user, savedQuestion)) { + try { + questionService.remove(id, session); + } catch (QuestionEditException showException) { return "qna/show_failed"; - } - - if (!canDeleteQuestion(savedQuestion, user)) { + } catch (QuestionDeleteException deleteException) { return "qna/delete_failed"; } - savedQuestion.changeDeleteFlag(); - - for (Answer answer : savedQuestion.getAnswers()) { - answer.changeDeletedFlag(); - } - return "redirect:/questions/" + id; } - - private Question findQuestionById(Long id) { - return questionRepository.findById(id) - .orElseThrow(NoSuchElementException::new); - } - - private boolean isQuestionMatchUser(User loginUser, Question question) { - return question.equalsWriter(loginUser); - } - - private boolean canDeleteQuestion(Question deletedQuestion, User user) { - if (deletedQuestion.hasAnswers()) { - for (Answer answer : deletedQuestion.getAnswers()) { - if (!answer.equalsWriter(user)) { - return false; - } - } - } - return true; - } - - private int countAnswers(Question question) { - int count = 0; - for (Answer answer : question.getAnswers()) { - if (!answer.isDeletedFlag()) { - count++; - } - } - return count; - } } \ No newline at end of file diff --git a/src/main/java/codesquad/qua/QuestionDto.java b/src/main/java/codesquad/qua/QuestionDto.java new file mode 100644 index 00000000..d201101e --- /dev/null +++ b/src/main/java/codesquad/qua/QuestionDto.java @@ -0,0 +1,13 @@ +package codesquad.qua; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class QuestionDto { + + private String writer; + private String title; + private String contents; +} diff --git a/src/main/java/codesquad/qua/QuestionRepository.java b/src/main/java/codesquad/qua/QuestionRepository.java index f70e48fa..bd64d29e 100644 --- a/src/main/java/codesquad/qua/QuestionRepository.java +++ b/src/main/java/codesquad/qua/QuestionRepository.java @@ -1,6 +1,14 @@ package codesquad.qua; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface QuestionRepository extends JpaRepository { + + @Query("select count(q.id) from Question q" + + " join Answer a" + + " on a.question.id=q.id" + + " where a.deletedFlag=false and q.id=:id") + Long countNotDeletedAnswers(@Param("id") long questionId); } diff --git a/src/main/java/codesquad/qua/QuestionService.java b/src/main/java/codesquad/qua/QuestionService.java new file mode 100644 index 00000000..85f078a8 --- /dev/null +++ b/src/main/java/codesquad/qua/QuestionService.java @@ -0,0 +1,126 @@ +package codesquad.qua; + +import codesquad.answer.Answer; +import codesquad.exception.QuestionDeleteException; +import codesquad.exception.QuestionEditException; +import codesquad.user.User; +import codesquad.utils.SessionUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpSession; +import java.util.List; +import java.util.NoSuchElementException; + +@Slf4j +@RequiredArgsConstructor +@Service +public class QuestionService { + + private final QuestionRepository questionRepository; + + public boolean setCreateForm(HttpSession session) { + User user = SessionUtil.getUserBySession(session); + + return user != null; + } + + public boolean create(QuestionDto questionDto, HttpSession session) { + log.info("작성자 = {}", questionDto.getWriter()); + log.info("제목 = {}", questionDto.getTitle()); + + User user = SessionUtil.getUserBySession(session); + + if (user == null) { + return false; + } + + questionRepository.save(new Question(questionDto, user)); + + return true; + } + + public List list() { + return questionRepository.findAll(); + } + + public void setUpdateForm(long id, HttpSession session) { + User user = SessionUtil.getUserBySession(session); + Question savedQuestion = findQuestionById(id); + + if (user == null || !isQuestionMatchUser(user, savedQuestion)) { + throw new QuestionEditException(); + } + + log.info("user: {}", user.getName()); + log.info("question: {}", savedQuestion.getWriter()); + } + + @Transactional + public void update(QuestionDto changedQuestion, long id, HttpSession session) { + User user = SessionUtil.getUserBySession(session); + Question savedQuestion = findQuestionById(id); + + if (user == null || !isQuestionMatchUser(user, savedQuestion)) { + throw new QuestionEditException(); + } + + log.info("user: {}", user.getName()); + log.info("question content: {}", changedQuestion.getContents()); + log.info("question title: {}", changedQuestion.getTitle()); + + savedQuestion.update(changedQuestion); + } + + @Transactional + public void remove(long id, HttpSession session) { + User user = SessionUtil.getUserBySession(session); + Question savedQuestion = findQuestionById(id); + + log.info("user: {}", user.getName()); + log.info("question: {}", savedQuestion.getWriter()); + + if (user == null || !isQuestionMatchUser(user, savedQuestion)) { + throw new QuestionEditException(); + } + + if (!canDeleteQuestion(savedQuestion, user)) { + throw new QuestionDeleteException(); + } + + savedQuestion.deleteQuestion(); + } + + public long countAnswers(long questionId) { + Long countAnswer = questionRepository.countNotDeletedAnswers(questionId); + + if (countAnswer == null) { + return 0L; + } + + return countAnswer; + } + + public Question findQuestionById(Long id) { + return questionRepository.findById(id) + .orElseThrow(NoSuchElementException::new); + } + + private boolean canDeleteQuestion(Question deletedQuestion, User user) { + if (deletedQuestion.hasAnswers()) { + for (Answer answer : deletedQuestion.getAnswers()) { + if (!answer.equalsWriter(user)) { + return false; + } + } + } + return true; + } + + private boolean isQuestionMatchUser(User loginUser, Question question) { + log.info("match User? = {}", question.equalsWriter(loginUser)); + return question.equalsWriter(loginUser); + } +} diff --git a/src/main/java/codesquad/response/Result.java b/src/main/java/codesquad/response/Result.java new file mode 100644 index 00000000..1d68186d --- /dev/null +++ b/src/main/java/codesquad/response/Result.java @@ -0,0 +1,24 @@ +package codesquad.response; + +import lombok.Getter; + +@Getter +public class Result { + + private final T result; + private final String message; + + public Result(T answer, String message) { + this.result = answer; + this.message = message; + } + + public static Result ok(T id) { + return new Result<>(id, null); + } + + public static Result fail(String message) { + return new Result<>(null, message); + } + +} \ No newline at end of file diff --git a/src/main/java/codesquad/user/LoginUserDto.java b/src/main/java/codesquad/user/LoginUserDto.java new file mode 100644 index 00000000..6c00e26b --- /dev/null +++ b/src/main/java/codesquad/user/LoginUserDto.java @@ -0,0 +1,14 @@ +package codesquad.user; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +public class LoginUserDto { + + private String userId; + private String password; +} diff --git a/src/main/java/codesquad/user/SignUpUserDto.java b/src/main/java/codesquad/user/SignUpUserDto.java new file mode 100644 index 00000000..bc6b0794 --- /dev/null +++ b/src/main/java/codesquad/user/SignUpUserDto.java @@ -0,0 +1,16 @@ +package codesquad.user; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +public class SignUpUserDto { + + private String userId; + private String password; + private String name; + private String email; +} diff --git a/src/main/java/codesquad/user/User.java b/src/main/java/codesquad/user/User.java index d6091477..cfa3a98a 100644 --- a/src/main/java/codesquad/user/User.java +++ b/src/main/java/codesquad/user/User.java @@ -1,10 +1,15 @@ package codesquad.user; +import lombok.Getter; +import lombok.NoArgsConstructor; + import javax.persistence.*; import java.util.Objects; @Entity +@NoArgsConstructor +@Getter public class User { @Id @@ -20,43 +25,14 @@ public class User { private String email; - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } - - public String getPassword() { - return password; + User(SignUpUserDto signUpUserDto) { + userId = signUpUserDto.getUserId(); + password = signUpUserDto.getPassword(); + name = signUpUserDto.getName(); + email = signUpUserDto.getEmail(); } - public void setPassword(String password) { - this.password = password; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public Long getId() { - return id; - } - - public void update(User user) { + public void update(SignUpUserDto user) { if (equalsPassword(user.getPassword())) { name = user.getName(); email = user.getEmail(); @@ -67,6 +43,10 @@ public boolean equalsPassword(String password) { return this.password.equals(password); } + public boolean equalsPassword(LoginUserDto loginUserDto) { + return password.equals(loginUserDto.getPassword()); + } + public boolean equalsId(Long id) { return this.id.equals(id); } @@ -76,15 +56,11 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; - return Objects.equals(getId(), user.getId()) && - Objects.equals(getUserId(), user.getUserId()) && - Objects.equals(getPassword(), user.getPassword()) && - Objects.equals(getName(), user.getName()) && - Objects.equals(getEmail(), user.getEmail()); + return Objects.equals(getId(), user.getId()); } @Override public int hashCode() { - return Objects.hash(getId(), getUserId(), getPassword(), getName(), getEmail()); + return Objects.hash(getId()); } } diff --git a/src/main/java/codesquad/user/UserController.java b/src/main/java/codesquad/user/UserController.java index 741fdfc5..7e22e8a6 100644 --- a/src/main/java/codesquad/user/UserController.java +++ b/src/main/java/codesquad/user/UserController.java @@ -1,9 +1,7 @@ package codesquad.user; -import codesquad.utils.SessionUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @@ -13,70 +11,56 @@ import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpSession; -import java.util.NoSuchElementException; @Controller @RequestMapping("/users") +@RequiredArgsConstructor +@Slf4j public class UserController { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - @Autowired - private UserRepository userRepository; + private final UserService userService; @PostMapping("") - public String create(User user) { - logger.info("user = {}", user); - userRepository.save(user); + public String join(SignUpUserDto signUpUserDto) { + userService.create(signUpUserDto); return "redirect:/users"; } @GetMapping("") - public String list(Model model) { - model.addAttribute("users", userRepository.findAll()); + public String showUserList(Model model) { + model.addAttribute("users", userService.list()); return "/user/list"; } @GetMapping("{id}") - public ModelAndView show(@PathVariable long id) { + public ModelAndView showUser(@PathVariable long id) { ModelAndView mav = new ModelAndView("user/profile"); - mav.addObject("user", findUserById(id)); + mav.addObject("user", userService.findUserById(id)); return mav; } @GetMapping("{id}/form") public String updateForm(Model model, @PathVariable("id") Long id) { - model.addAttribute("user", findUserById(id)); + model.addAttribute("user", userService.findUserById(id)); return "/user/updateForm"; } @PostMapping("{id}/update") - public String update(User changedUser, @PathVariable("id") Long id, HttpSession session) { - User user = SessionUtil.getUserBySession(session); + public String updateUser(SignUpUserDto changedUser, @PathVariable("id") Long id, HttpSession session) { - if (user == null || !user.equalsId(id)) { - return "/user/login_failed"; + if (userService.update(changedUser, id, session)) { + return "redirect:/users"; } - user.update(changedUser); - userRepository.save(user); - - return "redirect:/users"; + return "/user/login_failed"; } @PostMapping("/login") - public String login(String userId, String password, HttpSession session) { - User savedUser = userRepository.findByUserId(userId) - .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 회원")); - - if (savedUser.equalsPassword(password)) { - SessionUtil.setSession(session, savedUser); + public String loginUser(LoginUserDto loginUserDto, HttpSession session) { + if(userService.login(loginUserDto, session)){ + return "redirect:/users"; } - return "redirect:/users"; - } - - private User findUserById(Long id) { - return userRepository.findById(id) - .orElseThrow(NoSuchElementException::new); + return "/user/login_failed"; } } \ No newline at end of file diff --git a/src/main/java/codesquad/user/UserService.java b/src/main/java/codesquad/user/UserService.java new file mode 100644 index 00000000..9d52a70c --- /dev/null +++ b/src/main/java/codesquad/user/UserService.java @@ -0,0 +1,62 @@ +package codesquad.user; + +import codesquad.utils.SessionUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpSession; +import java.util.List; +import java.util.NoSuchElementException; + +@Service +@RequiredArgsConstructor +@Slf4j +public class UserService { + + private final UserRepository userRepository; + + public void create(SignUpUserDto signUpUserDto) { + log.info("singUpUserDto = {}", signUpUserDto); + userRepository.save(new User(signUpUserDto)); + } + + public List list() { + return userRepository.findAll(); + } + + @Transactional + public boolean update(SignUpUserDto changedUser, long userId, HttpSession session) { + log.info("changedUser = {}", changedUser); + log.info("userId = {}", userId); + + User user = SessionUtil.getUserBySession(session); + + if (user == null || !user.equalsId(userId)) { + return false; + } + + user.update(changedUser); + userRepository.save(user); + + return true; + } + + public boolean login(LoginUserDto loginUserDto, HttpSession session) { + User savedUser = userRepository.findByUserId(loginUserDto.getUserId()) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 회원")); + + if (savedUser.equalsPassword(loginUserDto)) { + SessionUtil.setSession(session, savedUser); + return true; + } + + return false; + } + + public User findUserById(long userId) { + return userRepository.findById(userId) + .orElseThrow(NoSuchElementException::new); + } +} diff --git a/src/main/resources/static/js/scripts.js b/src/main/resources/static/js/scripts.js index 01f85bd2..ee47ef4f 100755 --- a/src/main/resources/static/js/scripts.js +++ b/src/main/resources/static/js/scripts.js @@ -1,9 +1,147 @@ -String.prototype.format = function() { +String.prototype.format = function () { var args = arguments; - return this.replace(/{(\d+)}/g, function(match, number) { - return typeof args[number] != 'undefined' - ? args[number] - : match - ; + return this.replace(/{(\d+)}/g, function (match, number) { + return typeof args[number] != 'undefined' ? args[number] : match; }); -}; \ No newline at end of file +}; + + +function $(selector) { + return document.querySelector(selector); +} + +document.addEventListener("DOMContentLoaded", () => { + initEvents(); +}) + +function initEvents() { + const answerBtn = $(".submit-write .btn"); + console.log(answerBtn); + + answerBtn.addEventListener("click", registerAnswerHandler); + + const answerList = document.querySelectorAll(".article-hi"); + console.log("answerList 길이 = " + answerList.length); + + answerList.forEach(answer => { + console.log(answer.getElementsByClassName("delete-answer-button")[0]); + console.log(answer.getElementsByClassName("delete-answer-button")[1]); + answer.getElementsByClassName("delete-answer-button")[0].addEventListener("click", deleteAnswerHandler); + }); +} + +function fetchManager({url, method, body, headers, callback}) { + fetch(url, {method, body, headers, credentials: "same-origin"}) + .then((response) => { + const data = response.json(); + console.log(data); + return data.then(result => { + return { + 'result' : result, + 'status' : response.status + } + }) + }).then( ({result, status}) => { + if(status >= 400) { + console.log('error 가 발생했네요 ', result.error); + }else{ + console.log(result); + callback(result); + } + }).catch(err => { + console.log("oops..", err); + }) +} + +function registerAnswerHandler(evt) { + evt.preventDefault(); + const comment = $(".submit-write textarea").value; + document.querySelectorAll(".form-control")[1].value = ""; + + const url = $(".submit-write").action; + console.log(url); + + fetchManager({ + url: url, + method: "POST", + headers: {'content-type': 'application/json'}, + body: JSON.stringify({comment}), + callback: appendAnswer + }) +} + +function appendAnswer({result}) { + console.log("result = " + result); + id = result.id; + comment = result.comment; + questionId = result.questionId; + writer = result.writer; + + console.log("id = " + id); + console.log("comment = " + comment); + console.log("question = " + questionId); + console.log("writer = " + writer); + + const html = ` + ` + + $(".qna-comment-slipp-articles").insertAdjacentHTML("beforeend", html); +} + +function deleteAnswerHandler(target) { + if(target.className !== "delete-answer-button") return; + console.log("target = " + target); + const value = target.value.split("/"); + console.log("value = " + value); + const url = "/questions/" + value[1] + "/answers/" + value[0]; + console.log(url); + console.log("deleteAnswerHandler = " + url); + + fetchManager({ + url, + method: 'DELETE', + headers: {'content-type': 'application/json'}, + callback: deleteAnswer + }) +} + +function deleteAnswer({result}) { + console.log("result = " + result); + console.log("result.id = " + result.id); + const selector = `.article-hi[data-id='${result.id}']`; + console.log("deleteAnswer" + selector); + const target = $(selector); + target.parentNode.removeChild(target); +} \ No newline at end of file diff --git a/src/main/resources/templates/qna/form.html b/src/main/resources/templates/qna/form.html index d442fc9f..0d36189e 100644 --- a/src/main/resources/templates/qna/form.html +++ b/src/main/resources/templates/qna/form.html @@ -7,6 +7,10 @@
{{#sessionedUser}} +
+ + +
diff --git a/src/main/resources/templates/qna/show.html b/src/main/resources/templates/qna/show.html index 6e238477..66093d51 100644 --- a/src/main/resources/templates/qna/show.html +++ b/src/main/resources/templates/qna/show.html @@ -52,14 +52,14 @@

{{title}}

{{#question.answers}} {{^deletedFlag}} -