Skip to content

Commit 5229fac

Browse files
authored
Merge pull request #331 from MT-TEAM-Org/epic/adminCotentSearch
epic: admincontentsearch start
2 parents bd80d37 + 6d134ec commit 5229fac

24 files changed

+1711
-35
lines changed

build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ dependencies {
111111
implementation 'io.micrometer:micrometer-registry-prometheus'
112112
implementation 'org.springframework.boot:spring-boot-starter-actuator'
113113

114+
115+
//query dsl에서는 union연산같은걸 지원하지않아서 넣었습니다.
116+
implementation("com.blazebit:blaze-persistence-integration-querydsl-expressions-jakarta:1.6.15")
117+
implementation("com.blazebit:blaze-persistence-integration-hibernate-6.2:1.6.15")
118+
implementation("com.blazebit:blaze-persistence-core-impl-jakarta:1.6.15")
114119
}
115120

116121
test {
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package org.myteam.server.admin.controller;
2+
3+
4+
import io.swagger.v3.oas.annotations.Operation;
5+
import io.swagger.v3.oas.annotations.media.Content;
6+
import io.swagger.v3.oas.annotations.media.Schema;
7+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
8+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
9+
import io.swagger.v3.oas.annotations.tags.Tag;
10+
import jakarta.validation.Valid;
11+
import lombok.RequiredArgsConstructor;
12+
import org.myteam.server.admin.service.ContentSearchService;
13+
import org.myteam.server.global.exception.ErrorResponse;
14+
import org.myteam.server.global.web.response.ResponseDto;
15+
import org.myteam.server.global.web.response.ResponseStatus;
16+
import org.springframework.data.domain.Page;
17+
import org.springframework.http.ResponseEntity;
18+
import org.springframework.web.bind.annotation.PostMapping;
19+
import org.springframework.web.bind.annotation.RequestBody;
20+
import org.springframework.web.bind.annotation.RequestMapping;
21+
import org.springframework.web.bind.annotation.RestController;
22+
import static org.myteam.server.admin.dto.RequestContentDto.*;
23+
import static org.myteam.server.admin.dto.ResponseContentDto.*;
24+
25+
@RestController
26+
@RequiredArgsConstructor
27+
@Tag(name = "관리자 게시물,댓글 API", description = "관리자가 회원을 관리할 수 있는 API")
28+
@RequestMapping("/api/admin/content")
29+
public class AdminContentSearchController {
30+
31+
32+
private final ContentSearchService contentSearchService;
33+
@Operation(summary = "댓글,게시글의 상세조회",
34+
description = "관리자가 특정 댓,게시글의 정보를 상회조회합니다.")
35+
@ApiResponses(value = {
36+
@ApiResponse(responseCode = "200", description = "정보 조회 성공", useReturnTypeSchema = true),
37+
@ApiResponse(responseCode = "400", description = "잘못된 요청 형식", content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
38+
})
39+
@PostMapping("/detail")
40+
public ResponseEntity<ResponseDto<ResponseDetail>> getResponseDetail(@RequestBody @Valid RequestDetail requestDetail){
41+
return ResponseEntity.ok(new ResponseDto<>(ResponseStatus.SUCCESS.name(),"ok",
42+
contentSearchService.getContentDetail(requestDetail)));
43+
}
44+
@Operation(summary = "댓글,게시글 리스트 조회",
45+
description = "관리자가 제공한 조건에따라 댓,게시글의 리스트를 가져옵니다.")
46+
@ApiResponses(value = {
47+
@ApiResponse(responseCode = "200", description = "정보 조회 성공", useReturnTypeSchema = true),
48+
@ApiResponse(responseCode = "400", description = "잘못된 요청 형식", content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
49+
})
50+
@PostMapping("/list")
51+
public ResponseEntity<ResponseDto<Page<ResponseContentSearch>>> getContentData(@RequestBody @Valid RequestContentData requestContentData){
52+
53+
return ResponseEntity.ok(new ResponseDto<>(ResponseStatus.SUCCESS.name(),"ok",
54+
contentSearchService.getContentList(requestContentData)));
55+
}
56+
@Operation(summary = "신고 리스트 조회",
57+
description = "댓글 혹은 게시글의 신고 리스트를 조회해서 가져옵니다.")
58+
@ApiResponses(value = {
59+
@ApiResponse(responseCode = "200", description = "정보 조회 성공", useReturnTypeSchema = true),
60+
@ApiResponse(responseCode = "400", description = "잘못된 요청 형식", content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
61+
})
62+
@PostMapping("/reportList")
63+
public ResponseEntity<ResponseDto<Page<ResponseReportList>>> getContentDetail(@RequestBody @Valid RequestReportList requestReportList){
64+
65+
return ResponseEntity.ok(new ResponseDto<>(ResponseStatus.SUCCESS.name(),"ok",
66+
contentSearchService.getReportList(requestReportList)));
67+
}
68+
@Operation(summary = "관리자 메모 추가",
69+
description = "댓글,게시글에 대한 관리자 메모를 추가합니다.")
70+
@ApiResponses(value = {
71+
@ApiResponse(responseCode = "200", description = "정보 조회 성공", useReturnTypeSchema = true),
72+
@ApiResponse(responseCode = "400", description = "잘못된 요청 형식", content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
73+
})
74+
@PostMapping("/addAdminMemo")
75+
public ResponseEntity<ResponseDto<String>> addAdminMemo(@RequestBody @Valid AdminMemoRequest adminMemoRequest){
76+
77+
contentSearchService.addAdminMemo(adminMemoRequest);
78+
79+
return ResponseEntity.ok(new ResponseDto<>(ResponseStatus.SUCCESS.name(),"ok",
80+
"ok"));
81+
}
82+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.myteam.server.admin.dto;
2+
3+
4+
import com.blazebit.persistence.CTE;
5+
import jakarta.persistence.Entity;
6+
import jakarta.persistence.Id;
7+
8+
@Entity
9+
@CTE
10+
public class ContentCountCte {
11+
@Id
12+
private Long contentId;
13+
14+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.myteam.server.admin.dto;
2+
3+
4+
import com.blazebit.persistence.CTE;
5+
import jakarta.persistence.Entity;
6+
import jakarta.persistence.EnumType;
7+
import jakarta.persistence.Enumerated;
8+
import jakarta.persistence.Id;
9+
import lombok.Getter;
10+
import org.myteam.server.admin.utill.AdminControlType;
11+
import org.myteam.server.admin.utill.StaticDataType;
12+
import org.myteam.server.member.domain.MemberStatus;
13+
14+
import java.time.LocalDateTime;
15+
16+
@CTE
17+
@Getter
18+
@Entity
19+
public class ContentCte {
20+
21+
@Id
22+
private Long contentId;
23+
private String name;
24+
@Enumerated(EnumType.STRING)
25+
private StaticDataType staticDataType;
26+
private String content;
27+
private LocalDateTime createAt;
28+
@Enumerated(EnumType.STRING)
29+
private MemberStatus memberStatus;
30+
@Enumerated(EnumType.STRING)
31+
private AdminControlType adminControlType;
32+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.myteam.server.admin.dto;
2+
3+
4+
import com.blazebit.persistence.CTE;
5+
import jakarta.persistence.Entity;
6+
import jakarta.persistence.Id;
7+
import lombok.Getter;
8+
9+
@CTE
10+
@Getter
11+
@Entity
12+
public class MemberContentCountCte {
13+
@Id
14+
private Long contentId;
15+
private Long count;
16+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.myteam.server.admin.dto;
2+
3+
4+
import com.blazebit.persistence.CTE;
5+
import jakarta.persistence.Entity;
6+
import jakarta.persistence.EnumType;
7+
import jakarta.persistence.Enumerated;
8+
import jakarta.persistence.Id;
9+
import lombok.Getter;
10+
import org.myteam.server.report.domain.ReportType;
11+
12+
@Entity
13+
@Getter
14+
@CTE
15+
public class MemberReportCte {
16+
17+
@Id
18+
private Long reportedId;
19+
@Enumerated(EnumType.STRING)
20+
private ReportType reportType;
21+
22+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package org.myteam.server.admin.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import jakarta.validation.constraints.NotNull;
5+
import lombok.Builder;
6+
import lombok.Getter;
7+
import lombok.NoArgsConstructor;
8+
import org.myteam.server.admin.utill.AdminControlType;
9+
import org.myteam.server.admin.utill.StaticDataType;
10+
import org.myteam.server.board.domain.BoardSearchType;
11+
import org.myteam.server.global.util.date.DateFormatUtil;
12+
13+
import java.time.LocalDate;
14+
import java.time.LocalDateTime;
15+
import java.util.UUID;
16+
17+
public record RequestContentDto() {
18+
@Getter
19+
@NoArgsConstructor
20+
public static class RequestContentData {
21+
private BoardSearchType boardSearchType;
22+
private String searchKeyWord;
23+
private StaticDataType staticDataType;
24+
private Boolean isReported;
25+
private AdminControlType adminControlType;
26+
private String startTime;
27+
private String endTime;
28+
@NotNull
29+
private int offset;
30+
31+
@Builder
32+
public RequestContentData(BoardSearchType boardSearchType, String searchKeyWord, StaticDataType staticDataType,
33+
Boolean reported, AdminControlType adminControlType, String startTime,
34+
String endTime, int offset) {
35+
this.boardSearchType = boardSearchType;
36+
this.searchKeyWord = searchKeyWord;
37+
this.staticDataType = staticDataType;
38+
this.isReported = reported;
39+
this.adminControlType = adminControlType;
40+
this.startTime = startTime;
41+
this.endTime = endTime;
42+
this.offset = offset;
43+
}
44+
45+
public int getOffset() {
46+
return this.offset - 1;
47+
}
48+
49+
public LocalDateTime provideStartTime() {
50+
if (this.startTime == null) {
51+
return null;
52+
}
53+
LocalDate localDate = LocalDate.parse(startTime, DateFormatUtil.formatByDot);
54+
return localDate.atStartOfDay();
55+
}
56+
57+
public LocalDateTime provideEndTime() {
58+
if (this.endTime == null) {
59+
return null;
60+
}
61+
LocalDate localDate = LocalDate.parse(endTime, DateFormatUtil.formatByDot);
62+
return localDate.atStartOfDay();
63+
}
64+
}
65+
66+
@Getter
67+
@NoArgsConstructor
68+
public static class RequestDetail {
69+
@NotNull
70+
@Schema(description = "게시물이면 BOARD 댓글이면 COMMENT 입니다")
71+
private StaticDataType staticDataType;
72+
@NotNull
73+
private Long contentId;
74+
75+
@Builder
76+
public RequestDetail(StaticDataType staticDataType, Long contentId) {
77+
this.staticDataType = staticDataType;
78+
this.contentId = contentId;
79+
}
80+
}
81+
82+
83+
@Getter
84+
@NoArgsConstructor
85+
@Schema(description = "관리자 메모 작성 요청시 쓰이는 값입니다.")
86+
public static class AdminMemoRequest {
87+
@NotNull
88+
private Long contentId;
89+
@Schema(description = "게시물이면 BOARD 댓글이면 COMMENT 입니다.")
90+
@NotNull
91+
private StaticDataType staticDataType;
92+
@Schema(description = "숨김은 HIDDEN,보류는 PENDING 노출은 SHOW입니다.")
93+
@NotNull
94+
private AdminControlType adminControlType;
95+
@Schema(description = "내용이 없다면 null로 주세요")
96+
private String content;
97+
@NotNull
98+
private UUID publicId;
99+
100+
@Builder
101+
public AdminMemoRequest(Long contentId, StaticDataType staticDataType,
102+
AdminControlType adminControlType, String content) {
103+
this.contentId = contentId;
104+
this.staticDataType = staticDataType;
105+
this.adminControlType = adminControlType;
106+
this.content = content;
107+
}
108+
}
109+
110+
@Getter
111+
@NoArgsConstructor
112+
public static class RequestReportList {
113+
@NotNull
114+
private StaticDataType staticDataType;
115+
@NotNull
116+
private Long contentId;
117+
@NotNull
118+
private int offset;
119+
120+
@Builder
121+
public RequestReportList(StaticDataType staticDataType, Long contentId, int offset) {
122+
this.staticDataType = staticDataType;
123+
this.contentId = contentId;
124+
this.offset = offset;
125+
}
126+
127+
public int getOffset() {
128+
return this.offset - 1;
129+
}
130+
131+
}
132+
133+
134+
}

0 commit comments

Comments
 (0)