From 0d24ab2f4358b3a8f19ef8daafdc80838afc64cf Mon Sep 17 00:00:00 2001 From: kanguk Date: Mon, 4 Nov 2024 02:25:59 +0900 Subject: [PATCH 1/9] =?UTF-8?q?feat:=20=EB=B0=B0=ED=8F=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 핫픽스이기 때문에 바로 배포한다 From 08a8292065ebb2697c7b5245a99fb219c1143f7f Mon Sep 17 00:00:00 2001 From: kanguk Date: Wed, 13 Nov 2024 22:38:34 +0900 Subject: [PATCH 2/9] =?UTF-8?q?refactor:=20FCM=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../splanet/core/exception/ErrorCode.java | 4 ++ .../notification/controller/FcmTokenApi.java | 5 +-- .../controller/FcmTokenController.java | 11 +++--- .../repository/FcmTokenRepository.java | 1 + .../notification/service/FcmTokenService.java | 12 +++--- .../service/FcmTokenServiceTest.java | 38 +++++++------------ 6 files changed, 33 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/splanet/splanet/core/exception/ErrorCode.java b/src/main/java/com/splanet/splanet/core/exception/ErrorCode.java index 145a5913..b96e6769 100644 --- a/src/main/java/com/splanet/splanet/core/exception/ErrorCode.java +++ b/src/main/java/com/splanet/splanet/core/exception/ErrorCode.java @@ -54,6 +54,10 @@ public enum ErrorCode { // redis REDIS_SCAN_FAILED("Redis 키 스캔 중 오류가 발생했습니다.", HttpStatus.SERVICE_UNAVAILABLE), + // fcm + TOKEN_NOT_FOUND("해당 FCM 토큰을 찾을 수 없습니다.", HttpStatus.NOT_FOUND), + + // ect INVALID_PLAN_FORMAT("", HttpStatus.BAD_REQUEST); diff --git a/src/main/java/com/splanet/splanet/notification/controller/FcmTokenApi.java b/src/main/java/com/splanet/splanet/notification/controller/FcmTokenApi.java index 5eb4ead0..ded58677 100644 --- a/src/main/java/com/splanet/splanet/notification/controller/FcmTokenApi.java +++ b/src/main/java/com/splanet/splanet/notification/controller/FcmTokenApi.java @@ -30,13 +30,13 @@ ResponseEntity registerFcmToken( @Operation(summary = "FCM 토큰 설정 수정", description = "알림 설정 및 알림 오프셋을 수정합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "FCM 토큰 설정이 성공적으로 수정되었습니다."), - @ApiResponse(responseCode = "404", description = "유저를 찾을 수 없습니다.", content = @Content) + @ApiResponse(responseCode = "404", description = "토큰을 찾을 수 없습니다.", content = @Content) }) ResponseEntity updateFcmTokenSettings( - @AuthenticationPrincipal Long userId, @RequestBody FcmTokenUpdateRequest fcmTokenUpdateRequest ); + @DeleteMapping("/delete") @Operation(summary = "FCM 토큰 삭제", description = "유저의 FCM 토큰을 삭제합니다.") @ApiResponses(value = { @@ -44,7 +44,6 @@ ResponseEntity updateFcmTokenSettings( @ApiResponse(responseCode = "404", description = "해당 토큰을 찾을 수 없습니다.", content = @Content) }) ResponseEntity deleteFcmToken( - @AuthenticationPrincipal Long userId, @RequestParam String token ); } diff --git a/src/main/java/com/splanet/splanet/notification/controller/FcmTokenController.java b/src/main/java/com/splanet/splanet/notification/controller/FcmTokenController.java index 38523c35..93507b7b 100644 --- a/src/main/java/com/splanet/splanet/notification/controller/FcmTokenController.java +++ b/src/main/java/com/splanet/splanet/notification/controller/FcmTokenController.java @@ -21,14 +21,15 @@ public ResponseEntity registerFcmToken(Long userId, FcmTokenRequest fcmT } @Override - public ResponseEntity updateFcmTokenSettings(Long userId, FcmTokenUpdateRequest fcmTokenUpdateRequest) { - fcmTokenService.updateFcmTokenSettings(userId, fcmTokenUpdateRequest); - return ResponseEntity.ok("FCM token 수정 완료"); + public ResponseEntity updateFcmTokenSettings(FcmTokenUpdateRequest fcmTokenUpdateRequest) { + fcmTokenService.updateFcmTokenSettings(fcmTokenUpdateRequest); + return ResponseEntity.ok("FCM 토큰 수정 완료"); } + @Override - public ResponseEntity deleteFcmToken(Long userId, String token) { - fcmTokenService.deleteFcmToken(userId, token); + public ResponseEntity deleteFcmToken(String token) { + fcmTokenService.deleteFcmToken(token); return ResponseEntity.ok("FCM token 삭제 완료"); } } diff --git a/src/main/java/com/splanet/splanet/notification/repository/FcmTokenRepository.java b/src/main/java/com/splanet/splanet/notification/repository/FcmTokenRepository.java index 1f26d161..6fea10f3 100644 --- a/src/main/java/com/splanet/splanet/notification/repository/FcmTokenRepository.java +++ b/src/main/java/com/splanet/splanet/notification/repository/FcmTokenRepository.java @@ -12,4 +12,5 @@ public interface FcmTokenRepository extends JpaRepository { Optional findByUserIdAndToken(Long userId, String token); List findByUserId(Long userId); List findByUserIdIn(Collection userIds); + Optional findByToken(String token); } diff --git a/src/main/java/com/splanet/splanet/notification/service/FcmTokenService.java b/src/main/java/com/splanet/splanet/notification/service/FcmTokenService.java index 29190f26..6b3676d1 100644 --- a/src/main/java/com/splanet/splanet/notification/service/FcmTokenService.java +++ b/src/main/java/com/splanet/splanet/notification/service/FcmTokenService.java @@ -34,9 +34,9 @@ public void registerFcmToken(Long userId, String token) { } @Transactional - public void updateFcmTokenSettings(Long userId, FcmTokenUpdateRequest request) { - FcmToken fcmToken = fcmTokenRepository.findByUserIdAndToken(userId, request.token()) - .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); + public void updateFcmTokenSettings(FcmTokenUpdateRequest request) { + FcmToken fcmToken = fcmTokenRepository.findByToken(request.token()) + .orElseThrow(() -> new BusinessException(ErrorCode.TOKEN_NOT_FOUND)); fcmToken = fcmToken.toBuilder() .isNotificationEnabled(request.isNotificationEnabled() != null @@ -51,9 +51,9 @@ public void updateFcmTokenSettings(Long userId, FcmTokenUpdateRequest request) { } @Transactional - public void deleteFcmToken(Long userId, String token) { - FcmToken fcmToken = fcmTokenRepository.findByUserIdAndToken(userId, token) - .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); + public void deleteFcmToken(String token) { + FcmToken fcmToken = fcmTokenRepository.findByToken(token) + .orElseThrow(() -> new BusinessException(ErrorCode.TOKEN_NOT_FOUND)); fcmTokenRepository.delete(fcmToken); } } diff --git a/src/test/java/com/splanet/splanet/notification/service/FcmTokenServiceTest.java b/src/test/java/com/splanet/splanet/notification/service/FcmTokenServiceTest.java index 1390e6ff..2a8ece7d 100644 --- a/src/test/java/com/splanet/splanet/notification/service/FcmTokenServiceTest.java +++ b/src/test/java/com/splanet/splanet/notification/service/FcmTokenServiceTest.java @@ -1,6 +1,7 @@ package com.splanet.splanet.notification.service; import com.splanet.splanet.core.exception.BusinessException; +import com.splanet.splanet.core.exception.ErrorCode; import com.splanet.splanet.notification.dto.FcmTokenUpdateRequest; import com.splanet.splanet.notification.entity.FcmToken; import com.splanet.splanet.notification.repository.FcmTokenRepository; @@ -8,9 +9,10 @@ import com.splanet.splanet.user.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; import java.util.Optional; @@ -19,6 +21,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; +@ExtendWith(MockitoExtension.class) class FcmTokenServiceTest { @Mock @@ -30,11 +33,6 @@ class FcmTokenServiceTest { @InjectMocks private FcmTokenService fcmTokenService; - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - } - @Test void FCM토큰_등록_성공() { Long userId = 1L; @@ -65,61 +63,53 @@ void setUp() { @Test void FCM토큰_설정_수정_성공() { - Long userId = 1L; String token = "testToken"; FcmTokenUpdateRequest request = new FcmTokenUpdateRequest(token, true, 30); FcmToken fcmToken = FcmToken.builder() - .user(User.builder().id(userId).build()) .token(token) .isNotificationEnabled(false) .notificationOffset(15) .build(); - when(fcmTokenRepository.findByUserIdAndToken(userId, token)).thenReturn(Optional.of(fcmToken)); + when(fcmTokenRepository.findByToken(token)).thenReturn(Optional.of(fcmToken)); - assertDoesNotThrow(() -> fcmTokenService.updateFcmTokenSettings(userId, request)); + assertDoesNotThrow(() -> fcmTokenService.updateFcmTokenSettings(request)); verify(fcmTokenRepository, times(1)).save(any(FcmToken.class)); } @Test void FCM토큰_설정_수정_토큰없음_예외발생() { - Long userId = 1L; String token = "testToken"; FcmTokenUpdateRequest request = new FcmTokenUpdateRequest(token, true, 30); - when(fcmTokenRepository.findByUserIdAndToken(userId, token)).thenReturn(Optional.empty()); + when(fcmTokenRepository.findByToken(token)).thenReturn(Optional.empty()); BusinessException exception = assertThrows(BusinessException.class, () -> - fcmTokenService.updateFcmTokenSettings(userId, request)); + fcmTokenService.updateFcmTokenSettings(request)); verify(fcmTokenRepository, never()).save(any(FcmToken.class)); } @Test void FCM토큰_삭제_성공() { - Long userId = 1L; String token = "testToken"; - FcmToken fcmToken = FcmToken.builder() - .user(User.builder().id(userId).build()) - .token(token) - .build(); + FcmToken fcmToken = FcmToken.builder().token(token).build(); - when(fcmTokenRepository.findByUserIdAndToken(userId, token)).thenReturn(Optional.of(fcmToken)); + when(fcmTokenRepository.findByToken(token)).thenReturn(Optional.of(fcmToken)); - assertDoesNotThrow(() -> fcmTokenService.deleteFcmToken(userId, token)); + assertDoesNotThrow(() -> fcmTokenService.deleteFcmToken(token)); verify(fcmTokenRepository, times(1)).delete(fcmToken); } @Test void FCM토큰_삭제_토큰없음_예외발생() { - Long userId = 1L; String token = "testToken"; - when(fcmTokenRepository.findByUserIdAndToken(userId, token)).thenReturn(Optional.empty()); + when(fcmTokenRepository.findByToken(token)).thenReturn(Optional.empty()); BusinessException exception = assertThrows(BusinessException.class, () -> - fcmTokenService.deleteFcmToken(userId, token)); + fcmTokenService.deleteFcmToken(token)); verify(fcmTokenRepository, never()).delete(any(FcmToken.class)); } -} \ No newline at end of file +} From 2fbd42337ad7af861c14d836409f351dfe34ccef Mon Sep 17 00:00:00 2001 From: kanguk Date: Thu, 14 Nov 2024 09:23:23 +0900 Subject: [PATCH 3/9] =?UTF-8?q?refactor:=20GPT=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EB=8D=94=20=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 더 정확하게 한다. --- .../splanet/gpt/service/GptService.java | 14 ++++++++----- .../splanet/splanet/plan/dto/PlanTimeDto.java | 21 +++++++++++++++++++ .../plan/repository/PlanRepository.java | 3 +++ .../splanet/plan/service/PlanService.java | 12 ++++++----- 4 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/splanet/splanet/plan/dto/PlanTimeDto.java diff --git a/src/main/java/com/splanet/splanet/gpt/service/GptService.java b/src/main/java/com/splanet/splanet/gpt/service/GptService.java index a4fc07f2..0df8170d 100644 --- a/src/main/java/com/splanet/splanet/gpt/service/GptService.java +++ b/src/main/java/com/splanet/splanet/gpt/service/GptService.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.splanet.splanet.core.properties.GptProperties; import com.splanet.splanet.plan.dto.PlanResponseDto; +import com.splanet.splanet.plan.dto.PlanTimeDto; import com.splanet.splanet.plan.service.PlanService; import org.springframework.ai.openai.api.OpenAiApi; import org.springframework.http.ResponseEntity; @@ -25,9 +26,9 @@ public class GptService { private static final double RESPONSE_TEMPERATURE = 0.8; private static final Map PROMPT_TEMPLATES = Map.of( - 3, "사용자 입력: \"%s\" (deviceId: %s) (groupId: %s) 기존 일정이 있다면 해당 시간과는 겹치지 않게 해 줘 기존일정:%s 현재 시간 이후로 가능한 자주 반복하여 짧고 집중적으로 일정을 완수할 수 있도록 계획을 세워줘. 시험이 포함된 경우, 시험 당일이 아닌 전날까지 준비가 완료되도록 해줘 (%s 기준). 모든 일정은 한국 시간(UTC+9)을 기준으로 설정해줘.", - 2, "사용자 입력: \"%s\" (deviceId: %s) (groupId: %s) 기존 일정이 있다면 해당 시간과는 겹치지 않게 해 줘 기존일정:%s 현재 시간 이후로 적당한 간격을 두고 모든 일정을 완수할 수 있도록 계획해줘. 시험이 포함된 경우, 시험 당일이 아닌 전날까지 준비가 완료되도록 해줘 (%s 기준). 모든 일정은 한국 시간(UTC+9)을 기준으로 설정해줘.", - 1, "사용자 입력: \"%s\" (deviceId: %s) (groupId: %s) 기존 일정이 있다면 해당 시간과는 겹치지 않게 해 줘 기존일정:%s 현재 시간 이후로 여유 있게 모든 일정을 완수할 수 있도록 계획해줘. 시험이 포함된 경우, 시험 당일이 아닌 전날까지 준비가 완료되도록 해줘 (%s 기준). 모든 일정은 한국 시간(UTC+9)을 기준으로 설정해줘." + 3, "사용자 입력: \"%s\" (deviceId: %s) (groupId: %s) 기존 startDate와 endDate사이에 일정을 생성하지 말아줘. 기존 startDate, endDate:%s 현재 시간 이후로 가능한 자주 반복하여 짧고 집중적으로 일정을 완수할 수 있도록 계획을 세워줘. 시험이 포함된 경우, 시험 당일이 아닌 전날까지 준비가 완료되도록 해줘 (%s 기준). 모든 일정은 한국 시간(UTC+9)을 기준으로 설정해줘.", + 2, "사용자 입력: \"%s\" (deviceId: %s) (groupId: %s) 기존 startDate와 endDate사이에 일정을 생성하지 말아줘. 기존 startDate, endDate:%s 현재 시간 이후로 적당한 간격을 두고 모든 일정을 완수할 수 있도록 계획해줘. 시험이 포함된 경우, 시험 당일이 아닌 전날까지 준비가 완료되도록 해줘 (%s 기준). 모든 일정은 한국 시간(UTC+9)을 기준으로 설정해줘.", + 1, "사용자 입력: \"%s\" (deviceId: %s) (groupId: %s) 기존 startDate와 endDate사이에 일정을 생성하지 말아줘. 기존 startDate, endDate:%s 현재 시간 이후로 여유 있게 모든 일정을 완수할 수 있도록 계획해줘. 시험이 포함된 경우, 시험 당일이 아닌 전날까지 준비가 완료되도록 해줘 (%s 기준). 모든 일정은 한국 시간(UTC+9)을 기준으로 설정해줘." ); public GptService(OpenAiApi openAiApi, GptProperties gptProperties, PlanService planService, ObjectMapper objectMapper) { @@ -39,7 +40,7 @@ public GptService(OpenAiApi openAiApi, GptProperties gptProperties, PlanService public String generateResponse(String userInput, Long userId, String deviceId, int groupId) { String currentTime = getCurrentTime(); - List futurePlans = (userId != null) ? planService.getAllFuturePlansByUserId(userId) : List.of(); + List futurePlans = (userId != null) ? planService.getAllFuturePlanTimesByUserId(userId) : List.of(); String planJson = convertPlansToJson(futurePlans); String promptTemplate = PROMPT_TEMPLATES.get(groupId); String fullPrompt = String.format(promptTemplate, userInput, deviceId, groupId, planJson, currentTime); @@ -47,14 +48,17 @@ public String generateResponse(String userInput, Long userId, String deviceId, i OpenAiApi.ChatCompletionMessage userMessage = createUserMessage(fullPrompt); OpenAiApi.ChatCompletionRequest chatRequest = createChatRequest(userMessage); + System.out.println(fullPrompt); + return getGptResponse(chatRequest); + } private String getCurrentTime() { return LocalDateTime.now(ZoneId.of("Asia/Seoul")).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); } - private String convertPlansToJson(List futurePlans) { + private String convertPlansToJson(List futurePlans) { try { return objectMapper.writeValueAsString(futurePlans); } catch (JsonProcessingException e) { diff --git a/src/main/java/com/splanet/splanet/plan/dto/PlanTimeDto.java b/src/main/java/com/splanet/splanet/plan/dto/PlanTimeDto.java new file mode 100644 index 00000000..09a951a6 --- /dev/null +++ b/src/main/java/com/splanet/splanet/plan/dto/PlanTimeDto.java @@ -0,0 +1,21 @@ +package com.splanet.splanet.plan.dto; + +import java.time.LocalDateTime; + +public class PlanTimeDto { + private LocalDateTime startDate; + private LocalDateTime endDate; + + public PlanTimeDto(LocalDateTime startDate, LocalDateTime endDate) { + this.startDate = startDate; + this.endDate = endDate; + } + + public LocalDateTime getStartDate() { + return startDate; + } + + public LocalDateTime getEndDate() { + return endDate; + } +} diff --git a/src/main/java/com/splanet/splanet/plan/repository/PlanRepository.java b/src/main/java/com/splanet/splanet/plan/repository/PlanRepository.java index 731c1f0c..5a57110d 100644 --- a/src/main/java/com/splanet/splanet/plan/repository/PlanRepository.java +++ b/src/main/java/com/splanet/splanet/plan/repository/PlanRepository.java @@ -18,4 +18,7 @@ public interface PlanRepository extends JpaRepository { @Query("SELECT p FROM Plan p JOIN FETCH p.user WHERE p.startDate > :now AND p.isCompleted = false") List findUpcomingPlans(@Param("now") LocalDateTime now); + @Query("SELECT p FROM Plan p WHERE p.user.id = :userId AND p.startDate > :currentTime") + List findAllFuturePlansByUserId(@Param("userId") Long userId, @Param("currentTime") LocalDateTime currentTime); + } \ No newline at end of file diff --git a/src/main/java/com/splanet/splanet/plan/service/PlanService.java b/src/main/java/com/splanet/splanet/plan/service/PlanService.java index d40d1796..f7dfa42c 100644 --- a/src/main/java/com/splanet/splanet/plan/service/PlanService.java +++ b/src/main/java/com/splanet/splanet/plan/service/PlanService.java @@ -2,6 +2,7 @@ import com.splanet.splanet.plan.dto.PlanRequestDto; import com.splanet.splanet.plan.dto.PlanResponseDto; +import com.splanet.splanet.plan.dto.PlanTimeDto; import com.splanet.splanet.plan.entity.Plan; import com.splanet.splanet.plan.mapper.PlanMapper; import com.splanet.splanet.plan.repository.PlanRepository; @@ -16,6 +17,7 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Set; @@ -118,11 +120,11 @@ private Plan convertToPlan(PlanCardResponseDto previewCard, User user, DateTimeF } @Transactional(readOnly = true) - public List getAllFuturePlansByUserId(Long userId) { - LocalDateTime now = LocalDateTime.now(); - List futurePlans = planRepository.findAllByUserIdAndStartDateAfter(userId, now); - return futurePlans.stream() - .map(planMapper::toResponseDto) + public List getAllFuturePlanTimesByUserId(Long userId) { + LocalDateTime currentTime = LocalDateTime.now(ZoneId.of("Asia/Seoul")); + return planRepository.findAllFuturePlansByUserId(userId, currentTime) + .stream() + .map(plan -> new PlanTimeDto(plan.getStartDate(), plan.getEndDate())) .collect(Collectors.toList()); } From 27f2884fe34783b6c9503185f33ee6f19a455829 Mon Sep 17 00:00:00 2001 From: kanguk Date: Thu, 14 Nov 2024 09:26:13 +0900 Subject: [PATCH 4/9] =?UTF-8?q?deploy:=20=EC=9D=BC=EB=8B=A8=20=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd.yml | 2 +- .gitignore | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 872194b9..3defda5a 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -5,7 +5,7 @@ on: branches: - develop - 'weekly/**' - - 142-refactor-cd-update + - refactor/166-refactor-fcm jobs: deploy: diff --git a/.gitignore b/.gitignore index b502fe8e..f8c40ac3 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,5 @@ splanet-db ### env ### .env /src/main/resources/env.properties +/src/main/resources/env.properties.base64 splanet-firebase.json \ No newline at end of file From 12131a0abf2d9d308077d578c39e9daa4d4719c8 Mon Sep 17 00:00:00 2001 From: kanguk Date: Thu, 14 Nov 2024 13:21:38 +0900 Subject: [PATCH 5/9] =?UTF-8?q?refactor:=20plan=20=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=9D=98=EB=8F=84=EC=B9=98=20=EC=95=8A=EA=B2=8C=20=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EB=B6=80=EB=B6=84=EC=9D=B4=20=EB=A6=AC?= =?UTF-8?q?=ED=84=B4=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=B6=80?= =?UTF-8?q?=EB=B6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/splanet/splanet/plan/dto/PlanResponseDto.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/com/splanet/splanet/plan/dto/PlanResponseDto.java b/src/main/java/com/splanet/splanet/plan/dto/PlanResponseDto.java index 49279433..33ab0619 100644 --- a/src/main/java/com/splanet/splanet/plan/dto/PlanResponseDto.java +++ b/src/main/java/com/splanet/splanet/plan/dto/PlanResponseDto.java @@ -14,11 +14,9 @@ public class PlanResponseDto { private String description; private LocalDateTime startDate; private LocalDateTime endDate; - - @JsonIgnore private Boolean accessibility; - @JsonIgnore private Boolean isCompleted; + @JsonIgnore private LocalDateTime createdAt; @JsonIgnore From f34540cbf6d9597df75f316cb03289877423a67e Mon Sep 17 00:00:00 2001 From: kanguk Date: Thu, 14 Nov 2024 20:46:09 +0900 Subject: [PATCH 6/9] =?UTF-8?q?refactor:=20GPT=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/splanet/splanet/gpt/service/GptService.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/splanet/splanet/gpt/service/GptService.java b/src/main/java/com/splanet/splanet/gpt/service/GptService.java index 0df8170d..576dfbc7 100644 --- a/src/main/java/com/splanet/splanet/gpt/service/GptService.java +++ b/src/main/java/com/splanet/splanet/gpt/service/GptService.java @@ -26,9 +26,9 @@ public class GptService { private static final double RESPONSE_TEMPERATURE = 0.8; private static final Map PROMPT_TEMPLATES = Map.of( - 3, "사용자 입력: \"%s\" (deviceId: %s) (groupId: %s) 기존 startDate와 endDate사이에 일정을 생성하지 말아줘. 기존 startDate, endDate:%s 현재 시간 이후로 가능한 자주 반복하여 짧고 집중적으로 일정을 완수할 수 있도록 계획을 세워줘. 시험이 포함된 경우, 시험 당일이 아닌 전날까지 준비가 완료되도록 해줘 (%s 기준). 모든 일정은 한국 시간(UTC+9)을 기준으로 설정해줘.", - 2, "사용자 입력: \"%s\" (deviceId: %s) (groupId: %s) 기존 startDate와 endDate사이에 일정을 생성하지 말아줘. 기존 startDate, endDate:%s 현재 시간 이후로 적당한 간격을 두고 모든 일정을 완수할 수 있도록 계획해줘. 시험이 포함된 경우, 시험 당일이 아닌 전날까지 준비가 완료되도록 해줘 (%s 기준). 모든 일정은 한국 시간(UTC+9)을 기준으로 설정해줘.", - 1, "사용자 입력: \"%s\" (deviceId: %s) (groupId: %s) 기존 startDate와 endDate사이에 일정을 생성하지 말아줘. 기존 startDate, endDate:%s 현재 시간 이후로 여유 있게 모든 일정을 완수할 수 있도록 계획해줘. 시험이 포함된 경우, 시험 당일이 아닌 전날까지 준비가 완료되도록 해줘 (%s 기준). 모든 일정은 한국 시간(UTC+9)을 기준으로 설정해줘." + 3, "사용자 입력: \"%s\" (deviceId: %s) (groupId: %s) 제공된 가이드라인을 따르지 않으면 페널티가 부과될 것입니다. 모든 지침을 주의깊게 읽고 그에 따라 행동하세요. 기존 startDate와 endDate사이에 일정을 생성하지 말아줘. 기존 startDate, endDate:%s 현재 시간 이후로 가능한 자주 반복하여 짧고 집중적으로 일정을 완수할 수 있도록 계획을 세워줘. 현재 시간 : (%s 기준). 모든 일정은 한국 시간(UTC+9)을 기준으로 설정해줘. 또한, 기존 일정을 생각하고 새로운 일정을 적당한 간격을 두고 배치해줘.", + 2, "사용자 입력: \"%s\" (deviceId: %s) (groupId: %s) 제공된 가이드라인을 따르지 않으면 페널티가 부과될 것입니다. 모든 지침을 주의깊게 읽고 그에 따라 행동하세요. 기존 startDate와 endDate사이에 일정을 생성하지 말아줘. 기존 startDate, endDate:%s 현재 시간 이후로 적당한 간격을 두고 모든 일정을 완수할 수 있도록 계획해줘. 현재 시간 : (%s 기준). 모든 일정은 한국 시간(UTC+9)을 기준으로 설정해줘. 또한, 기존 일정을 생각하고 새로운 일정을 적당한 간격을 두고 배치해줘.", + 1, "사용자 입력: \"%s\" (deviceId: %s) (groupId: %s) 제공된 가이드라인을 따르지 않으면 페널티가 부과될 것입니다. 모든 지침을 주의깊게 읽고 그에 따라 행동하세요. 기존 startDate와 endDate사이에 일정을 생성하지 말아줘. 기존 startDate, endDate:%s 현재 시간 이후로 여유 있게 모든 일정을 완수할 수 있도록 계획해줘. 현재 시간 : (%s 기준). 모든 일정은 한국 시간(UTC+9)을 기준으로 설정해줘. 또한, 기존 일정을 생각하고 새로운 일정을 적당한 간격을 두고 배치해줘." ); public GptService(OpenAiApi openAiApi, GptProperties gptProperties, PlanService planService, ObjectMapper objectMapper) { @@ -89,3 +89,4 @@ private String getGptResponse(OpenAiApi.ChatCompletionRequest chatRequest) { } } } + From 9100e0c4ae93dc1121d9cdf1d072e40435fcd401 Mon Sep 17 00:00:00 2001 From: kanguk Date: Fri, 15 Nov 2024 01:49:04 +0900 Subject: [PATCH 7/9] =?UTF-8?q?refactor:=20FCM=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20API=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/controller/FcmTokenApi.java | 27 ++++-------- .../controller/FcmTokenController.java | 12 ++++-- .../notification/service/FcmTokenService.java | 24 +++++++---- .../service/FcmTokenServiceTest.java | 43 +++++++++++++++---- 4 files changed, 66 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/splanet/splanet/notification/controller/FcmTokenApi.java b/src/main/java/com/splanet/splanet/notification/controller/FcmTokenApi.java index ded58677..9b14df7c 100644 --- a/src/main/java/com/splanet/splanet/notification/controller/FcmTokenApi.java +++ b/src/main/java/com/splanet/splanet/notification/controller/FcmTokenApi.java @@ -16,33 +16,24 @@ public interface FcmTokenApi { @PostMapping("/register") - @Operation(summary = "FCM 토큰 등록", description = "유저가 FCM 토큰을 등록합니다.") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "FCM 토큰이 성공적으로 등록되었습니다."), - @ApiResponse(responseCode = "404", description = "유저를 찾을 수 없습니다.", content = @Content) - }) ResponseEntity registerFcmToken( @AuthenticationPrincipal Long userId, @RequestBody FcmTokenRequest fcmTokenRequest ); - @PutMapping("/update") - @Operation(summary = "FCM 토큰 설정 수정", description = "알림 설정 및 알림 오프셋을 수정합니다.") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "FCM 토큰 설정이 성공적으로 수정되었습니다."), - @ApiResponse(responseCode = "404", description = "토큰을 찾을 수 없습니다.", content = @Content) - }) - ResponseEntity updateFcmTokenSettings( - @RequestBody FcmTokenUpdateRequest fcmTokenUpdateRequest + @PutMapping("/update/notification-enabled") + ResponseEntity updateNotificationEnabled( + @RequestParam String token, + @RequestParam Boolean isNotificationEnabled ); + @PutMapping("/update/notification-offset") + ResponseEntity updateNotificationOffset( + @RequestParam String token, + @RequestParam Integer notificationOffset + ); @DeleteMapping("/delete") - @Operation(summary = "FCM 토큰 삭제", description = "유저의 FCM 토큰을 삭제합니다.") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "FCM 토큰이 성공적으로 삭제되었습니다."), - @ApiResponse(responseCode = "404", description = "해당 토큰을 찾을 수 없습니다.", content = @Content) - }) ResponseEntity deleteFcmToken( @RequestParam String token ); diff --git a/src/main/java/com/splanet/splanet/notification/controller/FcmTokenController.java b/src/main/java/com/splanet/splanet/notification/controller/FcmTokenController.java index 93507b7b..d4b66f01 100644 --- a/src/main/java/com/splanet/splanet/notification/controller/FcmTokenController.java +++ b/src/main/java/com/splanet/splanet/notification/controller/FcmTokenController.java @@ -1,7 +1,6 @@ package com.splanet.splanet.notification.controller; import com.splanet.splanet.notification.dto.FcmTokenRequest; -import com.splanet.splanet.notification.dto.FcmTokenUpdateRequest; import com.splanet.splanet.notification.service.FcmTokenService; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -21,11 +20,16 @@ public ResponseEntity registerFcmToken(Long userId, FcmTokenRequest fcmT } @Override - public ResponseEntity updateFcmTokenSettings(FcmTokenUpdateRequest fcmTokenUpdateRequest) { - fcmTokenService.updateFcmTokenSettings(fcmTokenUpdateRequest); - return ResponseEntity.ok("FCM 토큰 수정 완료"); + public ResponseEntity updateNotificationEnabled(String token, Boolean isNotificationEnabled) { + fcmTokenService.updateNotificationEnabled(token, isNotificationEnabled); + return ResponseEntity.ok("FCM 알림 여부 수정 완료"); } + @Override + public ResponseEntity updateNotificationOffset(String token, Integer notificationOffset) { + fcmTokenService.updateNotificationOffset(token, notificationOffset); + return ResponseEntity.ok("FCM 알림 오프셋 수정 완료"); + } @Override public ResponseEntity deleteFcmToken(String token) { diff --git a/src/main/java/com/splanet/splanet/notification/service/FcmTokenService.java b/src/main/java/com/splanet/splanet/notification/service/FcmTokenService.java index 6b3676d1..fea0ddc0 100644 --- a/src/main/java/com/splanet/splanet/notification/service/FcmTokenService.java +++ b/src/main/java/com/splanet/splanet/notification/service/FcmTokenService.java @@ -1,4 +1,3 @@ -// src/main/java/com/splanet/splanet/notification/service/FcmTokenService.java package com.splanet.splanet.notification.service; import com.splanet.splanet.core.exception.BusinessException; @@ -34,17 +33,24 @@ public void registerFcmToken(Long userId, String token) { } @Transactional - public void updateFcmTokenSettings(FcmTokenUpdateRequest request) { - FcmToken fcmToken = fcmTokenRepository.findByToken(request.token()) + public void updateNotificationEnabled(String token, Boolean isNotificationEnabled) { + FcmToken fcmToken = fcmTokenRepository.findByToken(token) + .orElseThrow(() -> new BusinessException(ErrorCode.TOKEN_NOT_FOUND)); + + fcmToken = fcmToken.toBuilder() + .isNotificationEnabled(isNotificationEnabled != null ? isNotificationEnabled : fcmToken.getIsNotificationEnabled()) + .build(); + + fcmTokenRepository.save(fcmToken); + } + + @Transactional + public void updateNotificationOffset(String token, Integer notificationOffset) { + FcmToken fcmToken = fcmTokenRepository.findByToken(token) .orElseThrow(() -> new BusinessException(ErrorCode.TOKEN_NOT_FOUND)); fcmToken = fcmToken.toBuilder() - .isNotificationEnabled(request.isNotificationEnabled() != null - ? request.isNotificationEnabled() - : fcmToken.getIsNotificationEnabled()) - .notificationOffset(request.notificationOffset() != null - ? request.notificationOffset() - : fcmToken.getNotificationOffset()) + .notificationOffset(notificationOffset != null ? notificationOffset : fcmToken.getNotificationOffset()) .build(); fcmTokenRepository.save(fcmToken); diff --git a/src/test/java/com/splanet/splanet/notification/service/FcmTokenServiceTest.java b/src/test/java/com/splanet/splanet/notification/service/FcmTokenServiceTest.java index 2a8ece7d..766a0791 100644 --- a/src/test/java/com/splanet/splanet/notification/service/FcmTokenServiceTest.java +++ b/src/test/java/com/splanet/splanet/notification/service/FcmTokenServiceTest.java @@ -56,37 +56,62 @@ class FcmTokenServiceTest { when(userRepository.findById(userId)).thenReturn(Optional.empty()); - BusinessException exception = assertThrows(BusinessException.class, () -> + assertThrows(BusinessException.class, () -> fcmTokenService.registerFcmToken(userId, token)); verify(fcmTokenRepository, never()).save(any(FcmToken.class)); } @Test - void FCM토큰_설정_수정_성공() { + void FCM알림여부_수정_성공() { String token = "testToken"; - FcmTokenUpdateRequest request = new FcmTokenUpdateRequest(token, true, 30); + Boolean isNotificationEnabled = true; FcmToken fcmToken = FcmToken.builder() .token(token) .isNotificationEnabled(false) + .build(); + + when(fcmTokenRepository.findByToken(token)).thenReturn(Optional.of(fcmToken)); + + assertDoesNotThrow(() -> fcmTokenService.updateNotificationEnabled(token, isNotificationEnabled)); + verify(fcmTokenRepository, times(1)).save(any(FcmToken.class)); + } + + @Test + void FCM알림여부_수정_토큰없음_예외발생() { + String token = "testToken"; + + when(fcmTokenRepository.findByToken(token)).thenReturn(Optional.empty()); + + assertThrows(BusinessException.class, () -> + fcmTokenService.updateNotificationEnabled(token, true)); + verify(fcmTokenRepository, never()).save(any(FcmToken.class)); + } + + @Test + void FCM알림오프셋_수정_성공() { + String token = "testToken"; + Integer notificationOffset = 30; + + FcmToken fcmToken = FcmToken.builder() + .token(token) .notificationOffset(15) .build(); when(fcmTokenRepository.findByToken(token)).thenReturn(Optional.of(fcmToken)); - assertDoesNotThrow(() -> fcmTokenService.updateFcmTokenSettings(request)); + assertDoesNotThrow(() -> fcmTokenService.updateNotificationOffset(token, notificationOffset)); verify(fcmTokenRepository, times(1)).save(any(FcmToken.class)); } @Test - void FCM토큰_설정_수정_토큰없음_예외발생() { + void FCM알림오프셋_수정_토큰없음_예외발생() { String token = "testToken"; - FcmTokenUpdateRequest request = new FcmTokenUpdateRequest(token, true, 30); when(fcmTokenRepository.findByToken(token)).thenReturn(Optional.empty()); - BusinessException exception = assertThrows(BusinessException.class, () -> - fcmTokenService.updateFcmTokenSettings(request)); + assertThrows(BusinessException.class, () -> + fcmTokenService.updateNotificationOffset(token, 30)); verify(fcmTokenRepository, never()).save(any(FcmToken.class)); } @@ -108,7 +133,7 @@ class FcmTokenServiceTest { when(fcmTokenRepository.findByToken(token)).thenReturn(Optional.empty()); - BusinessException exception = assertThrows(BusinessException.class, () -> + assertThrows(BusinessException.class, () -> fcmTokenService.deleteFcmToken(token)); verify(fcmTokenRepository, never()).delete(any(FcmToken.class)); } From 81f229fbda26488ff2dc9847d841a0d3f08110c5 Mon Sep 17 00:00:00 2001 From: kanguk Date: Fri, 15 Nov 2024 02:25:47 +0900 Subject: [PATCH 8/9] =?UTF-8?q?refactor:=20FCM=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=ED=81=B4=EB=A6=AD=20=EC=8B=9C=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/service/NotificationService.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/splanet/splanet/notification/service/NotificationService.java b/src/main/java/com/splanet/splanet/notification/service/NotificationService.java index 500289ac..828d0237 100644 --- a/src/main/java/com/splanet/splanet/notification/service/NotificationService.java +++ b/src/main/java/com/splanet/splanet/notification/service/NotificationService.java @@ -42,7 +42,16 @@ public void sendNotification(FcmToken fcmToken, Plan plan) { Notification notification = new Notification(title, body); - Message message = Message.builder().setToken(fcmToken.getToken()).setNotification(notification).putData("title", plan.getTitle()).putData("title", plan.getDescription()).putData("startDate", plan.getStartDate().toString()).build(); + String clickActionUrl = "https://www.splanet.co.kr"; + + Message message = Message.builder().setToken(fcmToken.getToken()) + .setNotification(notification) + .putData("click_action", clickActionUrl) + .putData("title", plan.getTitle()) + .putData("description", plan.getDescription()) + .putData("startDate", plan.getStartDate().toString()) + .build(); + try { String response = firebaseMessaging.send(message); log.info("알림을 정상적으로 전송하였습니다. : {}", response); From fcaac31d0fb5b0ab7cf0d547c5adf781126d252e Mon Sep 17 00:00:00 2001 From: kanguk Date: Fri, 15 Nov 2024 02:29:15 +0900 Subject: [PATCH 9/9] =?UTF-8?q?refactor:=20=EB=94=94=EB=B2=84=EA=B9=85?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=B4=20=EC=B6=94=EA=B0=80=ED=96=88?= =?UTF-8?q?=EB=8D=98=20=EB=B6=80=EB=B6=84=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd.yml | 1 - src/main/java/com/splanet/splanet/gpt/service/GptService.java | 3 --- 2 files changed, 4 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 3defda5a..1bc58047 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -5,7 +5,6 @@ on: branches: - develop - 'weekly/**' - - refactor/166-refactor-fcm jobs: deploy: diff --git a/src/main/java/com/splanet/splanet/gpt/service/GptService.java b/src/main/java/com/splanet/splanet/gpt/service/GptService.java index 576dfbc7..89275423 100644 --- a/src/main/java/com/splanet/splanet/gpt/service/GptService.java +++ b/src/main/java/com/splanet/splanet/gpt/service/GptService.java @@ -48,10 +48,7 @@ public String generateResponse(String userInput, Long userId, String deviceId, i OpenAiApi.ChatCompletionMessage userMessage = createUserMessage(fullPrompt); OpenAiApi.ChatCompletionRequest chatRequest = createChatRequest(userMessage); - System.out.println(fullPrompt); - return getGptResponse(chatRequest); - } private String getCurrentTime() {