Skip to content

Commit

Permalink
Merge pull request #218 from Board-Buddy/feature/#213
Browse files Browse the repository at this point in the history
[Feature/#213] 모집글 작성 알림 구현 및 리팩토링
  • Loading branch information
runtime-zer0 authored Aug 4, 2024
2 parents 7830089 + 0bafadc commit 5abdc34
Show file tree
Hide file tree
Showing 19 changed files with 184 additions and 67 deletions.
13 changes: 13 additions & 0 deletions nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,17 @@ server {
proxy_set_header Connection "Upgrade";
proxy_set_header Origin "";
}

location /api/notifications {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_read_timeout 120s;
proxy_pass_request_headers on;
proxy_set_header Connection "";
proxy_set_header Cache-Control "no-cache";
proxy_set_header X-Accel-Buffering "no";
proxy_set_header Content-Type "text/event-stream";
proxy_buffering off;
chunked_transfer_encoding on;
}
}
5 changes: 3 additions & 2 deletions src/main/java/sumcoda/boardbuddy/config/WebMvcConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ public void addInterceptors(InterceptorRegistry registry) {
"/api/login/oauth2/code/**",
"/api/rankings",
"/api/auth/locations/search",
"/api/ws-stomp/**"
));
"/api/ws-stomp/**",
"/api/notifications/**"
));
WebMvcConfigurer.super.addInterceptors(registry);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import sumcoda.boardbuddy.service.ChatMessageService;
import sumcoda.boardbuddy.service.ChatRoomService;
import sumcoda.boardbuddy.service.GatherArticleService;
import sumcoda.boardbuddy.service.NotificationService;

