Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ public record DiscussionResponse(
Long replyCount,

@Schema(description = "현재 사용자의 추천 상태 (UP, DOWN, NONE)", example = "UP")
VoteType voteStatus
VoteType voteStatus,

@Schema(description = "로그인한 유저의 해당 토론글 작성 여부", example = "true")
boolean isAuthor

) {

Expand All @@ -53,7 +56,8 @@ public static DiscussionResponse fromEntity(Discussion discussion) {
null,
null,
null,
null
null,
false
);
}

Expand All @@ -67,7 +71,8 @@ public static DiscussionResponse from(DiscussionQueryResult result) {
result.getUpvoteCount(),
result.getDownvoteCount(),
result.getReplyCount(),
result.getVoteStatus()
result.getVoteStatus(),
result.isAuthor()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ public record ReplyResponse(
Long childReplyCount,

@Schema(description = "현재 사용자의 추천 상태 (UP, DOWN, NONE)", example = "UP")
VoteType voteStatus
VoteType voteStatus,

@Schema(description = "로그인한 유저의 해당 토론글 작성 여부", example = "true")
boolean isAuthor
) {

public static ReplyResponse fromEntity(Reply reply) {
Expand All @@ -62,7 +64,8 @@ public static ReplyResponse fromEntity(Reply reply) {
null,
null,
null,
null
null,
false
);
}

Expand All @@ -78,7 +81,8 @@ public static ReplyResponse from(ReplyQueryResult result) {
result.getUpvoteCount(),
result.getDownvoteCount(),
result.getChildReplyCount(),
result.getVoteStatus()
result.getVoteStatus(),
result.isAuthor()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@
import org.ezcode.codetest.common.security.util.ExceptionHandlingFilter;
import org.ezcode.codetest.common.security.util.JwtFilter;
import org.ezcode.codetest.common.security.util.JwtUtil;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
Expand All @@ -38,13 +36,12 @@
@RequiredArgsConstructor
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

private final JwtUtil jwtUtil;
private final RedisTemplate<String, String> redisTemplate;
private final CustomOAuth2UserService customOAuth2UserService; //OAuth2.0 서비스
private final CustomSuccessHandler customSuccessHandler;



@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
JwtFilter jwtFilter = new JwtFilter(jwtUtil, redisTemplate);
Expand Down Expand Up @@ -81,6 +78,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
SecurityPath.PUBLIC_PATH).permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN") //어드민 권한 필요 (문제 생성, 관리 등)
.requestMatchers(HttpMethod.GET,
"/api/languages",
"/api/problems",
"/api/problems/{problemId}",
"/api/problems/*/discussions",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public class DiscussionQueryResult {

private final VoteType voteStatus;

private final boolean isAuthor;

@QueryProjection
public DiscussionQueryResult(
Long discussionId,
Expand All @@ -40,7 +42,7 @@ public DiscussionQueryResult(
Long upvoteCount,
Long downvoteCount,
Long replyCount,
VoteType voteType
VoteType voteType, boolean isAuthor
) {

this.discussionId = discussionId;
Expand All @@ -59,5 +61,7 @@ public DiscussionQueryResult(
} else {
this.voteStatus = VoteType.DOWN;
}

this.isAuthor = isAuthor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public class ReplyQueryResult {

private final VoteType voteStatus;

private final boolean isAuthor;

@QueryProjection
public ReplyQueryResult(
Long replyId,
Expand All @@ -43,7 +45,8 @@ public ReplyQueryResult(
Long upvoteCount,
Long downvoteCount,
Long childReplyCount,
VoteType voteType
VoteType voteType,
boolean isAuthor
) {

this.replyId = replyId;
Expand All @@ -63,5 +66,7 @@ public ReplyQueryResult(
} else {
this.voteStatus = VoteType.DOWN;
}

this.isAuthor = isAuthor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public enum CommunityExceptionCode implements ResponseCode {

REPLY_NOT_FOUND(false, HttpStatus.NOT_FOUND, "해당 ID의 댓글이 존재하지 않습니다."),
REPLY_DISCUSSION_MISMATCH(false, HttpStatus.BAD_REQUEST, "해당 댓글이 요청된 토론글에 속하지 않습니다."),

REPLY_PARENT_ALREADY_EXISTS(false, HttpStatus.BAD_REQUEST, "이미 부모 댓글이 있는 댓글에는 대댓글을 작성할 수 없습니다."),

USER_NOT_AUTHOR(false, HttpStatus.FORBIDDEN, "작성자만 수정/삭제할 수 있습니다."),
;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public Reply createReply(Discussion discussion, User user, Long parentReplyId, S
if (parentReplyId != null) {
parentReply = getReplyById(parentReplyId);
validateDiscussionMatches(parentReply, discussion);
checkNoExistingParentForReply(parentReply);
}

Reply reply = Reply.builder()
Expand Down Expand Up @@ -96,6 +97,7 @@ public void validateDiscussionMatches(Reply reply, Discussion discussion) {
if (!reply.isDiscussionMatches(discussion.getId())) {
throw new CommunityException(CommunityExceptionCode.REPLY_DISCUSSION_MISMATCH);
}

}

public void validateIsAuthor(Reply reply, Long userId) {
Expand All @@ -105,6 +107,13 @@ public void validateIsAuthor(Reply reply, Long userId) {
}
}

public void checkNoExistingParentForReply(Reply parentReply) {

if (parentReply.getParent() != null) {
throw new CommunityException(CommunityExceptionCode.REPLY_PARENT_ALREADY_EXISTS);
}
}

public NotificationCreateEvent createReplyNotification(User target, Reply reply) {

Long parentReplyId = reply.getParentReplyId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.querydsl.core.types.Order;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.CaseBuilder;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.NumberExpression;
Expand All @@ -40,11 +41,15 @@ public List<Long> findDiscussionIdsByProblemId(Long problemId, String sortBy, Pa

NumberExpression<Long> bestScore = upvoteCount.subtract(downvoteCount);

long offset = pageable.getOffset();
int pageNumber = pageable.getPageNumber();
int pageSize = pageable.getPageSize();

return jpaQueryFactory
.select(discussion.id)
.from(discussion)
.leftJoin(discussionVote).on(discussionVote.discussion.eq(discussion))
.where(discussion.problem.id.eq(problemId))
.where(discussion.problem.id.eq(problemId).and(discussion.isDeleted.isFalse()))
.groupBy(discussion.id)
.orderBy(getOrderSpecifier(sortBy, bestScore, upvoteCount))
.offset(pageable.getOffset())
Expand All @@ -65,12 +70,15 @@ public List<DiscussionQueryResult> findDiscussionsByIds(List<Long> discussionIds
Expression<Long> replyCount = reply.id.countDistinct();

Expression<VoteType> userVoteType;
BooleanExpression isAuthor;
if (currentUserId != null) {
userVoteType = new CaseBuilder()
.when(discussionVote.voter.id.eq(currentUserId)).then(discussionVote.voteType)
.otherwise(Expressions.nullExpression(VoteType.class)).max();
isAuthor = discussion.user.id.eq(currentUserId);
} else {
userVoteType = Expressions.nullExpression(VoteType.class);
isAuthor = Expressions.FALSE;
}

return jpaQueryFactory
Expand All @@ -88,7 +96,8 @@ public List<DiscussionQueryResult> findDiscussionsByIds(List<Long> discussionIds
upvoteCount,
downvoteCount,
replyCount,
userVoteType
userVoteType,
isAuthor
))
.from(discussion)
.join(discussion.user, user)
Expand All @@ -114,7 +123,7 @@ public Long countByProblemId(Long problemId) {
Long count = jpaQueryFactory
.select(discussion.count())
.from(discussion)
.where(discussion.problem.id.eq(problemId))
.where(discussion.problem.id.eq(problemId).and(discussion.isDeleted.isFalse()))
.fetchOne();

return count != null ? count : 0L;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,15 @@ private List<ReplyQueryResult> findRepliesByCondition(BooleanExpression conditio
Expression<Long> childReplyCount = childReply.id.count();

Expression<VoteType> userVoteType;
BooleanExpression isAuthor;
if (currentUserId != null) {
userVoteType = new CaseBuilder()
.when(replyVote.voter.id.eq(currentUserId)).then(replyVote.voteType)
.otherwise(Expressions.nullExpression(VoteType.class)).max();
isAuthor = reply.user.id.eq(currentUserId);
} else {
userVoteType = Expressions.nullExpression(VoteType.class);
isAuthor = Expressions.FALSE;
}

return jpaQueryFactory
Expand All @@ -90,13 +93,14 @@ private List<ReplyQueryResult> findRepliesByCondition(BooleanExpression conditio
upvoteCount,
downvoteCount,
childReplyCount,
userVoteType
userVoteType,
isAuthor
))
.from(reply)
.join(reply.user, user)
.leftJoin(replyVote).on(replyVote.reply.eq(reply))
.leftJoin(childReply).on(childReply.parent.eq(reply))
.where(condition)
.where(condition.and(reply.isDeleted.isFalse()))
.groupBy(reply.id)
.orderBy(reply.id.asc())
.offset(pageable.getOffset())
Expand All @@ -109,7 +113,7 @@ public Long countByDiscussionId(Long discussionId) {
return jpaQueryFactory
.select(reply.count())
.from(reply)
.where(reply.discussion.id.eq(discussionId).and(reply.parent.isNull()))
.where(reply.discussion.id.eq(discussionId).and(reply.parent.isNull()).and(reply.isDeleted.isFalse()))
.fetchOne();
}

Expand All @@ -118,7 +122,7 @@ public Long countByParentId(Long parentId) {
return jpaQueryFactory
.select(reply.count())
.from(reply)
.where(reply.parent.id.eq(parentId))
.where(reply.parent.id.eq(parentId).and(reply.isDeleted.isFalse()))
.fetchOne();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public String getGamePage() {
return "game-page";
}

@GetMapping("/test/notifications")
public String getNotificationPage() {
return "test-notifications";
}

@GetMapping("/ezlogin")
public String loginPage(){
return "login-page";
Expand Down
Loading