Skip to content

Commit

Permalink
[FEAT] Pull Notification Pagination 적용 (#113)
Browse files Browse the repository at this point in the history
  • Loading branch information
tidavid1 committed Feb 20, 2024
1 parent b32a54e commit 0539ba3
Show file tree
Hide file tree
Showing 13 changed files with 196 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

import io.oeid.mogakgo.common.base.CursorPaginationInfoReq;
import io.oeid.mogakgo.common.base.CursorPaginationResult;
import io.oeid.mogakgo.core.properties.swagger.error.SwaggerUserErrorExamples;
import io.oeid.mogakgo.domain.notification.presentation.dto.req.FCMTokenApiRequest;
import io.oeid.mogakgo.domain.notification.presentation.dto.res.NotificationPublicApiRes;
import io.oeid.mogakgo.exception.dto.ErrorResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand All @@ -29,4 +32,18 @@ public interface NotificationSwagger {
)
ResponseEntity<Void> manageFCMToken(@Parameter(hidden = true) Long userId,
FCMTokenApiRequest request);

@Operation(summary = "알림 조회", description = "회원의 알림을 조회할 때 사용하는 API")
@ApiResponse(responseCode = "200", description = "알림 조회 성공",
content = @Content(schema = @Schema(implementation = NotificationPublicApiRes.class)))
@ApiResponse(responseCode = "404", description = "요청한 유저가 존재하지 않음", content = @Content(
mediaType = APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ErrorResponse.class),
examples = {
@ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND)
})
)
ResponseEntity<CursorPaginationResult<NotificationPublicApiRes>> getByUserId(
@Parameter(hidden = true) Long id,
CursorPaginationInfoReq pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
authentication = new JwtAuthenticationToken(oAuth2User, null,
oAuth2User.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
response.sendRedirect("/oauth/login/success");
response.sendRedirect("/oauth2/login/success");
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package io.oeid.mogakgo.domain.notification.application;

import io.oeid.mogakgo.common.base.CursorPaginationInfoReq;
import io.oeid.mogakgo.common.base.CursorPaginationResult;
import io.oeid.mogakgo.domain.notification.application.dto.req.NotificationCreateRequest;
import io.oeid.mogakgo.domain.notification.application.dto.res.NotificationCreateResponse;
import io.oeid.mogakgo.domain.notification.domain.Notification;
import io.oeid.mogakgo.domain.notification.infrastructure.NotificationJpaRepository;
import io.oeid.mogakgo.domain.notification.presentation.dto.res.NotificationPublicApiRes;
import io.oeid.mogakgo.domain.user.application.UserCommonService;
import io.oeid.mogakgo.domain.user.domain.User;
import lombok.RequiredArgsConstructor;
Expand All @@ -23,8 +26,15 @@ public class NotificationService {
@Transactional
public NotificationCreateResponse createNotification(NotificationCreateRequest request) {
log.info("createNotification request: {}", request);
User user = userCommonService.getUserById(request.getUserId());
Notification notification = notificationRepository.save(request.toEntity(user));
User sender = userCommonService.getUserById(request.getSenderId());
User receiver = userCommonService.getUserById(request.getReceiverId());
Notification notification = notificationRepository.save(request.toEntity(sender, receiver));
return NotificationCreateResponse.from(notification);
}

public CursorPaginationResult<NotificationPublicApiRes> getNotifications(Long userId,
CursorPaginationInfoReq pageable) {
User user = userCommonService.getUserById(userId);
return notificationRepository.findByUserIdWithPagination(user.getId(), pageable);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class NotificationCreateRequest {

private final Long userId;
private final Long senderId;
private final Long receiverId;
private final NotificationTag notificationTag;
private final String detailData;

public static NotificationCreateRequest of(Long userId, NotificationTag notificationTag,
public static NotificationCreateRequest of(Long senderId, Long receiverId,
NotificationTag notificationTag,
String detailData) {
return new NotificationCreateRequest(userId, notificationTag, detailData);
return new NotificationCreateRequest(senderId, receiverId, notificationTag, detailData);
}

public Notification toEntity(User user) {
return Notification.of(user, notificationTag, detailData);
public Notification toEntity(User sender, User receiver) {
return Notification.of(sender, receiver, notificationTag, detailData);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
public class NotificationCreateResponse {

private final Long id;
private final Long userId;
private final Long senderId;
private final Long receiverId;
private final NotificationTag notificationTag;
private final String detailData;
private final LocalDateTime createdAt;
Expand All @@ -21,7 +22,8 @@ public class NotificationCreateResponse {
public static NotificationCreateResponse from(Notification notification) {
return new NotificationCreateResponse(
notification.getId(),
notification.getUser().getId(),
notification.getSender().getId(),
notification.getReceiver().getId(),
notification.getNotificationTag(),
notification.getDetailData(),
notification.getCreatedAt(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,12 @@ public class Notification {
private Long id;

@ManyToOne
@JoinColumn(name = "user_id")
private User user;
@JoinColumn(name = "sender_id")
private User sender;

@ManyToOne
@JoinColumn(name = "receiver_id")
private User receiver;

@Enumerated(EnumType.STRING)
@Column(name = "tag")
Expand All @@ -50,15 +54,18 @@ public class Notification {
@Column(name = "created_at")
private LocalDateTime createdAt;

private Notification(User user, NotificationTag notificationTag, String detailData) {
this.user = user;
private Notification(User sender, User receiver, NotificationTag notificationTag,
String detailData) {
this.sender = sender;
this.receiver = receiver;
this.notificationTag = validateNotificationTag(notificationTag);
this.detailData = validateDetailData(detailData);
this.checkedYn = false;
}

public static Notification of(User user, NotificationTag notificationTag, String detail) {
return new Notification(user, notificationTag, detail);
public static Notification of(User sender, User receiver, NotificationTag notificationTag,
String detail) {
return new Notification(sender, receiver, notificationTag, detail);
}

private NotificationTag validateNotificationTag(NotificationTag notificationTag) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.oeid.mogakgo.domain.notification.infrastructure;


import io.oeid.mogakgo.common.base.CursorPaginationInfoReq;
import io.oeid.mogakgo.common.base.CursorPaginationResult;
import io.oeid.mogakgo.domain.notification.presentation.dto.res.NotificationPublicApiRes;

public interface NotificationCustomRepository {

CursorPaginationResult<NotificationPublicApiRes> findByUserIdWithPagination(Long userId, CursorPaginationInfoReq pageable);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package io.oeid.mogakgo.domain.notification.infrastructure;


import static io.oeid.mogakgo.domain.notification.domain.QNotification.notification;
import static io.oeid.mogakgo.domain.user.domain.QUser.user;

import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import io.oeid.mogakgo.common.base.CursorPaginationInfoReq;
import io.oeid.mogakgo.common.base.CursorPaginationResult;
import io.oeid.mogakgo.domain.notification.presentation.dto.res.NotificationPublicApiRes;
import io.oeid.mogakgo.domain.notification.presentation.vo.NotificationDataVo;
import io.oeid.mogakgo.domain.notification.presentation.vo.NotificationSenderVo;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

@Repository
@RequiredArgsConstructor
public class NotificationCustomRepositoryImpl implements NotificationCustomRepository {

private final JPAQueryFactory jpaQueryFactory;

public CursorPaginationResult<NotificationPublicApiRes> findByUserIdWithPagination(Long userId,
CursorPaginationInfoReq pageable) {
List<NotificationPublicApiRes> result = jpaQueryFactory.select(
Projections.constructor(
NotificationPublicApiRes.class,
notification.id,
notification.notificationTag,
Projections.constructor(
NotificationSenderVo.class,
notification.sender.username,
notification.sender.id,
notification.sender.avatarUrl
),
Projections.constructor(
NotificationDataVo.class,
notification.detailData,
notification.createdAt
)
)
)
.from(notification)
.join(notification.sender, user)
.where(
cursorIdCondition(pageable.getCursorId()),
notification.receiver.id.eq(userId))
.orderBy(notification.id.desc())
.limit(pageable.getPageSize() + 1L)
.fetch();
return CursorPaginationResult.fromDataWithExtraItemForNextCheck(result,
pageable.getPageSize());
}

private BooleanExpression cursorIdCondition(Long cursorId) {
return cursorId != null ? notification.id.lt(cursorId) : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.springframework.stereotype.Repository;

@Repository
public interface NotificationJpaRepository extends JpaRepository<Notification, Long> {
public interface NotificationJpaRepository extends JpaRepository<Notification, Long>,
NotificationCustomRepository {

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package io.oeid.mogakgo.domain.notification.presentation;

import io.oeid.mogakgo.common.annotation.UserId;
import io.oeid.mogakgo.common.base.CursorPaginationInfoReq;
import io.oeid.mogakgo.common.base.CursorPaginationResult;
import io.oeid.mogakgo.common.swagger.template.NotificationSwagger;
import io.oeid.mogakgo.domain.notification.application.FCMNotificationService;
import io.oeid.mogakgo.domain.notification.application.NotificationService;
import io.oeid.mogakgo.domain.notification.presentation.dto.req.FCMTokenApiRequest;
import io.oeid.mogakgo.domain.notification.presentation.dto.res.NotificationPublicApiRes;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -18,6 +24,7 @@
public class NotificationController implements NotificationSwagger {

private final FCMNotificationService fcmNotificationService;
private final NotificationService notificationService;

@PostMapping("/fcm")
public ResponseEntity<Void> manageFCMToken(@UserId Long userId, @RequestBody @Valid
Expand All @@ -26,5 +33,9 @@ public ResponseEntity<Void> manageFCMToken(@UserId Long userId, @RequestBody @Va
return ResponseEntity.ok().build();
}


@GetMapping
public ResponseEntity<CursorPaginationResult<NotificationPublicApiRes>> getByUserId(
@UserId Long id, @Valid @ModelAttribute CursorPaginationInfoReq pageable) {
return ResponseEntity.ok().body(notificationService.getNotifications(id, pageable));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.oeid.mogakgo.domain.notification.presentation.dto.res;

import io.oeid.mogakgo.domain.notification.domain.enums.NotificationTag;
import io.oeid.mogakgo.domain.notification.presentation.vo.NotificationDataVo;
import io.oeid.mogakgo.domain.notification.presentation.vo.NotificationSenderVo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Schema(description = "알림 API 응답")
@Getter
@AllArgsConstructor
public class NotificationPublicApiRes {

@Schema(description = "알림 ID")
private Long id;
@Schema(description = "알림 형식")
private NotificationTag tag;
private NotificationSenderVo sender;
private NotificationDataVo data;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.oeid.mogakgo.domain.notification.presentation.vo;

import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Schema(description = "알림 데이터")
@Getter
@AllArgsConstructor
public class NotificationDataVo {

private final String detail;
private final LocalDateTime createdAt;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.oeid.mogakgo.domain.notification.presentation.vo;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Schema(description = "알림 발신자 정보")
@Getter
@AllArgsConstructor(access = AccessLevel.PUBLIC)
public class NotificationSenderVo {
@Schema(description = "알림 전송자 이름", defaultValue = "mogakgo")
private String name;
@Schema(description = "알림 전송자 아이디", nullable = true)
private Long id;
@Schema(description = "알림 전송자 프로필 이미지 URL", nullable = true)
private String profileImageUrl;

}

0 comments on commit 0539ba3

Please sign in to comment.