From ec1a7d1818a6bf07609c228940f7c9a51b3d6c31 Mon Sep 17 00:00:00 2001 From: ch8930 Date: Thu, 24 Oct 2024 04:25:13 +0900 Subject: [PATCH 1/8] feat: TT-486 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fcm기반 Notification 보내는 기능 개발 - gpt-api에게 STT 스크립트 내용 분석 요청하는 부분 개발 - Script Entity에 분석결과 컬럼 추가 및 gpt응답 결과 저장 후 fcm 보내도록 기능 - 녹음 기반 기능을 진행할 경우 STT 처리 후 분석결과 로직 추가함(+ 비동기로 처리함) --- .github/workflows/cd_prod.yml | 10 ++++ .github/workflows/ci_prod.yml | 11 ++++- .github/workflows/cicd_dev.yml | 10 ++++ .gitignore | 3 ++ build.gradle | 2 + .../twentythree/peech/PeechApplication.java | 2 + .../application/AnalyzeScriptFacade.java | 26 ++++++++++ .../client/AnalyzeScriptGPT.java | 15 ++++++ .../domain/AnalyzeScriptPredictor.java | 47 +++++++++++++++++++ .../analyzescript/dto/request/GPTRequest.java | 14 ++++++ .../fcm/application/NotificationService.java | 31 ++++++++++++ .../peech/fcm/client/FCMClient.java | 21 +++++++++ .../peech/fcm/config/FcmConfig.java | 37 +++++++++++++++ .../peech/fcm/dto/FCMMessageDTO.java | 35 ++++++++++++++ .../peech/fcm/entity/NotificationEntity.java | 34 ++++++++++++++ .../peech/fcm/event/FCMPushedEvent.java | 12 +++++ .../fcm/event/handler/FCMEventHandler.java | 41 ++++++++++++++++ .../fcm/infra/NotificationRepository.java | 14 ++++++ .../peech/script/domain/ScriptEntity.java | 6 ++- .../script/repository/ScriptRepository.java | 5 ++ .../peech/script/service/ScriptService.java | 6 +++ .../script/stt/service/ProcessSTTService.java | 23 +++++++-- src/main/resources/application.yml | 7 +++ 23 files changed, 405 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/twentythree/peech/analyzescript/application/AnalyzeScriptFacade.java create mode 100644 src/main/java/com/twentythree/peech/analyzescript/client/AnalyzeScriptGPT.java create mode 100644 src/main/java/com/twentythree/peech/analyzescript/domain/AnalyzeScriptPredictor.java create mode 100644 src/main/java/com/twentythree/peech/analyzescript/dto/request/GPTRequest.java create mode 100644 src/main/java/com/twentythree/peech/fcm/application/NotificationService.java create mode 100644 src/main/java/com/twentythree/peech/fcm/client/FCMClient.java create mode 100644 src/main/java/com/twentythree/peech/fcm/config/FcmConfig.java create mode 100644 src/main/java/com/twentythree/peech/fcm/dto/FCMMessageDTO.java create mode 100644 src/main/java/com/twentythree/peech/fcm/entity/NotificationEntity.java create mode 100644 src/main/java/com/twentythree/peech/fcm/event/FCMPushedEvent.java create mode 100644 src/main/java/com/twentythree/peech/fcm/event/handler/FCMEventHandler.java create mode 100644 src/main/java/com/twentythree/peech/fcm/infra/NotificationRepository.java diff --git a/.github/workflows/cd_prod.yml b/.github/workflows/cd_prod.yml index a64a8b5f..9e1b3461 100644 --- a/.github/workflows/cd_prod.yml +++ b/.github/workflows/cd_prod.yml @@ -39,6 +39,7 @@ jobs: logging.level.com.twentythree.peech: off logging.config: classpath:spring-logback.xml gpt.api.key: ${{secrets.GPT_API_KEY_PROD}} + gpt.prompt.system: ${{secrets.GPT_PROMPT_SYSTEM}} jwt.secret.key: ${{secrets.JWT_SECRET_KEY_PROD}} jwt.access.key: ${{secrets.JWT_ACCESS_KEY}} jwt.refresh.key: ${{secrets.JWT_REFRESH_KEY}} @@ -55,6 +56,9 @@ jobs: ffmpeg.path: ${{ secrets.FFMPEG_PATH_PROD }} ffprobe.path: ${{ secrets.FFPROBE_PATH_PROD }} spring.cors.allowed-origins: ${{ secrets.CORS_ALLOWED_ORIGINS_PROD }} + fcm.secret-key: ${{ secrets.FCM_SECRET_KEY }} + fcm.key-path: ${{ secrets.FCM_KEY_PATH }} + fcm.project-id: ${{ secrets.FCM_PROJECT_ID }} # application.yml 파일 내용 확인 @@ -64,6 +68,12 @@ jobs: - name: Run chmod to make gradlew executable run: chmod +x ./gradlew + # fcm 서버 키 설정 + - name: Set up FCM server key + run: | + cd ./peech/src/main/resources/ + echo "${{ secrets.FCM_SECRET_KEY }}" > ./peech_fcm.json + # 2. Spring Boot 애플리케이션 빌드 - name: Build with Gradle uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 diff --git a/.github/workflows/ci_prod.yml b/.github/workflows/ci_prod.yml index 8cb276d8..8b89ecbf 100644 --- a/.github/workflows/ci_prod.yml +++ b/.github/workflows/ci_prod.yml @@ -39,6 +39,7 @@ jobs: logging.level.com.twentythree.peech: off logging.config: classpath:spring-logback.xml gpt.api.key: ${{secrets.GPT_API_KEY_PROD}} + gpt.prompt.system: ${{secrets.GPT_PROMPT_SYSTEM}} jwt.secret.key: ${{secrets.JWT_SECRET_KEY_PROD}} jwt.access.key: ${{secrets.JWT_ACCESS_KEY}} jwt.refresh.key: ${{secrets.JWT_REFRESH_KEY}} @@ -55,7 +56,9 @@ jobs: ffmpeg.path: ${{ secrets.FFMPEG_PATH_PROD }} ffprobe.path: ${{ secrets.FFPROBE_PATH_PROD }} spring.cors.allowed-origins: ${{ secrets.CORS_ALLOWED_ORIGINS_PROD }} - + fcm.secret-key: ${{ secrets.FCM_SECRET_KEY }} + fcm.key-path: ${{ secrets.FCM_KEY_PATH }} + fcm.project-id: ${{ secrets.FCM_PROJECT_ID }} # application.yml 파일 내용 확인 - name: Display modified application.yml @@ -64,6 +67,12 @@ jobs: - name: Run chmod to make gradlew executable run: chmod +x ./gradlew + # fcm 서버 키 설정 + - name: Set up FCM server key + run: | + cd ./peech/src/main/resources/ + echo "${{ secrets.FCM_SECRET_KEY }}" > ./peech_fcm.json + # 2. Spring Boot 애플리케이션 빌드 - name: Build with Gradle uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 diff --git a/.github/workflows/cicd_dev.yml b/.github/workflows/cicd_dev.yml index b9d1b79c..c58d61bc 100644 --- a/.github/workflows/cicd_dev.yml +++ b/.github/workflows/cicd_dev.yml @@ -40,6 +40,7 @@ jobs: logging.level.com.twentythree.peech: off logging.config: classpath:spring-logback.xml gpt.api.key: ${{secrets.GPT_API_KEY}} + gpt.prompt.system: ${{secrets.GPT_PROMPT_SYSTEM}} jwt.secret.key: ${{secrets.JWT_SECRET_KEY}} jwt.access.key: ${{secrets.JWT_ACCESS_KEY}} jwt.refresh.key: ${{secrets.JWT_REFRESH_KEY}} @@ -56,6 +57,9 @@ jobs: ffmpeg.path: ${{ secrets.FFMPEG_PATH_DEV }} ffprobe.path: ${{ secrets.FFPROBE_PATH_DEV }} spring.cors.allowed-origins: ${{ secrets.CORS_ALLOWED_ORIGINS }} + fcm.secret-key: ${{ secrets.FCM_SECRET_KEY }} + fcm.key-path: ${{ secrets.FCM_KEY_PATH }} + fcm.project-id: ${{ secrets.FCM_PROJECT_ID }} # application.yml 파일 내용 확인 - name: Display modified application.yml @@ -63,6 +67,12 @@ jobs: # excute 허용 - name: Run chmod to make gradlew executable run: chmod +x ./gradlew + + # fcm 서버 키 설정 + - name: Set up FCM server key + run: | + cd ./peech/src/main/resources/ + echo "${{ secrets.FCM_SECRET_KEY }}" > ./peech_fcm.json # 2. Spring Boot 애플리케이션 빌드 - name: Build with Gradle diff --git a/.gitignore b/.gitignore index 2d92286e..43d45845 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,6 @@ data.sql ### Logging File ### /logs/** + +### FCM Admin SDK ### +**/src/main/resources/peech_fcm.json \ No newline at end of file diff --git a/build.gradle b/build.gradle index e0b0919d..da4b68e5 100644 --- a/build.gradle +++ b/build.gradle @@ -95,6 +95,8 @@ dependencies { // ffmpeg implementation 'net.bramp.ffmpeg:ffmpeg:0.8.0' + //firebase sdk + implementation 'com.google.firebase:firebase-admin:9.3.0' } diff --git a/src/main/java/com/twentythree/peech/PeechApplication.java b/src/main/java/com/twentythree/peech/PeechApplication.java index d064f5e6..e8168248 100644 --- a/src/main/java/com/twentythree/peech/PeechApplication.java +++ b/src/main/java/com/twentythree/peech/PeechApplication.java @@ -3,7 +3,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.scheduling.annotation.EnableAsync; +@EnableAsync @EnableJpaAuditing @SpringBootApplication public class PeechApplication { diff --git a/src/main/java/com/twentythree/peech/analyzescript/application/AnalyzeScriptFacade.java b/src/main/java/com/twentythree/peech/analyzescript/application/AnalyzeScriptFacade.java new file mode 100644 index 00000000..2360e641 --- /dev/null +++ b/src/main/java/com/twentythree/peech/analyzescript/application/AnalyzeScriptFacade.java @@ -0,0 +1,26 @@ +package com.twentythree.peech.analyzescript.application; + +import com.twentythree.peech.analyzescript.domain.AnalyzeScriptPredictor; +import com.twentythree.peech.fcm.application.NotificationService; +import com.twentythree.peech.script.service.ScriptService; +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@RequiredArgsConstructor +@Service +public class AnalyzeScriptFacade { + + private final AnalyzeScriptPredictor analyzeScriptPredictor; + private final ScriptService scriptService; + private final NotificationService notificationService; + + @Async + public void analyzeScriptAndSave(Long userId, Long scriptId, String scriptContent) { + analyzeScriptPredictor.requestAnalyzeScript(scriptContent) + .thenAccept(result -> { + scriptService.reflectAnalyzeResult(scriptId, result); + notificationService.pushNotification(userId); + }); + } +} diff --git a/src/main/java/com/twentythree/peech/analyzescript/client/AnalyzeScriptGPT.java b/src/main/java/com/twentythree/peech/analyzescript/client/AnalyzeScriptGPT.java new file mode 100644 index 00000000..95035993 --- /dev/null +++ b/src/main/java/com/twentythree/peech/analyzescript/client/AnalyzeScriptGPT.java @@ -0,0 +1,15 @@ +package com.twentythree.peech.analyzescript.client; + +import com.twentythree.peech.analyzescript.dto.request.GPTRequest; +import com.twentythree.peech.common.dto.response.GPTResponse; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; + +@FeignClient( + name = "analyzeScriptGPT", + url = "https://api.openai.com/") +public interface AnalyzeScriptGPT { + + @PostMapping("v1/chat/completions") + GPTResponse analyzeScript(GPTRequest gptRequest); +} diff --git a/src/main/java/com/twentythree/peech/analyzescript/domain/AnalyzeScriptPredictor.java b/src/main/java/com/twentythree/peech/analyzescript/domain/AnalyzeScriptPredictor.java new file mode 100644 index 00000000..423c8108 --- /dev/null +++ b/src/main/java/com/twentythree/peech/analyzescript/domain/AnalyzeScriptPredictor.java @@ -0,0 +1,47 @@ +package com.twentythree.peech.analyzescript.domain; + +import com.twentythree.peech.analyzescript.client.AnalyzeScriptGPT; +import com.twentythree.peech.analyzescript.dto.request.GPTRequest; +import com.twentythree.peech.aop.annotation.Trace; +import com.twentythree.peech.common.dto.Message; +import com.twentythree.peech.common.dto.response.GPTResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Async +@RequiredArgsConstructor +@Component +public class AnalyzeScriptPredictor { + + @Value("${gpt.prompt.system}") + private String gptSystemPrompt; + + private final AnalyzeScriptGPT analyzeScriptGPT; + + @Trace + public CompletableFuture requestAnalyzeScript(String scriptContent) { + List messages = new ArrayList<>(); + + String systemPrompt = gptSystemPrompt; + messages.add(new Message("system", systemPrompt)); + + String userPrompt = "아래의 글은 회사 면접을 위한 자기소개서입니다. 내용을 보고 자기소개서를 분석해주세요.\n"+ + "자기소개서: " + + scriptContent; + messages.add(new Message("user", userPrompt)); + + GPTRequest gptRequest = new GPTRequest("gpt-4o-mini", messages); + GPTResponse gptResponse = analyzeScriptGPT.analyzeScript(gptRequest); + String result = gptResponse.getChoices().get(0).getMessage().getContent(); + + return CompletableFuture.completedFuture(result); + } + +} diff --git a/src/main/java/com/twentythree/peech/analyzescript/dto/request/GPTRequest.java b/src/main/java/com/twentythree/peech/analyzescript/dto/request/GPTRequest.java new file mode 100644 index 00000000..62e3862b --- /dev/null +++ b/src/main/java/com/twentythree/peech/analyzescript/dto/request/GPTRequest.java @@ -0,0 +1,14 @@ +package com.twentythree.peech.analyzescript.dto.request; + +import com.twentythree.peech.common.dto.Message; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; + +@Getter +@AllArgsConstructor +public class GPTRequest { + private String model; + private List messages; +} diff --git a/src/main/java/com/twentythree/peech/fcm/application/NotificationService.java b/src/main/java/com/twentythree/peech/fcm/application/NotificationService.java new file mode 100644 index 00000000..26ff1fe1 --- /dev/null +++ b/src/main/java/com/twentythree/peech/fcm/application/NotificationService.java @@ -0,0 +1,31 @@ +package com.twentythree.peech.fcm.application; + +import com.twentythree.peech.aop.annotation.Trace; +import com.twentythree.peech.fcm.event.FCMPushedEvent; +import com.twentythree.peech.fcm.infra.NotificationRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; + +import java.util.List; + +@RequiredArgsConstructor +@Service +public class NotificationService { + + private final NotificationRepository notificationRepository; + private final ApplicationEventPublisher applicationEventPublisher; + + @Trace + public void pushNotification(Long userId) { +// List fcmTokenList = notificationRepository.findAllByUserId(userId); +// +// if(fcmTokenList.isEmpty()){ +// throw new IllegalStateException("FCM 토큰이 존재하지 않습니다."); +// } + + List fcmTokenList = List.of("testFcmToken1", "testFcmToken2", "testFcmToken3"); + + applicationEventPublisher.publishEvent(new FCMPushedEvent(fcmTokenList)); + } +} diff --git a/src/main/java/com/twentythree/peech/fcm/client/FCMClient.java b/src/main/java/com/twentythree/peech/fcm/client/FCMClient.java new file mode 100644 index 00000000..0ecadcbf --- /dev/null +++ b/src/main/java/com/twentythree/peech/fcm/client/FCMClient.java @@ -0,0 +1,21 @@ +package com.twentythree.peech.fcm.client; + + +import com.google.firebase.messaging.FirebaseMessaging; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.PostMapping; + +@FeignClient( + name = "FCMClient", + url = "https://fcm.googleapis.com/v1/projects/${fcm.project-id}/messages:send" +) +public interface FCMClient { + + @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE) + void sendNotification( + FirebaseMessaging message + ); + + +} diff --git a/src/main/java/com/twentythree/peech/fcm/config/FcmConfig.java b/src/main/java/com/twentythree/peech/fcm/config/FcmConfig.java new file mode 100644 index 00000000..5ad9ca36 --- /dev/null +++ b/src/main/java/com/twentythree/peech/fcm/config/FcmConfig.java @@ -0,0 +1,37 @@ +package com.twentythree.peech.fcm.config; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import jakarta.annotation.PostConstruct; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import java.io.IOException; +import java.io.InputStream; + + +@Configuration +public class FcmConfig { + + @Value("${fcm.key-path}") + private String fcmKeyPath; + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + @PostConstruct + private void init() throws IOException { + if (FirebaseApp.getApps().isEmpty()) { + log.info("FirebaseApp을 초기화합니다"); + InputStream firebaseAccount = new ClassPathResource(fcmKeyPath).getInputStream(); + + FirebaseOptions options = FirebaseOptions.builder() + .setCredentials(GoogleCredentials.fromStream(firebaseAccount)) + .build(); + + FirebaseApp.initializeApp(options); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/twentythree/peech/fcm/dto/FCMMessageDTO.java b/src/main/java/com/twentythree/peech/fcm/dto/FCMMessageDTO.java new file mode 100644 index 00000000..a722a373 --- /dev/null +++ b/src/main/java/com/twentythree/peech/fcm/dto/FCMMessageDTO.java @@ -0,0 +1,35 @@ +package com.twentythree.peech.fcm.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Getter +public class FCMMessageDTO { + + private boolean validateOnly; + private Message message; + + @Builder + @AllArgsConstructor + @NoArgsConstructor + @Getter + public static class Message { + private Notification notification; + private String token; + } + + @Builder + @AllArgsConstructor + @NoArgsConstructor + @Getter + public static class Notification { + private String title; + private String body; + private String image; + } +} diff --git a/src/main/java/com/twentythree/peech/fcm/entity/NotificationEntity.java b/src/main/java/com/twentythree/peech/fcm/entity/NotificationEntity.java new file mode 100644 index 00000000..d637edd5 --- /dev/null +++ b/src/main/java/com/twentythree/peech/fcm/entity/NotificationEntity.java @@ -0,0 +1,34 @@ +package com.twentythree.peech.fcm.entity; + +import com.twentythree.peech.common.domain.BaseCreatedAtEntity; +import com.twentythree.peech.user.entity.UserEntity; +import jakarta.persistence.*; +import lombok.*; + +@Getter +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "NOTIFICATION") +@Entity +public class NotificationEntity extends BaseCreatedAtEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "notification_id") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private UserEntity userEntity; + + @Column(name = "device_id") + private String deviceId; + + @Column(name = "fcm_token") + private String fcmToken; + + public static NotificationEntity of(Long id, UserEntity userEntity,String deviceId ,String fcmToken) { + return new NotificationEntity(id, userEntity, deviceId,fcmToken); + } + +} diff --git a/src/main/java/com/twentythree/peech/fcm/event/FCMPushedEvent.java b/src/main/java/com/twentythree/peech/fcm/event/FCMPushedEvent.java new file mode 100644 index 00000000..1c1a1081 --- /dev/null +++ b/src/main/java/com/twentythree/peech/fcm/event/FCMPushedEvent.java @@ -0,0 +1,12 @@ +package com.twentythree.peech.fcm.event; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; + +@Getter +@AllArgsConstructor +public class FCMPushedEvent { + private List fcmTokenList; +} diff --git a/src/main/java/com/twentythree/peech/fcm/event/handler/FCMEventHandler.java b/src/main/java/com/twentythree/peech/fcm/event/handler/FCMEventHandler.java new file mode 100644 index 00000000..19837bb9 --- /dev/null +++ b/src/main/java/com/twentythree/peech/fcm/event/handler/FCMEventHandler.java @@ -0,0 +1,41 @@ +package com.twentythree.peech.fcm.event.handler; + +import com.google.firebase.ErrorCode; +import com.google.firebase.messaging.*; +import com.twentythree.peech.fcm.event.FCMPushedEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +@Component +public class FCMEventHandler { + + static final String title = "분석이 완료되었습니다"; + static final String body = "히스토리로 이동하여 분석결과를 확인하세요"; + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + @Async + @EventListener + public void sendMessage(FCMPushedEvent fcmEventDTO) throws FirebaseMessagingException { + // 유저가 접속한 모든 기기에 완료 푸시 알림을 보냄 + MulticastMessage message = MulticastMessage.builder() + .putData("title", title) + .putData("body", body) + .addAllTokens(fcmEventDTO.getFcmTokenList()) + .build(); + + BatchResponse response = FirebaseMessaging.getInstance().sendEachForMulticast(message, true); + log.info("messsage 전송완료"); + + //Todo: 실패한 푸시 알림에 대한 처리 + response.getResponses().stream() + .filter(res -> !res.isSuccessful()) + .filter(res -> res.getException().getErrorCode() == ErrorCode.INVALID_ARGUMENT) + .forEach(res -> { + log.error("Failed to send message to: id = {} {}", res.getException().getMessagingErrorCode(), res.getException().getMessage()); + }); + + } +} diff --git a/src/main/java/com/twentythree/peech/fcm/infra/NotificationRepository.java b/src/main/java/com/twentythree/peech/fcm/infra/NotificationRepository.java new file mode 100644 index 00000000..91791827 --- /dev/null +++ b/src/main/java/com/twentythree/peech/fcm/infra/NotificationRepository.java @@ -0,0 +1,14 @@ +package com.twentythree.peech.fcm.infra; + +import com.twentythree.peech.fcm.entity.NotificationEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +public interface NotificationRepository extends JpaRepository { + + @Query("select n.fcmToken from NotificationEntity n where n.userEntity.id = :userId") + List findAllByUserId(Long userId); + +} diff --git a/src/main/java/com/twentythree/peech/script/domain/ScriptEntity.java b/src/main/java/com/twentythree/peech/script/domain/ScriptEntity.java index c9c24f86..2e5355ba 100644 --- a/src/main/java/com/twentythree/peech/script/domain/ScriptEntity.java +++ b/src/main/java/com/twentythree/peech/script/domain/ScriptEntity.java @@ -6,15 +6,15 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -import org.hibernate.annotations.Check; +import org.hibernate.annotations.DynamicUpdate; import java.time.LocalTime; -import java.util.List; @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PROTECTED) +@DynamicUpdate @Table(name = "SCRIPT") @Entity public class ScriptEntity extends BaseCreatedAtEntity { @@ -45,6 +45,8 @@ public class ScriptEntity extends BaseCreatedAtEntity { @Enumerated(EnumType.STRING) private InputAndSttType DType; + @Column(name = "analysis_result", length = 65535, columnDefinition = "TEXT") + private String analysisResult; private ScriptEntity(VersionEntity version, String scriptContent, LocalTime time, InputAndSttType DType) { this.version = version; diff --git a/src/main/java/com/twentythree/peech/script/repository/ScriptRepository.java b/src/main/java/com/twentythree/peech/script/repository/ScriptRepository.java index 372e1a26..54d33fcd 100644 --- a/src/main/java/com/twentythree/peech/script/repository/ScriptRepository.java +++ b/src/main/java/com/twentythree/peech/script/repository/ScriptRepository.java @@ -3,6 +3,7 @@ import com.twentythree.peech.script.domain.ScriptEntity; import com.twentythree.peech.script.domain.SentenceEntity; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -46,4 +47,8 @@ public interface ScriptRepository extends JpaRepository { @Query("select s from ScriptEntity s where s.version.themeEntity.themeId = :themeId and s.DType = 'STT'") List findScriptByThemeId(Long themeId); + + @Modifying + @Query("update ScriptEntity s set s.analysisResult = :result where s.scriptId = :scriptId") + void saveAnalyzeResult(Long scriptId, String result); } diff --git a/src/main/java/com/twentythree/peech/script/service/ScriptService.java b/src/main/java/com/twentythree/peech/script/service/ScriptService.java index 3bcd6e9a..685ccdf6 100644 --- a/src/main/java/com/twentythree/peech/script/service/ScriptService.java +++ b/src/main/java/com/twentythree/peech/script/service/ScriptService.java @@ -1,5 +1,6 @@ package com.twentythree.peech.script.service; +import com.twentythree.peech.aop.annotation.Trace; import com.twentythree.peech.common.dto.request.GPTRequest; import com.twentythree.peech.common.dto.response.GPTResponse; import com.twentythree.peech.script.cache.CacheService; @@ -419,4 +420,9 @@ public ScriptExpectedTimeDTO getParagraphExpectedTime(String fullScript) { return new ScriptExpectedTimeDTO(totalExpectedTime, paragraphExpectedTimeDTOList); } + + @Transactional + public void reflectAnalyzeResult(Long scriptId, String result) { + scriptRepository.saveAnalyzeResult(scriptId, result); + } } diff --git a/src/main/java/com/twentythree/peech/script/stt/service/ProcessSTTService.java b/src/main/java/com/twentythree/peech/script/stt/service/ProcessSTTService.java index 3e305044..454a4ba9 100644 --- a/src/main/java/com/twentythree/peech/script/stt/service/ProcessSTTService.java +++ b/src/main/java/com/twentythree/peech/script/stt/service/ProcessSTTService.java @@ -1,5 +1,6 @@ package com.twentythree.peech.script.stt.service; +import com.twentythree.peech.analyzescript.application.AnalyzeScriptFacade; import com.twentythree.peech.script.domain.SentenceEntity; import com.twentythree.peech.script.service.ScriptService; import com.twentythree.peech.script.service.SentenceService; @@ -46,6 +47,8 @@ public class ProcessSTTService { private final AudioChecker audioChecker; + private final AnalyzeScriptFacade analyzeScriptFacade; + private final Logger log = LoggerFactory.getLogger(this.getClass()); // 대본 입력 없이 STT 결과 생성 @@ -91,12 +94,15 @@ public Mono createSTTResult(STTRequestDto request, Long th // Sentence Entity 저장 return saveSTTScriptVOMono.flatMap(saveSTTScriptVO -> { - // 생성된 scriptId 가져오기 + // 생성된 scriptId 및 content 가져오기 long scriptId = saveSTTScriptVO.scriptEntity().getScriptId(); + String scriptContent = saveSTTScriptVO.scriptEntity().getScriptContent(); List sentenceEntityList = sentenceService.saveSTTSentences(saveSTTScriptVO.scriptEntity(), sentenceAndRealTimeList, paragraphDivideResponseDto.getResult().getSpan()); STTScriptResponseDTO sttScriptResponseDTO = createSTTResultService.createSTTResultResponseDto(clovaResponseDto, sentenceEntityList, sentenceAndRealTimeList, scriptId); // Redis 저장 로직 saveRedisService.saveSTTScriptInformation(userId, sentenceEntityList); + // 분석 결과 요청 + analyzeScriptFacade.analyzeScriptAndSave(userId, scriptId,scriptContent); // 최종 클라이언트 반환 DTO return Mono.just(sttScriptResponseDTO); @@ -162,13 +168,16 @@ public Mono createSTTResult(STTRequestDto request, Long th // Sentence Entity 저장 return saveSTTScriptVOMono.flatMap(saveSTTScriptVO -> { - // scriptId 저장 + // scriptId 및 scriptContent 가져오기 long newScriptId = saveSTTScriptVO.scriptEntity().getScriptId(); + String scriptContent = saveSTTScriptVO.scriptEntity().getScriptContent(); List sentenceEntityList = sentenceService.saveSTTSentences(saveSTTScriptVO.scriptEntity(), sentenceAndRealTimeList, paragraphDivideResponseDto.getResult().getSpan()); STTScriptResponseDTO sttScriptResponseDTO = createSTTResultService.createSTTResultResponseDto(clovaResponseDto, sentenceEntityList, sentenceAndRealTimeList, newScriptId); // Redis 저장 로직 saveRedisService.saveSTTScriptInformation(userId, sentenceEntityList); + // 분석 결과 요청 + analyzeScriptFacade.analyzeScriptAndSave(userId, newScriptId,scriptContent); // 최종 클라이언트 반환 DTO return Mono.just(sttScriptResponseDTO); @@ -232,13 +241,16 @@ public Mono createSTTResult(File file, Long themeId, Long // Sentence Entity 저장 return saveSTTScriptVOMono.flatMap(saveSTTScriptVO -> { - // scriptId 저장 + // scriptId 및 scriptContent 저장 long newScriptId = saveSTTScriptVO.scriptEntity().getScriptId(); + String scriptContent = saveSTTScriptVO.scriptEntity().getScriptContent(); List sentenceEntityList = sentenceService.saveSTTSentences(saveSTTScriptVO.scriptEntity(), sentenceAndRealTimeList, paragraphDivideResponseDto.getResult().getSpan()); STTScriptResponseDTO sttScriptResponseDTO = createSTTResultService.createSTTResultResponseDto(clovaResponseDto, sentenceEntityList, sentenceAndRealTimeList, newScriptId); // Redis 저장 로직 saveRedisService.saveSTTScriptInformation(userId, sentenceEntityList); + // 분석 결과 요청 + analyzeScriptFacade.analyzeScriptAndSave(userId, newScriptId,scriptContent); // 최종 클라이언트 반환 DTO return Mono.just(sttScriptResponseDTO); @@ -301,12 +313,15 @@ public Mono createSTTResult(File file, Long themeId, Long // Sentence Entity 저장 return saveSTTScriptVOMono.flatMap(saveSTTScriptVO -> { - // 생성된 scriptId 가져오기 + // 생성된 scriptId 및 scriptContent 가져오기 long scriptId = saveSTTScriptVO.scriptEntity().getScriptId(); + String scriptContent = saveSTTScriptVO.scriptEntity().getScriptContent(); List sentenceEntityList = sentenceService.saveSTTSentences(saveSTTScriptVO.scriptEntity(), sentenceAndRealTimeList, paragraphDivideResponseDto.getResult().getSpan()); STTScriptResponseDTO sttScriptResponseDTO = createSTTResultService.createSTTResultResponseDto(clovaResponseDto, sentenceEntityList, sentenceAndRealTimeList, scriptId); // Redis 저장 로직 saveRedisService.saveSTTScriptInformation(userId, sentenceEntityList); + // 분석 결과 요청 + analyzeScriptFacade.analyzeScriptAndSave(userId, scriptId,scriptContent); // 최종 클라이언트 반환 DTO return Mono.just(sttScriptResponseDTO); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b86fe307..49234c50 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -56,6 +56,8 @@ gpt: api: key: ${GPT_API_KEY} url: https://api.openai.com/v1/chat/completions + prompt: + system: ${GPT_PROMPT_SYSTEM} clova: speech-api: @@ -74,3 +76,8 @@ sentry: max-request-body-size: always send-default-pii: true traces-sample-rate: 1.0 + +fcm: + secret-key: ${FCM_SECRET_KEY} + key-path: ${FCM_KEY_PATH} + project-id: ${FCM_PROJECT_ID} \ No newline at end of file From ed40ec5813fed58ad32bb7d7c6c8c982b8a3870d Mon Sep 17 00:00:00 2001 From: ch8930 Date: Fri, 25 Oct 2024 00:54:31 +0900 Subject: [PATCH 2/8] feat: TT-486 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 로그인시 fcm토큰 및 deviceId를 입력받아 새로 insert 혹은 update를 통해 갱신 - 로그인시 userEntity가 생성되면 FCM 토큰 처리에 대한 event 생성 --- .../fcm/application/NotificationService.java | 31 ++----------- .../application/NotificationServiceImpl.java | 43 +++++++++++++++++++ .../peech/fcm/entity/NotificationEntity.java | 27 +++++++++++- .../peech/fcm/event/FCMTokenEvent.java | 13 ++++++ .../fcm/event/handler/FCMEventHandler.java | 13 ++++++ .../fcm/infra/NotificationRepository.java | 8 ++++ .../fcm/validator/NotificationValidator.java | 20 +++++++++ .../peech/user/controller/UserController.java | 5 +-- .../dto/request/LoginBySocialRequestDTO.java | 3 +- .../peech/user/service/UserService.java | 4 +- .../peech/user/service/UserServiceImpl.java | 19 ++++++-- 11 files changed, 147 insertions(+), 39 deletions(-) create mode 100644 src/main/java/com/twentythree/peech/fcm/application/NotificationServiceImpl.java create mode 100644 src/main/java/com/twentythree/peech/fcm/event/FCMTokenEvent.java create mode 100644 src/main/java/com/twentythree/peech/fcm/validator/NotificationValidator.java diff --git a/src/main/java/com/twentythree/peech/fcm/application/NotificationService.java b/src/main/java/com/twentythree/peech/fcm/application/NotificationService.java index 26ff1fe1..cea62781 100644 --- a/src/main/java/com/twentythree/peech/fcm/application/NotificationService.java +++ b/src/main/java/com/twentythree/peech/fcm/application/NotificationService.java @@ -1,31 +1,8 @@ package com.twentythree.peech.fcm.application; -import com.twentythree.peech.aop.annotation.Trace; -import com.twentythree.peech.fcm.event.FCMPushedEvent; -import com.twentythree.peech.fcm.infra.NotificationRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.stereotype.Service; +import com.twentythree.peech.fcm.event.FCMTokenEvent; -import java.util.List; - -@RequiredArgsConstructor -@Service -public class NotificationService { - - private final NotificationRepository notificationRepository; - private final ApplicationEventPublisher applicationEventPublisher; - - @Trace - public void pushNotification(Long userId) { -// List fcmTokenList = notificationRepository.findAllByUserId(userId); -// -// if(fcmTokenList.isEmpty()){ -// throw new IllegalStateException("FCM 토큰이 존재하지 않습니다."); -// } - - List fcmTokenList = List.of("testFcmToken1", "testFcmToken2", "testFcmToken3"); - - applicationEventPublisher.publishEvent(new FCMPushedEvent(fcmTokenList)); - } +public interface NotificationService { + void pushNotification(Long userId); + void saveOrUpdateToken(FCMTokenEvent fcmTokenEvent, boolean result); } diff --git a/src/main/java/com/twentythree/peech/fcm/application/NotificationServiceImpl.java b/src/main/java/com/twentythree/peech/fcm/application/NotificationServiceImpl.java new file mode 100644 index 00000000..f3076c46 --- /dev/null +++ b/src/main/java/com/twentythree/peech/fcm/application/NotificationServiceImpl.java @@ -0,0 +1,43 @@ +package com.twentythree.peech.fcm.application; + +import com.twentythree.peech.fcm.entity.NotificationEntity; +import com.twentythree.peech.fcm.event.FCMPushedEvent; +import com.twentythree.peech.fcm.event.FCMTokenEvent; +import com.twentythree.peech.fcm.infra.NotificationRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@RequiredArgsConstructor +@Service +public class NotificationServiceImpl implements NotificationService { + + private final NotificationRepository notificationRepository; + private final ApplicationEventPublisher applicationEventPublisher; + + public void pushNotification(Long userId) { + List fcmTokenList = notificationRepository.findAllByUserId(userId); + + if(fcmTokenList.isEmpty()){ + throw new IllegalStateException("FCM 토큰이 존재하지 않습니다."); + } + + applicationEventPublisher.publishEvent(new FCMPushedEvent(fcmTokenList)); + } + + @Transactional + @Override + public void saveOrUpdateToken(FCMTokenEvent fcmTokenEvent, boolean result) { + if(!result){ + NotificationEntity notificationEntity = NotificationEntity + .of(fcmTokenEvent.getUserEntity(), fcmTokenEvent.getDeviceId(), fcmTokenEvent.getFcmToken()); + notificationRepository.save(notificationEntity); + + }else { + notificationRepository.updateTokenByDeviceId(fcmTokenEvent.getFcmToken(), fcmTokenEvent.getDeviceId()); + } + } +} diff --git a/src/main/java/com/twentythree/peech/fcm/entity/NotificationEntity.java b/src/main/java/com/twentythree/peech/fcm/entity/NotificationEntity.java index d637edd5..38e06f16 100644 --- a/src/main/java/com/twentythree/peech/fcm/entity/NotificationEntity.java +++ b/src/main/java/com/twentythree/peech/fcm/entity/NotificationEntity.java @@ -4,10 +4,15 @@ import com.twentythree.peech.user.entity.UserEntity; import jakarta.persistence.*; import lombok.*; +import org.hibernate.annotations.DynamicUpdate; + +import java.util.Objects; + @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PROTECTED) +@DynamicUpdate @Table(name = "NOTIFICATION") @Entity public class NotificationEntity extends BaseCreatedAtEntity { @@ -27,8 +32,26 @@ public class NotificationEntity extends BaseCreatedAtEntity { @Column(name = "fcm_token") private String fcmToken; - public static NotificationEntity of(Long id, UserEntity userEntity,String deviceId ,String fcmToken) { - return new NotificationEntity(id, userEntity, deviceId,fcmToken); + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof NotificationEntity that)) return false; + return Objects.equals(deviceId, that.deviceId); + } + + @Override + public int hashCode() { + return Objects.hashCode(deviceId); + } + + public NotificationEntity(UserEntity userEntity, String deviceId, String fcmToken) { + this.userEntity = userEntity; + this.deviceId = deviceId; + this.fcmToken = fcmToken; + } + + public static NotificationEntity of(UserEntity userEntity, String deviceId ,String fcmToken) { + return new NotificationEntity(userEntity, deviceId, fcmToken); } } diff --git a/src/main/java/com/twentythree/peech/fcm/event/FCMTokenEvent.java b/src/main/java/com/twentythree/peech/fcm/event/FCMTokenEvent.java new file mode 100644 index 00000000..f7aee3aa --- /dev/null +++ b/src/main/java/com/twentythree/peech/fcm/event/FCMTokenEvent.java @@ -0,0 +1,13 @@ +package com.twentythree.peech.fcm.event; + +import com.twentythree.peech.user.entity.UserEntity; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class FCMTokenEvent { + private UserEntity userEntity; + private String deviceId; + private String fcmToken; +} diff --git a/src/main/java/com/twentythree/peech/fcm/event/handler/FCMEventHandler.java b/src/main/java/com/twentythree/peech/fcm/event/handler/FCMEventHandler.java index 19837bb9..bf29fc13 100644 --- a/src/main/java/com/twentythree/peech/fcm/event/handler/FCMEventHandler.java +++ b/src/main/java/com/twentythree/peech/fcm/event/handler/FCMEventHandler.java @@ -2,18 +2,25 @@ import com.google.firebase.ErrorCode; import com.google.firebase.messaging.*; +import com.twentythree.peech.fcm.application.NotificationService; import com.twentythree.peech.fcm.event.FCMPushedEvent; +import com.twentythree.peech.fcm.event.FCMTokenEvent; +import com.twentythree.peech.fcm.validator.NotificationValidator; +import lombok.RequiredArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; +@RequiredArgsConstructor @Component public class FCMEventHandler { static final String title = "분석이 완료되었습니다"; static final String body = "히스토리로 이동하여 분석결과를 확인하세요"; + private final NotificationValidator notificationValidator; + private final NotificationService notificationService; private final Logger log = LoggerFactory.getLogger(this.getClass()); @Async @@ -38,4 +45,10 @@ public void sendMessage(FCMPushedEvent fcmEventDTO) throws FirebaseMessagingExce }); } + + @EventListener + public void handleUserCreatedEvent(FCMTokenEvent fcmTokenEvent) { + boolean result = notificationValidator.existTokenByDeviceId(fcmTokenEvent.getDeviceId()); + notificationService.saveOrUpdateToken(fcmTokenEvent, result); + } } diff --git a/src/main/java/com/twentythree/peech/fcm/infra/NotificationRepository.java b/src/main/java/com/twentythree/peech/fcm/infra/NotificationRepository.java index 91791827..9dfcf440 100644 --- a/src/main/java/com/twentythree/peech/fcm/infra/NotificationRepository.java +++ b/src/main/java/com/twentythree/peech/fcm/infra/NotificationRepository.java @@ -2,13 +2,21 @@ import com.twentythree.peech.fcm.entity.NotificationEntity; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import java.util.List; +import java.util.Optional; public interface NotificationRepository extends JpaRepository { @Query("select n.fcmToken from NotificationEntity n where n.userEntity.id = :userId") List findAllByUserId(Long userId); + @Query("select n from NotificationEntity n where n.deviceId = :deviceId") + Optional findNotificationByDeviceId(String deviceId); + + @Modifying + @Query("update NotificationEntity n set n.fcmToken = :fcmToken where n.deviceId = :deviceId") + void updateTokenByDeviceId(String fcmToken, String deviceId); } diff --git a/src/main/java/com/twentythree/peech/fcm/validator/NotificationValidator.java b/src/main/java/com/twentythree/peech/fcm/validator/NotificationValidator.java new file mode 100644 index 00000000..26181248 --- /dev/null +++ b/src/main/java/com/twentythree/peech/fcm/validator/NotificationValidator.java @@ -0,0 +1,20 @@ +package com.twentythree.peech.fcm.validator; + +import com.twentythree.peech.fcm.infra.NotificationRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@RequiredArgsConstructor +@Component +@Transactional(readOnly = true) +public class NotificationValidator { + + private final NotificationRepository notificationRepository; + + public boolean existTokenByDeviceId(String deviceId) { + return notificationRepository.findNotificationByDeviceId(deviceId).isPresent(); + } +} diff --git a/src/main/java/com/twentythree/peech/user/controller/UserController.java b/src/main/java/com/twentythree/peech/user/controller/UserController.java index 8390a6e7..90d8da57 100644 --- a/src/main/java/com/twentythree/peech/user/controller/UserController.java +++ b/src/main/java/com/twentythree/peech/user/controller/UserController.java @@ -51,10 +51,7 @@ public UserIdTokenResponseDTO createUserByDeviceId(@RequestBody CreateUserReques @PostMapping("api/v1.1/user") public ResponseEntity> loginBySocial(@RequestBody LoginBySocialRequestDTO request, @RequestParam String funnel) { - String token = request.getSocialToken(); - AuthorizationServer authorizationServer = request.getAuthorizationServer(); - - LoginBySocial loginBySocial = userService.loginBySocial(token, authorizationServer, funnel); + LoginBySocial loginBySocial = userService.loginBySocial(request, funnel); UserIdTokenResponseDTO userIdTokenResponseDTO = new UserIdTokenResponseDTO(loginBySocial.getAccessToken(), loginBySocial.getRefreshToken()); log.info("{}", userIdTokenResponseDTO.getAccessToken()); return ResponseEntity.status(201).body(new WrappedResponseBody(loginBySocial.getResponseCode(), userIdTokenResponseDTO)); diff --git a/src/main/java/com/twentythree/peech/user/dto/request/LoginBySocialRequestDTO.java b/src/main/java/com/twentythree/peech/user/dto/request/LoginBySocialRequestDTO.java index 2b510236..cb95f9ed 100644 --- a/src/main/java/com/twentythree/peech/user/dto/request/LoginBySocialRequestDTO.java +++ b/src/main/java/com/twentythree/peech/user/dto/request/LoginBySocialRequestDTO.java @@ -5,8 +5,9 @@ import lombok.Getter; @Getter -@AllArgsConstructor public class LoginBySocialRequestDTO { private String socialToken; private AuthorizationServer authorizationServer; + private String deviceId; + private String fcmToken; } diff --git a/src/main/java/com/twentythree/peech/user/service/UserService.java b/src/main/java/com/twentythree/peech/user/service/UserService.java index c2a767b4..24e0f76e 100644 --- a/src/main/java/com/twentythree/peech/user/service/UserService.java +++ b/src/main/java/com/twentythree/peech/user/service/UserService.java @@ -3,9 +3,9 @@ import com.twentythree.peech.common.exception.UserAlreadyExistException; import com.twentythree.peech.user.dto.AccessAndRefreshToken; +import com.twentythree.peech.user.dto.request.LoginBySocialRequestDTO; import com.twentythree.peech.user.dto.response.GetUserInformationResponseDTO; import com.twentythree.peech.user.entity.UserEntity; -import com.twentythree.peech.user.value.AuthorizationServer; import com.twentythree.peech.user.value.UserGender; import com.twentythree.peech.user.domain.UserDomain; import com.twentythree.peech.user.dto.LoginBySocial; @@ -16,7 +16,7 @@ public interface UserService { String createUserByDeviceId(String deviceId) throws UserAlreadyExistException; String reIssuanceUserToken(String deviceId); UserDomain deleteUser(Long userId); - LoginBySocial loginBySocial(String socialToken, AuthorizationServer authorizationServer, String funnel); + LoginBySocial loginBySocial(LoginBySocialRequestDTO request, String funnel); LoginBySocial completeProfile(Long userId, String firstName, String lastName, String nickName, LocalDate birth, UserGender gender, String funnel); UserEntity existUserById(Long userId); GetUserInformationResponseDTO getUserInformation(Long userId); diff --git a/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java b/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java index b9655c33..c766108e 100644 --- a/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java +++ b/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java @@ -4,6 +4,7 @@ import com.twentythree.peech.common.exception.UserAlreadyExistException; import com.twentythree.peech.common.utils.JWTUtils; import com.twentythree.peech.common.utils.UserRoleConvertUtils; +import com.twentythree.peech.fcm.event.FCMTokenEvent; import com.twentythree.peech.script.service.ThemeService; import com.twentythree.peech.security.exception.JWTAuthenticationException; import com.twentythree.peech.security.exception.LoginExceptionCode; @@ -17,6 +18,7 @@ import com.twentythree.peech.user.dto.LoginBySocial; import com.twentythree.peech.user.dto.IdentityToken; import com.twentythree.peech.user.dto.KakaoAccount; +import com.twentythree.peech.user.dto.request.LoginBySocialRequestDTO; import com.twentythree.peech.user.dto.response.ApplePublicKeyResponseDTO; import com.twentythree.peech.user.dto.response.GetUserInformationResponseDTO; import com.twentythree.peech.user.entity.UserEntity; @@ -24,6 +26,7 @@ import com.twentythree.peech.user.validator.UserValidator; import com.twentythree.peech.user.value.*; import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; @@ -52,6 +55,7 @@ public class UserServiceImpl implements UserService { private final UserValidator userValidator; private final JWTUtils jwtUtils; + private final ApplicationEventPublisher eventPublisher; @Override @@ -75,13 +79,16 @@ public String createUserByDeviceId(String deviceId) { @Override @Transactional - public LoginBySocial loginBySocial(String socialToken, AuthorizationServer authorizationServer, String funnel) { + public LoginBySocial loginBySocial(LoginBySocialRequestDTO request, String funnel) { String userEmail = null; String accessToken = null; String refreshToken = null; + String socialToken = request.getSocialToken(); + AuthorizationServer authorizationServer = request.getAuthorizationServer(); + String bearerSocialToken = "Bearer " + socialToken; // Q: 도메인 규칙이라고 볼 수 없는 이런 코드는 위치를 어디로 해야하는가? @@ -113,20 +120,22 @@ public LoginBySocial loginBySocial(String socialToken, AuthorizationServer autho } Integer responseCode = 411; + Long userId = null; if (userValidator.notExistUserByEmail(userEmail)) { UserDomain userDomain = userCreator.createUserByEmail(authorizationServer, userEmail, SignUpFinished.PENDING); - Long userId = userMapper.saveUserDomain(userDomain); + userId = userMapper.saveUserDomain(userDomain); UserRole userRole = userDomain.getRole(); accessToken = jwtUtils.createAccessToken(userId, userRole, funnel); refreshToken = jwtUtils.createRefreshToken(userId, userRole, funnel); + } else if (userValidator.existUserByEmail(userEmail)) { UserDomain userDomain = userFetcher.fetchUserByEmail(userEmail); - Long userId = userDomain.getUserId(); + userId = userDomain.getUserId(); UserRole userRole = userDomain.getRole(); if (userValidator.singedUpFinishedUser(userId)) { @@ -135,9 +144,13 @@ public LoginBySocial loginBySocial(String socialToken, AuthorizationServer autho accessToken = jwtUtils.createAccessToken(userId, userRole, funnel); refreshToken = jwtUtils.createRefreshToken(userId, userRole, funnel); + } else { throw new RuntimeException("유저 생성에서 예상치 못한 문제가 생겼습니다."); } + // 예외를 제외하고 유저가 생성된 시점 + UserEntity userEntity = userRepository.findById(userId).orElseThrow(() -> new Unauthorized("유저가 생성되지 않았습니다.")); + eventPublisher.publishEvent(new FCMTokenEvent(userEntity, request.getDeviceId(), request.getFcmToken())); return new LoginBySocial(accessToken, refreshToken, responseCode); } From d583388ba12ec53763065db0c119a274cd10d06c Mon Sep 17 00:00:00 2001 From: ch8930 Date: Mon, 28 Oct 2024 20:06:16 +0900 Subject: [PATCH 3/8] fix: TT-486 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 유저 저장과 fcm 토큰 저장 api 분리하는 방식으로의 변경 --- .../fcm/application/NotificationService.java | 4 +-- .../application/NotificationServiceImpl.java | 35 +++++++++++++------ .../fcm/dto/request/RequestFCMTokenDTO.java | 11 ++++++ .../peech/fcm/entity/NotificationEntity.java | 5 ++- .../fcm/event/handler/FCMEventHandler.java | 11 +----- .../fcm/infra/NotificationRepository.java | 6 +--- .../peech/fcm/presentation/FCMController.java | 28 +++++++++++++++ .../peech/user/service/UserServiceImpl.java | 5 ++- 8 files changed, 74 insertions(+), 31 deletions(-) create mode 100644 src/main/java/com/twentythree/peech/fcm/dto/request/RequestFCMTokenDTO.java create mode 100644 src/main/java/com/twentythree/peech/fcm/presentation/FCMController.java diff --git a/src/main/java/com/twentythree/peech/fcm/application/NotificationService.java b/src/main/java/com/twentythree/peech/fcm/application/NotificationService.java index cea62781..57396d62 100644 --- a/src/main/java/com/twentythree/peech/fcm/application/NotificationService.java +++ b/src/main/java/com/twentythree/peech/fcm/application/NotificationService.java @@ -1,8 +1,8 @@ package com.twentythree.peech.fcm.application; -import com.twentythree.peech.fcm.event.FCMTokenEvent; +import com.twentythree.peech.fcm.dto.request.RequestFCMTokenDTO; public interface NotificationService { void pushNotification(Long userId); - void saveOrUpdateToken(FCMTokenEvent fcmTokenEvent, boolean result); + void saveOrUpdateToken(RequestFCMTokenDTO fcmTokenDTO, Long userId); } diff --git a/src/main/java/com/twentythree/peech/fcm/application/NotificationServiceImpl.java b/src/main/java/com/twentythree/peech/fcm/application/NotificationServiceImpl.java index f3076c46..98acfbd8 100644 --- a/src/main/java/com/twentythree/peech/fcm/application/NotificationServiceImpl.java +++ b/src/main/java/com/twentythree/peech/fcm/application/NotificationServiceImpl.java @@ -1,9 +1,12 @@ package com.twentythree.peech.fcm.application; + +import com.twentythree.peech.fcm.dto.request.RequestFCMTokenDTO; import com.twentythree.peech.fcm.entity.NotificationEntity; import com.twentythree.peech.fcm.event.FCMPushedEvent; -import com.twentythree.peech.fcm.event.FCMTokenEvent; import com.twentythree.peech.fcm.infra.NotificationRepository; +import com.twentythree.peech.user.entity.UserEntity; +import com.twentythree.peech.user.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @@ -16,6 +19,7 @@ public class NotificationServiceImpl implements NotificationService { private final NotificationRepository notificationRepository; + private final UserRepository userRepository; private final ApplicationEventPublisher applicationEventPublisher; public void pushNotification(Long userId) { @@ -30,14 +34,25 @@ public void pushNotification(Long userId) { @Transactional @Override - public void saveOrUpdateToken(FCMTokenEvent fcmTokenEvent, boolean result) { - if(!result){ - NotificationEntity notificationEntity = NotificationEntity - .of(fcmTokenEvent.getUserEntity(), fcmTokenEvent.getDeviceId(), fcmTokenEvent.getFcmToken()); - notificationRepository.save(notificationEntity); - - }else { - notificationRepository.updateTokenByDeviceId(fcmTokenEvent.getFcmToken(), fcmTokenEvent.getDeviceId()); - } + public void saveOrUpdateToken(RequestFCMTokenDTO request, Long userId) { + notificationRepository.findByDeviceId(request.getDeviceId()) + .ifPresentOrElse( + fcmToken -> updateFCMToken(fcmToken, request.getFcmToken()), + + () -> { + UserEntity userEntity = userRepository.findById(userId) + .orElseThrow(() -> new IllegalStateException("유저가 존재하지 않습니다.")); + NotificationEntity newEntity = NotificationEntity + .ofCreateFCMToken( + userEntity, + request.getDeviceId(), + request.getFcmToken() + ); + notificationRepository.save(newEntity); + }); + } + + private void updateFCMToken(NotificationEntity originEntity, String newToken){ + originEntity.updateToken(newToken); } } diff --git a/src/main/java/com/twentythree/peech/fcm/dto/request/RequestFCMTokenDTO.java b/src/main/java/com/twentythree/peech/fcm/dto/request/RequestFCMTokenDTO.java new file mode 100644 index 00000000..e8fa2d48 --- /dev/null +++ b/src/main/java/com/twentythree/peech/fcm/dto/request/RequestFCMTokenDTO.java @@ -0,0 +1,11 @@ +package com.twentythree.peech.fcm.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class RequestFCMTokenDTO { + private String deviceId; + private String fcmToken; +} diff --git a/src/main/java/com/twentythree/peech/fcm/entity/NotificationEntity.java b/src/main/java/com/twentythree/peech/fcm/entity/NotificationEntity.java index 38e06f16..0dcdef1f 100644 --- a/src/main/java/com/twentythree/peech/fcm/entity/NotificationEntity.java +++ b/src/main/java/com/twentythree/peech/fcm/entity/NotificationEntity.java @@ -50,8 +50,11 @@ public NotificationEntity(UserEntity userEntity, String deviceId, String fcmToke this.fcmToken = fcmToken; } - public static NotificationEntity of(UserEntity userEntity, String deviceId ,String fcmToken) { + public static NotificationEntity ofCreateFCMToken(UserEntity userEntity, String deviceId , String fcmToken) { return new NotificationEntity(userEntity, deviceId, fcmToken); } + public void updateToken(String fcmToken) { + this.fcmToken = fcmToken; + } } diff --git a/src/main/java/com/twentythree/peech/fcm/event/handler/FCMEventHandler.java b/src/main/java/com/twentythree/peech/fcm/event/handler/FCMEventHandler.java index bf29fc13..15e27864 100644 --- a/src/main/java/com/twentythree/peech/fcm/event/handler/FCMEventHandler.java +++ b/src/main/java/com/twentythree/peech/fcm/event/handler/FCMEventHandler.java @@ -4,8 +4,6 @@ import com.google.firebase.messaging.*; import com.twentythree.peech.fcm.application.NotificationService; import com.twentythree.peech.fcm.event.FCMPushedEvent; -import com.twentythree.peech.fcm.event.FCMTokenEvent; -import com.twentythree.peech.fcm.validator.NotificationValidator; import lombok.RequiredArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,8 +17,6 @@ public class FCMEventHandler { static final String title = "분석이 완료되었습니다"; static final String body = "히스토리로 이동하여 분석결과를 확인하세요"; - private final NotificationValidator notificationValidator; - private final NotificationService notificationService; private final Logger log = LoggerFactory.getLogger(this.getClass()); @Async @@ -33,7 +29,7 @@ public void sendMessage(FCMPushedEvent fcmEventDTO) throws FirebaseMessagingExce .addAllTokens(fcmEventDTO.getFcmTokenList()) .build(); - BatchResponse response = FirebaseMessaging.getInstance().sendEachForMulticast(message, true); + BatchResponse response = FirebaseMessaging.getInstance().sendEachForMulticast(message); log.info("messsage 전송완료"); //Todo: 실패한 푸시 알림에 대한 처리 @@ -46,9 +42,4 @@ public void sendMessage(FCMPushedEvent fcmEventDTO) throws FirebaseMessagingExce } - @EventListener - public void handleUserCreatedEvent(FCMTokenEvent fcmTokenEvent) { - boolean result = notificationValidator.existTokenByDeviceId(fcmTokenEvent.getDeviceId()); - notificationService.saveOrUpdateToken(fcmTokenEvent, result); - } } diff --git a/src/main/java/com/twentythree/peech/fcm/infra/NotificationRepository.java b/src/main/java/com/twentythree/peech/fcm/infra/NotificationRepository.java index 9dfcf440..60123f7a 100644 --- a/src/main/java/com/twentythree/peech/fcm/infra/NotificationRepository.java +++ b/src/main/java/com/twentythree/peech/fcm/infra/NotificationRepository.java @@ -14,9 +14,5 @@ public interface NotificationRepository extends JpaRepository findAllByUserId(Long userId); @Query("select n from NotificationEntity n where n.deviceId = :deviceId") - Optional findNotificationByDeviceId(String deviceId); - - @Modifying - @Query("update NotificationEntity n set n.fcmToken = :fcmToken where n.deviceId = :deviceId") - void updateTokenByDeviceId(String fcmToken, String deviceId); + Optional findByDeviceId(String deviceId); } diff --git a/src/main/java/com/twentythree/peech/fcm/presentation/FCMController.java b/src/main/java/com/twentythree/peech/fcm/presentation/FCMController.java new file mode 100644 index 00000000..80b887a9 --- /dev/null +++ b/src/main/java/com/twentythree/peech/fcm/presentation/FCMController.java @@ -0,0 +1,28 @@ +package com.twentythree.peech.fcm.presentation; + +import com.twentythree.peech.fcm.application.NotificationService; +import com.twentythree.peech.fcm.dto.request.RequestFCMTokenDTO; +import com.twentythree.peech.security.jwt.JWTAuthentication; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RequiredArgsConstructor +@RestController +public class FCMController { + + private final NotificationService notificationService; + + @PutMapping("api/v2/user/notification/token") + public ResponseEntity putFCMToken(RequestFCMTokenDTO request, @AuthenticationPrincipal JWTAuthentication jwtAuthentication) { + + Long userId = jwtAuthentication.getUserId(); + notificationService.saveOrUpdateToken(request, userId); + + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java b/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java index c766108e..8c5e12fd 100644 --- a/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java +++ b/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java @@ -4,7 +4,6 @@ import com.twentythree.peech.common.exception.UserAlreadyExistException; import com.twentythree.peech.common.utils.JWTUtils; import com.twentythree.peech.common.utils.UserRoleConvertUtils; -import com.twentythree.peech.fcm.event.FCMTokenEvent; import com.twentythree.peech.script.service.ThemeService; import com.twentythree.peech.security.exception.JWTAuthenticationException; import com.twentythree.peech.security.exception.LoginExceptionCode; @@ -125,7 +124,7 @@ public LoginBySocial loginBySocial(LoginBySocialRequestDTO request, String funne if (userValidator.notExistUserByEmail(userEmail)) { UserDomain userDomain = userCreator.createUserByEmail(authorizationServer, userEmail, SignUpFinished.PENDING); - userId = userMapper.saveUserDomain(userDomain); + Long userId = userMapper.saveUserDomain(userDomain); UserRole userRole = userDomain.getRole(); accessToken = jwtUtils.createAccessToken(userId, userRole, funnel); @@ -135,7 +134,7 @@ public LoginBySocial loginBySocial(LoginBySocialRequestDTO request, String funne } else if (userValidator.existUserByEmail(userEmail)) { UserDomain userDomain = userFetcher.fetchUserByEmail(userEmail); - userId = userDomain.getUserId(); + Long userId = userDomain.getUserId(); UserRole userRole = userDomain.getRole(); if (userValidator.singedUpFinishedUser(userId)) { From ea0d9075b61fae6be35d4e44f5b9dcb12769f479 Mon Sep 17 00:00:00 2001 From: ch8930 Date: Sun, 10 Nov 2024 13:26:52 +0900 Subject: [PATCH 4/8] fix: TT-486 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 분석결과 조회할 수 있는 api 추가 --- .../peech/script/controller/ScriptController.java | 7 +++++++ .../peech/script/dto/AnalyzeResultDTO.java | 11 +++++++++++ .../peech/script/repository/ScriptRepository.java | 3 +++ .../peech/script/service/ScriptService.java | 6 ++++++ 4 files changed, 27 insertions(+) create mode 100644 src/main/java/com/twentythree/peech/script/dto/AnalyzeResultDTO.java diff --git a/src/main/java/com/twentythree/peech/script/controller/ScriptController.java b/src/main/java/com/twentythree/peech/script/controller/ScriptController.java index 9fa5d13d..5380c5b2 100644 --- a/src/main/java/com/twentythree/peech/script/controller/ScriptController.java +++ b/src/main/java/com/twentythree/peech/script/controller/ScriptController.java @@ -10,6 +10,7 @@ import com.twentythree.peech.script.service.ScriptService; import io.swagger.v3.oas.annotations.Operation; import lombok.AllArgsConstructor; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -98,4 +99,10 @@ public HistoryListResponseDTO getScriptList(@PathVariable Long themeId){ public ScriptExpectedTimeDTO getExpectedTimeWithFullScript(@RequestBody ExpectedTimeRequestDTO request){ return scriptService.getParagraphExpectedTime(request.getFullScript()); } + + @GetMapping("api/v2/script/{scriptId}/analyze-result") + public ResponseEntity getAnalyzeResult(@PathVariable Long scriptId){ + AnalyzeResultDTO result = scriptService.getAnalyzeResult(scriptId); + return ResponseEntity.status(result.getHttpStatus()).body(result.getResult()); + } } diff --git a/src/main/java/com/twentythree/peech/script/dto/AnalyzeResultDTO.java b/src/main/java/com/twentythree/peech/script/dto/AnalyzeResultDTO.java new file mode 100644 index 00000000..aef5aad1 --- /dev/null +++ b/src/main/java/com/twentythree/peech/script/dto/AnalyzeResultDTO.java @@ -0,0 +1,11 @@ +package com.twentythree.peech.script.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class AnalyzeResultDTO { + private int httpStatus; + private String result; +} diff --git a/src/main/java/com/twentythree/peech/script/repository/ScriptRepository.java b/src/main/java/com/twentythree/peech/script/repository/ScriptRepository.java index 54d33fcd..9135033a 100644 --- a/src/main/java/com/twentythree/peech/script/repository/ScriptRepository.java +++ b/src/main/java/com/twentythree/peech/script/repository/ScriptRepository.java @@ -51,4 +51,7 @@ public interface ScriptRepository extends JpaRepository { @Modifying @Query("update ScriptEntity s set s.analysisResult = :result where s.scriptId = :scriptId") void saveAnalyzeResult(Long scriptId, String result); + + @Query("select s.analysisResult from ScriptEntity s where s.scriptId = :scriptId") + Optional findAnalyzeResultByScriptId(Long scriptId); } diff --git a/src/main/java/com/twentythree/peech/script/service/ScriptService.java b/src/main/java/com/twentythree/peech/script/service/ScriptService.java index 685ccdf6..558b2684 100644 --- a/src/main/java/com/twentythree/peech/script/service/ScriptService.java +++ b/src/main/java/com/twentythree/peech/script/service/ScriptService.java @@ -425,4 +425,10 @@ public ScriptExpectedTimeDTO getParagraphExpectedTime(String fullScript) { public void reflectAnalyzeResult(Long scriptId, String result) { scriptRepository.saveAnalyzeResult(scriptId, result); } + + public AnalyzeResultDTO getAnalyzeResult(Long scriptId) { + return scriptRepository.findAnalyzeResultByScriptId(scriptId) + .map(result -> new AnalyzeResultDTO(200, result)) + .orElseGet(() -> new AnalyzeResultDTO(202, "스크립트를 분석중입니다.")); + } } From 63b9988d824ba14834b0ce36ab14c4a63e1125d0 Mon Sep 17 00:00:00 2001 From: ch8930 Date: Sun, 10 Nov 2024 13:34:03 +0900 Subject: [PATCH 5/8] fix: TT-486 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 분석결과 조회할 수 있는 api 추가 --- .../twentythree/peech/script/controller/ScriptController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/twentythree/peech/script/controller/ScriptController.java b/src/main/java/com/twentythree/peech/script/controller/ScriptController.java index 5380c5b2..1e5f9a8e 100644 --- a/src/main/java/com/twentythree/peech/script/controller/ScriptController.java +++ b/src/main/java/com/twentythree/peech/script/controller/ScriptController.java @@ -1,6 +1,7 @@ package com.twentythree.peech.script.controller; import com.twentythree.peech.auth.service.SecurityContextHolder; +import com.twentythree.peech.script.dto.AnalyzeResultDTO; import com.twentythree.peech.script.dto.request.ExpectedTimeRequestDTO; import com.twentythree.peech.script.dto.request.ModifiedScriptRequestDTO; import com.twentythree.peech.script.dto.request.ParagraphsRequestDTO; From f8ee3fac4af220575c9232c06e3e81e18b756eb3 Mon Sep 17 00:00:00 2001 From: ch8930 Date: Sun, 10 Nov 2024 14:03:23 +0900 Subject: [PATCH 6/8] fix: TT-486 --- .../peech/user/controller/UserController.java | 5 ++++- .../user/dto/request/LoginBySocialRequestDTO.java | 3 --- .../twentythree/peech/user/service/UserService.java | 4 ++-- .../peech/user/service/UserServiceImpl.java | 10 +--------- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/twentythree/peech/user/controller/UserController.java b/src/main/java/com/twentythree/peech/user/controller/UserController.java index 8a51cbee..bb613ece 100644 --- a/src/main/java/com/twentythree/peech/user/controller/UserController.java +++ b/src/main/java/com/twentythree/peech/user/controller/UserController.java @@ -53,7 +53,10 @@ public UserIdTokenResponseDTO createUserByDeviceId(@RequestBody CreateUserReques @PostMapping("api/v1.1/user") public ResponseEntity> loginBySocial(@RequestBody LoginBySocialRequestDTO request, @RequestParam String funnel) { - LoginBySocial loginBySocial = userService.loginBySocial(request, funnel); + String token = request.getSocialToken(); + AuthorizationServer authorizationServer = request.getAuthorizationServer(); + + LoginBySocial loginBySocial = userService.loginBySocial(token, authorizationServer, funnel); UserIdTokenResponseDTO userIdTokenResponseDTO = new UserIdTokenResponseDTO(loginBySocial.getAccessToken(), loginBySocial.getRefreshToken()); log.info("{}", userIdTokenResponseDTO.getAccessToken()); return ResponseEntity.status(201).body(new WrappedResponseBody(loginBySocial.getResponseCode(), userIdTokenResponseDTO)); diff --git a/src/main/java/com/twentythree/peech/user/dto/request/LoginBySocialRequestDTO.java b/src/main/java/com/twentythree/peech/user/dto/request/LoginBySocialRequestDTO.java index cb95f9ed..dd323a84 100644 --- a/src/main/java/com/twentythree/peech/user/dto/request/LoginBySocialRequestDTO.java +++ b/src/main/java/com/twentythree/peech/user/dto/request/LoginBySocialRequestDTO.java @@ -1,13 +1,10 @@ package com.twentythree.peech.user.dto.request; import com.twentythree.peech.user.value.AuthorizationServer; -import lombok.AllArgsConstructor; import lombok.Getter; @Getter public class LoginBySocialRequestDTO { private String socialToken; private AuthorizationServer authorizationServer; - private String deviceId; - private String fcmToken; } diff --git a/src/main/java/com/twentythree/peech/user/service/UserService.java b/src/main/java/com/twentythree/peech/user/service/UserService.java index 24e0f76e..c2a767b4 100644 --- a/src/main/java/com/twentythree/peech/user/service/UserService.java +++ b/src/main/java/com/twentythree/peech/user/service/UserService.java @@ -3,9 +3,9 @@ import com.twentythree.peech.common.exception.UserAlreadyExistException; import com.twentythree.peech.user.dto.AccessAndRefreshToken; -import com.twentythree.peech.user.dto.request.LoginBySocialRequestDTO; import com.twentythree.peech.user.dto.response.GetUserInformationResponseDTO; import com.twentythree.peech.user.entity.UserEntity; +import com.twentythree.peech.user.value.AuthorizationServer; import com.twentythree.peech.user.value.UserGender; import com.twentythree.peech.user.domain.UserDomain; import com.twentythree.peech.user.dto.LoginBySocial; @@ -16,7 +16,7 @@ public interface UserService { String createUserByDeviceId(String deviceId) throws UserAlreadyExistException; String reIssuanceUserToken(String deviceId); UserDomain deleteUser(Long userId); - LoginBySocial loginBySocial(LoginBySocialRequestDTO request, String funnel); + LoginBySocial loginBySocial(String socialToken, AuthorizationServer authorizationServer, String funnel); LoginBySocial completeProfile(Long userId, String firstName, String lastName, String nickName, LocalDate birth, UserGender gender, String funnel); UserEntity existUserById(Long userId); GetUserInformationResponseDTO getUserInformation(Long userId); diff --git a/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java b/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java index cf22c71e..80abc596 100644 --- a/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java +++ b/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java @@ -19,7 +19,6 @@ import com.twentythree.peech.user.dto.LoginBySocial; import com.twentythree.peech.user.dto.IdentityToken; import com.twentythree.peech.user.dto.KakaoAccount; -import com.twentythree.peech.user.dto.request.LoginBySocialRequestDTO; import com.twentythree.peech.user.dto.response.ApplePublicKeyResponseDTO; import com.twentythree.peech.user.dto.response.GetUserInformationResponseDTO; import com.twentythree.peech.user.entity.UserEntity; @@ -82,16 +81,13 @@ public String createUserByDeviceId(String deviceId) { @MetaEventTrigger(name = FeatureType.LOGIN) @Override @Transactional - public LoginBySocial loginBySocial(LoginBySocialRequestDTO request, String funnel) { + public LoginBySocial loginBySocial(String socialToken, AuthorizationServer authorizationServer, String funnel) { String userEmail = null; String accessToken = null; String refreshToken = null; - String socialToken = request.getSocialToken(); - AuthorizationServer authorizationServer = request.getAuthorizationServer(); - String bearerSocialToken = "Bearer " + socialToken; // Q: 도메인 규칙이라고 볼 수 없는 이런 코드는 위치를 어디로 해야하는가? @@ -123,7 +119,6 @@ public LoginBySocial loginBySocial(LoginBySocialRequestDTO request, String funne } Integer responseCode = 411; - Long userId = null; if (userValidator.notExistUserByEmail(userEmail)) { @@ -153,9 +148,6 @@ public LoginBySocial loginBySocial(LoginBySocialRequestDTO request, String funne } // 예외를 제외하고 유저가 생성된 시점 - UserEntity userEntity = userRepository.findById(userId).orElseThrow(() -> new Unauthorized("유저가 생성되지 않았습니다.")); - eventPublisher.publishEvent(new FCMTokenEvent(userEntity, request.getDeviceId(), request.getFcmToken())); - UserEmailHolder.setUserEmail(userEmail); return new LoginBySocial(accessToken, refreshToken, responseCode); From d02bd0b3631511a4896b75d47ddfcf33a641aca2 Mon Sep 17 00:00:00 2001 From: ch8930 Date: Sun, 10 Nov 2024 14:11:48 +0900 Subject: [PATCH 7/8] fix: TT-486 --- .../fcm/validator/NotificationValidator.java | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 src/main/java/com/twentythree/peech/fcm/validator/NotificationValidator.java diff --git a/src/main/java/com/twentythree/peech/fcm/validator/NotificationValidator.java b/src/main/java/com/twentythree/peech/fcm/validator/NotificationValidator.java deleted file mode 100644 index 26181248..00000000 --- a/src/main/java/com/twentythree/peech/fcm/validator/NotificationValidator.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.twentythree.peech.fcm.validator; - -import com.twentythree.peech.fcm.infra.NotificationRepository; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -@Slf4j -@RequiredArgsConstructor -@Component -@Transactional(readOnly = true) -public class NotificationValidator { - - private final NotificationRepository notificationRepository; - - public boolean existTokenByDeviceId(String deviceId) { - return notificationRepository.findNotificationByDeviceId(deviceId).isPresent(); - } -} From 1b23397825bcd2a6209761b8dde50b4be6c35c4a Mon Sep 17 00:00:00 2001 From: ch8930 Date: Sun, 10 Nov 2024 14:17:34 +0900 Subject: [PATCH 8/8] fix: TT-486 --- .../peech/analyzescript/domain/AnalyzeScriptPredictor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/twentythree/peech/analyzescript/domain/AnalyzeScriptPredictor.java b/src/main/java/com/twentythree/peech/analyzescript/domain/AnalyzeScriptPredictor.java index 423c8108..7dffb223 100644 --- a/src/main/java/com/twentythree/peech/analyzescript/domain/AnalyzeScriptPredictor.java +++ b/src/main/java/com/twentythree/peech/analyzescript/domain/AnalyzeScriptPredictor.java @@ -25,7 +25,6 @@ public class AnalyzeScriptPredictor { private final AnalyzeScriptGPT analyzeScriptGPT; - @Trace public CompletableFuture requestAnalyzeScript(String scriptContent) { List messages = new ArrayList<>();