Skip to content

Commit

Permalink
feat: 신고 기능
Browse files Browse the repository at this point in the history
  • Loading branch information
umi0410 committed Mar 6, 2022
1 parent 6223a37 commit fa8ce96
Show file tree
Hide file tree
Showing 15 changed files with 271 additions and 48 deletions.
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@

# khumu-community의 주요 기능

- 1️⃣ 유저에 대한 CRUD
- 1️⃣ 유저에 대한 차단 기능
- 유저에 대한 CRUD
- 1️⃣ 유저에 대한 차단 기능 (게시글 작성자 차단하기)
- 게시판에 대한 CRUD
- 게시판에 대한 Follow / Unfollow
- ✅ 1️⃣ 게시글에 대한 CRUD
- 1️⃣ 내가 작성한, 댓글 단, 좋아요한 등 각각의 다양한 기준으로 게시글을 조회하기
- 1️⃣ comment 서버에서 comment 개수 가져오기
- 1️⃣ alimi 서버에서 게시글에 대한 알림 구독 정보 가져오기
- ✅ 1️⃣ 게시글에 대한 Like / Unlike
- ✅ 1️⃣ 게시글에 대한 Bookmark / Unbookomark
- 1️⃣ 게시글에 대한 차단 기능
- ✅ 1️⃣ 내가 작성한, 댓글 단, 좋아요한 등 각각의 다양한 기준으로 게시글을 조회하기
- ✅ 1️⃣ comment 서버에서 comment 개수 가져오기
- ✅ 1️⃣ alimi 서버에서 게시글에 대한 알림 구독 정보 가져오기
- 1️⃣ 게시글/게시판에 대한 검색 기능
- 1️⃣ 게시글 작성 시각 표현
- ✅ 1️⃣ 게시글에 대한 Like / Unlike
- ✅ 1️⃣ 게시글에 대한 Bookmark / Unbookomark
- 1️⃣ 다양한 엔티티에 대한 신고 기능
- 학사 일정에 대한 Read - 파이썬으로 할 지 고민
- 근데 파이썬으로 하는 것 자체가 불필요한 microservice화가 될 것 같다.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.khumu.community.application.dto;

