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

[REFACTOR] FCM 외부 API 호출 인터페이스 분리 및 기타 리팩토링 #239

Merged
merged 15 commits into from
Mar 22, 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
2 changes: 1 addition & 1 deletion .github/workflows/cd-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:

- name: Create FireBase JSON file From AWS
run: |
aws s3 cp --region ap-northeast-2 s3://${{ secrets.AWS_BUCKET_NAME }}/json/smeem_fcm.json src/main/resources/smeem_fcm.json
aws s3 cp --region ap-northeast-2 s3://${{ secrets.AWS_BUCKET_NAME }}/json/smeem_fcm.json smeem-external/src/main/resources/firebase/smeem_fcm.json

- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cd-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:

- name: Create FireBase JSON file From AWS
run: |
aws s3 cp --region ap-northeast-2 s3://${{ secrets.AWS_PROD_BUCKET_NAME }}/json/smeem_fcm.json src/main/resources/smeem_fcm.json
aws s3 cp --region ap-northeast-2 s3://${{ secrets.AWS_PROD_BUCKET_NAME }}/json/smeem_fcm.json smeem-external/src/main/resources/firebase/smeem_fcm.json

- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:

- name: Create FireBase JSON file From AWS
run: |
aws s3 cp --region ap-northeast-2 s3://${{ secrets.AWS_BUCKET_NAME }}/json/smeem_fcm.json src/main/resources/smeem_fcm.json
aws s3 cp --region ap-northeast-2 s3://${{ secrets.AWS_BUCKET_NAME }}/json/smeem_fcm.json smeem-external/src/main/resources/firebase/smeem_fcm.json

- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
Expand Down
1 change: 1 addition & 0 deletions smeem-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ dependencies {
implementation project(':smeem-common')
implementation project(':smeem-domain')
implementation project(':smeem-external')
implementation project(':smeem-batch')

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@ComponentScan(basePackages = {"com.smeem.common", "com.smeem.api", "com.smeem.domain", "com.smeem.external"})
@ComponentScan(basePackages = {"com.smeem.common", "com.smeem.api", "com.smeem.domain", "com.smeem.external", "com.smeem.batch"})
@EnableJpaRepositories(basePackages = {"com.smeem.domain"})
@EntityScan(basePackages = {"com.smeem.domain"})
public class SmemeServerRenewalApplication {
Expand Down
4 changes: 2 additions & 2 deletions smeem-api/src/main/java/com/smeem/api/test/api/TestApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public interface TestApi {
@ApiResponse(responseCode = "4xx", description = "유효하지 않은 요청"),
@ApiResponse(responseCode = "500", description = "서버 내부 오류")
})
ResponseEntity<SuccessResponse<?>> test();
ResponseEntity<SuccessResponse<?>> connect();

@Operation(summary = "푸시알림 테스트 API")
@Parameter(name = "Authorization", description = "Bearer ${Smeem Access Token}", in = HEADER, required = true)
Expand All @@ -31,5 +31,5 @@ public interface TestApi {
@ApiResponse(responseCode = "401", description = "유효하지 않은 토큰"),
@ApiResponse(responseCode = "500", description = "서버 내부 오류")
})
ResponseEntity<SuccessResponse<?>> alarmTest(Principal principal);
ResponseEntity<SuccessResponse<?>> sendMessage(Principal principal);
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ public class TestApiController implements TestApi {
private final TestService testService;

@GetMapping
public ResponseEntity<SuccessResponse<?>> test() {
public ResponseEntity<SuccessResponse<?>> connect() {
return ApiResponseUtil.success(SUCCESS_SERVER_CONNECT);
}

@GetMapping("/alarm")
public ResponseEntity<SuccessResponse<?>> alarmTest(Principal principal) {
public ResponseEntity<SuccessResponse<?>> sendMessage(Principal principal) {
val memberId = Util.getMemberId(principal);
testService.pushTest(TestPushAlarmServiceRequest.of(memberId));
testService.sendMessage(TestPushAlarmServiceRequest.of(memberId));
return ApiResponseUtil.success(SUCCESS_SEND_PUSH_ALARM);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import com.smeem.common.exception.MemberException;
import com.smeem.domain.member.model.Member;
import com.smeem.domain.member.repository.MemberRepository;
import com.smeem.external.firebase.FcmService;
import com.smeem.external.firebase.dto.request.MessagePushServiceRequest;
import com.smeem.external.firebase.NotificationService;
import com.smeem.external.firebase.dto.request.NotificationSingleRequest;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.stereotype.Service;
Expand All @@ -21,14 +21,14 @@ public class TestService {

private final MemberRepository memberRepository;

private final FcmService fcmService;
private final NotificationService notificationService;
private final ValueConfig valueConfig;

public void pushTest(final TestPushAlarmServiceRequest request) {
public void sendMessage(final TestPushAlarmServiceRequest request) {
val member = findMember(request.memberId());
val title = valueConfig.getMESSAGE_TITLE();
val body = valueConfig.getMESSAGE_BODY();
fcmService.pushMessage(MessagePushServiceRequest.of(member.getFcmToken(), title, body));
val title = valueConfig.getNOTIFICATION_TITLE();
val body = valueConfig.getNOTIFICATION_BODY();
notificationService.sendMessage(NotificationSingleRequest.of(member.getFcmToken(), title, body));
}

private Member findMember(long id) {
Expand Down
10 changes: 6 additions & 4 deletions smeem-api/src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@ logging.level:
org.hibernate.SQL: debug

fcm:
file_path: smeem_fcm.json
file_path: firebase/smeem_fcm.json
project_id: ${FCM.PROJECT_ID}
url: ${FCM.URL}
google_api: https://www.googleapis.com/auth/cloud-platform
smeem_title: "오늘의 영어 훈련, 딱 5분 걸려요!"
smeem_body: "지금 눌러서 일기 쓰기 ✍️"
cron_expression: "-"

jwt:
secret: ${JWT.SECRET}
Expand All @@ -49,6 +47,10 @@ smeem:
ios:
app: 2.0.0
force: 2.0.0
notification:
title: "오늘의 영어 훈련, 딱 5분 걸려요!"
body: "지금 눌러서 일기 쓰기 ✍️"
cron_expression: "-"

discord:
webhook:
Expand Down
17 changes: 13 additions & 4 deletions smeem-api/src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@ logging.level:
org.hibernate.SQL: debug

fcm:
file_path: smeem_fcm.json
file_path: firebase/smeem_fcm.json
project_id: ${FCM.PROJECT_ID}
url: ${FCM.URL}
google_api: https://www.googleapis.com/auth/cloud-platform
smeem_title: "오늘의 영어 훈련, 딱 5분 걸려요!"
smeem_body: "지금 눌러서 일기 쓰기 ✍️"
cron_expression: "-"

jwt:
secret: ${JWT.SECRET}
Expand All @@ -49,6 +47,17 @@ smeem:
duration:
expired: ${SMEEM.DURATION.EXPIRED}
remind: ${SMEEM.DURATION.REMIND}
client:
version:
title: "업데이트 알림"
content: "보다 나아진 스밈의 최신 버전을 준비했어요! 새로운 버전으로 업데이트 후 이용해주세요."
ios:
app: 2.0.0
force: 2.0.0
notification:
title: "오늘의 영어 훈련, 딱 5분 걸려요!"
body: "지금 눌러서 일기 쓰기 ✍️"
cron_expression: "-"

discord:
webhook:
Expand Down
10 changes: 6 additions & 4 deletions smeem-api/src/main/resources/application-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,10 @@ logging.level:
org.hibernate.SQL: debug

fcm:
file_path: smeem_fcm.json
file_path: firebase/smeem_fcm.json
project_id: ${FCM.PROJECT_ID}
url: ${FCM.URL}
google_api: https://www.googleapis.com/auth/cloud-platform
smeem_title: "오늘의 영어 훈련, 딱 5분 걸려요!"
smeem_body: "지금 눌러서 일기 쓰기 ✍️"
cron_expression: "0 0/30 * * * *"

jwt:
secret: ${JWT.SECRET}
Expand All @@ -50,6 +48,10 @@ smeem:
ios:
app: 2.0.1
force: 2.0.0 # 심사 통과 후 3.0.0 업데이트 필요
notification:
title: "오늘의 영어 훈련, 딱 5분 걸려요!"
body: "지금 눌러서 일기 쓰기 ✍️"
cron_expression: "0 0/30 * * * *"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

갑자기 궁금해졌는데, code 상에 별도로 Timezone을 명시 안했는데, 알람이 한국 시간 기준인 것은 서버 시간이 한국 시간으로 설정되어 있어서 그런거겠죠 ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵! TimezoneConfig를 통해서 디폴트 시각을 KST로 설정해두어서 그렇습니다!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아아 TimezonConfig 클래스를 만들어줬었죠 ㅋㅋㅋㅋ 굳이빈당


discord:
webhook:
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.smeem.batch.scheduler;

import com.smeem.common.config.ValueConfig;
import com.smeem.domain.member.model.Member;
import com.smeem.domain.member.repository.MemberRepository;
import com.smeem.external.firebase.NotificationService;
import com.smeem.external.firebase.dto.request.NotificationMulticastRequest;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

@Component
@EnableScheduling
@RequiredArgsConstructor
public class NotificationScheduler {

private final MemberRepository memberRepository;

private final NotificationService notificationService;
private final ValueConfig valueConfig;

@Scheduled(cron = "${smeem.notification.cron_expression}")
@Transactional(readOnly = true)
public void sendMessagesForTrainingTime() throws InterruptedException {
Thread.sleep(1000);

val members = memberRepository.findAllByTrainingTime(LocalDateTime.now());

if (!members.isEmpty()) {
val tokens = members.stream().map(Member::getFcmToken).toList();
val title = valueConfig.getNOTIFICATION_TITLE();
val body = valueConfig.getNOTIFICATION_BODY();
notificationService.sendMessages(NotificationMulticastRequest.of(tokens, title, body));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ public class ValueConfig {
@Value("${jwt.secret}")
private String JWT_SECRET;

@Value("${fcm.smeem_title}")
private String MESSAGE_TITLE;
@Value("${smeem.notification.title}")
private String NOTIFICATION_TITLE;

@Value("${fcm.smeem_body}")
private String MESSAGE_BODY;
@Value("${smeem.notification.body}")
private String NOTIFICATION_BODY;

@Value("${jwt.APPLE_URL}")
private String APPLE_URL;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.smeem.domain.member.repository;

import com.smeem.domain.member.model.Member;

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

public interface MemberCustomRepository {
List<Member> findAllByTrainingTime(LocalDateTime now);
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
package com.smeem.domain.member.repository;




import com.smeem.domain.member.model.Member;
import com.smeem.domain.member.model.SocialType;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface MemberRepository extends JpaRepository<Member, Long> {
public interface MemberRepository extends JpaRepository<Member, Long>, MemberCustomRepository {

boolean existsBySocialAndSocialId(SocialType socialType, String socialId);

Optional<Member> findBySocialAndSocialId(SocialType social, String socialId);

boolean existsByUsername(String username);

}
Original file line number Diff line number Diff line change
@@ -1,34 +1,31 @@
package com.smeem.domain.training.repository;

import static com.smeem.common.code.failure.TrainingTimeFailureCode.INVALID_DAY_OF_WEEK;
import static com.smeem.domain.member.model.QMember.member;
import static com.smeem.domain.training.model.DayType.*;
import static com.smeem.domain.training.model.QTrainingTime.trainingTime;

import java.time.LocalDateTime;
import java.util.List;
package com.smeem.domain.member.repository;

import com.querydsl.jpa.impl.JPAQueryFactory;
import com.smeem.common.exception.TrainingTimeException;
import com.smeem.domain.member.model.Member;
import com.smeem.domain.training.model.DayType;
import com.smeem.domain.training.model.TrainingTime;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import com.querydsl.jpa.impl.JPAQueryFactory;
import java.time.LocalDateTime;
import java.util.List;

import lombok.RequiredArgsConstructor;
import static com.smeem.common.code.failure.TrainingTimeFailureCode.INVALID_DAY_OF_WEEK;
import static com.smeem.domain.member.model.QMember.member;
import static com.smeem.domain.training.model.DayType.*;
import static com.smeem.domain.training.model.QTrainingTime.trainingTime;

@Repository
@RequiredArgsConstructor
public class TrainingTimeRepositoryImpl implements TrainingTimeCustomRepository {
public class MemberRepositoryImpl implements MemberCustomRepository {

private final JPAQueryFactory queryFactory;

@Override
public List<TrainingTime> getTrainingTimeForPushAlarm(LocalDateTime now) {
public List<Member> findAllByTrainingTime(LocalDateTime now) {
return queryFactory
.select(trainingTime)
.from(trainingTime)
.join(trainingTime.member, member).fetchJoin()
.selectFrom(member)
.join(member.trainingTimes, trainingTime).fetchJoin().distinct()
.where(
trainingTime.day.eq(getDayType(now.getDayOfWeek().getValue())),
trainingTime.hour.eq(now.getHour()),
Expand Down

This file was deleted.

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

import java.util.List;

public interface TrainingTimeRepository extends JpaRepository<TrainingTime, Long>, TrainingTimeCustomRepository {
public interface TrainingTimeRepository extends JpaRepository<TrainingTime, Long> {

List<TrainingTime> findAllByMember(Member member);

Expand Down
Loading
Loading