diff --git a/api/src/main/kotlin/dnd11th/blooming/api/dto/myplant/MyPlantResponse.kt b/api/src/main/kotlin/dnd11th/blooming/api/dto/myplant/MyPlantResponse.kt index 6800894c..48180e02 100644 --- a/api/src/main/kotlin/dnd11th/blooming/api/dto/myplant/MyPlantResponse.kt +++ b/api/src/main/kotlin/dnd11th/blooming/api/dto/myplant/MyPlantResponse.kt @@ -20,7 +20,7 @@ data class MyPlantResponse( @field:Schema(description = "등록 일자", example = "2024-09-03T14:30:45") val registeredDateTime: LocalDateTime, @field:Schema(description = "이미지 URL", example = "image.com/7") - val imageUrl: String, + val imageUrl: String?, @field:Schema(description = "내 식물 학명", example = "몬스테라 델리오사") val scientificName: String, @field:Schema(description = "마지막 물주기로부터 지난 날짜", example = "2") diff --git a/api/src/main/kotlin/dnd11th/blooming/api/service/myplant/MyPlantService.kt b/api/src/main/kotlin/dnd11th/blooming/api/service/myplant/MyPlantService.kt index d4e35ceb..611b592b 100644 --- a/api/src/main/kotlin/dnd11th/blooming/api/service/myplant/MyPlantService.kt +++ b/api/src/main/kotlin/dnd11th/blooming/api/service/myplant/MyPlantService.kt @@ -53,7 +53,7 @@ class MyPlantService( now: LocalDate, user: User, ): List { - val myPlantsWithImageUrl: List = imageRepository.findMyPlantAndMostRecentFavoriteImageByUser(user) + val myPlantsWithImageUrl: List = myPlantRepository.findMyPlantAndMostRecentFavoriteImageByUser(user) return MyPlantResponse.fromMyPlantWithImageUrlList(myPlantsWithImageUrl, now) } diff --git a/api/src/test/kotlin/dnd11th/blooming/api/service/myplant/MyPlantServiceTest.kt b/api/src/test/kotlin/dnd11th/blooming/api/service/myplant/MyPlantServiceTest.kt index 5fe4eadd..fbe78dda 100644 --- a/api/src/test/kotlin/dnd11th/blooming/api/service/myplant/MyPlantServiceTest.kt +++ b/api/src/test/kotlin/dnd11th/blooming/api/service/myplant/MyPlantServiceTest.kt @@ -39,14 +39,14 @@ import java.time.LocalDate class MyPlantServiceTest : DescribeSpec( { - val myPlantRepsitory = mockk() + val myPlantRepository = mockk() val plantRepository = mockk() val locationRepository = mockk() val imageRepository = mockk() val myPlantMessageFactory = mockk() val myPlantService = MyPlantService( - myPlantRepsitory, + myPlantRepository, plantRepository, locationRepository, myPlantMessageFactory, @@ -58,7 +58,7 @@ class MyPlantServiceTest : DescribeSpec( "등록 되었습니다." every { plantRepository.findByIdOrNull(PLANT_ID) } returns PLANT - every { myPlantRepsitory.save(any()) } returns + every { myPlantRepository.save(any()) } returns MyPlant( scientificName = SCIENTIFIC_NAME, nickname = NICKNAME, @@ -137,9 +137,9 @@ class MyPlantServiceTest : DescribeSpec( id = 3 location = null } - every { myPlantRepsitory.findAllByUser(any()) } returns + every { myPlantRepository.findAllByUser(any()) } returns listOf(myPlant1, myPlant2, myPlant3) - every { imageRepository.findMyPlantAndMostRecentFavoriteImageByUser(any()) } returns + every { myPlantRepository.findMyPlantAndMostRecentFavoriteImageByUser(any()) } returns listOf( MyPlantWithImageUrl(myPlant1, "url1"), MyPlantWithImageUrl(myPlant2, "url2"), @@ -190,7 +190,7 @@ class MyPlantServiceTest : DescribeSpec( } describe("내 식물 상세 조회") { - every { myPlantRepsitory.findByIdAndUser(MYPLANT_ID, any()) } returns + every { myPlantRepository.findByIdAndUser(MYPLANT_ID, any()) } returns MyPlant( scientificName = SCIENTIFIC_NAME, nickname = NICKNAME, @@ -202,7 +202,7 @@ class MyPlantServiceTest : DescribeSpec( ).apply { id = MYPLANT_ID } - every { myPlantRepsitory.findByIdAndUser(not(eq(MYPLANT_ID)), any()) } returns + every { myPlantRepository.findByIdAndUser(not(eq(MYPLANT_ID)), any()) } returns null every { imageRepository.findAllByMyPlant(any()) } returns listOf( @@ -224,7 +224,7 @@ class MyPlantServiceTest : DescribeSpec( FERTILIZER_TITLE every { myPlantMessageFactory.createFertilizerInfo(any(), any()) } returns FERTILIZER_INFO - every { myPlantRepsitory.findByIdOrNull(not(eq(MYPLANT_ID))) } returns + every { myPlantRepository.findByIdOrNull(not(eq(MYPLANT_ID))) } returns null context("존재하는 ID로 상세 조회하면") { it("내 식물의 상세 정보가 조회되어야 한다.") { @@ -254,7 +254,7 @@ class MyPlantServiceTest : DescribeSpec( } describe("내 식물 수정") { - every { myPlantRepsitory.findByIdAndUser(any(), any()) } returns + every { myPlantRepository.findByIdAndUser(any(), any()) } returns MyPlant( scientificName = SCIENTIFIC_NAME, nickname = NICKNAME, @@ -264,7 +264,7 @@ class MyPlantServiceTest : DescribeSpec( lastHealthCheckDate = LAST_HEALTHCHECK_DATE, alarm = ALARM, ) - every { myPlantRepsitory.findByIdAndUser(not(eq(MYPLANT_ID)), any()) } returns + every { myPlantRepository.findByIdAndUser(not(eq(MYPLANT_ID)), any()) } returns null every { locationRepository.findByIdAndUser(LOCATION_ID, any()) } returns Location( @@ -334,7 +334,7 @@ class MyPlantServiceTest : DescribeSpec( } describe("내 식물 삭제") { - every { myPlantRepsitory.findByIdAndUser(MYPLANT_ID, any()) } returns + every { myPlantRepository.findByIdAndUser(MYPLANT_ID, any()) } returns MyPlant( scientificName = SCIENTIFIC_NAME, nickname = NICKNAME, @@ -346,9 +346,9 @@ class MyPlantServiceTest : DescribeSpec( ).apply { id = MYPLANT_ID } - every { myPlantRepsitory.findByIdAndUser(not(eq(MYPLANT_ID)), any()) } returns + every { myPlantRepository.findByIdAndUser(not(eq(MYPLANT_ID)), any()) } returns null - every { myPlantRepsitory.delete(any()) } just runs + every { myPlantRepository.delete(any()) } just runs every { imageRepository.deleteAllInBatchByMyPlant(any()) } just runs context("정상 요청으로 삭제하면") { @@ -367,7 +367,7 @@ class MyPlantServiceTest : DescribeSpec( } describe("내 식물 물주기") { - every { myPlantRepsitory.findByIdAndUser(MYPLANT_ID, any()) } returns + every { myPlantRepository.findByIdAndUser(MYPLANT_ID, any()) } returns MyPlant( scientificName = SCIENTIFIC_NAME, nickname = NICKNAME, @@ -379,7 +379,7 @@ class MyPlantServiceTest : DescribeSpec( ).apply { id = MYPLANT_ID } - every { myPlantRepsitory.findByIdAndUser(not(eq(MYPLANT_ID)), any()) } returns + every { myPlantRepository.findByIdAndUser(not(eq(MYPLANT_ID)), any()) } returns null context("존재하는 내 식물 ID로 내 식물 물주기 요청하면") { it("정상 흐름이 반환된다.") { @@ -401,7 +401,7 @@ class MyPlantServiceTest : DescribeSpec( } describe("내 식물 비료주기") { - every { myPlantRepsitory.findByIdAndUser(MYPLANT_ID, any()) } returns + every { myPlantRepository.findByIdAndUser(MYPLANT_ID, any()) } returns MyPlant( scientificName = SCIENTIFIC_NAME, nickname = NICKNAME, @@ -413,7 +413,7 @@ class MyPlantServiceTest : DescribeSpec( ).apply { id = MYPLANT_ID } - every { myPlantRepsitory.findByIdAndUser(not(eq(MYPLANT_ID)), any()) } returns + every { myPlantRepository.findByIdAndUser(not(eq(MYPLANT_ID)), any()) } returns null context("존재하는 내 식물 ID로 내 식물 비료주기 요청하면") { it("정상 흐름이 반환된다.") { @@ -435,7 +435,7 @@ class MyPlantServiceTest : DescribeSpec( } describe("내 식물 눈길주기") { - every { myPlantRepsitory.findByIdAndUser(MYPLANT_ID, any()) } returns + every { myPlantRepository.findByIdAndUser(MYPLANT_ID, any()) } returns MyPlant( scientificName = SCIENTIFIC_NAME, nickname = NICKNAME, @@ -447,7 +447,7 @@ class MyPlantServiceTest : DescribeSpec( ).apply { id = MYPLANT_ID } - every { myPlantRepsitory.findByIdAndUser(not(eq(MYPLANT_ID)), any()) } returns + every { myPlantRepository.findByIdAndUser(not(eq(MYPLANT_ID)), any()) } returns null every { myPlantMessageFactory.createHealthCheckMessage() } returns "팁" @@ -471,7 +471,7 @@ class MyPlantServiceTest : DescribeSpec( } describe("알림 변경") { - every { myPlantRepsitory.findByIdAndUser(MYPLANT_ID, any()) } returns + every { myPlantRepository.findByIdAndUser(MYPLANT_ID, any()) } returns MyPlant( scientificName = SCIENTIFIC_NAME, nickname = NICKNAME, @@ -483,7 +483,7 @@ class MyPlantServiceTest : DescribeSpec( ).apply { id = MYPLANT_ID } - every { myPlantRepsitory.findByIdAndUser(not(eq(MYPLANT_ID)), any()) } returns + every { myPlantRepository.findByIdAndUser(not(eq(MYPLANT_ID)), any()) } returns null context("존재하는 ID와 요청으로 알림 변경 요청을 하면") { val request = diff --git a/batch/src/main/kotlin/dnd11th/blooming/batch/notification/PlantNotificationReader.kt b/batch/src/main/kotlin/dnd11th/blooming/batch/notification/PlantNotificationReader.kt index 7c17afc9..cde34eb3 100644 --- a/batch/src/main/kotlin/dnd11th/blooming/batch/notification/PlantNotificationReader.kt +++ b/batch/src/main/kotlin/dnd11th/blooming/batch/notification/PlantNotificationReader.kt @@ -17,8 +17,7 @@ class PlantNotificationReader( @StepScope fun waterNotificationItemReader(): ListItemReader { val now: LocalTime = LocalTime.now() - // val alarmTime = AlarmTime.fromHour(now) - val alarmTime = AlarmTime.TIME_10_11 + val alarmTime = AlarmTime.fromHour(now) val userPlantByAlarmTime: List = myPlantRepository.findNeedWaterPlantsByAlarmTimeInBatch(alarmTime) diff --git a/domain/core/src/main/kotlin/dnd11th/blooming/core/entity/myplant/MyPlant.kt b/domain/core/src/main/kotlin/dnd11th/blooming/core/entity/myplant/MyPlant.kt index 524a8aaa..942a1aee 100644 --- a/domain/core/src/main/kotlin/dnd11th/blooming/core/entity/myplant/MyPlant.kt +++ b/domain/core/src/main/kotlin/dnd11th/blooming/core/entity/myplant/MyPlant.kt @@ -39,7 +39,7 @@ class MyPlant( var id: Long? = null @Column - var plantImageUrl: String = "블루밍 대표 이미지" + var plantImageUrl: String? = null // TODO : 블루밍 대표 이미지 넣기 @ManyToOne(fetch = FetchType.LAZY) diff --git a/domain/core/src/main/kotlin/dnd11th/blooming/core/repository/image/ImageRepository.kt b/domain/core/src/main/kotlin/dnd11th/blooming/core/repository/image/ImageRepository.kt index fd8b2050..b5894d59 100644 --- a/domain/core/src/main/kotlin/dnd11th/blooming/core/repository/image/ImageRepository.kt +++ b/domain/core/src/main/kotlin/dnd11th/blooming/core/repository/image/ImageRepository.kt @@ -2,7 +2,6 @@ package dnd11th.blooming.core.repository.image import dnd11th.blooming.core.entity.image.Image import dnd11th.blooming.core.entity.myplant.MyPlant -import dnd11th.blooming.core.entity.myplant.MyPlantWithImageUrl import dnd11th.blooming.core.entity.user.User import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Modifying @@ -12,26 +11,6 @@ import org.springframework.data.repository.query.Param interface ImageRepository : JpaRepository { fun findAllByMyPlant(myPlant: MyPlant): List - @Query( - """ - SELECT new dnd11th.blooming.core.entity.myplant.MyPlantWithImageUrl(mp, i.url) - FROM Image i - JOIN i.myPlant mp - JOIN FETCH mp.location l - WHERE mp.user = :user - AND i.favorite = true - AND i.updatedDate = ( - SELECT MAX(i2.updatedDate) - FROM Image i2 - WHERE i2.myPlant = mp - AND i2.favorite = true - ) - """, - ) - fun findMyPlantAndMostRecentFavoriteImageByUser( - @Param("user") user: User, - ): List - @Modifying @Query( """ diff --git a/domain/core/src/main/kotlin/dnd11th/blooming/core/repository/myplant/MyPlantRepository.kt b/domain/core/src/main/kotlin/dnd11th/blooming/core/repository/myplant/MyPlantRepository.kt index 9959e716..e8104fdb 100644 --- a/domain/core/src/main/kotlin/dnd11th/blooming/core/repository/myplant/MyPlantRepository.kt +++ b/domain/core/src/main/kotlin/dnd11th/blooming/core/repository/myplant/MyPlantRepository.kt @@ -2,15 +2,14 @@ package dnd11th.blooming.core.repository.myplant import dnd11th.blooming.core.entity.location.Location import dnd11th.blooming.core.entity.myplant.MyPlant +import dnd11th.blooming.core.entity.myplant.MyPlantWithImageUrl import dnd11th.blooming.core.entity.user.User import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Modifying import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.query.Param -interface MyPlantRepository : - JpaRepository, - MyPlantQueryDslRepository { +interface MyPlantRepository : JpaRepository, MyPlantQueryDslRepository { fun findByIdAndUser( id: Long, user: User, @@ -31,4 +30,23 @@ interface MyPlantRepository : fun deleteAllByUser( @Param("user") user: User, ) + + @Query( + """ + SELECT new dnd11th.blooming.core.entity.myplant.MyPlantWithImageUrl( + mp, + (SELECT i.url + FROM Image i + WHERE i.myPlant = mp AND i.favorite = true + ORDER BY i.updatedDate + DESC LIMIT 1) + ) + FROM MyPlant mp + JOIN FETCH mp.location l + WHERE mp.user = :user + """, + ) + fun findMyPlantAndMostRecentFavoriteImageByUser( + @Param("user") user: User, + ): List }