import lombok.*;
import org.springframework.data.annotation.CreatedDate;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
public class BlockUserDto {
Long id;
// 차단을 수행한 사람
String blocker;
// 차단 당한 사람
SimpleUserDto blockee;
// 차단 당한 사람의 정보를 익명으로 가려줄 것인지
Boolean isBlockeeAnonymous;
// 차단한 이유
String reason;
// 언제 차단한 것인지
LocalDateTime createdAt;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
@Getter
@Setter
@Builder
public class CreateArticleRequest {
public class CreateArticleInput {
String title;
String board;
String content;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.khumu.community.application.dto.input;

import lombok.*;

// 게시글의 작성자를 차단한다.
// 게시글이 익명 게시글이라면 차단 후 정보 제공 시 익명으로 정보를 제공하고
// 기명 게시글이라면 기명으로 정보 제공
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
public class CreateBlockUserInput {
Integer article;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
@Getter
@Setter
@Builder
public class UpdateArticleRequest {
public class UpdateArticleInput {
String title;
String board;
String content;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
@Getter
@Setter
@Builder
public class BlockUser {
public class BlockUser extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
Expand All @@ -24,8 +24,7 @@ public class BlockUser {
// 차단 당한 사람
String blockee;
// 차단 당한 사람의 정보를 익명으로 가려줄 것인지
Boolean hidBlockee;
// 언제 차단한 것인지
@CreatedDate
LocalDateTime createdAt;
Boolean isBlockeeAnonymous;
// 차단한 이유
String reason;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.khumu.community.application.dto.ArticleDto;
import com.khumu.community.application.dto.DetailedArticleDto;
import com.khumu.community.application.dto.SimpleUserDto;
import com.khumu.community.application.entity.Article;
import com.khumu.community.application.entity.BookmarkArticle;
import com.khumu.community.application.entity.LikeArticle;
Expand All @@ -25,20 +26,24 @@ public class ArticleAdditionalDataInjector {
private final CommentRepository commentRepository;
private final AlimiRepository alimiRepository;

public ArticleDto inject(ArticleDto articleDto, User requestUser) {
articleDto.setCommentCount(commentRepository.countByArticle(articleDto.getId()));
if (requestUser != null){
articleDto.setLiked(likeArticleRepository.countByUserAndArticle(requestUser.getUsername(), Article.builder().id(articleDto.getId()).build()) != 0);
public ArticleDto inject(ArticleDto src, User requestUser) {
src.setCommentCount(commentRepository.countByArticle(src.getId()));
if (requestUser != null && requestUser.getUsername() != null){
src.setLiked(likeArticleRepository.countByUserAndArticle(requestUser.getUsername(), Article.builder().id(src.getId()).build()) != 0);
}
articleDto.setLikeArticleCount(likeArticleRepository.countByArticle(Article.builder().id(articleDto.getId()).build()));
src.setLikeArticleCount(likeArticleRepository.countByArticle(Article.builder().id(src.getId()).build()));

if (requestUser != null) {
articleDto.setBookmarked(bookmarkArticleRepository.countByUserAndArticle(requestUser.getUsername(), Article.builder().id(articleDto.getId()).build()) != 0);
if (requestUser != null && requestUser.getUsername() != null) {
src.setBookmarked(bookmarkArticleRepository.countByUserAndArticle(requestUser.getUsername(), Article.builder().id(src.getId()).build()) != 0);
}

src.setBookmarkArticleCount(bookmarkArticleRepository.countByArticle(Article.builder().id(src.getId()).build()));
if (src.getKind().equals("anonymous")) {
src.setAuthor(SimpleUserDto.builder().username("anonymous").nickname("익명").status("anonymous").build());
}

articleDto.setBookmarkArticleCount(bookmarkArticleRepository.countByArticle(Article.builder().id(articleDto.getId()).build()));

return articleDto;
return src;
}

public Page<ArticleDto> inject(Page<ArticleDto> articleDtos, User requestUser) {
Expand All @@ -59,6 +64,21 @@ public List<ArticleDto> inject(List<ArticleDto> articleDtos, User requestUser) {
}

public DetailedArticleDto inject(DetailedArticleDto src, User requestUser) {
// ArticleDto에 대한 inject와 동일
src.setCommentCount(commentRepository.countByArticle(src.getId()));
if (requestUser != null && requestUser.getUsername() != null){
src.setLiked(likeArticleRepository.countByUserAndArticle(requestUser.getUsername(), Article.builder().id(src.getId()).build()) != 0);
}
src.setLikeArticleCount(likeArticleRepository.countByArticle(Article.builder().id(src.getId()).build()));

if (requestUser != null && requestUser.getUsername() != null) {
src.setBookmarked(bookmarkArticleRepository.countByUserAndArticle(requestUser.getUsername(), Article.builder().id(src.getId()).build()) != 0);
}

src.setBookmarkArticleCount(bookmarkArticleRepository.countByArticle(Article.builder().id(src.getId()).build()));
if (src.getKind().equals("anonymous")) {
src.setAuthor(SimpleUserDto.builder().username("anonymous").nickname("익명").status("anonymous").build());
}

if (requestUser == null || requestUser.getUsername() == null) {
src.setIsSubscribed(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@

import com.khumu.community.application.dto.ArticleDto;
import com.khumu.community.application.dto.DetailedArticleDto;
import com.khumu.community.application.dto.input.CreateArticleRequest;
import com.khumu.community.application.dto.input.CreateArticleInput;
import com.khumu.community.application.dto.input.IsAuthorInput;
import com.khumu.community.application.dto.input.UpdateArticleRequest;
import com.khumu.community.application.dto.output.IsAuthorOutput;
import com.khumu.community.application.dto.input.UpdateArticleInput;
import com.khumu.community.application.entity.*;
import com.khumu.community.application.exception.ForbiddenException;
import com.khumu.community.application.port.out.messaging.MessagePublisher;
import com.khumu.community.application.port.out.repository.*;
import com.khumu.community.common.mapper.ArticleMapper;
import com.khumu.community.infra.messaging.SnsPublisher;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
Expand All @@ -20,7 +18,6 @@
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

Expand All @@ -40,7 +37,7 @@ public class ArticleService {
private final MessagePublisher messagePublisher;

@Transactional
public ArticleDto write(User requestUser, CreateArticleRequest input) {
public ArticleDto write(User requestUser, CreateArticleInput input) {
Article tmp = Article.builder()
.author(requestUser)
.board(Board.builder().name(input.getBoard()).build())
Expand All @@ -63,7 +60,7 @@ public ArticleDto write(User requestUser, CreateArticleRequest input) {
@Transactional
public Page<ArticleDto> listArticlesForFeed(User requestUser, Pageable pageable) {
List<Board> followingBoards = followBoardRepository.findAllByUser(requestUser.getUsername(), Pageable.unpaged()).map(FollowBoard::getBoard).toList();
List<BlockUser> blocks = blockUserRepository.findAllByBlocker(requestUser.getUsername());
List<BlockUser> blocks = blockUserRepository.findAllByBlocker(requestUser.getUsername(), Pageable.unpaged()).getContent();
List<String> blockedUsernames = blocks.stream().map(BlockUser::getBlockee).collect(Collectors.toList());

// list가 empty이면 JPQL에서 in query가 제대로 동작되지 못함.
Expand All @@ -90,7 +87,7 @@ public Page<ArticleDto> listArticlesIWrote(User requestUser, Pageable pageable)
// 내가 좋아요한 게시글 조회
@Transactional
public Page<ArticleDto> listArticlesILiked(User requestUser, Pageable pageable) {
List<BlockUser> blocks = blockUserRepository.findAllByBlocker(requestUser.getUsername());
List<BlockUser> blocks = blockUserRepository.findAllByBlocker(requestUser.getUsername(), Pageable.unpaged()).getContent();
List<String> blockedUsernames = blocks.stream().map(BlockUser::getBlockee).collect(Collectors.toList());

// list가 empty이면 JPQL에서 in query가 제대로 동작되지 못함.
Expand All @@ -106,7 +103,7 @@ public Page<ArticleDto> listArticlesILiked(User requestUser, Pageable pageable)
// 내가 북마크한 게시글 조회
@Transactional
public Page<ArticleDto> listArticlesIBookmarked(User requestUser, Pageable pageable) {
List<BlockUser> blocks = blockUserRepository.findAllByBlocker(requestUser.getUsername());
List<BlockUser> blocks = blockUserRepository.findAllByBlocker(requestUser.getUsername(), Pageable.unpaged()).getContent();
List<String> blockedUsernames = blocks.stream().map(BlockUser::getBlockee).collect(Collectors.toList());

// list가 empty이면 JPQL에서 in query가 제대로 동작되지 못함.
Expand All @@ -123,7 +120,7 @@ public Page<ArticleDto> listArticlesIBookmarked(User requestUser, Pageable pagea
// Page 정보를 올바르게 전달하기는 힘들어서 List로 전달
@Transactional
public List<ArticleDto> listArticlesICommented(User requestUser, String authorizationString, Pageable pageable) {
List<BlockUser> blocks = blockUserRepository.findAllByBlocker(requestUser.getUsername());
List<BlockUser> blocks = blockUserRepository.findAllByBlocker(requestUser.getUsername(), Pageable.unpaged()).getContent();
List<String> blockedUsernames = blocks.stream().map(BlockUser::getBlockee).collect(Collectors.toList());

// list가 empty이면 JPQL에서 in query가 제대로 동작되지 못함.
Expand All @@ -147,7 +144,7 @@ public List<ArticleDto> listArticlesICommented(User requestUser, String authoriz
// Page 정보를 올바르게 전달하기는 힘들어서 List로 전달
@Transactional
public Page<ArticleDto> listHotArticles(User requestUser, Pageable pageable) {
List<BlockUser> blocks = blockUserRepository.findAllByBlocker(requestUser.getUsername());
List<BlockUser> blocks = blockUserRepository.findAllByBlocker(requestUser.getUsername(), Pageable.unpaged()).getContent();
List<String> blockedUsernames = blocks.stream().map(BlockUser::getBlockee).collect(Collectors.toList());

// list가 empty이면 JPQL에서 in query가 제대로 동작되지 못함.
Expand All @@ -162,7 +159,7 @@ public Page<ArticleDto> listHotArticles(User requestUser, Pageable pageable) {
// 특정 게시판의 게시글들 조회
@Transactional
public Page<ArticleDto> listArticlesByBoard(User requestUser, String board, Pageable pageable) {
List<BlockUser> blocks = blockUserRepository.findAllByBlocker(requestUser.getUsername());
List<BlockUser> blocks = blockUserRepository.findAllByBlocker(requestUser.getUsername(), Pageable.unpaged()).getContent();
List<String> blockedUsernames = blocks.stream().map(BlockUser::getBlockee).collect(Collectors.toList());

// list가 empty이면 JPQL에서 in query가 제대로 동작되지 못함.
Expand All @@ -185,7 +182,7 @@ public DetailedArticleDto getArticle(User requestUser, Integer id) {
@Transactional
// TODO: 기존에는 Patch(부분 수정) 방식이었는데 이거 어떻게 대응해줄 것인가?
// 일단은 null일 수 없는 값들이기때문에 null이면 수정 안하기로.
public ArticleDto update(User requestUser, Integer id, UpdateArticleRequest input) {
public ArticleDto update(User requestUser, Integer id, UpdateArticleInput input) {

Article article = articleRepository.findById(id).get();
if (input.getBoard() != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,77 @@
package com.khumu.community.application.port.in;

import com.khumu.community.application.dto.BlockUserDto;
import com.khumu.community.application.dto.SimpleUserDto;
import com.khumu.community.application.dto.input.CreateBlockUserInput;
import com.khumu.community.application.entity.Article;
import com.khumu.community.application.entity.BlockUser;
import com.khumu.community.application.entity.User;
import com.khumu.community.application.exception.ForbiddenException;
import com.khumu.community.application.port.out.repository.ArticleRepository;
import com.khumu.community.application.port.out.repository.BlockUserRepository;
import com.khumu.community.application.port.out.repository.UserRepository;
import com.khumu.community.common.mapper.BlockUserMapper;
import com.khumu.community.common.mapper.UserMapper;
import com.khumu.community.common.util.Util;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
@Slf4j
public class BlockService {
private final BlockUserRepository blockUserRepository;
private final UserMapper userMapper;
private final BlockUserMapper blockUserMapper;
private final UserRepository userRepository;
private final ArticleRepository articleRepository;

public BlockUserDto blockUser(User requestUser, CreateBlockUserInput input) {
Article article = articleRepository.findById(input.getArticle()).get();
if (requestUser.getUsername().equals(article.getAuthor().getUsername())) {
throw new ForbiddenException("본인의 게시글을 바탕으로 작성자(본인)를 차단할 수 없습니다.");
}

BlockUser block = blockUserRepository.save(BlockUser.builder()
.blocker(requestUser.getUsername())
.blockee(article.getAuthor().getUsername())
.isBlockeeAnonymous(article.getKind().equals("anonymous"))
.reason("게시글 \"" + Util.getShortString(article.getTitle(), 16) + "\" 의 작성자를 차단했습니다.")
.build());


return map(block);
}

public Page<BlockUserDto> listMyBlocks(User requestUser, Pageable pageable) {
Page<BlockUser> blocks = blockUserRepository.findAllByBlocker(requestUser.getUsername(), pageable);
return blocks.map(this::map);
}

public void unblockUser(User requestUser, Long blockId) {
BlockUser block = blockUserRepository.findById(blockId).get();
// 본인이 신고자가 아닌 경우
if (!requestUser.getUsername().equals(block.getBlocker())) {
throw new ForbiddenException("본인의 차단 내역만 해제할 수 있습니다.");
}

blockUserRepository.delete(block);
}

private BlockUserDto map(BlockUser block) {
BlockUserDto dto = blockUserMapper.toDto(block);
if (dto.getIsBlockeeAnonymous()) {
dto.setBlockee(SimpleUserDto.builder().username("anonymous").nickname("익명").status("anonymous").build());
} else{
User user = userRepository.findById(block.getBlockee()).get();
userMapper.toSimpleDto(user);
}

return dto;
}


}
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package com.khumu.community.application.port.in;

import com.khumu.community.application.dto.ArticleDto;
import com.khumu.community.application.dto.input.UpdateArticleRequest;
import com.khumu.community.application.entity.*;
import com.khumu.community.application.exception.ForbiddenException;
import com.khumu.community.application.port.out.messaging.MessagePublisher;
import com.khumu.community.application.port.out.repository.ArticleRepository;
import com.khumu.community.application.port.out.repository.LikeArticleRepository;
Expand All @@ -12,8 +9,6 @@

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import com.khumu.community.application.entity.BlockUser;
import com.khumu.community.application.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface BlockUserRepository extends JpaRepository<BlockUser, String> {
List<BlockUser> findAllByBlocker(String blocker);
public interface BlockUserRepository extends JpaRepository<BlockUser, Long> {
Page<BlockUser> findAllByBlocker(String blocker, Pageable pageable);
}
Loading

0 comments on commit fa8ce96

Please sign in to comment.