diff --git a/api/src/docs/asciidoc/Feed-API.adoc b/api/src/docs/asciidoc/Feed-API.adoc index 9697e4b98..0e3a5d54b 100755 --- a/api/src/docs/asciidoc/Feed-API.adoc +++ b/api/src/docs/asciidoc/Feed-API.adoc @@ -143,3 +143,20 @@ include::{snippets}/feed-controller-test/add-text-feed/http-response.adoc[] === 응답 필드 설명(Response Fields) include::{snippets}/feed-controller-test/add-text-feed/response-fields.adoc[] + +== 7. 피드 수정 04/12 수정 + +=== 요청(Request) +include::{snippets}/feed-controller-test/update-text-feed/http-request.adoc[] + +=== 요청헤더(Request Headers) +include::{snippets}/feed-controller-test/update-text-feed/request-headers.adoc[] + +=== 요청 필드 설명(Request Fields) +include::{snippets}/feed-controller-test/update-text-feed/request-fields.adoc[] + +=== 응답(Response) +include::{snippets}/feed-controller-test/update-text-feed/http-response.adoc[] + +=== 응답 필드 설명(Response Fields) +include::{snippets}/feed-controller-test/update-text-feed/response-fields.adoc[] diff --git a/api/src/main/kotlin/org/chewing/v1/controller/auth/AuthController.kt b/api/src/main/kotlin/org/chewing/v1/controller/auth/AuthController.kt index 65bc61a2e..1400784c4 100755 --- a/api/src/main/kotlin/org/chewing/v1/controller/auth/AuthController.kt +++ b/api/src/main/kotlin/org/chewing/v1/controller/auth/AuthController.kt @@ -1,6 +1,7 @@ package org.chewing.v1.controller.auth import org.chewing.v1.dto.request.auth.LoginRequest +import org.chewing.v1.dto.request.auth.LogoutRequest import org.chewing.v1.dto.request.auth.SignUpRequest import org.chewing.v1.dto.request.auth.VerificationRequest import org.chewing.v1.dto.request.auth.VerifyOnlyRequest @@ -106,9 +107,13 @@ class AuthController( @DeleteMapping("/logout") fun logout( @RequestHeader("Authorization") refreshToken: String, + @RequestBody request: LogoutRequest, ): ResponseEntity> { jwtTokenUtil.validateRefreshToken(refreshToken) - authService.logout(refreshToken) + accountFacade.logout( + request.toDevice(), + refreshToken, + ) return ResponseHelper.successOnly() } diff --git a/api/src/main/kotlin/org/chewing/v1/controller/feed/FeedController.kt b/api/src/main/kotlin/org/chewing/v1/controller/feed/FeedController.kt index 5b8ad83e2..4cb54f52d 100755 --- a/api/src/main/kotlin/org/chewing/v1/controller/feed/FeedController.kt +++ b/api/src/main/kotlin/org/chewing/v1/controller/feed/FeedController.kt @@ -87,4 +87,13 @@ class FeedController( val feedId = feedService.makeText(userId, request.toFriendIds(), request.toContent(), request.toType()) return ResponseHelper.successCreate(FeedIdResponse.of(feedId)) } + + @PutMapping("/text") + fun updateTextFeed( + @CurrentUser userId: UserId, + @RequestBody request: FeedRequest.UpdateText, + ): SuccessResponseEntity { + feedService.changeText(userId, request.toFeedId(), request.toContent()) + return ResponseHelper.successOnly() + } } diff --git a/api/src/main/kotlin/org/chewing/v1/dto/request/auth/LogoutRequest.kt b/api/src/main/kotlin/org/chewing/v1/dto/request/auth/LogoutRequest.kt new file mode 100644 index 000000000..b78b0ab98 --- /dev/null +++ b/api/src/main/kotlin/org/chewing/v1/dto/request/auth/LogoutRequest.kt @@ -0,0 +1,13 @@ +package org.chewing.v1.dto.request.auth + +import org.chewing.v1.model.notification.PushInfo +import kotlin.text.uppercase + +data class LogoutRequest( + val deviceId: String, + val provider: String, +) { + fun toDevice(): PushInfo.Device { + return PushInfo.Device.of(deviceId, PushInfo.Provider.valueOf(provider.uppercase())) + } +} diff --git a/api/src/main/kotlin/org/chewing/v1/dto/request/feed/FeedRequest.kt b/api/src/main/kotlin/org/chewing/v1/dto/request/feed/FeedRequest.kt index db65a5306..4a95d91f8 100755 --- a/api/src/main/kotlin/org/chewing/v1/dto/request/feed/FeedRequest.kt +++ b/api/src/main/kotlin/org/chewing/v1/dto/request/feed/FeedRequest.kt @@ -27,4 +27,15 @@ class FeedRequest { return content } } + data class UpdateText( + val feedId: String, + val content: String, + ) { + fun toFeedId(): FeedId { + return FeedId.of(feedId) + } + fun toContent(): String { + return content + } + } } diff --git a/api/src/main/kotlin/org/chewing/v1/util/security/JwtTokenUtil.kt b/api/src/main/kotlin/org/chewing/v1/util/security/JwtTokenUtil.kt index eae1d9ab0..4ea02bd66 100755 --- a/api/src/main/kotlin/org/chewing/v1/util/security/JwtTokenUtil.kt +++ b/api/src/main/kotlin/org/chewing/v1/util/security/JwtTokenUtil.kt @@ -24,8 +24,7 @@ class JwtTokenUtil( @Value("\${jwt.access-expiration}") private val accessExpiration: Long, @Value("\${jwt.refresh-expiration}") private val refreshExpiration: Long, ) { - private val secretKey: SecretKey - get() = Keys.hmacShaKeyFor(secretKeyString.toByteArray()) + private val secretKey: SecretKey = Keys.hmacShaKeyFor(secretKeyString.toByteArray()) fun createJwtToken(userId: UserId): JwtToken { val accessToken = createAccessToken(userId) @@ -79,7 +78,7 @@ class JwtTokenUtil( // 토큰에서 사용자 ID 추출 fun getUserIdFromToken(token: String): UserId { - val claims = getClaimsFromToken(token) + val claims = getClaimsFromToken(cleanedToken(token)) return UserId.of(claims.subject) } diff --git a/api/src/test/kotlin/org/chewing/v1/controller/AuthControllerTest.kt b/api/src/test/kotlin/org/chewing/v1/controller/AuthControllerTest.kt index 070c89690..915f92ca8 100755 --- a/api/src/test/kotlin/org/chewing/v1/controller/AuthControllerTest.kt +++ b/api/src/test/kotlin/org/chewing/v1/controller/AuthControllerTest.kt @@ -8,7 +8,6 @@ import io.mockk.verify import org.chewing.v1.RestDocsTest import org.chewing.v1.RestDocsUtils.requestAccessTokenFields import org.chewing.v1.RestDocsUtils.requestPreprocessor -import org.chewing.v1.RestDocsUtils.requestRefreshTokenFields import org.chewing.v1.RestDocsUtils.responseErrorFields import org.chewing.v1.RestDocsUtils.responsePreprocessor import org.chewing.v1.RestDocsUtils.responseSuccessFields @@ -16,6 +15,7 @@ import org.chewing.v1.TestDataFactory.createJwtToken import org.chewing.v1.TestDataFactory.createUserId import org.chewing.v1.controller.auth.AuthController import org.chewing.v1.dto.request.auth.LoginRequest +import org.chewing.v1.dto.request.auth.LogoutRequest import org.chewing.v1.dto.request.auth.SignUpRequest import org.chewing.v1.dto.request.auth.VerificationRequest import org.chewing.v1.dto.request.auth.VerifyOnlyRequest @@ -740,11 +740,17 @@ class AuthControllerTest : RestDocsTest() { @Test @DisplayName("로그아웃") fun logout() { - every { authService.logout(any()) } just Runs + val requestBody = LogoutRequest( + deviceId = "testDeviceId", + provider = "ios", + ) + every { accountFacade.logout(any(), any()) } just Runs every { jwtTokenUtil.validateRefreshToken(any()) } just Runs given() + .contentType(MediaType.APPLICATION_JSON_VALUE) .header("Authorization", "Bearer refreshToken") + .body(requestBody) .delete("/api/auth/logout") .then() .assertCommonSuccessResponse() @@ -754,7 +760,13 @@ class AuthControllerTest : RestDocsTest() { "{class-name}/{method-name}", requestPreprocessor(), responsePreprocessor(), - requestRefreshTokenFields(), + requestHeaders( + headerWithName("Authorization").description("리프레시 토큰"), + ), + requestFields( + fieldWithPath("deviceId").description("디바이스 아이디(디바이스 식별을 위한 정보)"), + fieldWithPath("provider").description("플랫폼(ios, android)"), + ), responseSuccessFields(), ), ) diff --git a/api/src/test/kotlin/org/chewing/v1/controller/FeedControllerTest.kt b/api/src/test/kotlin/org/chewing/v1/controller/FeedControllerTest.kt index 4545faaa5..0b57e06a8 100755 --- a/api/src/test/kotlin/org/chewing/v1/controller/FeedControllerTest.kt +++ b/api/src/test/kotlin/org/chewing/v1/controller/FeedControllerTest.kt @@ -590,4 +590,34 @@ class FeedControllerTest : RestDocsTest() { ), ) } + + @Test + fun updateTextFeed() { + val requestBody = FeedRequest.UpdateText( + feedId = "testFeedId", + content = "testContent", + ) + every { feedService.changeText(any(), any(), any()) } just Runs + + given() + .setupAuthenticatedJsonRequest() + .body(requestBody) + .put("/api/feed/text") + .then() + .statusCode(HttpStatus.OK.value()) + .body("status", equalTo(200)) + .apply( + document( + "{class-name}/{method-name}", + requestPreprocessor(), + responsePreprocessor(), + requestAccessTokenFields(), + requestFields( + fieldWithPath("feedId").description("피드 아이디"), + fieldWithPath("content").description("피드 내용"), + ), + responseSuccessFields(), + ), + ) + } } diff --git a/api/src/test/kotlin/org/chewing/v1/security/SpringSecurityTest2.kt b/api/src/test/kotlin/org/chewing/v1/security/SpringSecurityTest2.kt index ffd095015..04178aa1b 100755 --- a/api/src/test/kotlin/org/chewing/v1/security/SpringSecurityTest2.kt +++ b/api/src/test/kotlin/org/chewing/v1/security/SpringSecurityTest2.kt @@ -90,10 +90,17 @@ class SpringSecurityTest2 : IntegrationTest() { fun logout() { val userId = TestDataFactory.createUserId() val jwtToken = jwtTokenUtil.createRefreshToken(userId) - every { authService.logout(any()) } just Runs + val deviceId = "testDeviceId" + val provider = "IOS" + val requestBody = mapOf( + "deviceId" to deviceId, + "provider" to provider, + ) + every { accountFacade.logout(any(), any()) } just Runs mockMvc.perform( MockMvcRequestBuilders.delete("/api/auth/logout") .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(requestBody)) .header("Authorization", "Bearer ${jwtToken.token}"), ).andExpect(status().isOk) } diff --git a/api/src/test/kotlin/org/chewing/v1/util/JwtTokenProviderTest.kt b/api/src/test/kotlin/org/chewing/v1/util/JwtTokenProviderTest.kt index 3b7626926..1bf4c6d4d 100755 --- a/api/src/test/kotlin/org/chewing/v1/util/JwtTokenProviderTest.kt +++ b/api/src/test/kotlin/org/chewing/v1/util/JwtTokenProviderTest.kt @@ -106,4 +106,37 @@ class JwtTokenProviderTest { val cleaned = jwtTokenProvider.cleanedToken(token) assert(cleaned == "someToken") } + + @Test + @DisplayName("Refresh 토큰으로 새로운 JwtToken을 재발급할 수 있어야 한다") + fun `test refresh`() { + val userId = TestDataFactory.createUserId() + val jwtToken = jwtTokenProvider.createJwtToken(userId) + val refreshToken = jwtToken.refreshToken.token + + val (newToken, extractedUserId) = jwtTokenProvider.refresh("Bearer $refreshToken") + + assert(newToken.accessToken.isNotBlank()) + assert(newToken.refreshToken.token.isNotBlank()) + assert(extractedUserId == userId) + } + + @Test + @DisplayName("정상적인 refresh token에 대해 validateRefreshToken이 성공하는지 테스트") + fun `test validateRefreshToken with valid token`() { + val userId = TestDataFactory.createUserId() + val refreshToken = jwtTokenProvider.createRefreshToken(userId).token + jwtTokenProvider.validateRefreshToken("Bearer $refreshToken") + } + + @Test + @DisplayName("Bearer prefix가 있는 토큰에서도 사용자 ID를 추출할 수 있어야 한다") + fun `test getUserIdFromToken with Bearer token`() { + val userId = TestDataFactory.createUserId() + val token = jwtTokenProvider.createAccessToken(userId) + val bearerToken = "Bearer $token" + + val extractedUserId = jwtTokenProvider.getUserIdFromToken(bearerToken) + assert(extractedUserId == userId) + } } diff --git a/domain/src/main/kotlin/org/chewing/v1/facade/AccountFacade.kt b/domain/src/main/kotlin/org/chewing/v1/facade/AccountFacade.kt index d80b20577..cc0619d9b 100755 --- a/domain/src/main/kotlin/org/chewing/v1/facade/AccountFacade.kt +++ b/domain/src/main/kotlin/org/chewing/v1/facade/AccountFacade.kt @@ -77,4 +77,12 @@ class AccountFacade( userService.createDeviceInfo(user.info, device, appToken) return user.info.userId } + + fun logout( + device: PushInfo.Device, + token: String, + ) { + authService.logout(token) + userService.removePushInfo(device) + } } diff --git a/domain/src/main/kotlin/org/chewing/v1/implementation/feed/FeedUpdater.kt b/domain/src/main/kotlin/org/chewing/v1/implementation/feed/FeedUpdater.kt new file mode 100644 index 000000000..1489778d2 --- /dev/null +++ b/domain/src/main/kotlin/org/chewing/v1/implementation/feed/FeedUpdater.kt @@ -0,0 +1,14 @@ +package org.chewing.v1.implementation.feed + +import org.chewing.v1.model.feed.FeedId +import org.chewing.v1.repository.feed.FeedRepository +import org.springframework.stereotype.Component + +@Component +class FeedUpdater( + private val feedRepository: FeedRepository, +) { + fun update(feedId: FeedId, content: String) { + feedRepository.update(feedId, content) + } +} diff --git a/domain/src/main/kotlin/org/chewing/v1/implementation/feed/FeedValidator.kt b/domain/src/main/kotlin/org/chewing/v1/implementation/feed/FeedValidator.kt index 69beec329..efb7ebfc2 100755 --- a/domain/src/main/kotlin/org/chewing/v1/implementation/feed/FeedValidator.kt +++ b/domain/src/main/kotlin/org/chewing/v1/implementation/feed/FeedValidator.kt @@ -19,6 +19,12 @@ class FeedValidator( } } + fun isFeedOwner(feedId: FeedId, userId: UserId) { + if (!feedRepository.isOwner(feedId, userId)) { + throw ConflictException(ErrorCode.FEED_IS_NOT_OWNED) + } + } + fun isFeedVisible(feedId: FeedId, userId: UserId) { if (!feedVisibilityRepository.isVisible(feedId, userId)) { throw ConflictException(ErrorCode.FEED_IS_NOT_VISIBLE) diff --git a/domain/src/main/kotlin/org/chewing/v1/repository/feed/FeedRepository.kt b/domain/src/main/kotlin/org/chewing/v1/repository/feed/FeedRepository.kt index ab3fe1fc7..5e593f440 100755 --- a/domain/src/main/kotlin/org/chewing/v1/repository/feed/FeedRepository.kt +++ b/domain/src/main/kotlin/org/chewing/v1/repository/feed/FeedRepository.kt @@ -13,6 +13,8 @@ interface FeedRepository { fun removes(feedIds: List) fun removesOwned(userId: UserId) fun append(userId: UserId, content: String, type: FeedType): FeedId + fun update(feedId: FeedId, content: String) fun isOwners(feedIds: List, userId: UserId): Boolean + fun isOwner(feedId: FeedId, userId: UserId): Boolean fun readsOneDay(targetUserIds: List): List } diff --git a/domain/src/main/kotlin/org/chewing/v1/service/feed/FeedService.kt b/domain/src/main/kotlin/org/chewing/v1/service/feed/FeedService.kt index 1d2df42b3..fce2fcbfa 100755 --- a/domain/src/main/kotlin/org/chewing/v1/service/feed/FeedService.kt +++ b/domain/src/main/kotlin/org/chewing/v1/service/feed/FeedService.kt @@ -4,6 +4,7 @@ import org.chewing.v1.implementation.feed.FeedAppender import org.chewing.v1.implementation.feed.FeedEnricher import org.chewing.v1.implementation.feed.FeedReader import org.chewing.v1.implementation.feed.FeedRemover +import org.chewing.v1.implementation.feed.FeedUpdater import org.chewing.v1.implementation.feed.FeedValidator import org.chewing.v1.implementation.media.FileHandler import org.chewing.v1.model.feed.* @@ -20,6 +21,7 @@ class FeedService( private val fileHandler: FileHandler, private val feedEnricher: FeedEnricher, private val feedRemover: FeedRemover, + private val feedUpdater: FeedUpdater, ) { fun getFeed(feedId: FeedId, userId: UserId): Feed { feedValidator.isFeedVisible(feedId, userId) @@ -73,4 +75,13 @@ class FeedService( feedAppender.appendVisibility(feedId, targetUserIds) return feedId } + + fun changeText( + userId: UserId, + feedId: FeedId, + content: String, + ) { + feedValidator.isFeedOwner(feedId, userId) + feedUpdater.update(feedId, content) + } } diff --git a/domain/src/main/kotlin/org/chewing/v1/service/user/UserService.kt b/domain/src/main/kotlin/org/chewing/v1/service/user/UserService.kt index 5e742e31a..dd1f92407 100755 --- a/domain/src/main/kotlin/org/chewing/v1/service/user/UserService.kt +++ b/domain/src/main/kotlin/org/chewing/v1/service/user/UserService.kt @@ -129,6 +129,12 @@ class UserService( return userReader.readPushToken(userId, deviceId) } + fun removePushInfo( + device: PushInfo.Device, + ) { + userRemover.removePushToken(device) + } + fun updatePushNotification( userId: UserId, deviceId: String, diff --git a/domain/src/test/kotlin/org/chewing/v1/service/FeedServiceTest.kt b/domain/src/test/kotlin/org/chewing/v1/service/FeedServiceTest.kt index 332e44aaf..5b2b23858 100755 --- a/domain/src/test/kotlin/org/chewing/v1/service/FeedServiceTest.kt +++ b/domain/src/test/kotlin/org/chewing/v1/service/FeedServiceTest.kt @@ -12,6 +12,7 @@ import org.chewing.v1.implementation.feed.FeedAppender import org.chewing.v1.implementation.feed.FeedEnricher import org.chewing.v1.implementation.feed.FeedReader import org.chewing.v1.implementation.feed.FeedRemover +import org.chewing.v1.implementation.feed.FeedUpdater import org.chewing.v1.implementation.feed.FeedValidator import org.chewing.v1.implementation.media.FileHandler import org.chewing.v1.model.feed.FeedType @@ -36,8 +37,9 @@ class FeedServiceTest { private val feedValidator: FeedValidator = FeedValidator(feedRepository, feedVisibilityRepository) private val feedEnricher: FeedEnricher = FeedEnricher() private val feedRemover: FeedRemover = FeedRemover(feedRepository, feedDetailRepository, feedVisibilityRepository) + private val feedUpdater: FeedUpdater = FeedUpdater(feedRepository) private val feedService: FeedService = - FeedService(feedReader, feedAppender, feedValidator, fileHandler, feedEnricher, feedRemover) + FeedService(feedReader, feedAppender, feedValidator, fileHandler, feedEnricher, feedRemover, feedUpdater) @Test fun `피드를 가져온다`() { diff --git a/storage/src/main/kotlin/org/chewing/v1/jpaentity/feed/FeedJpaEntity.kt b/storage/src/main/kotlin/org/chewing/v1/jpaentity/feed/FeedJpaEntity.kt index b3951c38b..fd0fa0ab7 100755 --- a/storage/src/main/kotlin/org/chewing/v1/jpaentity/feed/FeedJpaEntity.kt +++ b/storage/src/main/kotlin/org/chewing/v1/jpaentity/feed/FeedJpaEntity.kt @@ -24,7 +24,7 @@ import java.util.* internal class FeedJpaEntity( @Id private val feedId: String = UUID.randomUUID().toString(), - private val content: String, + private var content: String, private val userId: String, @Enumerated(EnumType.STRING) private val type: FeedType, @@ -59,6 +59,11 @@ internal class FeedJpaEntity( type = type, ) } + + fun updateContent(content: String) { + this.content = content + } + fun delete() { status = FeedStatus.DELETED } diff --git a/storage/src/main/kotlin/org/chewing/v1/jparepository/feed/FeedJpaRepository.kt b/storage/src/main/kotlin/org/chewing/v1/jparepository/feed/FeedJpaRepository.kt index 9fd268637..02c8eed19 100755 --- a/storage/src/main/kotlin/org/chewing/v1/jparepository/feed/FeedJpaRepository.kt +++ b/storage/src/main/kotlin/org/chewing/v1/jparepository/feed/FeedJpaRepository.kt @@ -10,6 +10,7 @@ internal interface FeedJpaRepository : JpaRepository { fun findAllByUserId(userId: String): List fun findAllByUserIdAndStatus(userId: String, status: FeedStatus, sort: Sort): List fun existsByFeedIdInAndUserId(feedIds: List, userId: String): Boolean + fun existsByFeedIdAndUserId(feedId: String, userId: String): Boolean fun findByFeedIdIn(feedIds: List): List fun findByFeedIdAndStatus(feedId: String, status: FeedStatus): FeedJpaEntity? fun findAllByUserIdInAndCreatedAtAfter(userIds: List, createdAt: LocalDateTime, sort: Sort): List diff --git a/storage/src/main/kotlin/org/chewing/v1/jparepository/user/PushNotificationJpaRepository.kt b/storage/src/main/kotlin/org/chewing/v1/jparepository/user/PushNotificationJpaRepository.kt index de82ddcc5..4bb50fc70 100755 --- a/storage/src/main/kotlin/org/chewing/v1/jparepository/user/PushNotificationJpaRepository.kt +++ b/storage/src/main/kotlin/org/chewing/v1/jparepository/user/PushNotificationJpaRepository.kt @@ -6,7 +6,7 @@ import org.chewing.v1.model.notification.PushInfo import org.springframework.data.jpa.repository.JpaRepository internal interface PushNotificationJpaRepository : JpaRepository { - fun deleteByDeviceIdAndProvider(deviceId: String, deviceProvider: PushInfo.Provider) + fun deleteAllByDeviceIdAndProvider(deviceId: String, deviceProvider: PushInfo.Provider) fun findAllByUserId(userId: String): List fun findAllByUserIdAndChatStatus(userId: String, chatStatus: NotificationStatus): List fun findAllByUserIdAndScheduleStatus(userId: String, scheduleStatus: NotificationStatus): List diff --git a/storage/src/main/kotlin/org/chewing/v1/repository/jpa/feed/FeedRepositoryImpl.kt b/storage/src/main/kotlin/org/chewing/v1/repository/jpa/feed/FeedRepositoryImpl.kt index 07ed7e135..2bc10b3d6 100755 --- a/storage/src/main/kotlin/org/chewing/v1/repository/jpa/feed/FeedRepositoryImpl.kt +++ b/storage/src/main/kotlin/org/chewing/v1/repository/jpa/feed/FeedRepositoryImpl.kt @@ -46,6 +46,10 @@ internal class FeedRepositoryImpl( return feedJpaRepository.existsByFeedIdInAndUserId(feedIds.map { it.id }, userId.id) } + override fun isOwner(feedId: FeedId, userId: UserId): Boolean { + return feedJpaRepository.existsByFeedIdAndUserId(feedId.id, userId.id) + } + override fun readsOneDay(targetUserIds: List): List { val now = LocalDateTime.now() val startDate = now.minusDays(1) @@ -56,4 +60,11 @@ internal class FeedRepositoryImpl( ) .map { it.toFeedInfo() } } + + override fun update(feedId: FeedId, content: String) { + feedJpaRepository.findById(feedId.id).ifPresent { + it.updateContent(content) + feedJpaRepository.save(it) + } + } } diff --git a/storage/src/main/kotlin/org/chewing/v1/repository/jpa/user/PushNotificationRepositoryImpl.kt b/storage/src/main/kotlin/org/chewing/v1/repository/jpa/user/PushNotificationRepositoryImpl.kt index 72ad31974..123b086c8 100755 --- a/storage/src/main/kotlin/org/chewing/v1/repository/jpa/user/PushNotificationRepositoryImpl.kt +++ b/storage/src/main/kotlin/org/chewing/v1/repository/jpa/user/PushNotificationRepositoryImpl.kt @@ -17,7 +17,7 @@ internal class PushNotificationRepositoryImpl( ) : PushNotificationRepository { @Transactional override fun remove(device: PushInfo.Device) { - pushNotificationJpaRepository.deleteByDeviceIdAndProvider(device.deviceId, device.provider) + pushNotificationJpaRepository.deleteAllByDeviceIdAndProvider(device.deviceId, device.provider) } override fun append(device: PushInfo.Device, appToken: String, userInfo: UserInfo) {