Skip to content

Commit ae5d9ba

Browse files
authored
feat : 반례 게시판 CRUD + 좋아요 기능 (#389)
1 parent bdfce34 commit ae5d9ba

File tree

16 files changed

+721
-4
lines changed

16 files changed

+721
-4
lines changed

src/main/java/com/gamzabat/algohub/exception/CustomExceptionHandler.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import com.gamzabat.algohub.common.jwt.exception.ExpiredTokenException;
1010
import com.gamzabat.algohub.common.jwt.exception.TokenException;
1111
import com.gamzabat.algohub.feature.comment.exception.CommentValidationException;
12+
import com.gamzabat.algohub.feature.edgecase.exception.CannotFoundEdgeCaseException;
13+
import com.gamzabat.algohub.feature.edgecase.exception.NotAuthorizedUserException;
1214
import com.gamzabat.algohub.feature.group.ranking.exception.CannotFoundRankingException;
1315
import com.gamzabat.algohub.feature.group.studygroup.exception.CannotFoundGroupException;
1416
import com.gamzabat.algohub.feature.group.studygroup.exception.CannotFoundProblemException;
@@ -231,4 +233,20 @@ protected ResponseEntity<ErrorResponse> handleCannotFoundVerificationCodeExcepti
231233
.status(HttpStatus.BAD_REQUEST)
232234
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), e.getMessage(), null));
233235
}
236+
237+
@ExceptionHandler(CannotFoundEdgeCaseException.class)
238+
protected ResponseEntity<ErrorResponse> handleCannotFoundEdgeCaseException(
239+
CannotFoundEdgeCaseException e) {
240+
return ResponseEntity
241+
.status(e.getHttpStatus())
242+
.body(new ErrorResponse(e.getHttpStatus().value(), e.getErrors(), null));
243+
}
244+
245+
@ExceptionHandler(NotAuthorizedUserException.class)
246+
protected ResponseEntity<ErrorResponse> handleNotAuthorizedUserException(
247+
NotAuthorizedUserException e) {
248+
return ResponseEntity
249+
.status(e.getHttpStatus())
250+
.body(new ErrorResponse(e.getHttpStatus().value(), e.getError(), null));
251+
}
234252
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.gamzabat.algohub.feature.edgecase.controller;
2+
3+
import org.springframework.http.MediaType;
4+
import org.springframework.http.ResponseEntity;
5+
import org.springframework.web.bind.annotation.DeleteMapping;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.PatchMapping;
8+
import org.springframework.web.bind.annotation.PathVariable;
9+
import org.springframework.web.bind.annotation.PostMapping;
10+
import org.springframework.web.bind.annotation.RequestBody;
11+
import org.springframework.web.bind.annotation.RequestMapping;
12+
import org.springframework.web.bind.annotation.RequestParam;
13+
import org.springframework.web.bind.annotation.RestController;
14+
15+
import com.gamzabat.algohub.common.annotation.AuthedUser;
16+
import com.gamzabat.algohub.exception.RequestException;
17+
import com.gamzabat.algohub.feature.edgecase.domain.EdgeCaseLike;
18+
import com.gamzabat.algohub.feature.edgecase.dto.CreateEdgeCaseRequest;
19+
import com.gamzabat.algohub.feature.edgecase.dto.GetEdgeCaseListResponse;
20+
import com.gamzabat.algohub.feature.edgecase.dto.TogleEdgeCaseResponse;
21+
import com.gamzabat.algohub.feature.edgecase.service.EdgeCaseService;
22+
import com.gamzabat.algohub.feature.user.domain.User;
23+
24+
import org.springframework.validation.Errors;
25+
import io.swagger.v3.oas.annotations.Operation;
26+
import io.swagger.v3.oas.annotations.tags.Tag;
27+
import jakarta.validation.Valid;
28+
import lombok.RequiredArgsConstructor;
29+
30+
@RestController
31+
@RequiredArgsConstructor
32+
@RequestMapping("/api/edge-case")
33+
@Tag(name = "반례 게시판 API", description = "반례 게시판 관련 API")
34+
public class EdgeCaseController {
35+
private final EdgeCaseService edgeCaseService;
36+
37+
@PostMapping
38+
@Operation(summary = "반례 등록")
39+
public ResponseEntity<Void> createEdgeCase(@AuthedUser User user, @RequestBody @Valid CreateEdgeCaseRequest creatEdgeCaseRequest,
40+
Errors errors) {
41+
if (errors.hasErrors())
42+
throw new RequestException("올바르지 않은 요청입니다.", errors);
43+
44+
edgeCaseService.createEdgeCase(user, creatEdgeCaseRequest);
45+
46+
return ResponseEntity.ok().build();
47+
}
48+
49+
@GetMapping("/list")
50+
@Operation(summary = "반례리스트 조회")
51+
public ResponseEntity<GetEdgeCaseListResponse> getEdgeCaseList(@AuthedUser User user, @RequestParam(required = false) Integer problemNumber) {
52+
GetEdgeCaseListResponse response = edgeCaseService.getEdgeCaseList(problemNumber);
53+
54+
return ResponseEntity.ok().body(response);
55+
}
56+
57+
@DeleteMapping("/{edgeCaseId}")
58+
@Operation(summary = "반례 삭제")
59+
public ResponseEntity<Void> deleteEdgeCase(@AuthedUser User user, @PathVariable Long edgeCaseId) {
60+
edgeCaseService.deleteEdgeCase(user, edgeCaseId);
61+
62+
return ResponseEntity.ok().build();
63+
}
64+
65+
@PatchMapping(value = "/{edgeCaseId}/like")
66+
@Operation(summary = "반례 좋아요 토글")
67+
public ResponseEntity<TogleEdgeCaseResponse> addEdgeCaseLike(@AuthedUser User user, @PathVariable Long edgeCaseId) {
68+
TogleEdgeCaseResponse result = edgeCaseService.togleEdgeCaseLike(user, edgeCaseId);
69+
70+
return ResponseEntity.ok().body(result);
71+
}
72+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.gamzabat.algohub.feature.edgecase.domain;
2+
3+
import java.time.LocalDateTime;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
7+
import org.hibernate.annotations.SQLDelete;
8+
9+
import com.gamzabat.algohub.feature.user.domain.User;
10+
11+
import jakarta.persistence.Column;
12+
import jakarta.persistence.Entity;
13+
import jakarta.persistence.FetchType;
14+
import jakarta.persistence.GeneratedValue;
15+
import jakarta.persistence.GenerationType;
16+
import jakarta.persistence.Id;
17+
import jakarta.persistence.JoinColumn;
18+
import jakarta.persistence.ManyToOne;
19+
import jakarta.persistence.OneToMany;
20+
import jakarta.persistence.OneToOne;
21+
import lombok.Builder;
22+
import lombok.Getter;
23+
import lombok.NoArgsConstructor;
24+
25+
@Entity
26+
@Getter
27+
@NoArgsConstructor
28+
@SQLDelete(sql = "UPDATE edge_case SET deleted_at = CURRENT_TIMESTAMP WHERE id = ?")
29+
public class EdgeCase {
30+
31+
@Id
32+
@GeneratedValue(strategy = GenerationType.IDENTITY)
33+
private Long id;
34+
private Integer level;
35+
private String link;
36+
private Integer problemNumber;
37+
private String title;
38+
@Column(columnDefinition = "TEXT")
39+
private String input;
40+
@Column(columnDefinition = "TEXT")
41+
private String output;
42+
43+
44+
@ManyToOne(fetch = FetchType.LAZY)
45+
@JoinColumn(name = "user_id")
46+
private User author;
47+
48+
private LocalDateTime deletedAt;
49+
50+
@Column(nullable = false)
51+
private int likeCount = 0;
52+
53+
@Builder
54+
public EdgeCase(Integer level, String link, Integer problemNumber, String title, String input, String output, User author) {
55+
this.level = level;
56+
this.link = link;
57+
this.problemNumber = problemNumber;
58+
this.title = title;
59+
this.input = input;
60+
this.output = output;
61+
this.author = author;
62+
}
63+
64+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.gamzabat.algohub.feature.edgecase.domain;
2+
3+
import org.hibernate.annotations.SQLDelete;
4+
5+
import com.gamzabat.algohub.feature.user.domain.User;
6+
7+
import jakarta.persistence.Column;
8+
import jakarta.persistence.Entity;
9+
import jakarta.persistence.FetchType;
10+
import jakarta.persistence.GeneratedValue;
11+
import jakarta.persistence.GenerationType;
12+
import jakarta.persistence.Id;
13+
import jakarta.persistence.JoinColumn;
14+
import jakarta.persistence.ManyToOne;
15+
import jakarta.persistence.OneToOne;
16+
import lombok.Builder;
17+
import lombok.Getter;
18+
import lombok.NoArgsConstructor;
19+
20+
@Entity
21+
@Getter
22+
@NoArgsConstructor
23+
public class EdgeCaseLike {
24+
@Id
25+
@GeneratedValue(strategy = GenerationType.IDENTITY)
26+
private Long id;
27+
28+
@ManyToOne(fetch = FetchType.LAZY)
29+
@JoinColumn(name = "edge_case_id", nullable = false)
30+
private EdgeCase edgeCase;
31+
32+
@ManyToOne(fetch = FetchType.LAZY, optional = false)
33+
@JoinColumn(name = "user_id", nullable = false)
34+
private User user;
35+
36+
@Builder
37+
public EdgeCaseLike(EdgeCase edgeCase, User user) {
38+
this.edgeCase = edgeCase;
39+
this.user = user;
40+
}
41+
42+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.gamzabat.algohub.feature.edgecase.dto;
2+
3+
import jakarta.validation.constraints.NotBlank;
4+
import lombok.Builder;
5+
6+
@Builder
7+
public record CreateEdgeCaseRequest(@NotBlank(message = "문제 링크 입력은 필수입니다.") String link,
8+
@NotBlank(message = "반례 input 입력은 필수입니다.") String input,
9+
@NotBlank(message = "반례 output 입력은 필수입니다.") String output){
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.gamzabat.algohub.feature.edgecase.dto;
2+
3+
import java.util.List;
4+
5+
import lombok.Builder;
6+
7+
@Builder
8+
public record GetEdgeCaseListResponse(
9+
List<GetEdgeCaseResponse> edgeCaseList) {
10+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.gamzabat.algohub.feature.edgecase.dto;
2+
3+
import lombok.Builder;
4+
5+
@Builder
6+
public record GetEdgeCaseResponse(
7+
Integer edgeCaseId,
8+
Integer level,
9+
Integer problemNumber,
10+
String title,
11+
String input,
12+
String output,
13+
Integer like) {
14+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.gamzabat.algohub.feature.edgecase.dto;
2+
3+
import lombok.Getter;
4+
5+
@Getter
6+
public class TogleEdgeCaseResponse {
7+
private final Boolean islike;
8+
9+
public TogleEdgeCaseResponse(Boolean islike) {
10+
this.islike = islike;
11+
}
12+
}
13+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.gamzabat.algohub.feature.edgecase.exception;
2+
3+
import org.springframework.http.HttpStatus;
4+
5+
import lombok.Getter;
6+
7+
@Getter
8+
public class CannotFoundEdgeCaseException extends RuntimeException {
9+
private final String errors;
10+
private final HttpStatus httpStatus;
11+
12+
public CannotFoundEdgeCaseException(String errors, HttpStatus httpStatus) {
13+
this.errors = errors;
14+
this.httpStatus = httpStatus;
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.gamzabat.algohub.feature.edgecase.exception;
2+
3+
import org.springframework.http.HttpStatus;
4+
5+
import lombok.Getter;
6+
7+
@Getter
8+
public class NotAuthorizedUserException extends RuntimeException {
9+
private final String error;
10+
private final HttpStatus httpStatus;
11+
12+
public NotAuthorizedUserException(String error, HttpStatus httpStatus) {
13+
this.error = error;
14+
this.httpStatus = httpStatus;
15+
}
16+
}

0 commit comments

Comments
 (0)