feat(board): 스팸 키워드 자동 블라인드 및 관리자 신고 목록 노출
Deploy / deploy (push) Failing after 14m15s

- BoardService: create/addComment에서 isSpam 감지 시 자동 블라인드 처리, 포인트 미지급
- ReportMapper: listReported 쿼리 확장 — 신고 누적 OR 스팸 감지 블라인드 항목 모두 포함
- ReportedItem: blockReason 필드 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ByungCheol
2026-07-05 13:46:50 +09:00
parent b3b42f0db6
commit 82eea0b908
3 changed files with 26 additions and 13 deletions
@@ -19,6 +19,7 @@ public class ReportedItem {
private Long authorId; // 작성자 id private Long authorId; // 작성자 id
private String authorName; // 작성자 표시명 private String authorName; // 작성자 표시명
private Boolean blocked; // 이미 블라인드 되었는지 private Boolean blocked; // 이미 블라인드 되었는지
private String blockReason; // 블라인드 사유 (글만 존재; 스팸 감지 / 신고 누적 등)
private Integer reportCount; // 누적 신고 수 private Integer reportCount; // 누적 신고 수
private LocalDateTime lastReportedAt; // 마지막 신고 시각 private LocalDateTime lastReportedAt; // 마지막 신고 시각
} }
@@ -191,7 +191,11 @@ public class BoardService {
.build(); .build();
postMapper.insert(post); postMapper.insert(post);
applyTags(post.getId(), req.getTagIds()); applyTags(post.getId(), req.getTagIds());
if (pointService.isSpam(req.getContent())) {
postMapper.updateBlocked(post.getId(), true, "스팸 키워드 감지");
} else {
pointService.awardBoardWrite(author.getId(), req.getContent()); pointService.awardBoardWrite(author.getId(), req.getContent());
}
return assemble(mustFindPost(post.getId()), author); return assemble(mustFindPost(post.getId()), author);
} }
@@ -245,7 +249,11 @@ public class BoardService {
.content(req.getContent()) .content(req.getContent())
.build(); .build();
commentMapper.insert(comment); commentMapper.insert(comment);
if (pointService.isSpam(req.getContent())) {
commentMapper.updateBlocked(comment.getId(), true);
} else {
pointService.awardBoardWrite(author.getId(), req.getContent()); pointService.awardBoardWrite(author.getId(), req.getContent());
}
return CommentResponse.from(commentMapper.findById(comment.getId())); return CommentResponse.from(commentMapper.findById(comment.getId()));
} }
+15 -11
View File
@@ -12,25 +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>
<!-- 신고/댓글 목록 (대상별 집계). 신고 많은 순 → 최근 신고 순. --> <!-- 신고/스팸·댓글 목록. 신고 1건 이상 OR 스팸 감지 블라인드 항목을 모두 포함. -->
<select id="listReported" resultType="com.sb.web.board.dto.ReportedItem"> <select id="listReported" resultType="com.sb.web.board.dto.ReportedItem">
SELECT 'POST' AS targetType, r.target_id AS targetId, p.id AS postId, SELECT 'POST' AS targetType, p.id AS targetId, p.id AS postId,
p.category AS category, p.title AS title, LEFT(p.content, 120) AS content, 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, p.author_id AS authorId, p.author_name AS authorName, p.blocked AS blocked,
COUNT(*) AS reportCount, MAX(r.created_at) AS lastReportedAt p.block_reason AS blockReason,
FROM report r COUNT(r.id) AS reportCount, MAX(r.created_at) AS lastReportedAt
JOIN post p ON p.id = r.target_id FROM post p
WHERE r.target_type = 'POST' LEFT JOIN report r ON r.target_id = p.id AND r.target_type = 'POST'
WHERE EXISTS (SELECT 1 FROM report WHERE target_type = 'POST' AND target_id = p.id)
OR p.block_reason = '스팸 키워드 감지'
GROUP BY p.id GROUP BY p.id
UNION ALL UNION ALL
SELECT 'COMMENT' AS targetType, r.target_id AS targetId, c.post_id AS postId, SELECT 'COMMENT' AS targetType, c.id AS targetId, c.post_id AS postId,
pp.category AS category, pp.title AS title, LEFT(c.content, 120) AS content, 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, c.author_id AS authorId, c.author_name AS authorName, c.blocked AS blocked,
COUNT(*) AS reportCount, MAX(r.created_at) AS lastReportedAt NULL AS blockReason,
FROM report r COUNT(r.id) AS reportCount, MAX(r.created_at) AS lastReportedAt
JOIN comment c ON c.id = r.target_id FROM comment c
JOIN post pp ON pp.id = c.post_id JOIN post pp ON pp.id = c.post_id
WHERE r.target_type = 'COMMENT' LEFT JOIN report r ON r.target_id = c.id AND r.target_type = 'COMMENT'
WHERE EXISTS (SELECT 1 FROM report WHERE target_type = 'COMMENT' AND target_id = c.id)
OR c.blocked = 1
GROUP BY c.id GROUP BY c.id
ORDER BY reportCount DESC, lastReportedAt DESC ORDER BY reportCount DESC, lastReportedAt DESC
</select> </select>