- GET /api/board/reports — 글/댓글 신고 대상별 집계(UNION, 신고 많은 순) - POST /api/board/reports/dismiss — 블라인드 없이 신고 기록만 초기화 - 관리자 신고 관리 화면 백엔드 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import com.sb.web.board.dto.PostDetail;
|
|||||||
import com.sb.web.board.dto.PostRequest;
|
import com.sb.web.board.dto.PostRequest;
|
||||||
import com.sb.web.board.dto.PostSummary;
|
import com.sb.web.board.dto.PostSummary;
|
||||||
import com.sb.web.board.dto.Recommender;
|
import com.sb.web.board.dto.Recommender;
|
||||||
|
import com.sb.web.board.dto.ReportedItem;
|
||||||
import com.sb.web.board.dto.TagCategoryResponse;
|
import com.sb.web.board.dto.TagCategoryResponse;
|
||||||
import com.sb.web.board.dto.VoteRequest;
|
import com.sb.web.board.dto.VoteRequest;
|
||||||
import com.sb.web.board.dto.VoteResponse;
|
import com.sb.web.board.dto.VoteResponse;
|
||||||
@@ -223,4 +224,20 @@ public class BoardController {
|
|||||||
boardService.unblockComment(commentId, current);
|
boardService.unblockComment(commentId, current);
|
||||||
return ResponseEntity.noContent().build();
|
return ResponseEntity.noContent().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 신고된 글/댓글 목록 (관리자) — 대상별 신고 수 집계 */
|
||||||
|
@GetMapping("/reports")
|
||||||
|
public List<ReportedItem> reports(
|
||||||
|
@RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) {
|
||||||
|
return boardService.listReportedItems(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 신고 무시 (관리자) — 블라인드 없이 신고 기록만 초기화 */
|
||||||
|
@PostMapping("/reports/dismiss")
|
||||||
|
public ResponseEntity<Void> dismissReport(
|
||||||
|
@RequestBody Map<String, String> body,
|
||||||
|
@RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) {
|
||||||
|
boardService.dismissReports(body.get("targetType"), Long.valueOf(body.get("targetId")), current);
|
||||||
|
return ResponseEntity.noContent().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.sb.web.board.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 신고 누적 항목 (관리자 신고 관리 화면). 대상별(글/댓글)로 신고 수를 집계.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ReportedItem {
|
||||||
|
|
||||||
|
private String targetType; // POST / COMMENT
|
||||||
|
private Long targetId; // 대상(글/댓글) id
|
||||||
|
private Long postId; // 링크용 글 id (POST=자기 자신, COMMENT=상위 글)
|
||||||
|
private String category; // 상위 글 게시판(community/saving/tips)
|
||||||
|
private String title; // 글 제목 (댓글이면 상위 글 제목)
|
||||||
|
private String content; // 본문/댓글 내용 (앞부분 요약)
|
||||||
|
private Long authorId; // 작성자 id
|
||||||
|
private String authorName; // 작성자 표시명
|
||||||
|
private Boolean blocked; // 이미 블라인드 되었는지
|
||||||
|
private Integer reportCount; // 누적 신고 수
|
||||||
|
private LocalDateTime lastReportedAt; // 마지막 신고 시각
|
||||||
|
}
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
package com.sb.web.board.mapper;
|
package com.sb.web.board.mapper;
|
||||||
|
|
||||||
|
import com.sb.web.board.dto.ReportedItem;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 신고(report) 매퍼 — 글/댓글 신고 누적 집계.
|
* 신고(report) 매퍼 — 글/댓글 신고 누적 집계.
|
||||||
*/
|
*/
|
||||||
@@ -15,6 +18,9 @@ public interface ReportMapper {
|
|||||||
@Param("memberId") Long memberId,
|
@Param("memberId") Long memberId,
|
||||||
@Param("reason") String reason);
|
@Param("reason") String reason);
|
||||||
|
|
||||||
|
/** 신고된 글/댓글 목록 (대상별 집계 — 관리자 화면) */
|
||||||
|
List<ReportedItem> listReported();
|
||||||
|
|
||||||
int countByTarget(@Param("targetType") String targetType, @Param("targetId") Long targetId);
|
int countByTarget(@Param("targetType") String targetType, @Param("targetId") Long targetId);
|
||||||
|
|
||||||
int deleteByTarget(@Param("targetType") String targetType, @Param("targetId") Long targetId);
|
int deleteByTarget(@Param("targetType") String targetType, @Param("targetId") Long targetId);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import com.sb.web.board.dto.PostDetail;
|
|||||||
import com.sb.web.board.dto.PostRequest;
|
import com.sb.web.board.dto.PostRequest;
|
||||||
import com.sb.web.board.dto.PostSummary;
|
import com.sb.web.board.dto.PostSummary;
|
||||||
import com.sb.web.board.dto.Recommender;
|
import com.sb.web.board.dto.Recommender;
|
||||||
|
import com.sb.web.board.dto.ReportedItem;
|
||||||
import com.sb.web.board.dto.VoteResponse;
|
import com.sb.web.board.dto.VoteResponse;
|
||||||
import com.sb.web.board.mapper.CommentMapper;
|
import com.sb.web.board.mapper.CommentMapper;
|
||||||
import com.sb.web.board.mapper.PostMapper;
|
import com.sb.web.board.mapper.PostMapper;
|
||||||
@@ -293,6 +294,23 @@ public class BoardService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 신고된 글/댓글 목록 (관리자 전용) — 대상별 신고 수 집계 */
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public List<ReportedItem> listReportedItems(SessionUser user) {
|
||||||
|
assertAdmin(user);
|
||||||
|
return reportMapper.listReported();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 신고 무시 (관리자 전용) — 블라인드 없이 신고 기록만 초기화 */
|
||||||
|
@Transactional
|
||||||
|
public void dismissReports(String targetType, Long targetId, SessionUser user) {
|
||||||
|
assertAdmin(user);
|
||||||
|
if (!T_POST.equals(targetType) && !T_COMMENT.equals(targetType)) {
|
||||||
|
throw new ApiException(HttpStatus.BAD_REQUEST, "잘못된 신고 대상 유형입니다.");
|
||||||
|
}
|
||||||
|
reportMapper.deleteByTarget(targetType, targetId);
|
||||||
|
}
|
||||||
|
|
||||||
/* ===================== 추천/비추천 ===================== */
|
/* ===================== 추천/비추천 ===================== */
|
||||||
|
|
||||||
/** 게시글 추천/비추천 토글. 같은 표 재요청 시 취소, 반대면 전환. */
|
/** 게시글 추천/비추천 토글. 같은 표 재요청 시 취소, 반대면 전환. */
|
||||||
|
|||||||
@@ -12,6 +12,29 @@
|
|||||||
SELECT COUNT(*) FROM report WHERE target_type = #{targetType} AND target_id = #{targetId}
|
SELECT COUNT(*) FROM report WHERE target_type = #{targetType} AND target_id = #{targetId}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<!-- 신고된 글/댓글 목록 (대상별 집계). 신고 많은 순 → 최근 신고 순. -->
|
||||||
|
<select id="listReported" resultType="com.sb.web.board.dto.ReportedItem">
|
||||||
|
SELECT 'POST' AS targetType, r.target_id AS targetId, p.id AS postId,
|
||||||
|
p.category AS category, p.title AS title, LEFT(p.content, 120) AS content,
|
||||||
|
p.author_id AS authorId, p.author_name AS authorName, p.blocked AS blocked,
|
||||||
|
COUNT(*) AS reportCount, MAX(r.created_at) AS lastReportedAt
|
||||||
|
FROM report r
|
||||||
|
JOIN post p ON p.id = r.target_id
|
||||||
|
WHERE r.target_type = 'POST'
|
||||||
|
GROUP BY p.id
|
||||||
|
UNION ALL
|
||||||
|
SELECT 'COMMENT' AS targetType, r.target_id AS targetId, c.post_id AS postId,
|
||||||
|
pp.category AS category, pp.title AS title, LEFT(c.content, 120) AS content,
|
||||||
|
c.author_id AS authorId, c.author_name AS authorName, c.blocked AS blocked,
|
||||||
|
COUNT(*) AS reportCount, MAX(r.created_at) AS lastReportedAt
|
||||||
|
FROM report r
|
||||||
|
JOIN comment c ON c.id = r.target_id
|
||||||
|
JOIN post pp ON pp.id = c.post_id
|
||||||
|
WHERE r.target_type = 'COMMENT'
|
||||||
|
GROUP BY c.id
|
||||||
|
ORDER BY reportCount DESC, lastReportedAt DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
<delete id="deleteByTarget">
|
<delete id="deleteByTarget">
|
||||||
DELETE FROM report WHERE target_type = #{targetType} AND target_id = #{targetId}
|
DELETE FROM report WHERE target_type = #{targetType} AND target_id = #{targetId}
|
||||||
</delete>
|
</delete>
|
||||||
|
|||||||
Reference in New Issue
Block a user