Skip to content

Commit

Permalink
내 알림 조회 및 푸쉬알림 기능 (#61)
Browse files Browse the repository at this point in the history
* Feat[#53] : 나의 모임 알림 기능

* Feat[#53] : 알림 기능 개발

* Refactor[#53] : 메인 로직 수정

* Refactor[#53] : notificationResponseList 생성 로직 수정

* Feat[#53] : 광고 알림

* Refactor[#53] : @EnableSchedule 제거

---------

Co-authored-by: Menhez Team <[email protected]>
  • Loading branch information
JaeyoungChoi98 and Menhez Team committed Mar 4, 2024
1 parent 208f66f commit 4ed75c8
Show file tree
Hide file tree
Showing 28 changed files with 454 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
public class GroupSaverApplication {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;
import java.util.function.BooleanSupplier;

import static com.sideteam.groupsaver.global.exception.club.ClubErrorCode.CLUB_MEMBER_DO_NOT_HAVE_PERMISSION;
Expand All @@ -27,6 +28,9 @@ public interface ClubMemberRepository extends JpaRepository<ClubMember, Long>, C
@Query("SELECT cm.member FROM ClubMember cm WHERE cm.club.id = :clubId")
Page<Member> findAllMembersByClubId(Long clubId, Pageable pageable);

@Query("SELECT cm.member FROM ClubMember cm WHERE cm.club.id = :clubId AND cm.member.id != :creatorId")
List<Member> findAllMembersExceptCreatorByClubId(Long clubId, long creatorId);

default void throwIfMemberNotInClub(Long memberId, Long clubId) {
if (!existsByClubIdAndMemberId(clubId, memberId)) {
throw new ClubErrorException(CLUB_MEMBER_DO_NOT_HAVE_PERMISSION, "멤버 ID: " + memberId + ", 모임 ID: " + clubId);
Expand All @@ -41,4 +45,6 @@ default BooleanSupplier isInClub(Long clubId, Long memberId) {
return () -> existsByClubIdAndMemberId(clubId, memberId);
}

@Query("SELECT cm.member FROM ClubMember cm WHERE cm.club.id = :clubId AND cm.member.id != :newMemberId")
List<Member> findAllMembersExceptNewMemberByClubId(long clubId, long newMemberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import com.sideteam.groupsaver.domain.club.repository.ClubMemberRepository;
import com.sideteam.groupsaver.domain.club.repository.ClubRepository;
import com.sideteam.groupsaver.domain.member.repository.MemberRepository;
import com.sideteam.groupsaver.domain.notification.service.NotificationService;
import com.sideteam.groupsaver.global.exception.BusinessException;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.security.access.prepost.PreAuthorize;
Expand All @@ -26,6 +28,7 @@ public class ClubMemberService {

private final ClubRepository clubRepository;
private final MemberRepository memberRepository;
private final NotificationService notificationService;

@Transactional(readOnly = true)
@PreAuthorize("@authorityChecker.hasAuthority(#memberId, @clubMemberRepository.isInClub(#clubId, #memberId))")
Expand All @@ -49,6 +52,7 @@ public void joinClub(Long clubId, Long memberId, ClubMemberRole role) {
memberRepository.getReferenceById(memberId),
role);
clubMemberRepository.save(clubMember);
notificationService.createNewMember(clubId, memberId, clubMember.getClub().getMainImage());
}

@PreAuthorize("@authorityChecker.hasAuthority(#memberId)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,24 @@
import com.sideteam.groupsaver.domain.club.repository.ClubRepository;
import com.sideteam.groupsaver.domain.location.domain.Location;
import com.sideteam.groupsaver.domain.location.repository.LocationRepository;
import com.sideteam.groupsaver.domain.member.domain.Member;
import com.sideteam.groupsaver.domain.notification.service.NotificationService;
import com.sideteam.groupsaver.global.auth.userdetails.GetAuthUserUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Random;

@Service
@RequiredArgsConstructor
@Transactional
public class ClubService {

private final ClubRepository clubRepository;

private final LocationRepository locationRepository;

private final NotificationService notificationService;

public ClubInfoResponse createClub(ClubRequest clubRequest) {
if (clubRequest.locationInfo() != null && clubRequest.locationInfo().isValidLocation()) {
Expand All @@ -29,6 +33,7 @@ public ClubInfoResponse createClub(ClubRequest clubRequest) {
}

Club club = clubRepository.save(Club.of(clubRequest));
notificationService.createNewClub(club, GetAuthUserUtils.getAuthUserId());
return ClubInfoResponse.of(club);
}

Expand Down Expand Up @@ -56,5 +61,4 @@ public void deactivateClub(Long clubId, Long memberId) {
clubRepository.deactivateClub(clubId);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
Expand All @@ -16,6 +17,7 @@
@RequiredArgsConstructor
@RequestMapping("/api/v1/club-schedules")
@RestController
@Slf4j
public class ClubScheduleController {

private final ClubScheduleService clubScheduleService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
import com.sideteam.groupsaver.domain.club_schedule.dto.request.ClubScheduleRequest;
import com.sideteam.groupsaver.domain.club_schedule.dto.response.ClubScheduleResponse;
import com.sideteam.groupsaver.domain.club_schedule.repository.ClubScheduleRepository;
import com.sideteam.groupsaver.domain.notification.service.NotificationService;
import com.sideteam.groupsaver.global.auth.userdetails.GetAuthUserUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
Expand All @@ -16,6 +19,7 @@
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Timer;

@RequiredArgsConstructor
@Slf4j
Expand All @@ -25,7 +29,7 @@ public class ClubScheduleService {

private final ClubRepository clubRepository;
private final ClubScheduleRepository clubScheduleRepository;

private final NotificationService notificationService;

@Transactional(readOnly = true)
public ClubScheduleResponse getSchedule(Long clubScheduleId) {
Expand All @@ -52,6 +56,7 @@ public Page<ClubScheduleResponse> getScheduleByClubId(Long clubId, Long memberId
public ClubScheduleResponse createSchedule(Long clubId, ClubScheduleRequest clubScheduleRequest, Long memberId) {
Club club = clubRepository.getReferenceById(clubId);
ClubSchedule clubSchedule = clubScheduleRepository.save(ClubSchedule.of(club, clubScheduleRequest));
notificationService.createNewSchedule(club.getId(), clubSchedule.getId(), club.getMainImage(), GetAuthUserUtils.getAuthUserId());
return ClubScheduleResponse.from(clubSchedule);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.sideteam.groupsaver.domain.firebase.controller;

import com.sideteam.groupsaver.domain.firebase.dto.CreateFcmTokenDto;
import com.sideteam.groupsaver.domain.firebase.dto.CreateFcmTokenRequest;
import com.sideteam.groupsaver.domain.firebase.dto.DeleteFcmTokenRequest;
import com.sideteam.groupsaver.domain.firebase.service.FcmTokenService;
import lombok.RequiredArgsConstructor;
Expand All @@ -14,7 +14,7 @@ public class FcmTokenController {
private final FcmTokenService fcmTokenService;

@PostMapping("/submit")
public ResponseEntity<?> submitFcmToken(@RequestBody CreateFcmTokenDto dto) {
public ResponseEntity<?> submitFcmToken(@RequestBody CreateFcmTokenRequest dto) {
fcmTokenService.createFcmToken(dto);
return ResponseEntity.noContent().build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import lombok.Getter;

@Getter
public class CreateFcmTokenDto {
public class CreateFcmTokenRequest {
private String email;
private String token;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ public interface FcmTokenRepository extends JpaRepository<FcmToken, Long> {
List<String> findAllTokenByEmail(String email);

void deleteByToken(String token);

List<FcmToken> findAllByEmail(String email);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
import com.google.firebase.messaging.Message;
import com.google.firebase.messaging.Notification;
import com.sideteam.groupsaver.domain.firebase.domain.FcmToken;
import com.sideteam.groupsaver.domain.firebase.dto.CreateFcmTokenDto;
import com.sideteam.groupsaver.domain.firebase.dto.CreateFcmTokenRequest;
import com.sideteam.groupsaver.domain.firebase.dto.DeleteFcmTokenRequest;
import com.sideteam.groupsaver.domain.firebase.repository.FcmTokenRepository;
import com.sideteam.groupsaver.domain.member.service.MemberService;
import com.sideteam.groupsaver.domain.member.domain.Member;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -23,28 +23,30 @@
public class FcmTokenService {
private final FcmTokenRepository fcmRepository;
private final FirebaseMessaging firebaseMessaging;
private final MemberService memberService;

public void createFcmToken(CreateFcmTokenDto dto) {
public void createFcmToken(CreateFcmTokenRequest dto) {
if (!fcmRepository.existsByToken(dto.getToken())) {
fcmRepository.save(FcmToken.of(dto.getEmail(), dto.getToken()));
}
}

public void sendNotification(String title, String body) {
List<String> tokenList = fcmRepository.findAllTokenByEmail(memberService.findMember().getEmail());
tokenList.forEach(token -> {
public void sendPushAlarm(Member member, String body) {
List<FcmToken> tokenList = fcmRepository.findAllByEmail(member.getEmail());
tokenList.forEach(FCM -> {
try {
fcmTransmit(token, title, body);
} catch (FirebaseMessagingException exception) {
log.error(exception.toString());
fcmTransmit(FCM.getToken(), body);
} catch (FirebaseMessagingException e) {
log.error("푸쉬 알람 에러 발생 : ", e);
throw new RuntimeException(e);
} catch (Exception e1) {
log.error("푸쉬 알람 에러 발생 : ", e1);
}
});
}

public void fcmTransmit(String token, String title, String body) throws FirebaseMessagingException {
public void fcmTransmit(String token, String body) throws FirebaseMessagingException {
Notification notification = Notification.builder()
.setTitle(title)
.setTitle("사부작")
.setBody(body)
.build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.sideteam.groupsaver.domain.category.domain.ClubCategoryMajor;
import com.sideteam.groupsaver.domain.join.domain.WantClubCategory;
import com.sideteam.groupsaver.domain.member.domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
Expand All @@ -15,4 +16,6 @@ public interface WantClubCategoryRepository extends JpaRepository<WantClubCatego

void deleteAllByMemberId(@Param("memberId") Long memberId);

@Query("SELECT wcc.member FROM WantClubCategory wcc WHERE wcc.categoryMajor = :major AND wcc.member.id != :creatorId")
List<Member> findAllMembersExceptCreatorByMajor(ClubCategoryMajor major, long creatorId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.sideteam.groupsaver.domain.common.BaseTimeEntity;
import com.sideteam.groupsaver.domain.join.domain.WantClubCategory;
import com.sideteam.groupsaver.domain.member.dto.request.MemberProfileUpdateRequest;
import com.sideteam.groupsaver.domain.notification.domain.Notification;
import com.sideteam.groupsaver.domain.report.domain.ReportUser;
import jakarta.persistence.*;
import lombok.AccessLevel;
Expand Down Expand Up @@ -66,6 +67,10 @@ public class Member extends BaseTimeEntity {

@Enumerated(STRING)
@Column(nullable = false)
@OneToMany(mappedBy = "member", fetch = FetchType.LAZY)
private final List<Notification> notifications = new ArrayList<>();

@Enumerated(value = EnumType.STRING)
private MemberActive activeStatus;

@Embedded
Expand Down Expand Up @@ -114,4 +119,7 @@ public void suspend() {
this.activeStatus = MemberActive.SUSPEND;
}

public void addNotification(Notification notification) {
this.notifications.add(notification);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
import com.sideteam.groupsaver.global.exception.BusinessException;
import com.sideteam.groupsaver.global.exception.member.MemberErrorCode;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.time.Instant;
import java.util.List;
import java.util.Optional;

@Repository
Expand Down Expand Up @@ -37,4 +37,7 @@ default Member findByIdOrThrow(Long id) {
Optional<Member> findByPhoneNumber(String phoneNumber);

Optional<Member> findByIdAndActiveStatus(Long id, MemberActive activeStatus);

@Query("SELECT m FROM Member m WHERE m.activeStatus = ACTIVE")
List<Member> findAllByActiveStatusIsActive();
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class MemberService {
Expand All @@ -15,4 +17,9 @@ public Member findMember() {
long memberId = GetAuthUserUtils.getAuthUserId();
return memberRepository.findById(memberId).orElseThrow(IllegalArgumentException::new);
}

// todo
public List<Member> findMemberListByCategory() {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.sideteam.groupsaver.domain.notification.controller;

import com.sideteam.groupsaver.domain.notification.dto.NotificationListResponse;
import com.sideteam.groupsaver.domain.notification.service.NotificationInfoService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/v1/notification")
@RequiredArgsConstructor
public class NotificationInfoController {
private final NotificationInfoService notificationInfoService;

@GetMapping
public ResponseEntity<NotificationListResponse> getAllNotification() {
return ResponseEntity.ok(notificationInfoService.getAllNotification());
}

@PostMapping("/open/{notificationId}")
public ResponseEntity<String> checkNotification(@PathVariable("notificationId") long notificationId) {
notificationInfoService.checkNotification(notificationId);
return ResponseEntity.ok("OK");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.sideteam.groupsaver.domain.notification.domain;

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity(name = "ad_message")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ADMessage {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String message;
}
Loading

0 comments on commit 4ed75c8

Please sign in to comment.