Skip to content

Commit

Permalink
Merge pull request #69 from dd-jiyun/main
Browse files Browse the repository at this point in the history
Answer ๊ธฐ๋Šฅ ์™„์„ฑ
  • Loading branch information
dd-jiyun authored Feb 19, 2024
2 parents 6a0c3d1 + c91a54c commit 6cad292
Show file tree
Hide file tree
Showing 11 changed files with 345 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ public enum ErrorCode {
EMAIL_NOT_FOUND(HttpStatus.NOT_FOUND, "์‚ฌ์šฉ์ž์˜ ์ด๋ฉ”์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."),
PROFILE_IMAGE_NOT_FOUND(HttpStatus.NOT_FOUND, "์‚ฌ์šฉ์ž์˜ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."),

QUESTION_NOT_FOUND(HttpStatus.NOT_FOUND, "์งˆ๋ฌธ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
QUESTION_NOT_FOUND(HttpStatus.NOT_FOUND, "์งˆ๋ฌธ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."),
ANSWER_NOT_FOUND(HttpStatus.NOT_FOUND, "๋‹ต๋ณ€์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."),
MISMATCH_AUTHOR(HttpStatus.BAD_REQUEST, "๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.");

private final HttpStatus httpStatus;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.example.titto_backend.questionBoard.controller;

import com.example.titto_backend.auth.domain.User;
import com.example.titto_backend.auth.repository.UserRepository;
import com.example.titto_backend.common.exception.CustomException;
import com.example.titto_backend.common.exception.ErrorCode;
import com.example.titto_backend.questionBoard.dto.AnswerDTO;
import com.example.titto_backend.questionBoard.dto.AnswerDTO.Response;
import com.example.titto_backend.questionBoard.service.AnswerService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.security.Principal;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/answers")
@Tag(name = "Answer Controller", description = "๊ฒŒ์‹œ๊ธ€ ๋‹ต๋ณ€ ๊ด€๋ จ API")
public class AnswerController {

private final AnswerService answerService;
private final UserRepository userRepository;

// Create
@PostMapping("/create")
@Operation(
summary = "๋‹ต๋ณ€ ์ž‘์„ฑ",
description = "๋‹ต๋ณ€์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค",
responses = {
@ApiResponse(responseCode = "201", description = "๋‹ต๋ณ€ ์ž‘์„ฑ ์„ฑ๊ณต"),
@ApiResponse(responseCode = "500", description = "๊ด€๋ฆฌ์ž ๋ฌธ์˜")
})
public ResponseEntity<AnswerDTO.Response> createAnswer(@RequestBody AnswerDTO.Request request, Principal principal) {
String email = principal.getName();
AnswerDTO.Response savedAnswer = answerService.save(request, request.getPostId(), email);

return ResponseEntity.status(201).body(savedAnswer);
}

// Read
@GetMapping("/answers")
@Operation(
summary = "๋‹ต๋ณ€ ๋ชฉ๋ก ์กฐํšŒ",
description = "๋‹ต๋ณ€ ๋ชฉ๋ก์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค",
responses = {
@ApiResponse(responseCode = "200", description = "์š”์ฒญ ์„ฑ๊ณต"),
@ApiResponse(responseCode = "500", description = "๊ด€๋ฆฌ์ž ๋ฌธ์˜")
})
public ResponseEntity<Page<Response>> getAllQuestions(@Parameter(hidden = true) Pageable pageable) {
Page<AnswerDTO.Response> answers = answerService.findAll(pageable);
return ResponseEntity.ok(answers);
}

@GetMapping("/{answerId}")
@Operation(
summary = "๋‹ต๋ณ€ ์ƒ์„ธ ์กฐํšŒ",
description = "๋‹ต๋ณ€ ์ƒ์„ธ๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค",
responses = {
@ApiResponse(responseCode = "200", description = "์š”์ฒญ ์„ฑ๊ณต"),
@ApiResponse(responseCode = "404", description = "๋‹ต๋ณ€ ์—†์Œ")
})
public ResponseEntity<AnswerDTO.Response> getAnswerById(@PathVariable("answerId") Long answerId) {
try {
AnswerDTO.Response answer = answerService.findById(answerId);
return ResponseEntity.ok(answer);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
}

// Delete
@DeleteMapping("/{answerId}")
@Operation(
summary = "๋‹ต๋ณ€ ์‚ญ์ œ",
description = "๋‹ต๋ณ€์„ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค",
responses = {
@ApiResponse(responseCode = "204", description = "๋‹ต๋ณ€ ์‚ญ์ œ ์„ฑ๊ณต"),
@ApiResponse(responseCode = "500", description = "๊ด€๋ฆฌ์ž ๋ฌธ์˜")
})
public ResponseEntity<Void> deleteAnswer(@PathVariable("answerId") Long answerId) {
String currentEmail = SecurityContextHolder.getContext().getAuthentication().getName(); // ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ ์ด๋ฉ”์ผ ์ฃผ์†Œ ๊ฐ€์ ธ์˜ค๊ธฐ
User currentUser = userRepository.findByEmail(currentEmail)
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); // ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ ID๋ฅผ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋กœ ๊ฒ€์ƒ‰ํ•˜์—ฌ ๊ฐ€์ ธ์˜ค๊ธฐ
answerService.delete(answerId, currentUser.getId()); // ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ ID๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ์‚ญ์ œ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ
return ResponseEntity.noContent().build();
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.example.titto_backend.questionBoard.controller;

import com.example.titto_backend.auth.domain.User;
import com.example.titto_backend.auth.repository.UserRepository;
import com.example.titto_backend.common.exception.CustomException;
import com.example.titto_backend.common.exception.ErrorCode;
import com.example.titto_backend.questionBoard.dto.QuestionDTO;
import com.example.titto_backend.questionBoard.service.QuestionService;
import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -12,6 +16,8 @@
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -28,6 +34,7 @@
public class QuestionController {

private final QuestionService questionService;
private final UserRepository userRepository;

// Create
@PostMapping("/create")
Expand Down Expand Up @@ -101,10 +108,14 @@ public ResponseEntity<Page<QuestionDTO.Response>> getQuestionsByCategory(@PathVa
@ApiResponse(responseCode = "404", description = "์งˆ๋ฌธ์„ ์ฐพ์„ ์ˆ˜ ์—†์Œ")
})
public ResponseEntity<String> updateQuestion(@PathVariable("postId") Long postId,
@RequestBody QuestionDTO.Update update,
Principal principal) {
String email = principal.getName();
questionService.update(email, update, postId);
@RequestBody QuestionDTO.Update update) {

String currentEmail = SecurityContextHolder.getContext().getAuthentication().getName();
User currentUser = userRepository.findByEmail(currentEmail)
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));

questionService.update(update, postId, currentUser.getId());

return ResponseEntity.ok("์งˆ๋ฌธ ์ˆ˜์ • ์„ฑ๊ณต");
}

Expand All @@ -118,7 +129,10 @@ public ResponseEntity<String> updateQuestion(@PathVariable("postId") Long postId
@ApiResponse(responseCode = "404", description = "์งˆ๋ฌธ์„ ์ฐพ์„ ์ˆ˜ ์—†์Œ")
})
public ResponseEntity<Void> deleteQuestion(@PathVariable("postId") Long postId) {
questionService.delete(postId);
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
String currentEmail = SecurityContextHolder.getContext().getAuthentication().getName(); // ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ ์ด๋ฉ”์ผ ์ฃผ์†Œ ๊ฐ€์ ธ์˜ค๊ธฐ
User currentUser = userRepository.findByEmail(currentEmail)
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
questionService.delete(postId, currentUser.getId()); // ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ ID๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ์‚ญ์ œ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.example.titto_backend.questionBoard.domain;

import com.example.titto_backend.auth.domain.User;
import com.example.titto_backend.common.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Answer extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JoinColumn(name = "question_id")
private Question question;

// ๋‹ต๊ธ€ ์ž‘์„ฑ์ž
@ManyToOne
@JoinColumn(name = "author")
private User author;

// ๋‹ต๊ธ€ ๋‚ด์šฉ
@Column(name = "answer_content", nullable = false, columnDefinition = "TEXT")
private String content;

// ์ฑ„ํƒ ์—ฌ๋ถ€
@Column(name = "is_accepted")
private boolean isAccepted;

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.example.titto_backend.auth.domain.User;
import com.example.titto_backend.common.BaseEntity;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
Expand All @@ -11,6 +12,8 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
Expand Down Expand Up @@ -59,7 +62,7 @@ public void update(String title, String content, Department department, Status s
// @Column(name = "view")
// private int view;
//
// @OneToMany(mappedBy = "question", cascade = CascadeType.REMOVE)
// private List<Answer> answerList;
@OneToMany(mappedBy = "question", cascade = CascadeType.REMOVE)
private List<Answer> answerList;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.example.titto_backend.questionBoard.dto;

import com.example.titto_backend.questionBoard.domain.Answer;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

public class AnswerDTO {

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "์งˆ๋ฌธ ๊ธ€์— ๋Œ“๊ธ€ ์ž‘์„ฑ")
public static class Request {

@Schema(description = "์งˆ๋ฌธ ID")
private Long postId;

@Schema(description = "๋‹ต๋ณ€ ๋‚ด์šฉ")
@NotBlank
private String content;
}

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@Schema(description = "์งˆ๋ฌธ ๊ธ€์— ๋Œ“๊ธ€ ์กฐํšŒ")
public static class Response {
@Schema(description = "๋‹ต๋ณ€ ID")
private Long id;

@Schema(description = "์งˆ๋ฌธ ID")
private Long postId;

@Schema(description = "๋‹ต๋ณ€ ์ž‘์„ฑ์ž ID")
private String authorId;

@Schema(description = "๋‹ต๋ณ€ ์ž‘์„ฑ์ž ๋‹‰๋„ค์ž„")
private String authorNickname;

@Schema(description = "๋‹ต๋ณ€ ๋‚ด์šฉ")
private String content;

@Schema(description = "์ฑ„ํƒ ์—ฌ๋ถ€", defaultValue = "false")
private boolean isAccepted;

public Response(Answer answer) {
this.id = answer.getId();
this.postId = answer.getQuestion().getId();
this.authorId = answer.getAuthor().getId().toString();
this.authorNickname = answer.getAuthor().getNickname();
this.content = answer.getContent();
this.isAccepted = answer.isAccepted();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,17 @@ public static class Request {
@NotBlank
private String content;

// ์•„์ง ๋ฏธ์™„์„ฑ ์ƒํƒœ
@Schema(description = "์ด๋ฏธ์ง€")
private List<String> imageList;

@Schema(description = "์นดํ…Œ๊ณ ๋ฆฌ")
@Schema(description = "์นดํ…Œ๊ณ ๋ฆฌ", example = "HUMANITIES, MANAGEMENT, SOCIETY, MEDIA_CONTENT, FUTURE_FUSION, SOFTWARE")
@NotBlank
private String department;

@Schema(description = "์ƒํƒœ", example = "SOLVED or UNSOLVED")
@NotBlank
private String status;

@Schema(description = "์กฐํšŒ์ˆ˜", defaultValue = "1")
private int view;
}

@Data
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.titto_backend.questionBoard.repository;

import com.example.titto_backend.questionBoard.domain.Answer;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface AnswerRepository extends JpaRepository<Answer, Long> {
Page<Answer> findAllByOrderByCreateDateDesc(Pageable pageable);
}
Loading

0 comments on commit 6cad292

Please sign in to comment.