Skip to content
Merged

Step5 #142

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions src/main/java/codesquad/domain/issue/Issue.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

import codesquad.UnAuthorizedException;
import codesquad.domain.DeleteHistory;
import codesquad.domain.issue.answer.Answers;
import codesquad.domain.label.Label;
import codesquad.domain.milestone.Milestone;
import codesquad.domain.user.User;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.slf4j.Logger;
import support.domain.AbstractEntity;

import javax.persistence.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static org.slf4j.LoggerFactory.getLogger;
Expand Down Expand Up @@ -39,6 +40,10 @@ public class Issue extends AbstractEntity {
@JoinColumn(foreignKey = @ForeignKey(name = "fk_assignee"))
private User assignee;

@Embedded
@JsonIgnore
private Answers answers = new Answers();

private Boolean deleted = false;

public Issue() {
Expand Down Expand Up @@ -76,7 +81,12 @@ public List<DeleteHistory> delete(User loginUser) {
throw new UnAuthorizedException("로그인 유저가 이슈 작성자와 달라 삭제할 수 없습니다");
}

List<DeleteHistory> histories = new ArrayList<>();
long otherAnswers = answers.otherAnswerCount(writer);
if (otherAnswers > 0) {
throw new UnAuthorizedException("다른 댓글 작성자가 있어 삭제가 불가능 합니다.");
}

List<DeleteHistory> histories = answers.delete(loginUser);

this.deleted = true;

Expand Down Expand Up @@ -135,4 +145,12 @@ public User getAssignee() {
public void setAssignee(User assignee) {
this.assignee = assignee;
}

public Answers getAnswers() {
return answers;
}

public void setAnswers(Answers answers) {
this.answers = answers;
}
}
111 changes: 111 additions & 0 deletions src/main/java/codesquad/domain/issue/answer/Answer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package codesquad.domain.issue.answer;

import codesquad.UnAuthenticationException;
import codesquad.UnAuthorizedException;
import codesquad.domain.DeleteHistory;
import codesquad.domain.issue.ContentType;
import codesquad.domain.issue.Issue;
import codesquad.domain.user.User;
import com.fasterxml.jackson.annotation.JsonIgnore;
import support.domain.AbstractEntity;

import javax.persistence.*;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
import java.util.Objects;

@Entity
public class Answer extends AbstractEntity {
@ManyToOne
@JoinColumn(foreignKey = @ForeignKey(name = "fk_answer_writer"))
private User writer;

@ManyToOne
@JoinColumn(foreignKey = @ForeignKey(name = "fk_answer_to_issue"))
private Issue issue;

@Size(min = 1)
@Lob
private String contents;

private boolean deleted = false;

public Answer() {
}

public Answer(User writer, String contents) {
if (isLogin(writer)) {
this.writer = writer;
this.contents = contents;
}
}

public Answer(User writer, Issue issue, String contents) {
this(writer, contents);
this.issue = issue;
this.deleted = false;
}

public boolean isOwner(User loginUser) {
isLogin(loginUser);
return writer.equals(loginUser);
}

private boolean isLogin(User loginUser) {
if (Objects.isNull(loginUser)) {
// TODO security에 지정되어 있는 예외인데 왜 오류? UnAuthenticationException
throw new UnAuthorizedException("로그인이 필요합니다.");
}
return true;
}

public DeleteHistory delete(User loginUser) {
if (!isOwner(loginUser)) {
throw new UnAuthorizedException("삭제할 수 없습니다.");
}
this.deleted = true;
return new DeleteHistory(ContentType.ANSWER, getId(), loginUser, LocalDateTime.now());
}

public boolean isDeleted() {
return this.deleted;
}

public User getWriter() {
return writer;
}

public void setWriter(User writer) {
this.writer = writer;
}

public Issue getIssue() {
return issue;
}

public void setIssue(Issue issue) {
this.issue = issue;
}

public String getContents() {
return contents;
}

public void setContents(String contents) {
this.contents = contents;
}

public void setDeleted(boolean deleted) {
this.deleted = deleted;
}

@Override
public String toString() {
return "Answer{" +
"writer=" + writer +
", issue=" + issue +
", contents='" + contents + '\'' +
", deleted=" + deleted +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package codesquad.domain.issue.answer;

import org.springframework.data.jpa.repository.JpaRepository;

public interface AnswerRepository extends JpaRepository<Answer, Long> {
}
44 changes: 44 additions & 0 deletions src/main/java/codesquad/domain/issue/answer/Answers.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package codesquad.domain.issue.answer;

import codesquad.domain.DeleteHistory;
import codesquad.domain.user.User;
import org.hibernate.annotations.Where;

import javax.persistence.CascadeType;
import javax.persistence.Embeddable;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Embeddable
public class Answers {
@OneToMany(mappedBy = "issue", cascade = CascadeType.ALL)
@Where(clause = "deleted = false")
@OrderBy("id ASC")
private List<Answer> answers = new ArrayList<>();

public void add(Answer answer) {
answers.add(answer);
}

public long otherAnswerCount(User writer) {
return answers.stream()
.filter(answer -> !answer.isOwner(writer))
.filter(answer -> !answer.isDeleted())
.count();
}

public List<DeleteHistory> delete(User loginUser) {
List<DeleteHistory> histories = new ArrayList<>();
for (Answer answer : answers) {
histories.add(answer.delete(loginUser));
}
return histories;
}

public List<Answer> getAnswers() {
return answers;
}
}
3 changes: 2 additions & 1 deletion src/main/java/codesquad/domain/user/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import codesquad.UnAuthorizedException;
import codesquad.dto.UserDto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import support.domain.AbstractEntity;

import javax.persistence.Column;
Expand All @@ -19,7 +20,7 @@ public class User extends AbstractEntity {

@Size(min = 6, max = 20)
@Column(nullable = false, length = 20)
@JsonIgnore
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String password;

@Size(min = 3, max = 20)
Expand Down
57 changes: 57 additions & 0 deletions src/main/java/codesquad/service/AnswerService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package codesquad.service;

import codesquad.UnAuthorizedException;
import codesquad.domain.issue.Issue;
import codesquad.domain.issue.IssueRepository;
import codesquad.domain.issue.answer.Answer;
import codesquad.domain.issue.answer.AnswerRepository;
import codesquad.domain.user.User;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

import static org.slf4j.LoggerFactory.getLogger;

@Service
public class AnswerService {
private static final Logger log = getLogger(AnswerService.class);

@Autowired
private AnswerRepository answerRepository;

@Autowired
private IssueRepository issueRepository;

@Resource(name = "deleteHistoryService")
private DeleteHistoryService deleteHistoryService;

public Answer add(User loginUser, Issue issue, String comment) {
log.debug("answer add!");
return answerRepository.save(new Answer(loginUser, issue, comment));
}

public List<Answer> findByIssueId(long id) {
return issueRepository.findById(id).orElse(null).getAnswers().getAnswers();
}

public Answer findById(long id) {
return answerRepository.findById(id).filter(answer -> !answer.isDeleted()).orElseThrow(UnAuthorizedException::new);
}

public void delete(long answerId, User loginUser) {
Answer answer = findById(answerId);
deleteHistoryService.save(answer.delete(loginUser));
}

@Transactional
public Answer update(User loginUser, Answer answer, String comment) {
answer.isOwner(loginUser);
answer.setContents(comment);
log.debug("업데이트 댓글 : " + answer.getContents());
return answer;
}
}
60 changes: 60 additions & 0 deletions src/main/java/codesquad/web/ApiAnswerController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package codesquad.web;

import codesquad.UnAuthorizedException;
import codesquad.domain.issue.Issue;
import codesquad.domain.issue.answer.Answer;
import codesquad.domain.user.User;
import codesquad.security.LoginUser;
import codesquad.service.AnswerService;
import codesquad.service.IssueService;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import support.domain.Result;

import static org.slf4j.LoggerFactory.getLogger;

@RestController
@RequestMapping("/api/issues/{id}/answers")
public class ApiAnswerController {
private static final Logger log = getLogger(ApiAnswerController.class);

@Autowired
private AnswerService answerService;

@Autowired
private IssueService issueService;

@PostMapping("")
public Answer create(@LoginUser User loginUser, @PathVariable long id, String comment) {
Issue issue = issueService.findById(id);
return answerService.add(loginUser, issue, comment);
}

@GetMapping("/{answerId}")
public ResponseEntity<Answer> modifyForm(@LoginUser User loginUser, @PathVariable long id, @PathVariable long answerId) {
Answer answer = answerService.findById(answerId);
if (!answer.isOwner(loginUser)) {
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
return new ResponseEntity<>(answer, HttpStatus.OK);
}

@DeleteMapping("/{answerId}")
public Result delete(@LoginUser User loginUser, @PathVariable long id, @PathVariable long answerId) {
try {
answerService.delete(answerId, loginUser);
return Result.ok();
} catch (Exception e) {
return Result.error("삭제할 수 없습니다.");
}
}

@PutMapping("/{answerId}")
public ResponseEntity<Answer> update(@LoginUser User loginUser, @PathVariable long id, @PathVariable long answerId, String updateComment) {
Answer answer = answerService.findById(answerId);
return new ResponseEntity<>(answerService.update(loginUser, answer, updateComment), HttpStatus.OK);
}
}
11 changes: 9 additions & 2 deletions src/main/java/codesquad/web/ApiUserController.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import codesquad.dto.UserDto;
import codesquad.security.LoginUser;
import codesquad.service.UserService;
import org.slf4j.Logger;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -16,10 +17,13 @@
import java.net.URI;

import static codesquad.security.HttpSessionUtils.USER_SESSION_KEY;
import static org.slf4j.LoggerFactory.getLogger;

@RestController
@RequestMapping("/api/users")
public class ApiUserController {
private static final Logger log = getLogger(ApiUserController.class);

@Resource(name = "userService")
private UserService userService;

Expand All @@ -33,8 +37,11 @@ public ResponseEntity<Void> create(@Valid @RequestBody UserDto user) {
}

@PostMapping("/login")
public ResponseEntity<User> login(String userId, String password, HttpSession httpSession) throws UnAuthenticationException {
User loginUser = userService.login(userId, password);
public ResponseEntity<User> login(@RequestBody User user, HttpSession httpSession) throws UnAuthenticationException {
log.debug("유저 아이디 : " + user.getUserId());
log.debug("유저 패스워드 : " + user.getPassword());

User loginUser = userService.login(user.getUserId(), user.getPassword());
httpSession.setAttribute(USER_SESSION_KEY, loginUser);

HttpHeaders headers = new HttpHeaders();
Expand Down
Loading