import java.util.List;
import java.util.Map;
Expand All @@ -31,6 +32,8 @@ public class GatherArticleController {

private final ChatMessageService chatMessageService;

private final NotificationService notificationService;

/**
* 모집글 작성 컨트롤러
*
Expand All @@ -56,6 +59,8 @@ public ResponseEntity<ApiResponse<Map<String, GatherArticleResponse.CreateDTO>>>
// 채팅방 입장 메세지 전송
chatMessageService.publishEnterOrExitChatMessage(chatRoomAndNicknamePair, MessageType.ENTER);

notificationService.notifyGatherArticle(gatherArticleId, username);

return buildSuccessResponseWithPairKeyData("post", createResponse, "모집글이 업로드 되었습니다", HttpStatus.CREATED);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import sumcoda.boardbuddy.dto.NotificationResponse;
Expand All @@ -29,30 +29,34 @@ public class NotificationController {
/**
* SSE Emitter 구독 요청
*
* @param username 유저 아이디
* @param nickname 알람 구독 요청 사용자 닉네임
**/
@GetMapping(value = "/api/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter subscribe(
@RequestAttribute String username
@GetMapping(value = "/api/notifications/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public ResponseEntity<SseEmitter> subscribe(
@RequestParam String nickname
) {
log.info("User {} subscribed for notifications", username);
SseEmitter sseEmitter = notificationService.subscribe(username);
log.info("User {} subscribed for notifications", nickname);
SseEmitter sseEmitter = notificationService.subscribe(nickname);

return sseEmitter;
HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache");
headers.add("X-Accel-Buffering", "no");

return new ResponseEntity<>(sseEmitter, headers, HttpStatus.OK);
}

/**
* 알림 목록 조회 요청
*
// * @param username 유저 아이디
* @param nickname 알람 구독 요청 사용자 닉네임
* @return 알림 목록 조회 성공 시 약속된 SuccessResponse 반환
**/
@GetMapping(value = "/api/notifications")
public ResponseEntity<ApiResponse<Map<String, List<NotificationResponse.NotificationDTO>>>> getNotifications(
@RequestAttribute String username
@RequestParam String nickname
) {

List<NotificationResponse.NotificationDTO> notificationDTOs = notificationService.getNotifications(username);
List<NotificationResponse.NotificationDTO> notificationDTOs = notificationService.getNotifications(nickname);

return buildSuccessResponseWithPairKeyData("notifications", notificationDTOs, "알림이 조회되었습니다.", HttpStatus.OK);
}
Expand Down
22 changes: 19 additions & 3 deletions src/main/java/sumcoda/boardbuddy/dto/GatherArticleResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -279,9 +279,6 @@ public SimpleInfoDTO(Long gatherArticleId, String title, String meetingLocation,
}
}




@Getter
@NoArgsConstructor
public static class TitleDTO {
Expand All @@ -292,4 +289,23 @@ public TitleDTO(String title) {
this.title = title;
}
}

@Getter
@NoArgsConstructor
public static class LocationInfoDTO {
private String sido;

private String sgg;

private String emd;

@Builder
public LocationInfoDTO(String sido, String sgg, String emd) {
this.sido = sido;
this.sgg = sgg;
this.emd = emd;
}
}


}
4 changes: 2 additions & 2 deletions src/main/java/sumcoda/boardbuddy/dto/MemberResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ public LocationWithRadiusDTO(String sido, String sgg, String emd, Integer radius

@Getter
@NoArgsConstructor
public static class UserNameDTO {
public static class UsernameDTO {
private String username;

@Builder
public UserNameDTO(String username) {
public UsernameDTO(String username) {
this.username = username;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ public interface CommentRepositoryCustom {

Optional<Comment> findCommentByCommentId(Long commentId);

MemberResponse.UserNameDTO findCommentAuthorByCommentId(Long commentId);
MemberResponse.UsernameDTO findCommentAuthorByCommentId(Long commentId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ public Optional<Comment> findCommentByCommentId(Long commentId) {
}

@Override
public MemberResponse.UserNameDTO findCommentAuthorByCommentId(Long commentId) {
public MemberResponse.UsernameDTO findCommentAuthorByCommentId(Long commentId) {
return jpaQueryFactory.
select(Projections.fields(MemberResponse.UserNameDTO.class,
select(Projections.fields(MemberResponse.UsernameDTO.class,
member.username))
.from(comment)
.join(comment.member, member)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ Slice<GatherArticleResponse.ReadSliceDTO> findReadSliceDTOByLocationAndStatusAnd
GatherArticleResponse.ReadDTO findGatherArticleReadDTOByGatherArticleId(Long gatherArticleId, Long memberId);

Optional<GatherArticleResponse.TitleDTO> findTitleDTOById(Long gatherArticleId);

Optional<GatherArticleResponse.LocationInfoDTO> findLocationInfoDTOById(Long gatherArticleId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -253,4 +253,17 @@ public Optional<GatherArticleResponse.TitleDTO> findTitleDTOById(Long gatherArti
.where(gatherArticle.id.eq(gatherArticleId))
.fetchOne());
}

@Override
public Optional<GatherArticleResponse.LocationInfoDTO> findLocationInfoDTOById(Long gatherArticleId) {
return Optional.ofNullable(jpaQueryFactory
.select(Projections.fields(GatherArticleResponse.LocationInfoDTO.class,
gatherArticle.sido,
gatherArticle.sgg,
gatherArticle.emd
))
.from(gatherArticle)
.where(gatherArticle.id.eq(gatherArticleId))
.fetchOne());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ public interface MemberRepositoryCustom {

Optional<MemberResponse.LocationWithRadiusDTO> findLocationWithRadiusDTOByUsername(String username);

Optional<MemberResponse.UserNameDTO> findUserNameDTOByUsername(String username);
Optional<MemberResponse.UsernameDTO> findUserNameDTOByUsername(String username);

Optional<MemberResponse.IdDTO> findIdDTOByUsername(String username);

Optional<MemberResponse.UserNameDTO> findUsernameDTOByNickname(String nickname);
Optional<MemberResponse.UsernameDTO> findUsernameDTOByNickname(String nickname);

Optional<MemberResponse.NicknameDTO> findNicknameDTOByUsername(String username);

List<String> findUsernamesWithGatherArticleInRange(String username, String sido, String sgg, String emd);


}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sumcoda.boardbuddy.repository.member;

import com.querydsl.core.types.Projections;
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import sumcoda.boardbuddy.dto.AuthResponse;
Expand All @@ -12,7 +13,9 @@

import static sumcoda.boardbuddy.entity.QBadgeImage.badgeImage;
import static sumcoda.boardbuddy.entity.QMember.*;
import static sumcoda.boardbuddy.entity.QNearPublicDistrict.*;
import static sumcoda.boardbuddy.entity.QProfileImage.*;
import static sumcoda.boardbuddy.entity.QPublicDistrict.*;

@RequiredArgsConstructor
public class MemberRepositoryCustomImpl implements MemberRepositoryCustom {
Expand Down Expand Up @@ -112,9 +115,9 @@ public Optional<MemberResponse.LocationWithRadiusDTO> findLocationWithRadiusDTOB
}

@Override
public Optional<MemberResponse.UserNameDTO> findUserNameDTOByUsername(String username) {
public Optional<MemberResponse.UsernameDTO> findUserNameDTOByUsername(String username) {
return Optional.ofNullable(jpaQueryFactory
.select(Projections.fields(MemberResponse.UserNameDTO.class,
.select(Projections.fields(MemberResponse.UsernameDTO.class,
member.username))
.from(member)
.where(member.username.eq(username))
Expand All @@ -132,9 +135,9 @@ public Optional<MemberResponse.IdDTO> findIdDTOByUsername(String username) {
}

@Override
public Optional<MemberResponse.UserNameDTO> findUsernameDTOByNickname(String nickname) {
public Optional<MemberResponse.UsernameDTO> findUsernameDTOByNickname(String nickname) {
return Optional.ofNullable(jpaQueryFactory
.select(Projections.fields(MemberResponse.UserNameDTO.class,
.select(Projections.fields(MemberResponse.UsernameDTO.class,
member.username))
.from(member)
.where(member.nickname.eq(nickname))
Expand All @@ -150,4 +153,29 @@ public Optional<MemberResponse.NicknameDTO> findNicknameDTOByUsername(String use
.where(member.username.eq(username))
.fetchOne());
}

@Override
public List<String> findUsernamesWithGatherArticleInRange(String username, String sido, String sgg, String emd) {
return jpaQueryFactory
.select(member.username)
.from(member)
.where(
member.username.ne(username)
.and(
JPAExpressions
.selectOne()
.from(publicDistrict)
.join(nearPublicDistrict).on(publicDistrict.id.eq(nearPublicDistrict.publicDistrict.id))
.where(
nearPublicDistrict.sido.eq(sido)
.and(nearPublicDistrict.sgg.eq(sgg))
.and(nearPublicDistrict.emd.eq(emd))
.and(member.radius.goe(nearPublicDistrict.radius)) // 반경 조건
)
.exists()
)
)
.fetch();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public interface MemberGatherArticleRepositoryCustom {

boolean isHasRole(Long gatherArticleId, String username);

Optional<MemberResponse.UserNameDTO> findAuthorUsernameByGatherArticleId(Long gatherArticleId);
Optional<MemberResponse.UsernameDTO> findAuthorUsernameByGatherArticleId(Long gatherArticleId);

List<MemberResponse.UserNameDTO> findParticipantsByGatherArticleId(Long gatherArticleId);
List<MemberResponse.UsernameDTO> findParticipantsByGatherArticleId(Long gatherArticleId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ public boolean isHasRole(Long gatherArticleId, String username) {

// 모집글의 작성자를 찾는 메서드
@Override
public Optional<MemberResponse.UserNameDTO> findAuthorUsernameByGatherArticleId(Long gatherArticleId) {
public Optional<MemberResponse.UsernameDTO> findAuthorUsernameByGatherArticleId(Long gatherArticleId) {
return Optional.ofNullable(jpaQueryFactory
.select(Projections.fields(MemberResponse.UserNameDTO.class,
.select(Projections.fields(MemberResponse.UsernameDTO.class,
member.username))
.from(memberGatherArticle)
.join(memberGatherArticle.member, member)
Expand All @@ -62,9 +62,9 @@ public Optional<MemberResponse.UserNameDTO> findAuthorUsernameByGatherArticleId(

//모집글의 모든 참가자를 찾는 메서드
@Override
public List<MemberResponse.UserNameDTO> findParticipantsByGatherArticleId(Long gatherArticleId) {
public List<MemberResponse.UsernameDTO> findParticipantsByGatherArticleId(Long gatherArticleId) {
return jpaQueryFactory
.select(Projections.fields(MemberResponse.UserNameDTO.class,
.select(Projections.fields(MemberResponse.UsernameDTO.class,
member.username))
.from(memberGatherArticle)
.join(memberGatherArticle.member, member)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package sumcoda.boardbuddy.repository.notification;

import sumcoda.boardbuddy.entity.Notification;
import sumcoda.boardbuddy.dto.NotificationResponse;

import java.util.List;

public interface NotificationRepositoryCustom {

List<Notification> findNotificationByMemberUsername(String username);
List< NotificationResponse.NotificationDTO> findNotificationByMemberUsername(String username);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package sumcoda.boardbuddy.repository.notification;

import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import sumcoda.boardbuddy.entity.Notification;
import sumcoda.boardbuddy.dto.NotificationResponse;

import java.util.List;

Expand All @@ -22,8 +23,10 @@ public class NotificationRepositoryCustomImpl implements NotificationRepositoryC
* @return 최신순으로 정렬된 알림 내역
**/
@Override
public List<Notification> findNotificationByMemberUsername(String username) {
return jpaQueryFactory.selectFrom(notification)
public List< NotificationResponse.NotificationDTO> findNotificationByMemberUsername(String username) {
return jpaQueryFactory.select(Projections.fields(NotificationResponse.NotificationDTO.class,
notification.message,
notification.createdAt))
.join(notification.member, member)
.where(member.username.eq(username))
.orderBy(notification.createdAt.desc())
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/sumcoda/boardbuddy/service/CommentService.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public List<CommentResponse.InfoDTO> getComments(Long gatherArticleId, String us
public void updateComment(Long gatherArticleId, Long commentId, CommentRequest.UpdateDTO updateDTO, String username) {

// 사용자 검증
MemberResponse.UserNameDTO userNameDTO = memberRepository.findUserNameDTOByUsername(username)
MemberResponse.UsernameDTO userNameDTO = memberRepository.findUserNameDTOByUsername(username)
.orElseThrow(() -> new MemberRetrievalException("유효하지 않은 사용자입니다."));

// 모집글 검증
Expand Down Expand Up @@ -158,7 +158,7 @@ public void updateComment(Long gatherArticleId, Long commentId, CommentRequest.U
public void deleteComment(Long gatherArticleId, Long commentId, String username) {

// 사용자 검증
MemberResponse.UserNameDTO userNameDTO = memberRepository.findUserNameDTOByUsername(username)
MemberResponse.UsernameDTO userNameDTO = memberRepository.findUserNameDTOByUsername(username)
.orElseThrow(() -> new MemberRetrievalException("유효하지 않은 사용자입니다."));

// 모집글 검증
Expand Down
Loading

0 comments on commit 5abdc34

Please sign in to comment.