Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/feat/community' into dev-check
Browse files Browse the repository at this point in the history
  • Loading branch information
versatile0010 committed Nov 16, 2023
2 parents 07476d8 + 64e5db2 commit ccc4310
Show file tree
Hide file tree
Showing 13 changed files with 103 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public ResponseEntity<GetArticleDetailResponse> getArticleDetails(@PathVariable(
@GetMapping
public ResponseEntity<Slice<GetArticleListResponse>> getArticlePages(
Pageable pageable,
@ModelAttribute ArticleSearchParameter param) { // todo: 해당 유저가 좋아요를 눌렀는지 여부까지 표시되도록 수정
@ModelAttribute ArticleSearchParameter param) {
return ResponseEntity.ok(articleService.getArticleListPaging(param, pageable));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class GetArticleDetailResponse {
private String content;
private boolean isLiked;
private ArticleTag articleTag;
private Long commentCount;

// 작성자 관련
private String ownerName;
Expand All @@ -43,7 +44,8 @@ public static GetArticleDetailResponse of(
List<String> imageUrls,
String thumbNailImageUrl,
Member owner,
List<Long> memberLikedArticleList) {
List<Long> memberLikedArticleList,
Long commentCount ) {
return GetArticleDetailResponse.builder()
.articleId(article.getId())
.title(article.getTitle())
Expand All @@ -64,8 +66,8 @@ public static GetArticleDetailResponse of(
.ownerProfileImageUrl(owner.getProfileImageUrl())
.isLiked(memberLikedArticleList.contains(article.getId()))
.articleTag(article.getArticleTag())
.commentCount(commentCount)
.build();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class GetArticleListResponse {
private Long thumbNailImageId;

private Integer articleLikeCount;
private Integer commentCount;
private Long commentCount;
private Boolean isLiked;


Expand All @@ -48,7 +48,6 @@ public GetArticleListResponse(Article article, Long ownerId, Long thumbNailImage
this.articleStatus = article.getArticleStatus();
this.thumbNailImageId = thumbNailImageId;
this.articleLikeCount = article.getLikeCount();
this.commentCount = article.getCommentCount();
}

public void setOwnerNickName(String nickName){
Expand All @@ -59,7 +58,14 @@ public void setThumbNailImageUrl(String thumbNailImageUrl){
this.thumbNailImageUrl = thumbNailImageUrl;
}

public void updateInfo(Optional<Member> owner, Optional<ArticleImage> articleImage, List<Long> memberLikedArticleIdList){
public void setCommentCount(Long commentCount){
this.commentCount = commentCount;
}

public void updateInfo(Optional<Member> owner,
Optional<ArticleImage> articleImage,
List<Long> memberLikedArticleIdList,
Long commentCount ){
owner.ifPresentOrElse(
o -> setOwnerNickName(o.getNickName()),
() -> setOwnerNickName("알 수 없는 사용자")
Expand All @@ -69,6 +75,7 @@ public void updateInfo(Optional<Member> owner, Optional<ArticleImage> articleIma
() -> setThumbNailImageUrl("")
);
this.isLiked = memberLikedArticleIdList.contains(id);
this.commentCount = commentCount;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ public class Article extends BaseTimeEntity {
@Comment("게시글 좋아요 개수")
private Integer likeCount;

@ColumnDefault("0")
@Comment("게시글에 달린 댓글 개수")
private Integer commentCount;

@Comment("작성자 ID")
private Long articleOwnerId;

Expand All @@ -71,7 +67,6 @@ public Article(String title, String content, Long articleOwnerId, ArticleTag tag
this.articleOwnerId = articleOwnerId;
this.articleTag = tag;
this.articleStatus = ArticleStatus.ACTIVATED;
this.commentCount = 0;
this.likeCount = 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ public GetArticleDetailResponse getArticleDetail(Long articleId) {


Optional<ArticleImage> thumbNailImage = articleImageRepository.findById(article.getThumbNailImageUrlId());
Long commentCount = commentRepository.countAllByArticle(articleId);

String thumbNailImageUrl = "";
if (thumbNailImage.isPresent()) {
Expand All @@ -152,7 +153,7 @@ public GetArticleDetailResponse getArticleDetail(Long articleId) {
.stream().map(ArticleLike::getArticleId)
.toList();

return GetArticleDetailResponse.of(article, imageUrls, thumbNailImageUrl, owner, memberLikedArticleIdList);
return GetArticleDetailResponse.of(article, imageUrls, thumbNailImageUrl, owner, memberLikedArticleIdList, commentCount);
}

public Slice<GetArticleListResponse> getArticleListPaging(ArticleSearchParameter param, Pageable pageable) {
Expand All @@ -177,8 +178,9 @@ public void updateArticleInfo(GetArticleListResponse articleInfo, List<Long> mem

Optional<Member> owner = memberRepository.findById(ownerId);
Optional<ArticleImage> articleImage = articleImageRepository.findById(thumbNailImageUrlId);
Long commentCount = commentRepository.countAllByArticle(articleInfo.getId());

articleInfo.updateInfo(owner, articleImage, memberLikedArticleIdList);
articleInfo.updateInfo(owner, articleImage, memberLikedArticleIdList, commentCount);
}

@Transactional
Expand All @@ -193,8 +195,8 @@ public CreateCommentResponse createComment(Long articleId, CreateCommentRequest
);

articleParticipantRepository.save(new ArticleParticipant(article, member));
// 게시글 작성자에게 알림을 보낸다.
fcmMessageProvider.sendFcm(member, ARTICLE_COMMENT_FCM_ALARM, NotificationTag.COMMUNITY);

return CreateCommentResponse.of(savedComment);
}

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

import com.numberone.backend.domain.comment.dto.request.CreateChildCommentRequest;
import com.numberone.backend.domain.comment.dto.response.CreateChildCommentResponse;
import com.numberone.backend.domain.comment.dto.response.DeleteCommentResponse;
import com.numberone.backend.domain.comment.dto.response.GetCommentDto;
import com.numberone.backend.domain.comment.service.CommentService;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.sql.Delete;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

Expand Down Expand Up @@ -56,10 +58,22 @@ public ResponseEntity<CreateChildCommentResponse> createChildComment(
""")
@GetMapping("{article-id}")
public ResponseEntity<List<GetCommentDto>> getCommentsByArticle(@PathVariable("article-id") Long articleId){
List<GetCommentDto> response = commentService.getCommentsByArticle(articleId); // todo: 해당 유저가 좋아요를 눌렀는지 여부까지 표시되도록 수정
List<GetCommentDto> response = commentService.getCommentsByArticle(articleId);
return ResponseEntity.ok(response);
}

// todo: 댓글 삭제, 가장 많은 좋아요 상단 고정, 대댓글 달리면 푸시 알람 전송, 상단 고정된 작성자에게 푸시알람 전송, 댓글 신고 기능
@Operation(summary = "댓글 삭제 API 입니다", description = """
삭제할 댓글의 id 를 path variable 으로 보내주세요.
대댓글이 존재하는 댓글을 삭제 요청하는 경우에는, 대댓글까지 모두 삭제됩니다.
대댓글이 없는 댓글을 삭제 요청하는 경우에는 해당 댓글만 삭제됩니다.
""")
@DeleteMapping("{comment-id}")
public ResponseEntity<DeleteCommentResponse> deleteComment(@PathVariable("comment-id") Long commentId){
return ResponseEntity.ok(commentService.deleteComment(commentId));
}

// todo: 가장 많은 좋아요 상단 고정, 대댓글 달리면 푸시 알람 전송, 상단 고정된 작성자에게 푸시알람 전송, 댓글 신고 기능

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.numberone.backend.domain.comment.dto.response;

import lombok.*;

@ToString
@Builder
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class DeleteCommentResponse {
private Long commentId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class GetCommentDto {
private Long authorId;
private String authorNickName;
private String authorProfileImageUrl;
private boolean isLiked;


@QueryProjection
Expand All @@ -47,7 +48,7 @@ public GetCommentDto(CommentEntity comment){
this.likeCount = comment.getLikeCount();
}

public void updateCommentInfo(Optional<Member> author){
public void updateCommentInfo(Optional<Member> author, List<Long> likedCommentIdList){
author.ifPresentOrElse(
a -> {
this.authorNickName = a.getNickName();
Expand All @@ -57,6 +58,7 @@ public void updateCommentInfo(Optional<Member> author){
this.authorNickName = "알 수 없는 사용자";
}
);
this.isLiked = likedCommentIdList.contains(commentId);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.List;

public interface CommentRepositoryCustom {
public List<GetCommentDto> findAllByArticle(Long articleId);
List<GetCommentDto> findAllByArticle(Long articleId);
Long countAllByArticle(Long articleId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,15 @@ public List<GetCommentDto> findAllByArticle(Long articleId) {
)
.fetch();
}


@Override
public Long countAllByArticle(Long articleId) {
return queryFactory.select(commentEntity.count())
.from(commentEntity)
.innerJoin(article, article)
.where(article.id.eq(articleId))
.fetchOne();

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
import com.numberone.backend.domain.articleparticipant.repository.ArticleParticipantRepository;
import com.numberone.backend.domain.comment.dto.request.CreateChildCommentRequest;
import com.numberone.backend.domain.comment.dto.response.CreateChildCommentResponse;
import com.numberone.backend.domain.comment.dto.response.DeleteCommentResponse;
import com.numberone.backend.domain.comment.dto.response.GetCommentDto;
import com.numberone.backend.domain.comment.entity.CommentEntity;
import com.numberone.backend.domain.comment.repository.CommentRepository;
import com.numberone.backend.domain.like.entity.CommentLike;
import com.numberone.backend.domain.like.repository.CommentLikeRepository;
import com.numberone.backend.domain.member.entity.Member;
import com.numberone.backend.domain.member.repository.MemberRepository;
import com.numberone.backend.domain.token.util.SecurityContextProvider;
Expand All @@ -32,6 +35,7 @@ public class CommentService {
private final ArticleRepository articleRepository;
private final ArticleParticipantRepository articleParticipantRepository;
private final MemberRepository memberRepository;
private final CommentLikeRepository commentLikeRepository;

@Transactional
public CreateChildCommentResponse createChildComment(
Expand All @@ -56,10 +60,15 @@ public CreateChildCommentResponse createChildComment(
}

public List<GetCommentDto> getCommentsByArticle(Long articleId) {
String principal = SecurityContextProvider.getAuthenticatedUserEmail();
Member member = memberRepository.findByEmail(principal)
.orElseThrow(NotFoundMemberException::new);
Article article = articleRepository.findById(articleId)
.orElseThrow(NotFoundArticleException::new);
List<GetCommentDto> comments = commentRepository.findAllByArticle(article.getId());

List<Long> likedCommentIdList = commentLikeRepository.findByMember(member)
.stream().map(CommentLike::getCommentId)
.toList();
// 계층 구조로 변환 (추후 리팩토링 필요)
List<GetCommentDto> result = new ArrayList<>();
Map<Long, GetCommentDto> map = new HashMap<>();
Expand All @@ -68,7 +77,7 @@ public List<GetCommentDto> getCommentsByArticle(Long articleId) {
CommentEntity commentEntity = commentRepository.findById(comment.getCommentId())
.orElseThrow(NotFoundCommentException::new);
Optional<Member> author = memberRepository.findById(commentEntity.getAuthorId());
comment.updateCommentInfo(author);
comment.updateCommentInfo(author, likedCommentIdList);

map.put(comment.getCommentId(), comment);

Expand All @@ -85,4 +94,14 @@ public List<GetCommentDto> getCommentsByArticle(Long articleId) {
return result;
}

@Transactional
public DeleteCommentResponse deleteComment(Long commentId){
CommentEntity commentEntity = commentRepository.findById(commentId)
.orElseThrow(NotFoundCommentException::new);
commentRepository.delete(commentEntity);
return DeleteCommentResponse.builder()
.commentId(commentId)
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,24 @@
import com.numberone.backend.domain.like.repository.CommentLikeRepository;
import com.numberone.backend.domain.member.entity.Member;
import com.numberone.backend.domain.member.repository.MemberRepository;
import com.numberone.backend.domain.notification.entity.NotificationTag;
import com.numberone.backend.domain.token.util.SecurityContextProvider;
import com.numberone.backend.exception.conflict.AlreadyLikedException;
import com.numberone.backend.exception.conflict.AlreadyUnLikedException;
import com.numberone.backend.exception.notfound.NotFoundApiException;
import com.numberone.backend.exception.notfound.NotFoundCommentException;
import com.numberone.backend.exception.notfound.NotFoundMemberException;
import com.numberone.backend.support.fcm.service.FcmMessageProvider;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.id.IntegralDataTypeHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

import static com.numberone.backend.support.notification.NotificationMessage.BEST_ARTICLE_FCM_ALARM;

@Slf4j
@Service
@RequiredArgsConstructor
Expand All @@ -34,7 +39,9 @@ public class LikeService {
private final CommentLikeRepository commentLikeRepository;
private final CommentRepository commentRepository;
private final MemberRepository memberRepository;
private final FcmMessageProvider fcmMessageProvider;

private final Integer BEST_ARTICLE_LIKE_COUNT = 20;

@Transactional
public Integer increaseArticleLike(Long articleId) {
Expand All @@ -50,6 +57,13 @@ public Integer increaseArticleLike(Long articleId) {
article.increaseLikeCount();
articleLikeRepository.save(new ArticleLike(member, article));

if (article.getLikeCount() >= BEST_ARTICLE_LIKE_COUNT) {
Long ownerId = article.getArticleOwnerId();
Member owner = memberRepository.findById(ownerId)
.orElseThrow(NotFoundMemberException::new);
fcmMessageProvider.sendFcm(owner, BEST_ARTICLE_FCM_ALARM, NotificationTag.COMMUNITY);
}

return article.getLikeCount();
}

Expand Down Expand Up @@ -97,7 +111,7 @@ public Integer decreaseCommentLike(Long commentId) {
.orElseThrow(NotFoundMemberException::new);
CommentEntity commentEntity = commentRepository.findById(commentId)
.orElseThrow(NotFoundCommentException::new);
if (!isAlreadyLikedComment(member, commentId)){
if (!isAlreadyLikedComment(member, commentId)) {
// 좋아요를 누르지 않은 댓글이라 좋아요를 취소할 수 없습니다.
throw new AlreadyUnLikedException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
@RequiredArgsConstructor
public enum NotificationMessage implements NotificationMessageSpec {

ARTICLE_COMMENT_FCM_ALARM("[대피로 알림]", "게시글에 댓글이 달렸어요!", null);
ARTICLE_COMMENT_FCM_ALARM("[대피로 알림]", "게시글에 댓글이 달렸어요!", null),
BEST_ARTICLE_FCM_ALARM("[대피로 알림]", "축하드립니다! 베스트 게시글로 선정되었습니다. 🎉", null);
;

private final String title;
private final String body;
Expand Down

0 comments on commit ccc4310

Please sign in to comment.