Skip to content

Commit

Permalink
Merge pull request #150 from Gamegoo-repo/feat/145
Browse files Browse the repository at this point in the history
[Feat/145] 알림 관련 API 구현
  • Loading branch information
Eunjin3395 authored Aug 11, 2024
2 parents 126e5db + ef857ca commit ddce0b7
Show file tree
Hide file tree
Showing 13 changed files with 584 additions and 261 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,14 @@ public enum ErrorStatus implements BaseErrorCode {
NOT_STAR_FRIEND(HttpStatus.BAD_REQUEST, "FRIEND410", "즐겨찾기 되어 있는 친구가 아닙니다."),

// 알림 관련 에러
NOTIFICATION_TYPE_NOT_FOUND(HttpStatus.NOT_FOUND, "NOTI401", "잘못된 알림 타입입니다."),
NOTIFICATION_TYPE_NOT_FOUND(HttpStatus.NOT_FOUND, "NOTI401", "해당 알림 타입 데이터를 찾을 수 없습니다."),
NOTIFICATION_METHOD_BAD_REQUEST(HttpStatus.BAD_REQUEST, "NOTI402", "알림 생성 메소드 호출이 잘못되었습니다."),
INVALID_NOTIFICATION_TYPE(HttpStatus.BAD_REQUEST, "NOTI403",
"잘못된 알림 조회 타입입니다. general과 friend 중 하나를 입력하세요."),
NOTIFICATION_NOT_FOUND(HttpStatus.NOT_FOUND, "NOTI404", "해당 알림 내역을 찾을 수 없습니다."),

// SOCKET 서버 API 호출 에러
SOCKET_API_RESPONSE_ERR(HttpStatus.INTERNAL_SERVER_ERROR, "SOCKET501",
SOCKET_API_RESPONSE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "SOCKET501",
"socket서버 api 요청에 실패했습니다.");

private final HttpStatus httpStatus;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package com.gamegoo.controller.notification;

import com.gamegoo.apiPayload.ApiResponse;
import com.gamegoo.converter.NotificationConverter;
import com.gamegoo.domain.notification.Notification;
import com.gamegoo.dto.notification.NotificationResponse;
import com.gamegoo.dto.notification.NotificationResponse.notificationReadDTO;
import com.gamegoo.service.notification.NotificationService;
import com.gamegoo.util.JWTUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Slice;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@Slf4j
@RequestMapping("/v1/notification")
@Tag(name = "Notification", description = "Notification 관련 API")
public class NotificationController {

private final NotificationService notificationService;

@Operation(summary = "알림 목록 조회 API", description = "알림 팝업 화면에서 알림 목록을 조회하는 API 입니다.")
@Parameters({
@Parameter(name = "cursor", description = "페이징을 위한 커서, Long 타입 notificationId를 보내주세요. 보내지 않으면 가장 최근 알림 10개를 조회합니다."),
@Parameter(name = "type", description = "알림 타입 조회 필터, general 또는 friend를 입력해주세요.")
})
@GetMapping
public ApiResponse<NotificationResponse.cursorNotificationListDTO> getNotificationList(
@RequestParam(name = "type") String type,
@RequestParam(name = "cursor", required = false) Long cursor
) {

Long memberId = JWTUtil.getCurrentUserId();

Slice<Notification> notifications = notificationService.getNotificationListByCursor(
memberId, type, cursor);

return ApiResponse.onSuccess(
NotificationConverter.toCursorNotificationListDTO(notifications));
}

@Operation(summary = "알림 전체 목록 조회 API", description = "알림 전체보기 화면에서 알림 목록을 조회하는 API 입니다.")
@Parameter(name = "page", description = "페이지 번호, 1 이상의 숫자를 입력해 주세요.")
@GetMapping("/total")
public ApiResponse<NotificationResponse.pageNotificationListDTO> getTotalNotificationList(
@RequestParam(name = "page") Integer page
) {
Long memberId = JWTUtil.getCurrentUserId();

Page<Notification> notifications = notificationService.getNotificationListByPage(
memberId, page - 1);

return ApiResponse.onSuccess(
NotificationConverter.toPageNotificationListDTO(notifications)
);
}

@Operation(summary = "알림 읽음 처리 API", description = "특정 알림을 읽음 처리하는 API 입니다.")
@Parameter(name = "notificationId", description = "읽음 처리할 알림의 id 입니다.")
@PatchMapping("/{notificationId}")
public ApiResponse<NotificationResponse.notificationReadDTO> getTotalNotificationList(
@PathVariable(name = "notificationId") Long notificationId
) {
Long memberId = JWTUtil.getCurrentUserId();

Notification notification = notificationService.readNotification(memberId, notificationId);

NotificationResponse.notificationReadDTO result = notificationReadDTO.builder()
.notificationId(notification.getId())
.message("알림 읽음 처리 성공")
.build();

return ApiResponse.onSuccess(result);
}

@Operation(summary = "안읽은 알림 개수 조회 API", description = "해당 회원의 안읽은 알림의 개수를 조회하는 API 입니다.")
@GetMapping("/unread/count")
public ApiResponse<Long> getUnreadNotificationCount(
) {
Long memberId = JWTUtil.getCurrentUserId();

return ApiResponse.onSuccess(notificationService.countUnreadNotification(memberId));
}


}
67 changes: 67 additions & 0 deletions src/main/java/com/gamegoo/converter/NotificationConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.gamegoo.converter;

import com.gamegoo.domain.notification.Notification;
import com.gamegoo.dto.notification.NotificationResponse;
import com.gamegoo.dto.notification.NotificationResponse.notificationDTO;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Slice;

public class NotificationConverter {

public static NotificationResponse.cursorNotificationListDTO toCursorNotificationListDTO(
Slice<Notification> notifications) {
List<notificationDTO> notificationDTOList = notifications.stream()
.map(NotificationConverter::toNotificationDTO).collect(Collectors.toList());

return NotificationResponse.cursorNotificationListDTO.builder()
.notificationDTOList(notificationDTOList)
.list_size(notificationDTOList.size())
.has_next(notifications.hasNext())
.next_cursor(notifications.hasNext() ? notifications.getContent().get(9).getId()
: null) // next cursor를 현재 notificationList의 가장 마지막 요소의 id로 주기
.build();
}

public static NotificationResponse.pageNotificationListDTO toPageNotificationListDTO(
Page<Notification> notifications) {
List<notificationDTO> notificationDTOList = notifications.stream()
.map(NotificationConverter::toNotificationDTO).collect(Collectors.toList());

return NotificationResponse.pageNotificationListDTO.builder()
.notificationDTOList(notificationDTOList)
.listSize(notificationDTOList.size())
.totalPage(notifications.getTotalPages())
.totalElements(notifications.getTotalElements())
.isFirst(notifications.isFirst())
.isLast(notifications.isLast())
.build();
}

public static NotificationResponse.notificationDTO toNotificationDTO(
Notification notification) {

String pageUrl = null;

if (notification.getNotificationType().getSourceUrl() != null) {
StringBuilder urlBuilder = new StringBuilder(
notification.getNotificationType().getSourceUrl());

if (notification.getSourceId() != null) {
urlBuilder.append(notification.getSourceId());
}

pageUrl = urlBuilder.toString();
}

return NotificationResponse.notificationDTO.builder()
.notificationId(notification.getId())
.notificationType(notification.getNotificationType().getId().intValue())
.content(notification.getContent())
.pageUrl(pageUrl)
.read(notification.isRead())
.createdAt(notification.getCreatedAt().withNano(0))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package com.gamegoo.domain.notification;

import com.gamegoo.domain.member.Member;
import com.gamegoo.domain.common.BaseDateTimeEntity;

import com.gamegoo.domain.member.Member;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
Expand All @@ -11,7 +10,6 @@
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
Expand Down Expand Up @@ -55,4 +53,8 @@ public void setMember(Member member) {
this.member.getNotificationList().add(this);
}

public void updateIsRead(boolean isRead) {
this.isRead = isRead;
}

}
15 changes: 13 additions & 2 deletions src/main/java/com/gamegoo/dto/board/BoardResponse.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
package com.gamegoo.dto.board;

import com.gamegoo.domain.member.Tier;
import lombok.*;

import java.time.LocalDateTime;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

public class BoardResponse {

@Getter
@Builder
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class boardInsertResponseDTO {

Long boardId;
Long memberId;
Integer profileImage;
Expand All @@ -35,6 +40,7 @@ public static class boardInsertResponseDTO {
@NoArgsConstructor
@AllArgsConstructor
public static class boardUpdateResponseDTO {

Long boardId;
Long memberId;
Integer profileImage;
Expand All @@ -56,6 +62,7 @@ public static class boardUpdateResponseDTO {
@NoArgsConstructor
@AllArgsConstructor
public static class boardListResponseDTO {

Long boardId;
Long memberId;
Integer profileImage;
Expand All @@ -78,6 +85,7 @@ public static class boardListResponseDTO {
@NoArgsConstructor
@AllArgsConstructor
public static class boardByIdResponseDTO {

Long boardId;
Long memberId;
LocalDateTime createdAt;
Expand All @@ -104,10 +112,12 @@ public static class boardByIdResponseDTO {
@NoArgsConstructor
@AllArgsConstructor
public static class boardByIdResponseForMemberDTO {

Long boardId;
Long memberId;
Boolean isBlocked;
Boolean isFriend;
Long friendRequestMemberId;
LocalDateTime createdAt;
Integer profileImage;
String gameName;
Expand All @@ -132,6 +142,7 @@ public static class boardByIdResponseForMemberDTO {
@NoArgsConstructor
@AllArgsConstructor
public static class myBoardListResponseDTO {

Long boardId;
Long memberId;
Integer profileImage;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.gamegoo.dto.notification;

import java.time.LocalDateTime;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

public class NotificationResponse {

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class cursorNotificationListDTO {

List<notificationDTO> notificationDTOList;
Integer list_size;
Boolean has_next;
Long next_cursor;
}

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class pageNotificationListDTO {

List<notificationDTO> notificationDTOList;
Integer listSize;
Integer totalPage;
Long totalElements;
Boolean isFirst;
Boolean isLast;
}

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class notificationDTO {

Long notificationId;
int notificationType;
String content;
String pageUrl;
boolean read;
LocalDateTime createdAt;
}

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class notificationReadDTO {

Long notificationId;
String message;
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
package com.gamegoo.repository.notification;

import com.gamegoo.domain.member.Member;
import com.gamegoo.domain.notification.Notification;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface NotificationRepository extends JpaRepository<Notification, Long> {
public interface NotificationRepository extends JpaRepository<Notification, Long>,
NotificationRepositoryCustom {

Page<Notification> findNotificationsByMember(Member member, Pageable pageable);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.gamegoo.repository.notification;

import com.gamegoo.domain.notification.Notification;
import org.springframework.data.domain.Slice;

public interface NotificationRepositoryCustom {

Slice<Notification> findNotificationsByCursorAndType(Long memberId, String type, Long cursor);
}
Loading

0 comments on commit ddce0b7

Please sign in to comment.