diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml deleted file mode 100644 index 93dfa74e..00000000 --- a/.github/workflows/cd.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: CD Backend - -on: - push: - branches: [ "main", "dev" ] - -permissions: - contents: read - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - # 자바 버전 설정 - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: '17' - distribution: 'temurin' - - # yml 파일 생성 - - name: Generate application-core.yml - run: | - mkdir -p ./core/src/main/resources - echo "${{ secrets.APPLICATION_CORE }}" | base64 -d > ./core/src/main/resources/application-core.yml - - # firebase json 파일 생성 - - name : Generate firebase_account.json - run: | - mkdir -p ./core/src/main/resources/firebase - echo "${{ secrets.FIREBASE_ACCOUNT }}" | base64 -d > ./core/src/main/resources/firebase/firebase_account.json - - # gradle 권한 부여 - - name: Grant execute permission for gradlew - run: chmod +x ./gradlew - shell: bash - - # 빌드 시 캐시 적용 - - name: Gradle Caching - uses: actions/cache@v3 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- - - # 빌드 - - name: Build with Gradle - run: ./gradlew build -x test - - - # 도커 허브 로그인 - - name: Docker Hub Login - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - # 도커 이미지 빌드 및 푸시 - - name: docker image build and push - run: | - docker build -f Dockerfile -t ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_APP_NAME }} . - docker push ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_APP_NAME }} - - # 서버 백그라운드 실행 - - name: pull image and run container - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.EC2_HOST }} - username: ${{ secrets.EC2_USERNAME }} - key: ${{ secrets.EC2_KEY }} - port: ${{ secrets.EC2_PORT }} - script: | - cd compose - docker rm -f $(docker ps -qa) - docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_APP_NAME }} - docker-compose up -d - docker system prune -f \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 486b9136..baa0fef3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI Backend on: pull_request: - branches: ["main", "dev"] + branches: [ "main", "dev" ] permissions: contents: read @@ -27,16 +27,16 @@ jobs: distribution: 'temurin' # firebase json 파일 생성 - - name : Generate firebase_account.json + - name: Generate serviceAccountKey.json run: | mkdir -p ./core/src/main/resources/firebase - echo "${{ secrets.FIREBASE_ACCOUNT }}" | base64 -d > ./core/src/main/resources/firebase/firebase_account.json - mkdir -p ./core/src/test/resources/firebase - echo "${{ secrets.FIREBASE_ACCOUNT }}" | base64 -d > ./core/src/test/resources/firebase/firebase_account.json - mkdir -p ./api/src/test/resources/firebase - echo "${{ secrets.FIREBASE_ACCOUNT }}" | base64 -d > ./api/src/test/resources/firebase/firebase_account.json + echo "${{ secrets.FIREBASE_KEY }}" | base64 -d > ./core/src/main/resources/firebase/serviceAccountKey.json +# mkdir -p ./core/src/test/resources/firebase +# echo "${{ secrets.FIREBASE_KEY }}" | base64 -d > ./core/src/test/resources/firebase/serviceAccountKey.json +# mkdir -p ./api/src/test/resources/firebase +# echo "${{ secrets.FIREBASE_KEY }}" | base64 -d > ./api/src/test/resources/firebase/serviceAccountKey.json - # gradle 권한 부여 + # gradle 권한 부여 - name: Grant execute permission for gradlew run: chmod +x ./gradlew shell: bash diff --git a/.gitignore b/.gitignore index 50eb0168..0c305aeb 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,6 @@ out/ core/src/main/resources/application-core-prod.yml /api/src/main/resources/application.yml /core/src/main/generated/ -/core/src/main/resources/firebase/firebase_account.json -/core/src/test/resources/firebase/firebase_account.json -/api/src/test/resources/firebase/firebase_account.json /core/src/main/resources/application-core-local.yml +/core/src/main/resources/firebase/serviceAccountKey.json +/core/src/test/http diff --git a/api/src/main/java/dev/handsup/auth/controller/AuthApiController.java b/api/src/main/java/dev/handsup/auth/controller/AuthApiController.java index 7c999749..558ef250 100644 --- a/api/src/main/java/dev/handsup/auth/controller/AuthApiController.java +++ b/api/src/main/java/dev/handsup/auth/controller/AuthApiController.java @@ -17,7 +17,7 @@ import dev.handsup.auth.dto.response.TokenReIssueResponse; import dev.handsup.auth.jwt.JwtAuthorization; import dev.handsup.auth.service.AuthService; -import dev.handsup.notification.service.FCMService; +import dev.handsup.notification.service.FcmService; import dev.handsup.user.domain.User; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -35,7 +35,7 @@ public class AuthApiController { private final AuthService authService; - private final FCMService fcmService; + private final FcmService fcmService; @NoAuth @PostMapping("/login") @@ -60,7 +60,7 @@ public ResponseEntity login( public ResponseEntity logout( @Parameter(hidden = true) @JwtAuthorization User user ) { - fcmService.deleteFcmToken(user.getEmail()); + fcmService.deleteFcmToken(user.getId()); return ResponseEntity.ok(HttpStatus.OK); } diff --git a/api/src/main/java/dev/handsup/notification/controller/FcmController.java b/api/src/main/java/dev/handsup/notification/controller/FcmController.java new file mode 100644 index 00000000..969cf3e4 --- /dev/null +++ b/api/src/main/java/dev/handsup/notification/controller/FcmController.java @@ -0,0 +1,34 @@ +package dev.handsup.notification.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import dev.handsup.auth.jwt.JwtAuthorization; +import dev.handsup.notification.dto.SaveFcmTokenRequest; +import dev.handsup.notification.service.FcmService; +import dev.handsup.user.domain.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +public class FcmController { + private final FcmService fcmService; + + @PostMapping("/api/fcm-tokens") + @Operation(summary = "FCM 토큰 저장 API", description = "{사용자 아이디 : FCM 토큰}을 redis에 저장") + @ApiResponse(useReturnTypeSchema = true) + public ResponseEntity saveFCMToken( + @Parameter(hidden = true) @JwtAuthorization User user, + @RequestBody @Valid SaveFcmTokenRequest request + ) { + fcmService.saveFcmToken(user.getId(), request.fcmToken()); + return ResponseEntity.ok(HttpStatus.OK); + } +} diff --git a/api/src/main/java/dev/handsup/notification/controller/NotificationApiController.java b/api/src/main/java/dev/handsup/notification/controller/NotificationApiController.java deleted file mode 100644 index 832c6d3f..00000000 --- a/api/src/main/java/dev/handsup/notification/controller/NotificationApiController.java +++ /dev/null @@ -1,71 +0,0 @@ -package dev.handsup.notification.controller; - -import org.springframework.data.domain.Pageable; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import dev.handsup.auth.jwt.JwtAuthorization; -import dev.handsup.common.dto.PageResponse; -import dev.handsup.notification.dto.request.SaveFCMTokenRequest; -import dev.handsup.notification.dto.response.CountUserNotificationsResponse; -import dev.handsup.notification.dto.response.NotificationResponse; -import dev.handsup.notification.service.FCMService; -import dev.handsup.notification.service.NotificationService; -import dev.handsup.user.domain.User; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.RequiredArgsConstructor; - -@Tag(name = "알림 API") -@RequestMapping("/api/notifications") -@RestController -@RequiredArgsConstructor -public class NotificationApiController { - - private final NotificationService notificationService; - private final FCMService fcmService; - - @PostMapping("/fcm-tokens") - @Operation(summary = "FCM 토큰 저장 API", description = "사용자의 Email, FCM 토큰을 key, value 로 저장한다") - @ApiResponse(useReturnTypeSchema = true) - public ResponseEntity saveFCMToken( - @Parameter(hidden = true) @JwtAuthorization User user, - @RequestBody SaveFCMTokenRequest request - ) { - fcmService.saveFcmToken(user.getEmail(), request); - return ResponseEntity.ok(HttpStatus.OK); - } - - @GetMapping("/count") - @Operation(summary = "미확인 알림 수 조회 API", description = "특정 사용자의 확인하지 않은 알림 수를 조회한다") - @ApiResponse(useReturnTypeSchema = true) - public ResponseEntity countUserNotifications( - @Parameter(hidden = true) @JwtAuthorization User user - ) { - long readNotificationCount = user.getReadNotificationCount(); - long notificationsCount = notificationService.countNotificationsByUserEmail(user.getEmail()); - CountUserNotificationsResponse response = CountUserNotificationsResponse.from( - notificationsCount - readNotificationCount - ); - return ResponseEntity.ok(response); - } - - @GetMapping() - @Operation(summary = "알림 전체 조회 API", description = "특정 사용자가 받은 알림을 최근 생성 순으로 전체 조회한다") - @ApiResponse(useReturnTypeSchema = true) - public ResponseEntity> getUserReviewLabels( - @Parameter(hidden = true) @JwtAuthorization User user, - Pageable pageable - ) { - PageResponse response = notificationService.getNotifications(user, pageable); - return ResponseEntity.ok(response); - } - -} diff --git a/api/src/main/java/dev/handsup/notification/controller/NotificationController.java b/api/src/main/java/dev/handsup/notification/controller/NotificationController.java new file mode 100644 index 00000000..3b31e6ad --- /dev/null +++ b/api/src/main/java/dev/handsup/notification/controller/NotificationController.java @@ -0,0 +1,33 @@ +package dev.handsup.notification.controller; + +import org.springframework.data.domain.Pageable; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import dev.handsup.auth.jwt.JwtAuthorization; +import dev.handsup.common.dto.PageResponse; +import dev.handsup.notification.dto.NotificationResponse; +import dev.handsup.notification.service.NotificationService; +import dev.handsup.user.domain.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +public class NotificationController { + private final NotificationService notificationService; + + @GetMapping("/api/notifications") + @Operation(summary = "알림 전체 조회 API", description = "특정 사용자가 받은 알림을 최근 생성 순으로 전체 조회한다") + @ApiResponse(useReturnTypeSchema = true) + public ResponseEntity> getUserNotifications( + @Parameter(hidden = true) @JwtAuthorization User user, + Pageable pageable + ) { + PageResponse response = notificationService.getNotifications(user, pageable); + return ResponseEntity.ok(response); + } +} diff --git a/api/src/test/java/dev/handsup/bidding/controller/BiddingApiControllerTest.java b/api/src/test/java/dev/handsup/bidding/controller/BiddingApiControllerTest.java index 61fb1844..ea8b878c 100644 --- a/api/src/test/java/dev/handsup/bidding/controller/BiddingApiControllerTest.java +++ b/api/src/test/java/dev/handsup/bidding/controller/BiddingApiControllerTest.java @@ -32,7 +32,6 @@ import dev.handsup.fixture.AuctionFixture; import dev.handsup.fixture.BiddingFixture; import dev.handsup.fixture.UserFixture; -import dev.handsup.notification.repository.FCMTokenRepository; import dev.handsup.user.domain.User; import dev.handsup.user.repository.UserRepository; @@ -56,8 +55,7 @@ class BiddingApiControllerTest extends ApiTestSupport { private AuctionService auctionService; @Autowired private JwtProvider jwtProvider; - @Autowired - private FCMTokenRepository fcmTokenRepository; + @BeforeEach void setUp() { @@ -170,7 +168,6 @@ void getTop3BidsForAuctionTest() throws Exception { @Test void completeTrading() throws Exception { //given - fcmTokenRepository.saveFcmToken(bidder.getEmail(), "fcmToken123"); ReflectionTestUtils.setField(auction1, "status", AuctionStatus.TRADING); //변경 감지 Bidding bidding = BiddingFixture.bidding(bidder, auction1, TradingStatus.PROGRESSING); biddingRepository.save(bidding); @@ -204,7 +201,6 @@ void completeTrading_fails() throws Exception { @Test void cancelTrading() throws Exception { //given - fcmTokenRepository.saveFcmToken(bidder.getEmail(), "fcmToken123"); Bidding waitingBidding1 = BiddingFixture.bidding(bidder, auction1, TradingStatus.WAITING, 200000); Bidding waitingBidding2 = BiddingFixture.bidding(bidder, auction1, TradingStatus.WAITING, 300000); Bidding anotherAuctionBidding = BiddingFixture.bidding(bidder, auction2, TradingStatus.WAITING, 400000); diff --git a/api/src/test/java/dev/handsup/bookmark/controller/BookmarkApiControllerTest.java b/api/src/test/java/dev/handsup/bookmark/controller/BookmarkApiControllerTest.java index 721f4b7e..9e2073d7 100644 --- a/api/src/test/java/dev/handsup/bookmark/controller/BookmarkApiControllerTest.java +++ b/api/src/test/java/dev/handsup/bookmark/controller/BookmarkApiControllerTest.java @@ -23,7 +23,6 @@ import dev.handsup.fixture.AuctionFixture; import dev.handsup.fixture.BookmarkFixture; import dev.handsup.fixture.UserFixture; -import dev.handsup.notification.repository.FCMTokenRepository; import dev.handsup.user.domain.User; @DisplayName("[Bookmark 통합 테스트]") @@ -37,8 +36,7 @@ class BookmarkApiControllerTest extends ApiTestSupport { private AuctionRepository auctionRepository; @Autowired private ProductCategoryRepository productCategoryRepository; - @Autowired - private FCMTokenRepository fcmTokenRepository; + @BeforeEach void setUp() { @@ -54,8 +52,6 @@ void setUp() { @Test @DisplayName("[북마크를 추가할 수 있다.]") void addBookmark() throws Exception { - // fcm 토큰 저장, seller 는 receiver - fcmTokenRepository.saveFcmToken(seller.getEmail(), "fcmToken123"); mockMvc.perform(post("/api/auctions/bookmarks/{auctionId}", auction.getId()) .contentType(APPLICATION_JSON) diff --git a/api/src/test/java/dev/handsup/comment/controller/CommentApiControllerTest.java b/api/src/test/java/dev/handsup/comment/controller/CommentApiControllerTest.java index ad1e68b7..833584c7 100644 --- a/api/src/test/java/dev/handsup/comment/controller/CommentApiControllerTest.java +++ b/api/src/test/java/dev/handsup/comment/controller/CommentApiControllerTest.java @@ -24,7 +24,6 @@ import dev.handsup.fixture.CommentFixture; import dev.handsup.fixture.ProductFixture; import dev.handsup.fixture.UserFixture; -import dev.handsup.notification.repository.FCMTokenRepository; import dev.handsup.user.domain.User; @DisplayName("[Comment 통합 테스트]") @@ -36,8 +35,7 @@ class CommentApiControllerTest extends ApiTestSupport { private ProductCategory productCategory; @Autowired private CommentRepository commentRepository; - @Autowired - private FCMTokenRepository fcmTokenRepository; + @BeforeEach void setUp() { @@ -50,7 +48,6 @@ void setUp() { @DisplayName("[댓글을 등록할 수 있다.]") @Test void registerComment() throws Exception { - fcmTokenRepository.saveFcmToken(seller.getEmail(), "fcmToken123"); RegisterCommentRequest request = RegisterCommentRequest.of("와"); mockMvc.perform(post("/api/auctions/{auctionId}/comments", auction.getId()) diff --git a/api/src/test/java/dev/handsup/notification/controller/NotificationApiControllerTest.java b/api/src/test/java/dev/handsup/notification/controller/NotificationApiControllerTest.java deleted file mode 100644 index e4021074..00000000 --- a/api/src/test/java/dev/handsup/notification/controller/NotificationApiControllerTest.java +++ /dev/null @@ -1,120 +0,0 @@ -package dev.handsup.notification.controller; - -import static org.springframework.http.HttpHeaders.*; -import static org.springframework.http.MediaType.*; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; - -import java.util.List; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.PageRequest; -import org.springframework.test.util.ReflectionTestUtils; - -import dev.handsup.auction.domain.Auction; -import dev.handsup.auction.repository.auction.AuctionRepository; -import dev.handsup.auction.repository.product.ProductCategoryRepository; -import dev.handsup.auth.service.JwtProvider; -import dev.handsup.common.support.ApiTestSupport; -import dev.handsup.fixture.AuctionFixture; -import dev.handsup.fixture.UserFixture; -import dev.handsup.notification.domain.Notification; -import dev.handsup.notification.domain.NotificationType; -import dev.handsup.notification.dto.request.SaveFCMTokenRequest; -import dev.handsup.notification.repository.NotificationRepository; -import dev.handsup.user.domain.User; -import dev.handsup.user.repository.UserRepository; - -@DisplayName("[Notification 통합 테스트]") -class NotificationApiControllerTest extends ApiTestSupport { - - @Autowired - private NotificationRepository notificationRepository; - @Autowired - private AuctionRepository auctionRepository; - @Autowired - private ProductCategoryRepository productCategoryRepository; - @Autowired - private UserRepository userRepository; - @Autowired - private JwtProvider jwtProvider; - - private User receiver; - private String receiverAccessToken; - - @BeforeEach - void setUp() { - receiver = UserFixture.user2(); - ReflectionTestUtils.setField(receiver, "readNotificationCount", 1); - userRepository.save(receiver); - receiverAccessToken = jwtProvider.createAccessToken(receiver.getId()); - - Auction auction = AuctionFixture.auction(receiver); - productCategoryRepository.save(auction.getProduct().getProductCategory()); - auctionRepository.save(auction); - - Notification notification1 = Notification.of( - user.getEmail(), - receiver.getEmail(), - NotificationType.BOOKMARK.getContent(), - NotificationType.BOOKMARK, - auction - ); - Notification notification2 = Notification.of( - user.getEmail(), - receiver.getEmail(), - NotificationType.CHAT.getContent(), - NotificationType.CHAT, - auction - ); - Notification notification3 = Notification.of( - user.getEmail(), - receiver.getEmail(), - NotificationType.PURCHASE_WINNING.getContent(), - NotificationType.PURCHASE_WINNING, - auction - ); - notificationRepository.saveAll(List.of(notification1, notification2, notification3)); - } - - @Test - @DisplayName("FCM 토큰을 저장에 성공하면 HttpSatus.Ok 를 받는다") - void saveFCMToken() throws Exception { - SaveFCMTokenRequest request = SaveFCMTokenRequest.from("fcmToken123"); - - mockMvc.perform(post("/api/notifications/fcm-tokens") - .contentType(APPLICATION_JSON) - .header(AUTHORIZATION, "Bearer " + accessToken) - .content(toJson(request))) - .andExpect(status().isOk()); - } - - @Test - @DisplayName("사용자의 미확인 알림 수를 조회한다") - void countUserNotifications() throws Exception { - mockMvc.perform(get("/api/notifications/count") - .header(AUTHORIZATION, "Bearer " + receiverAccessToken)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.count").value(2)); - } - - @Test - @DisplayName("사용자가 받은 전체 알림을 최근 생성 순으로 조회한다") - void getUserReviewLabels() throws Exception { - PageRequest pageRequest = PageRequest.of(0, 5); - - mockMvc.perform(get("/api/notifications") - .header(AUTHORIZATION, "Bearer " + receiverAccessToken) - .contentType(APPLICATION_JSON) - .content(toJson(pageRequest)) - ) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.content.size()").value(3)) - .andExpect(jsonPath("$.content[0].content").value(NotificationType.PURCHASE_WINNING.getContent())) - .andExpect(jsonPath("$.content[1].content").value(NotificationType.CHAT.getContent())) - .andExpect(jsonPath("$.content[2].content").value(NotificationType.BOOKMARK.getContent())); - } -} diff --git a/api/src/test/java/dev/handsup/review/controller/ReviewApiControllerTest.java b/api/src/test/java/dev/handsup/review/controller/ReviewApiControllerTest.java index 9e0da3fb..80da1f6d 100644 --- a/api/src/test/java/dev/handsup/review/controller/ReviewApiControllerTest.java +++ b/api/src/test/java/dev/handsup/review/controller/ReviewApiControllerTest.java @@ -32,7 +32,6 @@ import dev.handsup.fixture.AuctionFixture; import dev.handsup.fixture.ReviewFixture; import dev.handsup.fixture.ReviewLabelFixture; -import dev.handsup.notification.repository.FCMTokenRepository; import dev.handsup.review.domain.Review; import dev.handsup.review.domain.ReviewLabel; import dev.handsup.review.domain.ReviewLabelValue; @@ -68,8 +67,6 @@ class ReviewApiControllerTest extends ApiTestSupport { private BiddingService biddingService; @Autowired private UserRepository userRepository; - @Autowired - private FCMTokenRepository fcmTokenRepository; @BeforeEach void setUp() { @@ -83,7 +80,6 @@ void setUp() { @DisplayName("[리뷰 등록 API] 작성자가 경매에 대한 리뷰를 등록한다") void registerReviewTest() throws Exception { // given - fcmTokenRepository.saveFcmToken(auction.getSeller().getEmail(), "fcmToken123"); ReflectionTestUtils.setField(auction, "status", AuctionStatus.TRADING); Long auctionId = auction.getId(); int beforeSellerScore = auction.getSeller().getScore(); diff --git a/api/src/test/resources/application.yml b/api/src/test/resources/application.yml index 060e11e0..6991e513 100644 --- a/api/src/test/resources/application.yml +++ b/api/src/test/resources/application.yml @@ -23,7 +23,4 @@ cloud: s3: bucket: s3-bucket-name stack: - auto: false - -fcm: - certification: firebase/firebase_account.json + auto: false \ No newline at end of file diff --git a/core/src/main/java/dev/handsup/auction/dto/mapper/AuctionMapper.java b/core/src/main/java/dev/handsup/auction/dto/mapper/AuctionMapper.java index 2b50f514..a40aa6b6 100644 --- a/core/src/main/java/dev/handsup/auction/dto/mapper/AuctionMapper.java +++ b/core/src/main/java/dev/handsup/auction/dto/mapper/AuctionMapper.java @@ -76,7 +76,7 @@ public static AuctionDetailResponse toAuctionDetailResponse(Auction auction) { } public static AuctionSearchResponse toAuctionSearchResponse(Auction auction) { - boolean isProgress = auction.getStatus()== AuctionStatus.BIDDING; + boolean isProgress = auction.getStatus() == AuctionStatus.BIDDING; return AuctionSearchResponse.of( auction.getId(), auction.getTitle(), diff --git a/core/src/main/java/dev/handsup/auction/repository/auction/AuctionSearchRepository.java b/core/src/main/java/dev/handsup/auction/repository/auction/AuctionSearchRepository.java index 51c7b2da..b0aa1d9e 100644 --- a/core/src/main/java/dev/handsup/auction/repository/auction/AuctionSearchRepository.java +++ b/core/src/main/java/dev/handsup/auction/repository/auction/AuctionSearchRepository.java @@ -13,19 +13,19 @@ public interface AuctionSearchRepository extends JpaRepository new NotFoundException(BiddingErrorCode.NOT_FOUND_NEXT_BIDDING)); nextBidding.updateTradingStatusPreparing(); // 다음 입찰 준비중 상태로 변경 - // 현재 입찰자 거래 취소 알림 - sendMessage(user, bidding, NotificationType.CANCELED_PURCHASE_TRADING); - - // 다음 입찰자 낙찰 알림 - sendMessage(user, nextBidding, NotificationType.PURCHASE_WINNING); - return BiddingMapper.toBiddingResponse(bidding); } @@ -114,14 +108,12 @@ private Auction getAuctionById(Long auctionId) { .orElseThrow(() -> new NotFoundException(AuctionErrorCode.NOT_FOUND_AUCTION)); } - private void sendMessage(User seller, Bidding bidding, NotificationType completedPurchaseTrading) { - fcmService.sendMessage( - seller.getEmail(), - seller.getNickname(), - bidding.getBidder().getEmail(), - completedPurchaseTrading, - bidding.getAuction() + private void sendBiddingNotification(User bidder, Auction auction) { + notificationSender.sendNotification( + bidder, + auction.getSeller(), + auction.getId(), + NotificationType.BIDDING_CREATED ); } - } diff --git a/core/src/main/java/dev/handsup/bookmark/service/BookmarkService.java b/core/src/main/java/dev/handsup/bookmark/service/BookmarkService.java index 61dc2c80..55300782 100644 --- a/core/src/main/java/dev/handsup/bookmark/service/BookmarkService.java +++ b/core/src/main/java/dev/handsup/bookmark/service/BookmarkService.java @@ -21,8 +21,6 @@ import dev.handsup.common.dto.PageResponse; import dev.handsup.common.exception.NotFoundException; import dev.handsup.common.exception.ValidationException; -import dev.handsup.notification.domain.NotificationType; -import dev.handsup.notification.service.FCMService; import dev.handsup.user.domain.User; import lombok.RequiredArgsConstructor; @@ -32,7 +30,6 @@ public class BookmarkService { private final BookmarkRepository bookmarkRepository; private final AuctionRepository auctionRepository; - private final FCMService fcmService; @Transactional public EditBookmarkResponse addBookmark(User user, Long auctionId) { @@ -44,22 +41,9 @@ public EditBookmarkResponse addBookmark(User user, Long auctionId) { bookmarkRepository.save(bookmark); - // user 는 sender - sendMessage(user, auction); - return BookmarkMapper.toEditBookmarkResponse(auction.getBookmarkCount()); } - private void sendMessage(User user, Auction auction) { - fcmService.sendMessage( - user.getEmail(), - user.getNickname(), - auction.getSeller().getEmail(), - NotificationType.BOOKMARK, - auction - ); - } - private void validateSelfBookmark(User user, Auction auction) { if (Objects.equals(auction.getSeller().getId(), user.getId())) { throw new ValidationException(BookmarkErrorCode.NOT_ALLOW_SELF_BOOKMARK); diff --git a/core/src/main/java/dev/handsup/chat/service/ChatMessageService.java b/core/src/main/java/dev/handsup/chat/service/ChatMessageService.java index 4fcf2251..39050ce0 100644 --- a/core/src/main/java/dev/handsup/chat/service/ChatMessageService.java +++ b/core/src/main/java/dev/handsup/chat/service/ChatMessageService.java @@ -3,8 +3,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import dev.handsup.auction.domain.Auction; -import dev.handsup.auction.exception.AuctionErrorCode; import dev.handsup.auction.repository.auction.AuctionRepository; import dev.handsup.chat.domain.ChatMessage; import dev.handsup.chat.domain.ChatRoom; @@ -15,10 +13,6 @@ import dev.handsup.chat.repository.ChatMessageRepository; import dev.handsup.chat.repository.ChatRoomRepository; import dev.handsup.common.exception.NotFoundException; -import dev.handsup.notification.domain.NotificationType; -import dev.handsup.notification.service.FCMService; -import dev.handsup.user.domain.User; -import dev.handsup.user.exception.UserErrorCode; import dev.handsup.user.repository.UserRepository; import lombok.RequiredArgsConstructor; @@ -30,7 +24,6 @@ public class ChatMessageService { private final ChatMessageRepository chatMessageRepository; private final UserRepository userRepository; private final AuctionRepository auctionRepository; - private final FCMService fcmService; @Transactional public ChatMessageResponse registerChatMessage(Long chatRoomId, ChatMessageRequest request) { @@ -38,34 +31,11 @@ public ChatMessageResponse registerChatMessage(Long chatRoomId, ChatMessageReque ChatMessage chatMessage = ChatMessageMapper.toChatMessage(chatRoom, request); ChatMessage savedChatMessage = chatMessageRepository.save(chatMessage); - User sender = getUserById(request.senderId()); - sendMessage(sender, chatRoom.getReceiver(sender), chatRoom); - return ChatMessageMapper.toChatMessageResponse(savedChatMessage); } - private void sendMessage(User sender, User receiver, ChatRoom chatRoom) { - fcmService.sendMessage( - sender.getEmail(), - sender.getNickname(), - receiver.getEmail(), - NotificationType.BOOKMARK, - getAuctionById(chatRoom.getAuctionId()) - ); - } - private ChatRoom getChatRoomById(Long chatRoomId) { return chatRoomRepository.findById(chatRoomId) .orElseThrow(() -> new NotFoundException(ChatRoomErrorCode.NOT_FOUND_CHAT_ROOM)); } - - private User getUserById(Long userId) { - return userRepository.findById(userId) - .orElseThrow(() -> new NotFoundException(UserErrorCode.NOT_FOUND_USER)); - } - - public Auction getAuctionById(Long auctionId) { - return auctionRepository.findById(auctionId) - .orElseThrow(() -> new NotFoundException(AuctionErrorCode.NOT_FOUND_AUCTION)); - } } diff --git a/core/src/main/java/dev/handsup/comment/service/CommentService.java b/core/src/main/java/dev/handsup/comment/service/CommentService.java index a89daf9d..3ffa3aeb 100644 --- a/core/src/main/java/dev/handsup/comment/service/CommentService.java +++ b/core/src/main/java/dev/handsup/comment/service/CommentService.java @@ -16,8 +16,6 @@ import dev.handsup.common.dto.CommonMapper; import dev.handsup.common.dto.PageResponse; import dev.handsup.common.exception.NotFoundException; -import dev.handsup.notification.domain.NotificationType; -import dev.handsup.notification.service.FCMService; import dev.handsup.user.domain.User; import lombok.RequiredArgsConstructor; @@ -27,7 +25,6 @@ public class CommentService { private final AuctionRepository auctionRepository; private final CommentRepository commentRepository; - private final FCMService fcmService; @Transactional public CommentResponse registerAuctionComment(Long auctionId, RegisterCommentRequest request, User user) { @@ -36,21 +33,9 @@ public CommentResponse registerAuctionComment(Long auctionId, RegisterCommentReq auction.validateIfCommentAvailable(); Comment comment = commentRepository.save(CommentMapper.toComment(request, auction, user)); - sendMessage(user, auction); - return CommentMapper.toCommentResponse(comment); } - private void sendMessage(User user, Auction auction) { - fcmService.sendMessage( - user.getEmail(), - user.getNickname(), - auction.getSeller().getEmail(), - NotificationType.COMMENT, - auction - ); - } - @Transactional(readOnly = true) public PageResponse getAuctionComments(Long auctionId, Pageable pageable) { Auction auction = getAuctionById(auctionId); diff --git a/core/src/main/java/dev/handsup/common/config/FCMConfig.java b/core/src/main/java/dev/handsup/common/config/FcmConfig.java similarity index 51% rename from core/src/main/java/dev/handsup/common/config/FCMConfig.java rename to core/src/main/java/dev/handsup/common/config/FcmConfig.java index ebd71340..2a809fa8 100644 --- a/core/src/main/java/dev/handsup/common/config/FCMConfig.java +++ b/core/src/main/java/dev/handsup/common/config/FcmConfig.java @@ -1,11 +1,7 @@ package dev.handsup.common.config; import java.io.IOException; -import java.io.InputStream; -import javax.annotation.PostConstruct; - -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; @@ -15,28 +11,26 @@ import com.google.firebase.FirebaseOptions; import com.google.firebase.messaging.FirebaseMessaging; +import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; -@Slf4j @Configuration -public class FCMConfig { - - @Value("${fcm.certification}") - private String googleApplicationCredentials; - +@Slf4j +public class FcmConfig { + private static final String FIREBASE_KEY_PATH = "firebase/serviceAccountKey.json"; @PostConstruct - public void initialize() throws IOException { - ClassPathResource resource = new ClassPathResource(googleApplicationCredentials); - - try (InputStream inputStream = resource.getInputStream()) { + public void initialize() { + if (!FirebaseApp.getApps().isEmpty()) + return; + try { + GoogleCredentials googleCredentials = GoogleCredentials + .fromStream(new ClassPathResource(FIREBASE_KEY_PATH).getInputStream()); FirebaseOptions options = FirebaseOptions.builder() - .setCredentials(GoogleCredentials.fromStream(inputStream)) + .setCredentials(googleCredentials) .build(); - - if (FirebaseApp.getApps().isEmpty()) { - FirebaseApp.initializeApp(options); - log.info("FirebaseApp initialization complete"); - } + FirebaseApp.initializeApp(options); + } catch (IOException e) { + log.error(e.getMessage()); } } @@ -44,4 +38,4 @@ public void initialize() throws IOException { public FirebaseMessaging firebaseMessaging() { return FirebaseMessaging.getInstance(); } -} +} \ No newline at end of file diff --git a/core/src/main/java/dev/handsup/notification/domain/Notification.java b/core/src/main/java/dev/handsup/notification/domain/Notification.java index ecd99964..137427d3 100644 --- a/core/src/main/java/dev/handsup/notification/domain/Notification.java +++ b/core/src/main/java/dev/handsup/notification/domain/Notification.java @@ -1,28 +1,23 @@ package dev.handsup.notification.domain; -import static jakarta.persistence.ConstraintMode.*; -import static jakarta.persistence.EnumType.*; -import static jakarta.persistence.FetchType.*; import static jakarta.persistence.GenerationType.*; import static lombok.AccessLevel.*; -import dev.handsup.auction.domain.Auction; import dev.handsup.common.entity.TimeBaseEntity; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; -import jakarta.persistence.ForeignKey; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @Entity -@Getter @NoArgsConstructor(access = PROTECTED) +@Getter public class Notification extends TimeBaseEntity { @Id @@ -30,54 +25,47 @@ public class Notification extends TimeBaseEntity { @Column(name = "notification_id") private Long id; - @Column(name = "sender_email", nullable = false) - private String senderEmail; + @Column(name = "receiver_id") + private Long receiverId; - @Column(name = "receiver_email", nullable = false) - private String receiverEmail; + @Column(name = "sender_id") + private Long senderId; - @Column(name = "content", nullable = false) - private String content; + @Column(name = "auction_id") + private Long auctionId; - @Column(name = "type", nullable = false) - @Enumerated(STRING) + @Column(name = "type") + @Enumerated(EnumType.STRING) private NotificationType type; - @ManyToOne(fetch = LAZY) - @JoinColumn(name = "auction_id", - nullable = false, - foreignKey = @ForeignKey(NO_CONSTRAINT)) - private Auction auction; + @Column(name = "content") + private String content; - @Builder - private Notification( - String senderEmail, - String receiverEmail, - String content, - NotificationType type, - Auction auction - ) { - this.senderEmail = senderEmail; - this.receiverEmail = receiverEmail; - this.content = content; + @Column(name = "is_read") + private boolean isRead = false; + + @Builder(access = AccessLevel.PRIVATE) + private Notification(Long receiverId, Long senderId, Long auctionId, NotificationType type, String content) { + this.receiverId = receiverId; + this.senderId = senderId; + this.auctionId = auctionId; this.type = type; - this.auction = auction; + this.content = content; } public static Notification of( - String senderEmail, - String receiverEmail, + Long receiverId, + Long senderId, + Long auctionId, String content, - NotificationType type, - Auction auction + NotificationType type ) { return Notification.builder() - .senderEmail(senderEmail) - .receiverEmail(receiverEmail) + .receiverId(receiverId) + .senderId(senderId) + .auctionId(auctionId) .content(content) .type(type) - .auction(auction) .build(); } - } diff --git a/core/src/main/java/dev/handsup/notification/domain/NotificationType.java b/core/src/main/java/dev/handsup/notification/domain/NotificationType.java index d8049c93..65e9cdb3 100644 --- a/core/src/main/java/dev/handsup/notification/domain/NotificationType.java +++ b/core/src/main/java/dev/handsup/notification/domain/NotificationType.java @@ -8,12 +8,20 @@ public enum NotificationType { CHAT("채팅 알림", "님이 회원님과의 채팅방에서 속삭이고 있어요."), - COMMENT("자신의 경매의 댓글 알림 알림", "님이 회원님의 경매 물품에서 얘기하고 있어요."), - BOOKMARK("자신의 경매의 북마크 알림", "님이 회원님의 경매 물품을 관심있어 해요."), - PURCHASE_WINNING("구매 입찰의 낙찰 알림", "입찰하신 물품이 낙찰되었습니다."), - CANCELED_PURCHASE_TRADING("구매 입찰의 거래 취소 알림", "거래가 취소되었습니다."), - COMPLETED_PURCHASE_TRADING("구매 입찰의 거래 완료 알림", "거래가 완료되었습니다."); + COMMENT("경매 댓글 알림", "님이 회원님의 경매 물품에서 얘기하고 있어요."), + BOOKMARK("경매 북마크 알림", "님이 회원님의 경매 물품을 관심있어 해요."), + BIDDING_CREATED("입찰 알림", "님이 회원님 경매에 입찰하였습니다."), + PURCHASE_WINNING("낙찰 알림", "입찰하신 물품이 낙찰되었습니다."), + CANCELED_PURCHASE_TRADING("거래 취소 알림", "거래가 취소되었습니다."), + COMPLETED_PURCHASE_TRADING("거래 완료 알림", "거래가 완료되었습니다."); private final String title; private final String content; + + public String processContent(String senderNickname) { + if (this == PURCHASE_WINNING || this == CANCELED_PURCHASE_TRADING) { + return this.content; + } + return senderNickname + this.content; + } } diff --git a/core/src/main/java/dev/handsup/notification/dto/NotificationMapper.java b/core/src/main/java/dev/handsup/notification/dto/NotificationMapper.java index 61298030..a593b83a 100644 --- a/core/src/main/java/dev/handsup/notification/dto/NotificationMapper.java +++ b/core/src/main/java/dev/handsup/notification/dto/NotificationMapper.java @@ -1,29 +1,23 @@ package dev.handsup.notification.dto; -import static lombok.AccessLevel.*; - -import dev.handsup.notification.domain.NotificationType; -import dev.handsup.notification.dto.response.NotificationResponse; +import dev.handsup.notification.domain.Notification; +import lombok.AccessLevel; import lombok.NoArgsConstructor; -@NoArgsConstructor(access = PRIVATE) +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class NotificationMapper { public static NotificationResponse toNotificationResponse( - Long notificationId, - NotificationType notificationType, - String content, - String senderProfileImageUrl, - Long auctionId, - String auctionImageUrl + Notification notification ) { - return NotificationResponse.of( - notificationId, - notificationType, - content, - senderProfileImageUrl, - auctionId, - auctionImageUrl + return new NotificationResponse( + notification.getId(), + notification.getReceiverId(), + notification.getSenderId(), + notification.getAuctionId(), + notification.getType().getTitle(), + notification.getContent(), + notification.getCreatedAt().toString() ); } } diff --git a/core/src/main/java/dev/handsup/notification/dto/NotificationResponse.java b/core/src/main/java/dev/handsup/notification/dto/NotificationResponse.java new file mode 100644 index 00000000..1534b2ed --- /dev/null +++ b/core/src/main/java/dev/handsup/notification/dto/NotificationResponse.java @@ -0,0 +1,12 @@ +package dev.handsup.notification.dto; + +public record NotificationResponse( + Long notificationId, + Long receiverId, + Long senderId, + Long auctionId, + String type, + String content, + String createdAt +) { +} \ No newline at end of file diff --git a/core/src/main/java/dev/handsup/notification/dto/SaveFcmTokenRequest.java b/core/src/main/java/dev/handsup/notification/dto/SaveFcmTokenRequest.java new file mode 100644 index 00000000..784d1f79 --- /dev/null +++ b/core/src/main/java/dev/handsup/notification/dto/SaveFcmTokenRequest.java @@ -0,0 +1,18 @@ +package dev.handsup.notification.dto; + +import static lombok.AccessLevel.*; + +import jakarta.validation.constraints.NotEmpty; +import lombok.Builder; + +@Builder(access = PRIVATE) +public record SaveFcmTokenRequest( + @NotEmpty(message = "fcmToken을 입력해주세요.") + String fcmToken +) { + public static SaveFcmTokenRequest from(String fcmToken) { + return SaveFcmTokenRequest.builder() + .fcmToken(fcmToken) + .build(); + } +} \ No newline at end of file diff --git a/core/src/main/java/dev/handsup/notification/dto/request/SaveFCMTokenRequest.java b/core/src/main/java/dev/handsup/notification/dto/request/SaveFCMTokenRequest.java deleted file mode 100644 index de7370f9..00000000 --- a/core/src/main/java/dev/handsup/notification/dto/request/SaveFCMTokenRequest.java +++ /dev/null @@ -1,19 +0,0 @@ -package dev.handsup.notification.dto.request; - -import static lombok.AccessLevel.*; - -import jakarta.validation.constraints.NotNull; -import lombok.Builder; - -@Builder(access = PRIVATE) -public record SaveFCMTokenRequest( - - @NotNull(message = "fcmToken 은 null일 수 없습니다.") - String fcmToken -) { - public static SaveFCMTokenRequest from(String fcmToken) { - return SaveFCMTokenRequest.builder() - .fcmToken(fcmToken) - .build(); - } -} diff --git a/core/src/main/java/dev/handsup/notification/dto/response/CountUserNotificationsResponse.java b/core/src/main/java/dev/handsup/notification/dto/response/CountUserNotificationsResponse.java deleted file mode 100644 index 8d592d62..00000000 --- a/core/src/main/java/dev/handsup/notification/dto/response/CountUserNotificationsResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package dev.handsup.notification.dto.response; - -public record CountUserNotificationsResponse( - - long count -) { - public static CountUserNotificationsResponse from(long count) { - return new CountUserNotificationsResponse(count); - } -} diff --git a/core/src/main/java/dev/handsup/notification/dto/response/NotificationResponse.java b/core/src/main/java/dev/handsup/notification/dto/response/NotificationResponse.java deleted file mode 100644 index 700ff276..00000000 --- a/core/src/main/java/dev/handsup/notification/dto/response/NotificationResponse.java +++ /dev/null @@ -1,31 +0,0 @@ -package dev.handsup.notification.dto.response; - -import dev.handsup.notification.domain.NotificationType; - -public record NotificationResponse( - - Long notificationId, - NotificationType notificationType, - String content, - String senderProfileImageUrl, - Long auctionId, - String auctionImageUrl -) { - public static NotificationResponse of( - Long notificationId, - NotificationType notificationType, - String content, - String senderProfileImageUrl, - Long auctionId, - String auctionImageUrl - ) { - return new NotificationResponse( - notificationId, - notificationType, - content, - senderProfileImageUrl, - auctionId, - auctionImageUrl - ); - } -} diff --git a/core/src/main/java/dev/handsup/notification/exception/NotificationErrorCode.java b/core/src/main/java/dev/handsup/notification/exception/NotificationErrorCode.java deleted file mode 100644 index ee41e94e..00000000 --- a/core/src/main/java/dev/handsup/notification/exception/NotificationErrorCode.java +++ /dev/null @@ -1,17 +0,0 @@ -package dev.handsup.notification.exception; - -import dev.handsup.common.exception.ErrorCode; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public enum NotificationErrorCode implements ErrorCode { - - FAILED_TO_SEND_FIREBASE_MESSAGE("FIREBASE 의 메시지 전송에 실패했습니다.", "NOTIF_001"), - FAILED_TO_SEND_MESSAGE("메시지 전송에 실패했습니다.", "NOTIF_002"), - NOT_FOUND_FCM_TOKEN("FCMTokenRepository 에 해당 FCM토큰이 존재하지 않습니다.", "NOTIF_003"); - - private final String message; - private final String code; -} diff --git a/core/src/main/java/dev/handsup/notification/repository/FCMTokenRepository.java b/core/src/main/java/dev/handsup/notification/repository/FCMTokenRepository.java deleted file mode 100644 index dfdf40dc..00000000 --- a/core/src/main/java/dev/handsup/notification/repository/FCMTokenRepository.java +++ /dev/null @@ -1,30 +0,0 @@ -package dev.handsup.notification.repository; - -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.stereotype.Component; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Component -public class FCMTokenRepository { - - private final StringRedisTemplate tokenRedisTemplate; - - public void saveFcmToken(String receiverEmail, String fcmToken) { - tokenRedisTemplate.opsForValue() - .set(receiverEmail, fcmToken); - } - - public String getFcmToken(String email) { - return tokenRedisTemplate.opsForValue().get(email); - } - - public void deleteFcmToken(String email) { - tokenRedisTemplate.delete(email); - } - - public boolean hasKey(String email) { - return Boolean.TRUE.equals(tokenRedisTemplate.hasKey(email)); - } -} diff --git a/core/src/main/java/dev/handsup/notification/repository/FcmTokenRepository.java b/core/src/main/java/dev/handsup/notification/repository/FcmTokenRepository.java new file mode 100644 index 00000000..3039b3a6 --- /dev/null +++ b/core/src/main/java/dev/handsup/notification/repository/FcmTokenRepository.java @@ -0,0 +1,36 @@ +package dev.handsup.notification.repository; + +import java.util.concurrent.TimeUnit; + +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Component +public class FcmTokenRepository { + + private static final String PREFIX = "fcmToken:"; + + private final StringRedisTemplate redisTemplate; + + public void saveFcmToken(Long userId, String fcmToken) { + if (!hasKey(userId)) { + redisTemplate.opsForValue() + .set(PREFIX + userId, fcmToken, 3000, TimeUnit.DAYS); + } + } + + public String getFcmToken(Long userId) { + return redisTemplate.opsForValue().get(PREFIX + userId); + } + + public void deleteFcmToken(Long userId) { + redisTemplate.delete(PREFIX + userId); + } + + public boolean hasKey(Long userId) { + return redisTemplate.hasKey(PREFIX + userId); + } +} \ No newline at end of file diff --git a/core/src/main/java/dev/handsup/notification/repository/NotificationRepository.java b/core/src/main/java/dev/handsup/notification/repository/NotificationRepository.java index 1079fca1..9a35c7e2 100644 --- a/core/src/main/java/dev/handsup/notification/repository/NotificationRepository.java +++ b/core/src/main/java/dev/handsup/notification/repository/NotificationRepository.java @@ -1,7 +1,5 @@ package dev.handsup.notification.repository; -import java.time.LocalDateTime; - import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; @@ -9,10 +7,5 @@ import dev.handsup.notification.domain.Notification; public interface NotificationRepository extends JpaRepository { - - long countByReceiverEmail(String receiverEmail); - - Slice findByReceiverEmailOrderByCreatedAtDesc(String receiverEmail, Pageable pageable); - - void deleteByCreatedAtBefore(LocalDateTime dateTime); + Slice findByReceiverIdOrderByCreatedAtDesc(Long receiverId, Pageable pageable); } diff --git a/core/src/main/java/dev/handsup/notification/service/FCMService.java b/core/src/main/java/dev/handsup/notification/service/FCMService.java deleted file mode 100644 index ace0e1a5..00000000 --- a/core/src/main/java/dev/handsup/notification/service/FCMService.java +++ /dev/null @@ -1,79 +0,0 @@ -package dev.handsup.notification.service; - -import org.springframework.stereotype.Service; - -import com.google.firebase.messaging.FirebaseMessaging; -import com.google.firebase.messaging.FirebaseMessagingException; -import com.google.firebase.messaging.Message; -import com.google.firebase.messaging.Notification; - -import dev.handsup.auction.domain.Auction; -import dev.handsup.common.exception.ValidationException; -import dev.handsup.notification.domain.NotificationType; -import dev.handsup.notification.dto.request.SaveFCMTokenRequest; -import dev.handsup.notification.repository.FCMTokenRepository; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@RequiredArgsConstructor -@Service -public class FCMService { - - private final FCMTokenRepository fcmTokenRepository; - private final FirebaseMessaging firebaseMessaging; - private final NotificationService notificationService; - - public void sendMessage( - String senderEmail, - String senderNickname, - String receiverEmail, - NotificationType notificationType, - Auction auction - ) { - String fcmToken = fcmTokenRepository.getFcmToken(receiverEmail); - if (fcmToken == null) { - return; - } - - if (notificationType.equals(NotificationType.CANCELED_PURCHASE_TRADING) || - notificationType.equals(NotificationType.PURCHASE_WINNING)) { - senderNickname = ""; - } - - Message message = Message.builder() - .setNotification(Notification.builder() - .setTitle(notificationType.getTitle()) - .setBody(senderNickname + notificationType.getContent()) - .build()) - .setToken(fcmToken) - .build(); - - send(message, receiverEmail); - - notificationService.saveNotification( - senderEmail, - receiverEmail, - senderNickname + notificationType.getContent(), - notificationType, - auction - ); - } - - private void send(Message message, String receiverEmail) { - try { - firebaseMessaging.send(message); - log.info("Sent message: {}, to: {}", message, receiverEmail); - } catch (FirebaseMessagingException e) { - throw new ValidationException(e.getMessage()); - } - } - - public void saveFcmToken(String userEmail, SaveFCMTokenRequest request) { - fcmTokenRepository.saveFcmToken(userEmail, request.fcmToken()); - } - - public void deleteFcmToken(String email) { - fcmTokenRepository.deleteFcmToken(email); - } -} diff --git a/core/src/main/java/dev/handsup/notification/service/FcmService.java b/core/src/main/java/dev/handsup/notification/service/FcmService.java new file mode 100644 index 00000000..bc79c809 --- /dev/null +++ b/core/src/main/java/dev/handsup/notification/service/FcmService.java @@ -0,0 +1,60 @@ +package dev.handsup.notification.service; + +import org.springframework.stereotype.Service; + +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.FirebaseMessagingException; +import com.google.firebase.messaging.Message; +import com.google.firebase.messaging.Notification; + +import dev.handsup.common.exception.ValidationException; +import dev.handsup.notification.domain.NotificationType; +import dev.handsup.notification.repository.FcmTokenRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RequiredArgsConstructor +@Service +public class FcmService { + private final FcmTokenRepository fcmTokenRepository; + private final FirebaseMessaging firebaseMessaging; + + public void sendNotification( + Long receiverId, + String content, + NotificationType notificationType + ) { + String fcmToken = fcmTokenRepository.getFcmToken(receiverId); + if (fcmToken == null) { + return; + } + + Message message = Message.builder() + .setNotification(Notification.builder() + .setTitle(notificationType.getTitle()) + .setBody(content) + .build()) + .setToken(fcmToken) + .build(); + + send(message, receiverId); + } + + private void send(Message message, Long receiverId) { + try { + firebaseMessaging.send(message); + log.info("Sent message: {}, to: {}", message, receiverId); + } catch (FirebaseMessagingException e) { + throw new ValidationException(e.getMessage()); + } + } + + public void saveFcmToken(Long userId, String fcmToken) { + fcmTokenRepository.saveFcmToken(userId, fcmToken); + } + + public void deleteFcmToken(Long userId) { + fcmTokenRepository.deleteFcmToken(userId); + } +} diff --git a/core/src/main/java/dev/handsup/notification/service/NotificationCleanupService.java b/core/src/main/java/dev/handsup/notification/service/NotificationCleanupService.java deleted file mode 100644 index eb439ebd..00000000 --- a/core/src/main/java/dev/handsup/notification/service/NotificationCleanupService.java +++ /dev/null @@ -1,24 +0,0 @@ -package dev.handsup.notification.service; - -import java.time.LocalDateTime; - -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import dev.handsup.notification.repository.NotificationRepository; -import lombok.RequiredArgsConstructor; - -@Service -@RequiredArgsConstructor -public class NotificationCleanupService { - - private final NotificationRepository notificationRepository; - - // 매일 자정에 실행 - @Transactional - @Scheduled(cron = "0 0 0 * * ?") - public void deleteOldNotifications() { - notificationRepository.deleteByCreatedAtBefore(LocalDateTime.now().minusWeeks(2)); - } -} diff --git a/core/src/main/java/dev/handsup/notification/service/NotificationSender.java b/core/src/main/java/dev/handsup/notification/service/NotificationSender.java new file mode 100644 index 00000000..c5a816a8 --- /dev/null +++ b/core/src/main/java/dev/handsup/notification/service/NotificationSender.java @@ -0,0 +1,24 @@ +package dev.handsup.notification.service; + +import org.springframework.stereotype.Service; + +import dev.handsup.notification.domain.NotificationType; +import dev.handsup.user.domain.User; +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class NotificationSender { + private final NotificationService notificationService; + private final FcmService fcmService; + + public void sendNotification(User sender, User receiver, Long auctionId, NotificationType notificationType) { + String content = notificationType.processContent(sender.getNickname()); + fcmService.sendNotification( + receiver.getId(), + content, + notificationType + ); + notificationService.saveNotification(sender, receiver, auctionId, content, notificationType); + } +} diff --git a/core/src/main/java/dev/handsup/notification/service/NotificationService.java b/core/src/main/java/dev/handsup/notification/service/NotificationService.java index 0b3eec5a..26b27282 100644 --- a/core/src/main/java/dev/handsup/notification/service/NotificationService.java +++ b/core/src/main/java/dev/handsup/notification/service/NotificationService.java @@ -5,82 +5,39 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import dev.handsup.auction.domain.Auction; -import dev.handsup.auction.exception.AuctionErrorCode; -import dev.handsup.auction.repository.auction.AuctionRepository; import dev.handsup.common.dto.CommonMapper; import dev.handsup.common.dto.PageResponse; -import dev.handsup.common.exception.NotFoundException; import dev.handsup.notification.domain.Notification; import dev.handsup.notification.domain.NotificationType; import dev.handsup.notification.dto.NotificationMapper; -import dev.handsup.notification.dto.response.NotificationResponse; +import dev.handsup.notification.dto.NotificationResponse; import dev.handsup.notification.repository.NotificationRepository; import dev.handsup.user.domain.User; -import dev.handsup.user.exception.UserErrorCode; -import dev.handsup.user.repository.UserRepository; import lombok.RequiredArgsConstructor; -@RequiredArgsConstructor @Service +@RequiredArgsConstructor public class NotificationService { - private final NotificationRepository notificationRepository; - private final UserRepository userRepository; - private final AuctionRepository auctionRepository; - - public long countNotificationsByUserEmail(String userEmail) { - return notificationRepository.countByReceiverEmail(userEmail); - } @Transactional - public void saveNotification( - String senderEmail, - String receiverEmail, - String content, - NotificationType notificationType, - Auction auction - ) { + public void saveNotification(User sender, User receiver, Long auctionId, String content, NotificationType type) { Notification notification = Notification.of( - senderEmail, receiverEmail, content, notificationType, auction + receiver.getId(), + sender.getId(), + auctionId, + content, + type ); - notificationRepository.save(notification); } - @Transactional + @Transactional(readOnly = true) public PageResponse getNotifications(User user, Pageable pageable) { Slice notificationResponsePage = notificationRepository - .findByReceiverEmailOrderByCreatedAtDesc(user.getEmail(), pageable) - .map(notification -> { - String senderEmail = notification.getSenderEmail(); - String senderProfileImageUrl = getUserByEmail(senderEmail).getProfileImageUrl(); - Auction auction = getAuctionById(notification.getAuction().getId()); - - return NotificationMapper.toNotificationResponse( - notification.getId(), - notification.getType(), - notification.getContent(), - senderProfileImageUrl, - auction.getId(), - auction.getProduct().getImages().get(0).getImageUrl() - ); - }); - - // 사용자의 읽은 알림 수 갱신 - user.updateReadNotificationCount(notificationResponsePage.getContent().size()); - userRepository.save(user); + .findByReceiverIdOrderByCreatedAtDesc(user.getId(), pageable) + .map(NotificationMapper::toNotificationResponse); return CommonMapper.toPageResponse(notificationResponsePage); } - - private User getUserByEmail(String email) { - return userRepository.findByEmail(email) - .orElseThrow(() -> new NotFoundException(UserErrorCode.NOT_FOUND_BY_EMAIL)); - } - - private Auction getAuctionById(Long auctionId) { - return auctionRepository.findById(auctionId) - .orElseThrow(() -> new NotFoundException(AuctionErrorCode.NOT_FOUND_AUCTION)); - } } diff --git a/core/src/main/java/dev/handsup/search/domain/AuctionSearch.java b/core/src/main/java/dev/handsup/search/domain/AuctionSearch.java index d1716f2a..a34c0639 100644 --- a/core/src/main/java/dev/handsup/search/domain/AuctionSearch.java +++ b/core/src/main/java/dev/handsup/search/domain/AuctionSearch.java @@ -22,7 +22,7 @@ @Entity @Getter @NoArgsConstructor(access = PROTECTED) -public class AuctionSearch{ +public class AuctionSearch { @Id @GeneratedValue(strategy = IDENTITY) diff --git a/core/src/main/java/dev/handsup/search/dto/AuctionSearchMapper.java b/core/src/main/java/dev/handsup/search/dto/AuctionSearchMapper.java index ddf3fe2b..f294c0f7 100644 --- a/core/src/main/java/dev/handsup/search/dto/AuctionSearchMapper.java +++ b/core/src/main/java/dev/handsup/search/dto/AuctionSearchMapper.java @@ -3,10 +3,10 @@ import static lombok.AccessLevel.*; import dev.handsup.auction.domain.Auction; -import dev.handsup.search.domain.AuctionSearch; import dev.handsup.auction.domain.auction_field.AuctionStatus; import dev.handsup.auction.domain.product.Product; import dev.handsup.recommend.dto.RecommendAuctionResponse; +import dev.handsup.search.domain.AuctionSearch; import lombok.NoArgsConstructor; @NoArgsConstructor(access = PRIVATE) @@ -18,7 +18,7 @@ public static AuctionSearch toAuctionSearch(Auction auction) { .productId(product.getId()) .category(product.getProductCategory().getValue()) .title(auction.getTitle()) - .isNewProduct(auction.getStatus()== AuctionStatus.BIDDING) + .isNewProduct(auction.getStatus() == AuctionStatus.BIDDING) .imgUrl(product.getImages().get(0).toString()) .endDate(auction.getEndDate()) .tradingLocation(auction.getTradingLocation()) diff --git a/core/src/main/java/dev/handsup/search/service/SearchService.java b/core/src/main/java/dev/handsup/search/service/SearchService.java index 79070795..554f4061 100644 --- a/core/src/main/java/dev/handsup/search/service/SearchService.java +++ b/core/src/main/java/dev/handsup/search/service/SearchService.java @@ -33,7 +33,6 @@ public class SearchService { private final RedisSearchRepository redisSearchRepository; private final PreferredProductCategoryRepository preferredProductCategoryRepository; - @Transactional(readOnly = true) public PageResponse searchAuctions(AuctionSearchCondition condition, Pageable pageable) { Slice auctionResponsePage = auctionRepository diff --git a/core/src/main/java/dev/handsup/user/domain/User.java b/core/src/main/java/dev/handsup/user/domain/User.java index 491dac17..aa3bf636 100644 --- a/core/src/main/java/dev/handsup/user/domain/User.java +++ b/core/src/main/java/dev/handsup/user/domain/User.java @@ -48,9 +48,6 @@ public class User extends TimeBaseEntity { @Column(name = "profile_image_url") private String profileImageUrl; - @Column(name = "report_count", nullable = false) - private int reportCount = 0; - @Column(name = "read_notification_count", nullable = false) private long readNotificationCount = 0; @@ -134,11 +131,6 @@ private void validateUser( Assert.isTrue(matcher.matches(), NON_VALIDATED_EMAIL.getMessage()); } - //== 비즈니스 메서드==// - public void updateReadNotificationCount(long readNotificationCount) { - this.readNotificationCount = readNotificationCount; - } - public void operateScore(int evaluationScore) { score += evaluationScore; diff --git a/core/src/main/java/dev/handsup/user/dto/response/UserDetailResponse.java b/core/src/main/java/dev/handsup/user/dto/response/UserDetailResponse.java index b56f2a8d..92098158 100644 --- a/core/src/main/java/dev/handsup/user/dto/response/UserDetailResponse.java +++ b/core/src/main/java/dev/handsup/user/dto/response/UserDetailResponse.java @@ -11,7 +11,6 @@ public record UserDetailResponse( int score, Address address, String profileImageUrl, - int reportCount, long readNotificationCount ) { public static UserDetailResponse of(User user) { @@ -23,7 +22,6 @@ public static UserDetailResponse of(User user) { user.getScore(), user.getAddress(), user.getProfileImageUrl(), - user.getReportCount(), user.getReadNotificationCount() ); } diff --git a/core/src/test/http/auction.http b/core/src/test/http/auction.http deleted file mode 100644 index 4b9c2203..00000000 --- a/core/src/test/http/auction.http +++ /dev/null @@ -1,21 +0,0 @@ -### GET request to example server -POST http://localhost:8080/api/auctions -Content-Type: application/json -Authorization: Bearer eyJ0eXBlIjoiand0IiwiYWxnIjoiSFMyNTYifQ.eyJ1c2VySWQiOjEsImlhdCI6MTc0OTk4ODQ3NiwiZXhwIjoyMDY1MzQ4NDc2fQ._I9ddh2ADiTV6aIitn19RRkW2sglpkRbRMZtlqC7xeM - -{ - "title": "에어팟 거의 새거", - "productCategory": "디지털 기기", - "initPrice": 3000, - "endDate": "2024-02-17", - "productStatus": "깨끗해요", - "purchaseTime": "6개월 이하", - "description": "거의 새거임", - "tradeMethod": "직거래", - "imageUrls": [ - "https://s3.ap-northeast-2.amazonaws.com/handsup-bucket/images/f2ed3069-3c65-4cb5-97dc-2f24a64ca103.jpg" - ], - "si": "서울시", - "gu": "성북구", - "dong": "동선동" -} \ No newline at end of file diff --git a/core/src/test/http/home.http b/core/src/test/http/home.http deleted file mode 100644 index b40ef5d9..00000000 --- a/core/src/test/http/home.http +++ /dev/null @@ -1,4 +0,0 @@ -### 경매 추천 - 지역 필터(서울시 관악구 봉천동) -### 최근생성, 마감일, 입찰수, 북마크수 -GET http://localhost:8080/api/auctions/recommend?page=0&size=10&sort=최근생성&si=서울시&gu=관악구&dong=봉천동 -Content-Type: application/json \ No newline at end of file diff --git a/core/src/test/http/recommend.http b/core/src/test/http/recommend.http deleted file mode 100644 index ba1b05fd..00000000 --- a/core/src/test/http/recommend.http +++ /dev/null @@ -1,18 +0,0 @@ -### 경매 추천 -GET http://localhost:8080/api/auctions/recommend?si=서울시&gu=강남구&dong=역삼동&page=0&size=10&sort=북마크수 - - -### 경매 조건 추천 ver2 -GET http://localhost:8080/api/v2/auctions/recommend?si=서울시&gu=강남구&dong=역삼동&page=0&size=10&sort=북마크수 - -### 경매 카테고리 추천 ver1 -GET http://localhost:8080/api/auctions/recommend/category?page=0&size=10 -Content-Type: application/json -Authorization: Bearer eyJ0eXBlIjoiand0IiwiYWxnIjoiSFMyNTYifQ.eyJ1c2VySWQiOjEsImlhdCI6MTc0OTk4ODQ3NiwiZXhwIjoyMDY1MzQ4NDc2fQ._I9ddh2ADiTV6aIitn19RRkW2sglpkRbRMZtlqC7xeM - -### 경매 카테고리 추천 ver2 -GET http://localhost:8080/api/v2/auctions/recommend/category?page=0&size=10 -Content-Type: application/json -Authorization: Bearer eyJ0eXBlIjoiand0IiwiYWxnIjoiSFMyNTYifQ.eyJ1c2VySWQiOjEsImlhdCI6MTc0OTk4ODQ3NiwiZXhwIjoyMDY1MzQ4NDc2fQ._I9ddh2ADiTV6aIitn19RRkW2sglpkRbRMZtlqC7xeM - - diff --git a/core/src/test/http/search.http b/core/src/test/http/search.http deleted file mode 100644 index b14d6903..00000000 --- a/core/src/test/http/search.http +++ /dev/null @@ -1,78 +0,0 @@ -### 기본 검색 (키워드만) -POST http://localhost:8080/api/auctions/search?page=0&size=10&sort=최신순 -Content-Type: application/json - -{ - "keyword": "에어팟" -} - -### - - - -### 카테고리, 거래방식 등 복합 검색 예시 -POST http://localhost:8080/api/auctions/search?page=0&size=10&sort=최신순 -Content-Type: application/json - -{ - "keyword": "에어팟", -"productCategory": "디지털 기기", - "si": "서울시", - "gu": "강남구", - "dong": "역삼동" -} - -### 카테고리, 거래방식 등 복합 검색 예시 -POST http://localhost:8080/api/auctions/search?page=0&size=10&sort=최신순 -Content-Type: application/json - -{ - "keyword": "에어팟", - "productCategory": "디지털 기기", - "si": "서울시", - "gu": "강남구", - "dong": "역삼동" -} - -### 카테고리, 거래방식 등 복합 검색 예시 -POST http://localhost:8080/api/v2/auctions/search?page=0&size=10&sort=최신순 -Content-Type: application/json - -{ - "keyword": "에어팟", - "productCategory": "디지털 기기", - "si": "서울시", - "gu": "강남구", - "dong": "역삼동" -} - -### - -### 북마크순 정렬 검색 -POST http://localhost:8080/api/auctions/search?page=0&size=10&sort=북마크수 -Content-Type: application/json - -{ - "keyword": "에어팟" -} - -### - -### 마감일 임박순 + 카테고리 -POST http://localhost:8080/api/auctions/search?page=0&size=10&sort=마감일 -Content-Type: application/json - -{ - "keyword": "청소기", - "productCategory": "APPLIANCES" -} - -### - -### 검색결과 없는 경우(키워드 없음) -POST http://localhost:8080/api/auctions/search?page=0&size=10 -Content-Type: application/json - -{ - "keyword": "존재하지않는상품명" -} \ No newline at end of file diff --git a/core/src/test/http/user.http b/core/src/test/http/user.http deleted file mode 100644 index 27d36e13..00000000 --- a/core/src/test/http/user.http +++ /dev/null @@ -1,8 +0,0 @@ -### 로그인 요청 (user1) -POST http://localhost:8080/api/auth/login -Content-Type: application/json - -{ - "email": "user1@email.com", - "password": "testpw1!" -} \ No newline at end of file diff --git a/core/src/test/java/dev/handsup/bidding/repository/BiddingConcurrencyTest.java b/core/src/test/java/dev/handsup/bidding/repository/BiddingConcurrencyTest.java index faa2028d..1dabb068 100644 --- a/core/src/test/java/dev/handsup/bidding/repository/BiddingConcurrencyTest.java +++ b/core/src/test/java/dev/handsup/bidding/repository/BiddingConcurrencyTest.java @@ -19,6 +19,7 @@ import dev.handsup.auction.repository.product.ProductCategoryRepository; import dev.handsup.bidding.dto.request.RegisterBiddingRequest; import dev.handsup.bidding.service.BiddingService; +import dev.handsup.common.config.FcmConfig; import dev.handsup.config.TestAuditingConfig; import dev.handsup.fixture.AuctionFixture; import dev.handsup.fixture.UserFixture; @@ -29,7 +30,7 @@ @SpringBootTest @Slf4j -@Import(TestAuditingConfig.class) +@Import({TestAuditingConfig.class, FcmConfig.class}) class BiddingConcurrencyTest extends TestContainerSupport { private Auction auction; diff --git a/core/src/test/java/dev/handsup/bidding/service/BiddingServiceTest.java b/core/src/test/java/dev/handsup/bidding/service/BiddingServiceTest.java index 23ea7d2e..f2d01069 100644 --- a/core/src/test/java/dev/handsup/bidding/service/BiddingServiceTest.java +++ b/core/src/test/java/dev/handsup/bidding/service/BiddingServiceTest.java @@ -35,7 +35,7 @@ import dev.handsup.fixture.AuctionFixture; import dev.handsup.fixture.BiddingFixture; import dev.handsup.fixture.UserFixture; -import dev.handsup.notification.service.FCMService; +import dev.handsup.notification.service.NotificationSender; import dev.handsup.user.domain.User; @ExtendWith(MockitoExtension.class) @@ -52,7 +52,7 @@ class BiddingServiceTest { @Mock private AuctionRepository auctionRepository; @Mock - private FCMService fcmService; + private NotificationSender notificationSender; @InjectMocks private BiddingService biddingService; diff --git a/core/src/test/java/dev/handsup/bookmark/service/BookmarkServiceTest.java b/core/src/test/java/dev/handsup/bookmark/service/BookmarkServiceTest.java index 32f2055d..3ee9621b 100644 --- a/core/src/test/java/dev/handsup/bookmark/service/BookmarkServiceTest.java +++ b/core/src/test/java/dev/handsup/bookmark/service/BookmarkServiceTest.java @@ -29,7 +29,6 @@ import dev.handsup.fixture.AuctionFixture; import dev.handsup.fixture.BookmarkFixture; import dev.handsup.fixture.UserFixture; -import dev.handsup.notification.service.FCMService; import dev.handsup.user.domain.User; @DisplayName("[BookmarkService 테스트]") @@ -42,8 +41,7 @@ class BookmarkServiceTest { private AuctionRepository auctionRepository; @Mock private BookmarkRepository bookmarkRepository; - @Mock - private FCMService fcmService; + @InjectMocks private BookmarkService bookmarkService; diff --git a/core/src/test/java/dev/handsup/chat/repository/ChatRoomRepositoryTest.java b/core/src/test/java/dev/handsup/chat/repository/ChatRoomRepositoryTest.java index d4672b74..25f6fd71 100644 --- a/core/src/test/java/dev/handsup/chat/repository/ChatRoomRepositoryTest.java +++ b/core/src/test/java/dev/handsup/chat/repository/ChatRoomRepositoryTest.java @@ -84,9 +84,9 @@ void findChatRoomsByUser() { assertAll( () -> assertThat(chatRoomSlice).hasSize(3), () -> assertThat(chatRoomSlice.hasNext()).isFalse(), - () -> assertThat(chatRooms.get(0)).isEqualTo(chatRoom1), - () -> assertThat(chatRooms.get(1)).isEqualTo(chatRoom2), - () -> assertThat(chatRooms.get(2)).isEqualTo(chatRoom3) + () -> assertThat(chatRooms.get(0).getId()).isEqualTo(chatRoom1.getId()), + () -> assertThat(chatRooms.get(1).getId()).isEqualTo(chatRoom2.getId()), + () -> assertThat(chatRooms.get(2).getId()).isEqualTo(chatRoom3.getId()) ); } } diff --git a/core/src/test/java/dev/handsup/comment/service/CommentServiceTest.java b/core/src/test/java/dev/handsup/comment/service/CommentServiceTest.java index 44ff83e3..c98c296f 100644 --- a/core/src/test/java/dev/handsup/comment/service/CommentServiceTest.java +++ b/core/src/test/java/dev/handsup/comment/service/CommentServiceTest.java @@ -27,7 +27,6 @@ import dev.handsup.fixture.AuctionFixture; import dev.handsup.fixture.CommentFixture; import dev.handsup.fixture.UserFixture; -import dev.handsup.notification.service.FCMService; import dev.handsup.user.domain.User; @DisplayName("[댓글 서비스 테스트]") @@ -40,8 +39,7 @@ class CommentServiceTest { private AuctionRepository auctionRepository; @Mock private CommentRepository commentRepository; - @Mock - private FCMService fcmService; + @InjectMocks private CommentService commentService; diff --git a/core/src/test/java/dev/handsup/notification/domain/service/FCMServiceTest.java b/core/src/test/java/dev/handsup/notification/domain/service/FCMServiceTest.java deleted file mode 100644 index 48d7dfa8..00000000 --- a/core/src/test/java/dev/handsup/notification/domain/service/FCMServiceTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package dev.handsup.notification.domain.service; - -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.BDDMockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.google.firebase.messaging.FirebaseMessaging; -import com.google.firebase.messaging.FirebaseMessagingException; - -import dev.handsup.auction.domain.Auction; -import dev.handsup.fixture.AuctionFixture; -import dev.handsup.fixture.UserFixture; -import dev.handsup.notification.domain.NotificationType; -import dev.handsup.notification.repository.FCMTokenRepository; -import dev.handsup.notification.service.FCMService; -import dev.handsup.notification.service.NotificationService; -import dev.handsup.user.domain.User; - -@DisplayName("[FCM 알림 서비스 테스트]") -@ExtendWith(MockitoExtension.class) -class FCMServiceTest { - - private final User receiver = UserFixture.user1(); - private final Auction auction = AuctionFixture.auction(); - @Mock - private FCMTokenRepository fcmTokenRepository; - @Mock - private FirebaseMessaging firebaseMessaging; - @Mock - private NotificationService notificationService; - @InjectMocks - private FCMService fcmService; - - @Test - @DisplayName("메시지를 성공적으로 보낸다]") - void sendMessageSuccessTest() throws FirebaseMessagingException { - // given - String receiverEmail = receiver.getEmail(); - String fcmToken = "fcmToken123"; - given(fcmTokenRepository.getFcmToken(receiverEmail)).willReturn(fcmToken); - - // when - fcmService.sendMessage( - "senderEmail", - "senderNickname", - receiverEmail, - NotificationType.BOOKMARK, - auction - ); - - // then - verify(firebaseMessaging, times(1)).send(any()); - } - -} diff --git a/core/src/test/resources/application.yml b/core/src/test/resources/application.yml index 060e11e0..6991e513 100644 --- a/core/src/test/resources/application.yml +++ b/core/src/test/resources/application.yml @@ -23,7 +23,4 @@ cloud: s3: bucket: s3-bucket-name stack: - auto: false - -fcm: - certification: firebase/firebase_account.json + auto: false \ No newline at end of file diff --git a/insert_auction_dummy_data.sql b/insert_auction_dummy_data.sql deleted file mode 100644 index 718ab2af..00000000 --- a/insert_auction_dummy_data.sql +++ /dev/null @@ -1,22 +0,0 @@ -DELIMITER $$ - -DROP PROCEDURE IF EXISTS insert_auction_dummy_data; -CREATE PROCEDURE insert_auction_dummy_data() - -BEGIN - DECLARE i INT DEFAULT 0; - WHILE i < 3000 DO - INSERT INTO auction - (created_at, updated_at, bidding_count, bookmark_count, current_bidding_price, end_date, init_price, auction_status, title, trade_method, dong, gu, si, buyer_id, product_id, seller_id, buy_price) - VALUES - (NOW(), NOW(), FLOOR(RAND() * 10), FLOOR(RAND() * 10), 3000, '2024-04-07', 3000, 'BIDDING', '에어팟 거의 새거', 'DIRECT', '동선동', '성북구', '서울시', NULL, 1 + i, 2, NULL); - SET i = i + 1; - END WHILE; -END$$ - -DELIMITER ; - -CALL insert_auction_dummy_data(); - -# ALTER TABLE auction AUTO_INCREMENT = 1; -# DELETE FROM auction WHERE auction_id >= 1; diff --git a/insert_product_dummy_data.sql b/insert_product_dummy_data.sql deleted file mode 100644 index c5916d46..00000000 --- a/insert_product_dummy_data.sql +++ /dev/null @@ -1,19 +0,0 @@ -DELIMITER $$ - -DROP PROCEDURE IF EXISTS insert_product_dummy_data; -CREATE PROCEDURE insert_product_dummy_data() - -BEGIN - DECLARE i INT DEFAULT 0; - WHILE i < 3000 DO - INSERT INTO product (created_at, updated_at, description, purchase_time, status, product_category_id) - VALUES (NOW(), NOW(), '애플 에어팟 맛집입니다^^', 'UNDER_ONE_MONTH', 'CLEAN', 1); - SET i = i + 1; - END WHILE; -END$$ - -DELIMITER ; -CALL insert_product_dummy_data(); - -# ALTER TABLE product AUTO_INCREMENT = 1; -# DELETE FROM product WHERE product_id >= 1; diff --git a/insert_product_image_dummy_data.sql b/insert_product_image_dummy_data.sql deleted file mode 100644 index df07f2eb..00000000 --- a/insert_product_image_dummy_data.sql +++ /dev/null @@ -1,19 +0,0 @@ -DELIMITER $$ - -DROP PROCEDURE IF EXISTS insert_product_image_dummy_data; -CREATE PROCEDURE insert_product_image_dummy_data() - -BEGIN - DECLARE i INT DEFAULT 0; - WHILE i < 3000 DO - INSERT INTO product_image (created_at, updated_at, image_url, product_id) - VALUES (NOW(), NOW(), "image_url_string", i + 1); - SET i = i + 1; - END WHILE; -END$$ - -DELIMITER ; -CALL insert_product_image_dummy_data(); - -# ALTER TABLE product_image AUTO_INCREMENT = 1; -# DELETE FROM product_image WHERE product_image_id >= 1;