Skip to content

Commit

Permalink
Merge pull request #55 from Familing/develop
Browse files Browse the repository at this point in the history
알림 조회 기능 구현 배포
  • Loading branch information
JunHyeong-99 authored Aug 28, 2024
2 parents cf9b2c7 + 938f360 commit 82c152c
Show file tree
Hide file tree
Showing 20 changed files with 689 additions and 284 deletions.
2 changes: 1 addition & 1 deletion appspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ permissions:

hooks:
ApplicationStart:
- location: /home/ubuntu/action/scripts/deploy.sh #최상위 디렉토리의 script 폴더 내의 shell script가 실행된다.
- location: scripts/deploy.sh #최상위 디렉토리의 script 폴더 내의 shell script가 실행된다.
timeout: 60
runas: ubuntu
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.pinu.familing.domain.alarm;


import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public enum AlarmType {

SNAPSHOT_SUBJECT("스냅샷 주제등록"),
SNAPSHOT_REGISTER("스냅샷 등록"),
LOVECARD_RECEIVE("애정카드 받음");


private String value;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.pinu.familing.domain.alarm.controller;


import com.pinu.familing.domain.alarm.service.AlarmService;
import com.pinu.familing.global.oauth.dto.CustomOAuth2User;
import com.pinu.familing.global.oauth.dto.PrincipalDetails;
import com.pinu.familing.global.util.ApiUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1")
public class AlarmController {
private final AlarmService alarmService;

//나의 알람을 불러온다.
@GetMapping("alarms")
public ApiUtils.ApiResult<?> getAlarm(@AuthenticationPrincipal PrincipalDetails principalDetails) {

return ApiUtils.success(alarmService.loadAlarm(principalDetails.getUsername()));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.pinu.familing.domain.alarm.dto;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.pinu.familing.domain.alarm.AlarmType;
import com.pinu.familing.domain.alarm.entity.Alarm;

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public record AlarmDto(
Long id,
Boolean isRead,
String message,
AlarmType alarmType,
String alarmImg
) {
public static AlarmDto fromEntity(Alarm alarm) {
return new AlarmDto(
alarm.getId(),
alarm.getIsRead(),
alarm.getMessage(),
alarm.getAlarmType(),
alarm.getAlarmImg()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.pinu.familing.domain.alarm.dto;

import lombok.Builder;

import java.util.List;

@Builder
public record AlarmResponseDto(
List<AlarmDto> read,
List<AlarmDto> unread,
List<AlarmDto> yesterday,
List<AlarmDto> sevenday
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.pinu.familing.domain.alarm.entity;

import com.pinu.familing.domain.BaseEntity;
import com.pinu.familing.domain.alarm.AlarmType;
import com.pinu.familing.domain.user.entity.User;
import jakarta.persistence.*;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
public class Alarm extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private Boolean isRead = false; // 기본 값은 false로 읽지 않은 상태이다.

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

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

private String message;

@Enumerated(EnumType.STRING)
private AlarmType alarmType;

private String AlarmImg;

@Builder
private Alarm(Boolean isRead, User sender, User receiver, String message, AlarmType alarmType, String alarmImg) {
this.sender = sender;
this.receiver = receiver;
this.message = message;
this.alarmType = alarmType;
this.isRead = isRead != null ? isRead : false; // null일 경우 기본값으로 false 설정
this.AlarmImg = alarmImg;
}

public void readAlarm() {
this.isRead = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.pinu.familing.domain.alarm.repository;

import com.pinu.familing.domain.alarm.entity.Alarm;
import com.pinu.familing.domain.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

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

public interface AlarmRepository extends JpaRepository<Alarm, Long> {
// 특정 수신자와 읽지 않은 상태의 알람 목록을 조회하는 메서드
List<Alarm> findByReceiverAndIsReadFalse(User receiver);
List<Alarm> findByReceiverAndIsReadTrue(User receiver);

// isRead가 true이고, 24시간 이내에 생성된 알람을 조회
@Query("SELECT a FROM Alarm a WHERE a.receiver = :receiver AND a.isRead = true AND a.createDateTime >= :since")
List<Alarm> findReadAlarmsWithin24Hours(@Param("receiver") User receiver, @Param("since") LocalDateTime since);

// isRead가 true이고, 24시간 이상 7일 이내에 생성된 알람을 조회
@Query("SELECT a FROM Alarm a WHERE a.receiver = :receiver AND a.isRead = true AND a.createDateTime < :until AND a.createDateTime >= :since")
List<Alarm> findReadAlarmsBetween24HoursAnd7Days(@Param("receiver") User receiver, @Param("since") LocalDateTime since, @Param("until") LocalDateTime until);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package com.pinu.familing.domain.alarm.service;

import com.pinu.familing.domain.alarm.AlarmType;
import com.pinu.familing.domain.alarm.dto.AlarmDto;
import com.pinu.familing.domain.alarm.dto.AlarmResponseDto;
import com.pinu.familing.domain.alarm.entity.Alarm;
import com.pinu.familing.domain.alarm.repository.AlarmRepository;
import com.pinu.familing.domain.user.entity.User;
import com.pinu.familing.domain.user.repository.UserRepository;
import com.pinu.familing.global.error.CustomException;
import com.pinu.familing.global.error.ExceptionCode;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

import static com.pinu.familing.global.error.ExceptionCode.USER_NOT_FOUND;

@Service
@RequiredArgsConstructor
public class AlarmService {

private final AlarmRepository alarmRepository;
private final UserRepository userRepository;

@Transactional
public void sendAlarm(User sender, User receiver, AlarmType alarmType) {

String message = "";
String alarmImg = "";

if (alarmType == AlarmType.LOVECARD_RECEIVE) {
message = sender.getNickname() + "님이 애정카드를 보냈어요.";
alarmImg = sender.getProfileImg();
}
else if (alarmType == AlarmType.SNAPSHOT_REGISTER) {
message = sender.getNickname() + "님이 SnapShot에 사진을 등록했어요.";
alarmImg = sender.getProfileImg();
}
else if (alarmType == AlarmType.SNAPSHOT_SUBJECT) {
message = "Snap Shot의 주제 등록되었어요.";
alarmImg = "";
}

alarmRepository.save(Alarm.builder()
.sender(sender)
.message(message)
.receiver(receiver)
.alarmType(alarmType)
.alarmImg(alarmImg)
.build());
}

@Transactional
public AlarmResponseDto loadAlarm(String username){
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new CustomException(USER_NOT_FOUND));
List<Alarm> byReceiverAndIsReadFalse = alarmRepository.findByReceiverAndIsReadFalse(user);
List<Alarm> byReceiverAndIsReadTrue = alarmRepository.findByReceiverAndIsReadTrue(user);
// 현재 시간
LocalDateTime now = LocalDateTime.now();

// 24시간 전의 시간 계산
LocalDateTime oneDayAgo = now.minusHours(24);
// 7일 전 시간 계산
LocalDateTime sevenDaysAgo = now.minusDays(7);

List<Alarm> alarmsWithin24Hours = alarmRepository.findReadAlarmsWithin24Hours(user, oneDayAgo);

// 메서드 호출하여 24시간 이상 7일 이내의 알람 조회
List<Alarm> alarmsBetween24HoursAnd7Days = alarmRepository.findReadAlarmsBetween24HoursAnd7Days(user, sevenDaysAgo, oneDayAgo);

AlarmResponseDto alarmResponseDto = AlarmResponseDto.builder()
.read(byReceiverAndIsReadTrue.stream()
.map(AlarmDto::fromEntity)
.collect(Collectors.toList()))
.unread(byReceiverAndIsReadFalse.stream()
.map(AlarmDto::fromEntity)
.collect(Collectors.toList()))
.yesterday(alarmsWithin24Hours.stream()
.map(AlarmDto::fromEntity)
.collect(Collectors.toList()))
.sevenday(alarmsBetween24HoursAnd7Days.stream()
.map(AlarmDto::fromEntity)
.collect(Collectors.toList()))
.build();
// 조회한 알림 읽음으로 처리
byReceiverAndIsReadFalse.forEach(alarm -> {
alarm.readAlarm();
alarmRepository.save(alarm); // 변경된 상태를 저장하기 위해 필요
});
return alarmResponseDto;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.pinu.familing.domain.chat.entity.Message;
import com.pinu.familing.domain.chat.service.ChatService;
import com.pinu.familing.global.oauth.dto.CustomOAuth2User;
import com.pinu.familing.global.oauth.dto.PrincipalDetails;
import com.pinu.familing.global.util.ApiUtils;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
Expand All @@ -27,15 +28,15 @@ public class ChatController {

// 자기 단톡방 채팅내역 조회
@GetMapping("/chatroom/message")
public ResponseEntity<ChattingHistoryResponseDto> chattingList(@AuthenticationPrincipal CustomOAuth2User principal) {
ChattingHistoryResponseDto chattingList = chatService.getChattingList(principal.getName());
public ResponseEntity<ChattingHistoryResponseDto> chattingList(@AuthenticationPrincipal PrincipalDetails principalDetails) {
ChattingHistoryResponseDto chattingList = chatService.getChattingList(principalDetails.getUsername());
return ResponseEntity.ok(chattingList);
}

// 자신의 채팅방 정보 조회
@GetMapping("/chatroom/user")
public ApiUtils.ApiResult<?> chatRoomInfo(@AuthenticationPrincipal CustomOAuth2User principal) {
return ApiUtils.success(chatService.getChatRoomInfo(principal.getName()));
public ApiUtils.ApiResult<?> chatRoomInfo(@AuthenticationPrincipal PrincipalDetails principalDetails) {
return ApiUtils.success(chatService.getChatRoomInfo(principalDetails.getUsername()));
}

// ws.send("/pub/message", {}, JSON.stringify("메시지"); 로들어오는 요청을 처리한다.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ public ApiUtils.ApiResult<?> getLoveCardLogList(@AuthenticationPrincipal Princip
}

//원하는 가족에게 카드보내기
@PostMapping("/familys/{familys_username}")
public ApiUtils.ApiResult<?> getLoveCardLogList(@AuthenticationPrincipal PrincipalDetails principalDetails,
@PostMapping("/familys/{family_username}")
public ApiUtils.ApiResult<?> sendLoveCard(@AuthenticationPrincipal PrincipalDetails principalDetails,
@PathVariable("family_username") String familyUsername,
@RequestBody LovecardRequest lovecardRequest) {
lovecardService.sendLoveCardToFamily(principalDetails.getUsername(), familyUsername, lovecardRequest);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.pinu.familing.domain.lovecard.service;

import com.pinu.familing.domain.alarm.AlarmType;
import com.pinu.familing.domain.alarm.service.AlarmService;
import com.pinu.familing.domain.lovecard.dto.LovecardLogResponse;
import com.pinu.familing.domain.lovecard.dto.LovecardResponse;
import com.pinu.familing.domain.lovecard.entity.Lovecard;
Expand All @@ -15,14 +17,17 @@
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
@Service
@Transactional(readOnly = true)
public class LovecardService {

private final LovecardLogRepository lovecardLogRepository;
private final LovecardRepository lovecardRepository;
private final UserRepository userRepository;
private final AlarmService alarmService;

public Page<?> getLovecardPage(Pageable pageable) {
Page<LovecardResponse> lovecardResponsePage= lovecardRepository.findAll(pageable)
Expand All @@ -42,6 +47,7 @@ public Page<LovecardLogResponse> getLovecardByFamilyLogPage(String username, Str
return lovecardLogResponses;
}

@Transactional
public void sendLoveCardToFamily(String username, String familyUsername, LovecardRequest lovecardRequest) {
User sender = userRepository.findByUsername(username)
.orElseThrow(() -> new CustomException(ExceptionCode.USER_NOT_FOUND));
Expand All @@ -51,7 +57,7 @@ public void sendLoveCardToFamily(String username, String familyUsername, Lovecar

Lovecard lovecard = lovecardRepository.findById(lovecardRequest.cardId())
.orElseThrow(()-> new CustomException(ExceptionCode.LOVECARD_NOT_FOUND));

alarmService.sendAlarm(sender, receiver, AlarmType.LOVECARD_RECEIVE);
lovecardLogRepository.save(LovecardLog.builder().lovecard(lovecard).receiver(receiver).sender(sender).build());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.pinu.familing.domain.snapshot.service;

import com.pinu.familing.domain.alarm.AlarmType;
import com.pinu.familing.domain.alarm.service.AlarmService;
import com.pinu.familing.domain.family.entity.Family;
import com.pinu.familing.domain.family.repository.FamilyRepository;
import com.pinu.familing.domain.snapshot.dto.SnapshotImageRequest;
Expand Down Expand Up @@ -33,6 +35,7 @@ public class SnapshotService {
private final UserRepository userRepository;
private final TitleService titleService;
private final AwsS3Service awsS3Service;
private final AlarmService alarmService;


// 스냅샷에 이미지 등록하기 (스냅샷 이미지가 없으면 생성)
Expand All @@ -47,6 +50,9 @@ public void registerSnapshotImage(LocalDate day, String username, MultipartFile
.orElseGet(() -> createSnapshotImage(snapshot, user, day));

snapshotImage.updateImage(s3ImgDto.getUploadFileUrl());
user.getFamily().getUsers().stream()
.filter(familyMember -> !familyMember.equals(user)) // 본인을 제외하고 알람을 보내고 싶다면 이 필터를 추가합니다.
.forEach(familyMember -> alarmService.sendAlarm(user, familyMember, AlarmType.SNAPSHOT_REGISTER));
}

// 스냅샷 페이지 조회
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ public ApiUtils.ApiResult<?> changeFamilyStatus(@AuthenticationPrincipal Princip
statusService.getFamilyStatusList(principalDetails.getUsername());
return ApiUtils.success("User's status has been successfully changed.");
}
}
}
Loading

0 comments on commit 82c152c

Please sign in to comment.