Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/19 ✨ 알림 관련 기능 및 알림 조회 API 개발 #87

Merged
merged 2 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/main/java/cmc/peerna/apiResponse/code/ResponseStatus.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ public enum ResponseStatus implements BaseCode {
ALREADY_EXIST_PROJECT_MEMBER(OK, 2302, "이미 해당 프로젝트에 참여중입니다."),
PROJECT_SELF_INVITE(OK, 2303, "자신이 만든 프로젝트엔 참여할 수 없습니다."),

// Notice 에러
NOTICE_COUNT_ZERO(OK, 2350, "조회된 알림이 0개입니다."),



// 400번대 에러

Expand Down
36 changes: 36 additions & 0 deletions src/main/java/cmc/peerna/converter/NoticeConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cmc.peerna.converter;

import cmc.peerna.domain.Notice;
import cmc.peerna.web.dto.responseDto.NoticeResponseDto;
import org.springframework.data.domain.Page;

import java.util.List;
import java.util.stream.Collectors;

public class NoticeConverter {

public static NoticeResponseDto.NoticeSimpleInfoDto toNoticeSimpleProfile(Notice notice) {
return NoticeResponseDto.NoticeSimpleInfoDto.builder()
.targetId(notice.getTargetId())
.noticeType(notice.getNoticeType())
.contents(notice.getContents())
.createdTime(notice.getCreatedAt())
.build();
}

public static NoticeResponseDto.NoticePageDto toNoticePageDto(Page<Notice> noticePage) {
if(noticePage.getTotalElements()==0L) return null;
List<NoticeResponseDto.NoticeSimpleInfoDto> noticeSimpleInfoDtoList = noticePage.stream()
.map(notice -> toNoticeSimpleProfile(notice))
.collect(Collectors.toList());

return NoticeResponseDto.NoticePageDto.builder()
.noticeList(noticeSimpleInfoDtoList)
.isFirst(noticePage.isFirst())
.isLast(noticePage.isLast())
.totalPage(noticePage.getTotalPages())
.totalElements(noticePage.getTotalElements())
.currentPageElements(noticePage.getNumberOfElements())
.build();
}
}
5 changes: 5 additions & 0 deletions src/main/java/cmc/peerna/domain/Notice.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmc.peerna.domain;

import cmc.peerna.domain.common.BaseEntity;
import cmc.peerna.domain.enums.NoticeGroup;
import cmc.peerna.domain.enums.NoticeType;
import jakarta.persistence.*;
import lombok.*;
Expand All @@ -23,8 +24,12 @@ public class Notice extends BaseEntity {
@JoinColumn(name = "receiver_id")
private Member receiver;

@Enumerated(EnumType.STRING)
private NoticeGroup noticeGroup;

@Enumerated(EnumType.STRING)
private NoticeType noticeType;
private Long targetId;

private String contents;

Expand Down
13 changes: 13 additions & 0 deletions src/main/java/cmc/peerna/domain/enums/NoticeGroup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package cmc.peerna.domain.enums;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum NoticeGroup {
PROJECT("프로젝트 관련 알림"),
PEER_TEST("피어테스트 관련 알림");

private final String description;
}
14 changes: 13 additions & 1 deletion src/main/java/cmc/peerna/domain/enums/NoticeType.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
package cmc.peerna.domain.enums;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum NoticeType {
PROJECT_SUGGEST, PROJECT_INVITE
INVITED_TO_OTHER_PROJECT("남의 프로젝트에 참여 제안 받음"),
OTHER_USER_REQUESTED_MY_PROJECT("남이 내 프로젝트에 참여 신청함."),
OTHER_PROJECT_MY_REQUEST_ACCEPTED("남의 프로젝트에 대한 내 참여 요청이 수락됨."),
OTHER_PROJECT_MY_REQUEST_DECLINED("남의 프로젝트에 대한 내 참여 요청이 거절됨."),
MY_PROJECT_MY_INVITE_ACCEPTED("나의 프로젝트에 대한 내 참여 제안이 수락됨."),
MY_PROJECT_MY_INVITE_DECLINED("나의 프로젝트에 대한 내 참여 제안이 거절됨.");

private final String description;
}
13 changes: 0 additions & 13 deletions src/main/java/cmc/peerna/domain/enums/NotificationType.java

This file was deleted.

13 changes: 13 additions & 0 deletions src/main/java/cmc/peerna/repository/NoticeRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package cmc.peerna.repository;

import cmc.peerna.domain.Member;
import cmc.peerna.domain.Notice;
import cmc.peerna.domain.enums.NoticeGroup;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.repository.JpaRepository;

public interface NoticeRepository extends JpaRepository<Notice, Long> {

Page<Notice> findAllByNoticeGroupAndReceiver(NoticeGroup noticeGroup, Member receiver, PageRequest pageRequest);
}
15 changes: 15 additions & 0 deletions src/main/java/cmc/peerna/service/NoticeService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cmc.peerna.service;

import cmc.peerna.domain.Member;
import cmc.peerna.domain.enums.NoticeGroup;
import cmc.peerna.domain.enums.NoticeType;
import cmc.peerna.web.dto.responseDto.NoticeResponseDto;

public interface NoticeService {
void createNotice(Member sender, Long receiverId, NoticeType noticeType);

NoticeResponseDto.NoticePageDto getNoticePageByNoticeGroup(Member receiver, NoticeGroup noticeGroup, Integer page);

NoticeResponseDto.NoticePageDto getProjectNoticePage(Member receiver, Integer page);
NoticeResponseDto.NoticePageDto getPeerTestNoticePage(Member receiver, Integer page);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package cmc.peerna.service.serviceImpl;

import cmc.peerna.apiResponse.code.ResponseStatus;
import cmc.peerna.apiResponse.exception.handler.MemberException;
import cmc.peerna.apiResponse.exception.handler.RootException;
import cmc.peerna.converter.NoticeConverter;
import cmc.peerna.domain.Member;
import cmc.peerna.domain.Notice;
import cmc.peerna.domain.enums.NoticeGroup;
import cmc.peerna.domain.enums.NoticeType;
import cmc.peerna.repository.MemberRepository;
import cmc.peerna.repository.NoticeRepository;
import cmc.peerna.service.NoticeService;
import cmc.peerna.web.dto.responseDto.NoticeResponseDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Slf4j
@RequiredArgsConstructor
public class NoticeServiceImpl implements NoticeService {

private final NoticeRepository noticeRepository;
private final MemberRepository memberRepository;

@Value("${paging.size}")
private Integer pageSize;

@Override
@Transactional
public void createNotice(Member sender, Long receiverId, NoticeType noticeType) {
Member receiver = memberRepository.findById(receiverId).orElseThrow(() -> new MemberException(ResponseStatus.MEMBER_NOT_FOUND));
noticeRepository.save(Notice.builder()
.sender(sender)
.receiver(receiver)
.noticeType(noticeType)
.build()
);
}

@Override
public NoticeResponseDto.NoticePageDto getNoticePageByNoticeGroup(Member receiver, NoticeGroup noticeGroup, Integer page) {

PageRequest pageRequest = PageRequest.of(page, pageSize, Sort.by(Sort.Order.desc("createdAt")));
Page<Notice> noticeByNoticeGroup = noticeRepository.findAllByNoticeGroupAndReceiver(noticeGroup, receiver, pageRequest);
if (noticeByNoticeGroup.getTotalElements() == 0L) {
throw new RootException(ResponseStatus.NOTICE_COUNT_ZERO);
}
if (noticeByNoticeGroup.getTotalPages() <= page)
throw new MemberException(ResponseStatus.OVER_PAGE_INDEX_ERROR);

NoticeResponseDto.NoticePageDto noticePageDto = NoticeConverter.toNoticePageDto(noticeByNoticeGroup);
return noticePageDto;
}

@Override
public NoticeResponseDto.NoticePageDto getProjectNoticePage(Member receiver, Integer page) {
return getNoticePageByNoticeGroup(receiver, NoticeGroup.PROJECT, page);
}

@Override
public NoticeResponseDto.NoticePageDto getPeerTestNoticePage(Member receiver, Integer page) {
return getNoticePageByNoticeGroup(receiver, NoticeGroup.PEER_TEST, page);
}

}
79 changes: 78 additions & 1 deletion src/main/java/cmc/peerna/web/controller/HomeController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

import cmc.peerna.apiResponse.code.ResponseStatus;
import cmc.peerna.apiResponse.exception.handler.MemberException;
import cmc.peerna.apiResponse.response.PageResponseDto;
import cmc.peerna.apiResponse.response.ResponseDto;
import cmc.peerna.domain.Member;
import cmc.peerna.fcm.service.FcmService;
import cmc.peerna.jwt.handler.annotation.AuthMember;
import cmc.peerna.service.MemberService;
import cmc.peerna.service.NoticeService;
import cmc.peerna.service.RootService;
import cmc.peerna.validation.annotation.CheckPage;
import cmc.peerna.web.dto.requestDto.RootRequestDto;
import cmc.peerna.web.dto.responseDto.HomeResponseDto;
import cmc.peerna.web.dto.responseDto.NoticeResponseDto;
import cmc.peerna.web.dto.responseDto.ProjectResponseDto;
import cmc.peerna.web.dto.responseDto.RootResponseDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand All @@ -26,6 +30,8 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@Slf4j
@RequiredArgsConstructor
Expand All @@ -44,6 +50,7 @@ public class HomeController {

private final MemberService memberService;
private final RootService rootService;
private final NoticeService noticeService;


@Operation(summary = "피어 유형으로 동료 찾기 API ✔️🔑", description = "피어 유형으로 동료 찾기 API입니다.")
Expand Down Expand Up @@ -127,4 +134,74 @@ else if (page < 1)
RootResponseDto.AllFeedbackDto feedbackList = rootService.getFeedbackList(peer, page);
return ResponseDto.of(feedbackList);
}

@Operation(summary = "알림 - 피어테스트 알림 조회 API ✔️🔑", description = "알림 - 피어테스트 알림 조회 API입니다.")
@ApiResponses({
@ApiResponse(responseCode = "2200", description = "BAD_REQUEST, 존재하지 않는 유저를 조회한 경우."),
@ApiResponse(responseCode = "2350", description = "BAD_REQUEST, 조회된 알림이 0개입니다."),
@ApiResponse(responseCode = "4012", description = "BAD_REQUEST , 페이지 번호는 1 이상이여야 합니다.", content = @Content(schema = @Schema(implementation = ResponseDto.class))),
@ApiResponse(responseCode = "4013", description = "BAD_REQUEST , 페이지 번호가 페이징 범위를 초과했습니다.", content = @Content(schema = @Schema(implementation = ResponseDto.class))),
})
@Parameters({
@Parameter(name = "member", hidden = true)
})
@GetMapping("/home/notice/peer-test")
public PageResponseDto<List<NoticeResponseDto.NoticeSimpleInfoDto>> getPeerTestNotice(@AuthMember Member member, @CheckPage @RequestParam(name = "page") Integer page) {
if (page == null)
page = 1;
else if (page < 1)
throw new MemberException(ResponseStatus.UNDER_PAGE_INDEX_ERROR);
page -= 1;

NoticeResponseDto.NoticePageDto peerTestNoticePage = noticeService.getPeerTestNoticePage(member, page);

List<NoticeResponseDto.NoticeSimpleInfoDto> peerTestNoticeList;
peerTestNoticeList = peerTestNoticePage.getNoticeList();

RootRequestDto.PageRequestDto pageRequestDto = RootRequestDto.PageRequestDto.builder()
.totalElements(peerTestNoticePage.getTotalElements())
.currentPageElements(peerTestNoticePage.getCurrentPageElements())
.totalPage(peerTestNoticePage.getTotalPage())
.isFirst(peerTestNoticePage.getIsFirst())
.isLast(peerTestNoticePage.getIsLast())
.build();

return PageResponseDto.of(peerTestNoticeList, pageRequestDto);
}


@Operation(summary = "알림 - 프로젝트 알림 조회 API ✔️🔑", description = "알림 - 프로젝트 알림 조회 API입니다.")
@ApiResponses({
@ApiResponse(responseCode = "2200", description = "BAD_REQUEST, 존재하지 않는 유저를 조회한 경우."),
@ApiResponse(responseCode = "2350", description = "BAD_REQUEST, 조회된 알림이 0개입니다."),
@ApiResponse(responseCode = "4012", description = "BAD_REQUEST , 페이지 번호는 1 이상이여야 합니다.", content = @Content(schema = @Schema(implementation = ResponseDto.class))),
@ApiResponse(responseCode = "4013", description = "BAD_REQUEST , 페이지 번호가 페이징 범위를 초과했습니다.", content = @Content(schema = @Schema(implementation = ResponseDto.class))),
})
@Parameters({
@Parameter(name = "member", hidden = true)
})
@GetMapping("/home/notice/project")
public PageResponseDto<List<NoticeResponseDto.NoticeSimpleInfoDto>> getProjectNotice(@AuthMember Member member, @CheckPage @RequestParam(name = "page") Integer page) {
if (page == null)
page = 1;
else if (page < 1)
throw new MemberException(ResponseStatus.UNDER_PAGE_INDEX_ERROR);
page -= 1;

NoticeResponseDto.NoticePageDto peerTestNoticePage = noticeService.getProjectNoticePage(member, page);

List<NoticeResponseDto.NoticeSimpleInfoDto> projectNoticeList;
projectNoticeList = peerTestNoticePage.getNoticeList();

RootRequestDto.PageRequestDto pageRequestDto = RootRequestDto.PageRequestDto.builder()
.totalElements(peerTestNoticePage.getTotalElements())
.currentPageElements(peerTestNoticePage.getCurrentPageElements())
.totalPage(peerTestNoticePage.getTotalPage())
.isFirst(peerTestNoticePage.getIsFirst())
.isLast(peerTestNoticePage.getIsLast())
.build();

return PageResponseDto.of(projectNoticeList, pageRequestDto);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cmc.peerna.web.dto.responseDto;

import cmc.peerna.domain.enums.NoticeType;
import lombok.*;

import java.time.LocalDateTime;
import java.util.List;

public class NoticeResponseDto {
@Builder
@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public static class NoticeSimpleInfoDto {
private Long targetId;

// 알림의 좌측 아이콘 구분 위한 필드
private NoticeType noticeType;
private String contents;
private LocalDateTime createdTime;

}

@Builder
@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public static class NoticePageDto{
List<NoticeResponseDto.NoticeSimpleInfoDto> noticeList;
Long totalElements;
Integer currentPageElements;
Integer totalPage;
Boolean isFirst;
Boolean isLast;
}
}
Loading