diff --git a/src/intTest/kotlin/com/yapp/web2/domain/account/controller/AccountControllerTest.kt b/src/intTest/kotlin/com/yapp/web2/domain/account/controller/AccountControllerTest.kt index c89ac19..925a088 100644 --- a/src/intTest/kotlin/com/yapp/web2/domain/account/controller/AccountControllerTest.kt +++ b/src/intTest/kotlin/com/yapp/web2/domain/account/controller/AccountControllerTest.kt @@ -6,10 +6,10 @@ import com.yapp.web2.domain.folder.controller.FolderController import com.yapp.web2.security.jwt.TokenDto import com.yapp.web2.util.AbstractControllerTest import com.yapp.web2.util.Message +import com.yapp.web2.util.RandomUtils import io.mockk.Runs import io.mockk.every import io.mockk.just -import org.apache.commons.lang3.RandomStringUtils import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration @@ -293,10 +293,12 @@ class AccountControllerTest : AbstractControllerTest() { @Test fun `비밀번호 재설정 시 임시 비밀번호를 생성하고 메일을 발송한다`() { // given - val tempPassword = RandomStringUtils.randomAlphanumeric(12) + "!" + val tempPassword = RandomUtils.shuffleCharacters( + RandomUtils.getRandomAlphanumeric(12) + RandomUtils.getRandomSpecialCharacter() + ) every { accountService.createTempPassword() } returns tempPassword every { accountService.updatePassword(any(), any()) } just Runs - every { accountService.sendMail(any(), tempPassword) } returns Message.SUCCESS_SEND_MAIL + every { accountService.sendMail(any(), tempPassword) } just Runs // when val resultAction = util.postResultAction("/api/v1/user/password/reset", "", mockMvc) diff --git a/src/main/kotlin/com/yapp/web2/batch/job/NotificationJob.kt b/src/main/kotlin/com/yapp/web2/batch/job/NotificationJob.kt index 381358f..d7ffd53 100644 --- a/src/main/kotlin/com/yapp/web2/batch/job/NotificationJob.kt +++ b/src/main/kotlin/com/yapp/web2/batch/job/NotificationJob.kt @@ -51,9 +51,12 @@ class NotificationJob( fun remindBookmarkReader(): ListItemReader { val bookmarkOfList = notificationService.getRemindBookmark() + log.info("리마인드 발송할 도토리 갯수: ${bookmarkOfList.size}") + return ListItemReader(bookmarkOfList) } + // TODO: Notification 실패 처리 -> Queue(Kafka) 적재 후 Retry 처리 @Bean fun remindBookmarkProcessor(): ItemProcessor { return ItemProcessor { @@ -62,13 +65,14 @@ class NotificationJob( } } + // TODO: 코드 수정 @Bean fun remindBookmarkWriter(): ItemWriter { return ItemWriter { it.stream().forEach { bookmark -> - bookmark.successRemind() +// bookmark.successRemind() notificationService.save(bookmark) - log.info("{} -> {} 푸쉬 발송", bookmark.userId, bookmark.title) + log.info("{} -> {} Send Notification", bookmark.userId, bookmark.title) } } } diff --git a/src/main/kotlin/com/yapp/web2/config/SecurityConfig.kt b/src/main/kotlin/com/yapp/web2/config/SecurityConfig.kt index 8ebdb8b..8ddefde 100644 --- a/src/main/kotlin/com/yapp/web2/config/SecurityConfig.kt +++ b/src/main/kotlin/com/yapp/web2/config/SecurityConfig.kt @@ -47,7 +47,6 @@ class SecurityConfig( http.authorizeRequests() .antMatchers("/actuator/**").permitAll() -// .antMatchers("/api/v1/page/open/**").permitAll() .anyRequest().authenticated() http.apply(JwtSecurityConfig(jwtProvider)) diff --git a/src/main/kotlin/com/yapp/web2/domain/account/controller/AccountController.kt b/src/main/kotlin/com/yapp/web2/domain/account/controller/AccountController.kt index fc46176..81a694f 100644 --- a/src/main/kotlin/com/yapp/web2/domain/account/controller/AccountController.kt +++ b/src/main/kotlin/com/yapp/web2/domain/account/controller/AccountController.kt @@ -235,8 +235,9 @@ class AccountController( val token = ControllerUtil.extractAccessToken(request) val tempPassword = accountService.createTempPassword() accountService.updatePassword(token, tempPassword) + accountService.sendMail(token, tempPassword) - return ResponseEntity.status(HttpStatus.OK).body(accountService.sendMail(token, tempPassword)) + return ResponseEntity.status(HttpStatus.OK).body(Message.SUCCESS) } } \ No newline at end of file diff --git a/src/main/kotlin/com/yapp/web2/domain/account/entity/Account.kt b/src/main/kotlin/com/yapp/web2/domain/account/entity/Account.kt index 9e4e4dd..0c218df 100644 --- a/src/main/kotlin/com/yapp/web2/domain/account/entity/Account.kt +++ b/src/main/kotlin/com/yapp/web2/domain/account/entity/Account.kt @@ -7,7 +7,10 @@ import com.yapp.web2.security.jwt.TokenDto import io.swagger.annotations.ApiModel import io.swagger.annotations.ApiModelProperty import org.springframework.transaction.annotation.Transactional -import javax.persistence.* +import javax.persistence.CascadeType +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.OneToMany import javax.validation.constraints.NotBlank import javax.validation.constraints.NotEmpty @@ -17,33 +20,6 @@ class Account( var email: String ) : BaseTimeEntity() { - companion object { - fun signUpToAccount(dto: AccountRequestDto.SignUpRequest, encryptPassword: String, name: String): Account { - return Account(dto.email, encryptPassword, dto.fcmToken, name) - } - - fun profileToAccount(dto: AccountProfile): Account { - return Account(dto.email, dto.image, dto.name, dto.socialType, dto.fcmToken) - } - - fun accountToProfile(account: Account): AccountProfile { - return AccountProfile( - account.email, - account.name, - account.image, - account.socialType, - account.fcmToken ?: "" - ) - } - - fun accountToRemindElements(account: Account): RemindElements { - return RemindElements(account.remindCycle, account.remindToggle) - } - - const val BASIC_IMAGE_URL: String = "https://yapp-bucket-test.s3.ap-northeast-2.amazonaws.com/basicImage.png" - } - - @Column(nullable = true) var password: String? = null @@ -74,6 +50,36 @@ class Account( @OneToMany(mappedBy = "account", cascade = [CascadeType.ALL], orphanRemoval = true) var accountFolderList: MutableList = mutableListOf() + fun inverseRemindToggle(reverse: Boolean) { + this.remindToggle = reverse + } + + companion object { + fun signUpToAccount(dto: AccountRequestDto.SignUpRequest, encryptPassword: String, name: String): Account { + return Account(dto.email, encryptPassword, dto.fcmToken, name) + } + + fun profileToAccount(dto: AccountProfile): Account { + return Account(dto.email, dto.image, dto.name, dto.socialType, dto.fcmToken) + } + + fun accountToProfile(account: Account): AccountProfile { + return AccountProfile( + account.email, + account.name, + account.image, + account.socialType, + account.fcmToken ?: "" + ) + } + + fun accountToRemindElements(account: Account): RemindElements { + return RemindElements(account.remindCycle, account.remindToggle) + } + + const val BASIC_IMAGE_URL: String = "https://yapp-bucket-test.s3.ap-northeast-2.amazonaws.com/basicImage.png" + } + constructor(email: String, password: String) : this(email) { this.password = password } diff --git a/src/main/kotlin/com/yapp/web2/domain/account/service/AccountService.kt b/src/main/kotlin/com/yapp/web2/domain/account/service/AccountService.kt index b2e32c6..73a808f 100644 --- a/src/main/kotlin/com/yapp/web2/domain/account/service/AccountService.kt +++ b/src/main/kotlin/com/yapp/web2/domain/account/service/AccountService.kt @@ -282,7 +282,8 @@ class AccountService( return RandomUtils.shuffleCharacters(randomAlphanumeric + randomSpecialCharacter) } - fun sendMail(token: String, tempPassword: String): String { + // TODO: 2022/07/16 비동기 처리 + fun sendMail(token: String, tempPassword: String) { val account = jwtProvider.getAccountFromToken(token) val mailMessage = SimpleMailMessage() mailMessage.setTo(account.email) @@ -292,8 +293,6 @@ class AccountService( mailSender.send(mailMessage) log.info("${account.email} 계정으로 임시 비밀번호를 발송하였습니다.") - - return Message.SUCCESS_SEND_MAIL } fun updatePassword(token: String, tempPassword: String) { diff --git a/src/main/kotlin/com/yapp/web2/domain/bookmark/BookmarkDto.kt b/src/main/kotlin/com/yapp/web2/domain/bookmark/BookmarkDto.kt index d07308b..522bada 100644 --- a/src/main/kotlin/com/yapp/web2/domain/bookmark/BookmarkDto.kt +++ b/src/main/kotlin/com/yapp/web2/domain/bookmark/BookmarkDto.kt @@ -55,7 +55,6 @@ class BookmarkDto { @ApiModel(description = "북마크 생성 DTO") data class AddBookmarkDto( - // TODO: 2021/12/04 RequestParam 데이터 검증 @ApiModelProperty(value = "북마크 url", required = true, example = "https://www.naver.com") var url: String, diff --git a/src/main/kotlin/com/yapp/web2/domain/bookmark/controller/TrashController.kt b/src/main/kotlin/com/yapp/web2/domain/bookmark/controller/TrashController.kt index 8464ed8..6daa296 100644 --- a/src/main/kotlin/com/yapp/web2/domain/bookmark/controller/TrashController.kt +++ b/src/main/kotlin/com/yapp/web2/domain/bookmark/controller/TrashController.kt @@ -8,7 +8,11 @@ import io.swagger.annotations.ApiOperation import io.swagger.annotations.ApiParam import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.* +import org.springframework.web.bind.annotation.PatchMapping +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 @RestController @RequestMapping("/api/v1/trash") @@ -19,14 +23,14 @@ class TrashController( @ApiOperation("북마크 복원 API") @PatchMapping("/restore") fun restoreBookmarks(@RequestBody @ApiParam(value = "복원할 북마크 ID 리스트", required = true) request: BookmarkDto.RestoreBookmarkRequest): ResponseEntity { - bookmarkService.restore(request.bookmarkIdList) + bookmarkService.restoreBookmarks(request.bookmarkIdList) return ResponseEntity.status(HttpStatus.OK).body(Message.SUCCESS) } @ApiOperation("북마크 영구삭제 API") @PostMapping("/truncate") fun permanentDelete(@RequestBody @ApiParam(value = "영구삭제할 북마크 ID 리스트", required = true) request: BookmarkDto.TruncateBookmarkRequest): ResponseEntity { - bookmarkService.permanentDelete(request.bookmarkIdList) + bookmarkService.deleteBookmarkPermanently(request.bookmarkIdList) return ResponseEntity.status(HttpStatus.OK).body(Message.SUCCESS) } } \ No newline at end of file diff --git a/src/main/kotlin/com/yapp/web2/domain/bookmark/entity/Bookmark.kt b/src/main/kotlin/com/yapp/web2/domain/bookmark/entity/Bookmark.kt index e0918ad..1417275 100644 --- a/src/main/kotlin/com/yapp/web2/domain/bookmark/entity/Bookmark.kt +++ b/src/main/kotlin/com/yapp/web2/domain/bookmark/entity/Bookmark.kt @@ -12,19 +12,29 @@ class Bookmark( var folderId: Long?, val link: String ) { + @Id + lateinit var id: String + + var title: String? = "" + var folderEmoji: String? = "" + var folderName: String? = "" + + var clickCount: Int = 0 + var deleteTime: LocalDateTime? = null + var deleted: Boolean = false + var description: String? = null + var image: String? = null + + var saveTime: LocalDateTime = LocalDateTime.now() + + var remindList = mutableListOf() + + var shared: Boolean = false + constructor(userId: Long, folderId: Long?, link: String, title: String?) : this(userId, folderId, link) { this.title = title } - constructor(userId: Long, folderId: Long?, link: String, title: String?, remindTime: String?) : this( - userId, - folderId, - link, - title - ) { - this.remindTime = remindTime - } - constructor( userId: Long, folderId: Long?, @@ -48,44 +58,22 @@ class Bookmark( if (remind) remindOn(Remind(account)) } - constructor( - userId: Long, - folderId: Long?, - folderEmoji: String?, - folderName: String?, - link: String, - title: String?, - remindTime: String?, - image: String?, - description: String? - ) : this(userId, folderId, link, title, remindTime) { - this.folderEmoji = folderEmoji - this.folderName = folderName - this.description = description - this.image = image - } - - @Id - lateinit var id: String - - var title: String? = "" - var folderEmoji: String? = "" - var folderName: String? = "" - - var clickCount: Int = 0 - var deleteTime: LocalDateTime? = null - var deleted: Boolean = false - var description: String? = null - var image: String? = null - - var saveTime: LocalDateTime = LocalDateTime.now() - var remindTime: String? = null - var remindCheck: Boolean = false - var remindStatus: Boolean = false - - var remindList = mutableListOf() - - var shared: Boolean = false +// constructor( +// userId: Long, +// folderId: Long?, +// folderEmoji: String?, +// folderName: String?, +// link: String, +// title: String?, +// remindTime: String?, +// image: String?, +// description: String? +// ) : this(userId, folderId, link, title, remindTime) { +// this.folderEmoji = folderEmoji +// this.folderName = folderName +// this.description = description +// this.image = image +// } fun restore(): Bookmark { this.deleted = false @@ -137,19 +125,16 @@ class Bookmark( remindList.add(remind) } - fun updateRemindCheck() { - this.remindCheck = true - } - fun moveFolder(nextFolderId: Long) { this.folderId = nextFolderId } - fun successRemind() { - this.remindStatus = true - } - fun hitClickCount() { this.clickCount++ } + + override fun toString(): String { + return "Bookmark(userId=$userId, link='$link', id='$id', title=$title, remindList=$remindList)" + } + } \ No newline at end of file diff --git a/src/main/kotlin/com/yapp/web2/domain/bookmark/entity/Remind.kt b/src/main/kotlin/com/yapp/web2/domain/bookmark/entity/Remind.kt index 4d3e31a..0d13ecc 100644 --- a/src/main/kotlin/com/yapp/web2/domain/bookmark/entity/Remind.kt +++ b/src/main/kotlin/com/yapp/web2/domain/bookmark/entity/Remind.kt @@ -5,6 +5,12 @@ import java.time.LocalDate class Remind() { + var userId: Long = -1L + var remindTime: String = "" + var fcmToken: String = "" + var remindCheck: Boolean = false + var remindStatus: Boolean = false + constructor(userId: Long): this() { this.userId = userId } @@ -14,11 +20,6 @@ class Remind() { this.remindTime = LocalDate.now().plusDays(account.remindCycle.toLong()).toString() this.fcmToken = account.fcmToken!! } - var userId: Long = -1L - var remindTime: String = "" - var fcmToken: String = "" - var remindCheck: Boolean = false - var remindStatus: Boolean = false override fun equals(other: Any?): Boolean { if (this === other) return true @@ -34,4 +35,22 @@ class Remind() { override fun hashCode(): Int { return userId.hashCode() } + + override fun toString(): String { + return StringBuilder().append("Remind [") + .append("userId: $userId") + .append("remindTime: $remindTime") + .append("remindCheck: $remindCheck") + .append("remindStatus: $remindStatus") + .append("]") + .toString() + } + + fun updateRemindCheck() { + this.remindCheck = true + } + + fun successRemind() { + this.remindStatus = true + } } \ No newline at end of file diff --git a/src/main/kotlin/com/yapp/web2/domain/bookmark/repository/BookmarkRepository.kt b/src/main/kotlin/com/yapp/web2/domain/bookmark/repository/BookmarkRepository.kt index 32b75d9..36b9709 100644 --- a/src/main/kotlin/com/yapp/web2/domain/bookmark/repository/BookmarkRepository.kt +++ b/src/main/kotlin/com/yapp/web2/domain/bookmark/repository/BookmarkRepository.kt @@ -9,15 +9,13 @@ import org.springframework.stereotype.Repository import java.time.LocalDateTime @Repository -interface BookmarkRepository : MongoRepository { +interface BookmarkRepository : MongoRepository, MongoTemplateRepository { fun findBookmarkById(id: String): Bookmark? fun findAllByFolderId(folderId: Long): List fun findAllByFolderId(folderIdList: List): List - fun findAllByFolderIdAndDeleteTimeIsNullAndRemindTimeIsNotNull(folderId: Long, pageable: Pageable): Page - fun findAllByFolderIdAndDeletedIsFalse(folderId: Long, pageable: Pageable): Page fun findAllByUserIdAndDeletedIsTrue(userId: Long, pageable: Pageable): Page @@ -27,11 +25,8 @@ interface BookmarkRepository : MongoRepository { fun findByFolderId(id: Long): List - fun findAllByRemindTimeAndDeleteTimeIsNullAndRemindStatusIsFalse(remindTime: String): List - - fun findAllByUserId(userId: Long): List - - fun findAllByUserIdAndRemindCheckIsFalseAndRemindStatusIsTrueAndRemindTimeIsNotNull(userId: Long): List + @Query(value = "{remindList: {\$elemMatch: {remindTime: ?0}}}") + fun findAllBookmarkByRemindTime(today: String): List fun findAllByDeletedIsTrueAndDeleteTimeBefore(time: LocalDateTime): List @@ -45,8 +40,11 @@ interface BookmarkRepository : MongoRepository { fun findAllBookmark(userId: Long, folderIdList: List, pageable: Pageable): Page @Query(value = "{\$and: [{remindList: {\$elemMatch: {userId: ?0}}}, {remindList: {\$elemMatch: {remindTime: ?1}}}]}") - fun findTodayRemindBookmark(userId: Long, today: String): List + fun findAllTodayRemindBookmarksByUserId(userId: Long, today: String): List @Query(value = "{ 'remindList': { \$elemMatch: { 'userId' : ?0 } } }") fun findRemindBookmark(userId: Long, pageable: Pageable): Page + + @Query(value = "{ 'remindList': { \$elemMatch: { 'userId' : ?0 }}}") + fun findAllBookmarkByUserIdInRemindList(userId: Long): MutableList } \ No newline at end of file diff --git a/src/main/kotlin/com/yapp/web2/domain/bookmark/repository/BookmarkRepositoryImpl.kt b/src/main/kotlin/com/yapp/web2/domain/bookmark/repository/BookmarkRepositoryImpl.kt new file mode 100644 index 0000000..3442f86 --- /dev/null +++ b/src/main/kotlin/com/yapp/web2/domain/bookmark/repository/BookmarkRepositoryImpl.kt @@ -0,0 +1,41 @@ +package com.yapp.web2.domain.bookmark.repository + +import com.yapp.web2.domain.bookmark.entity.Bookmark +import org.springframework.data.mongodb.core.MongoTemplate +import org.springframework.data.mongodb.core.query.Criteria +import org.springframework.data.mongodb.core.query.Query + +class BookmarkRepositoryImpl( + private val mongoTemplate: MongoTemplate +) : MongoTemplateRepository { + + /** + * Bookmark의 remindList 내에서 userId 기준 아래 조건에 일치하는 북마크 리스트 조회 + * - 리마인드 발송된 상태(remindStatus = true) + * - 미확인 상태(remindCheck = false) + */ + override fun findAllBookmarkByUserIdAndRemindsInRemindList(userId: Long): List { + val query = Query() + + query.addCriteria( + Criteria.where("remindList").elemMatch( + Criteria.where("userId").`is`(userId) + .and("remindCheck").`is`(false) + .and("remindStatus").`is`(true) + ) + ) + setFieldsInclude(query) + + return mongoTemplate.find(query, Bookmark::class.java) + } + + /* 매핑할 컬럼 추가 */ + private fun setFieldsInclude(query: Query) { + query.fields().include("userId") + query.fields().include("folderId") + query.fields().include("link") + query.fields().include("remindList.$") + query.fields().include("title") + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/yapp/web2/domain/bookmark/repository/MongoTemplateRepository.kt b/src/main/kotlin/com/yapp/web2/domain/bookmark/repository/MongoTemplateRepository.kt new file mode 100644 index 0000000..545ad88 --- /dev/null +++ b/src/main/kotlin/com/yapp/web2/domain/bookmark/repository/MongoTemplateRepository.kt @@ -0,0 +1,9 @@ +package com.yapp.web2.domain.bookmark.repository + +import com.yapp.web2.domain.bookmark.entity.Bookmark + +interface MongoTemplateRepository { + + fun findAllBookmarkByUserIdAndRemindsInRemindList(userId: Long): List + +} \ No newline at end of file diff --git a/src/main/kotlin/com/yapp/web2/domain/bookmark/service/BookmarkPageService.kt b/src/main/kotlin/com/yapp/web2/domain/bookmark/service/BookmarkPageService.kt index ca607ec..a7ddf71 100644 --- a/src/main/kotlin/com/yapp/web2/domain/bookmark/service/BookmarkPageService.kt +++ b/src/main/kotlin/com/yapp/web2/domain/bookmark/service/BookmarkPageService.kt @@ -77,10 +77,11 @@ class BookmarkPageService( fun getTodayRemindBookmark(token: String): BookmarkDto.RemindList { val idFromToken = jwtProvider.getIdFromToken(token) + // TODO: todayRemind 조회인데 yesterday로 하는 이유? val yesterday = LocalDate.now().minusDays(1).toString() return BookmarkDto.RemindList( - bookmarkRepository.findTodayRemindBookmark(idFromToken, yesterday) + bookmarkRepository.findAllTodayRemindBookmarksByUserId(idFromToken, yesterday) ) } } \ No newline at end of file diff --git a/src/main/kotlin/com/yapp/web2/domain/bookmark/service/BookmarkService.kt b/src/main/kotlin/com/yapp/web2/domain/bookmark/service/BookmarkService.kt index 5a35424..b0fb856 100644 --- a/src/main/kotlin/com/yapp/web2/domain/bookmark/service/BookmarkService.kt +++ b/src/main/kotlin/com/yapp/web2/domain/bookmark/service/BookmarkService.kt @@ -12,6 +12,7 @@ import com.yapp.web2.exception.custom.FolderNotFoundException import com.yapp.web2.exception.custom.ObjectNotFoundException import com.yapp.web2.exception.custom.SameBookmarkException import com.yapp.web2.security.jwt.JwtProvider +import org.slf4j.LoggerFactory import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -26,6 +27,7 @@ class BookmarkService( companion object { private val bookmarkNotFoundException = BookmarkNotFoundException() + private val log = LoggerFactory.getLogger(BookmarkService::class.java) } fun addBookmark(token: String, folderId: Long?, bookmarkDto: BookmarkDto.AddBookmarkDto): Bookmark { @@ -97,20 +99,31 @@ class BookmarkService( fun toggleOnRemindBookmark(token: String, bookmarkId: String) { val account = jwtProvider.getAccountFromToken(token) - val bookmark = bookmarkRepository.findBookmarkById(bookmarkId) ?: throw BookmarkNotFoundException() val remind = Remind(account) - if(bookmark.isRemindExist(remind)) throw AlreadyExistRemindException() - bookmark.remindOn(remind) - bookmarkRepository.save(bookmark) + bookmarkRepository.findBookmarkById(bookmarkId)?.let { + if (it.isRemindExist(remind)) { + log.info("Remind already exist in bookmark => userId: ${account.id}, bookmarkId: $bookmarkId") + throw AlreadyExistRemindException() + } + it.remindOn(remind) + bookmarkRepository.save(it) + } ?: run { + log.error("Remind on failed. Bookmark not exist => userId: ${account.id}, bookmarkId: $bookmarkId") + throw BookmarkNotFoundException() + } } fun toggleOffRemindBookmark(token: String, bookmarkId: String) { val account = jwtProvider.getAccountFromToken(token) - val bookmark = bookmarkRepository.findBookmarkById(bookmarkId) ?: throw BookmarkNotFoundException() - bookmark.remindOff(account.id!!) - bookmarkRepository.save(bookmark) + bookmarkRepository.findBookmarkById(bookmarkId)?.let { + it.remindOff(account.id!!) + bookmarkRepository.save(it) + } ?: run { + log.error("Remind off failed. Bookmark not exist => userId: ${account.id}, bookmarkId: $bookmarkId") + throw BookmarkNotFoundException() + } } fun increaseBookmarkClickCount(bookmarkId: String): Bookmark { @@ -138,17 +151,16 @@ class BookmarkService( bookmarkRepository.saveAll(bookmarkList) } - fun restore(bookmarkIdList: MutableList?) { + fun restoreBookmarks(bookmarkIdList: MutableList?) { bookmarkIdList?.let { bookmarkIdList.forEach { - // TODO: 2021/12/02 Bookmark 예외처리 val restoreBookmark = bookmarkRepository.findByIdOrNull(it)?.restore() bookmarkRepository.save(restoreBookmark!!) } } } - fun permanentDelete(bookmarkIdList: MutableList?) { + fun deleteBookmarkPermanently(bookmarkIdList: MutableList?) { bookmarkIdList?.let { bookmarkIdList.forEach { val bookmark = bookmarkRepository.findByIdOrNull(it) diff --git a/src/main/kotlin/com/yapp/web2/domain/folder/entity/AccountFolder.kt b/src/main/kotlin/com/yapp/web2/domain/folder/entity/AccountFolder.kt index 23ea835..47d76a0 100644 --- a/src/main/kotlin/com/yapp/web2/domain/folder/entity/AccountFolder.kt +++ b/src/main/kotlin/com/yapp/web2/domain/folder/entity/AccountFolder.kt @@ -1,7 +1,15 @@ package com.yapp.web2.domain.folder.entity import com.yapp.web2.domain.account.entity.Account -import javax.persistence.* +import javax.persistence.Entity +import javax.persistence.EnumType +import javax.persistence.Enumerated +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne @Entity class AccountFolder( diff --git a/src/main/kotlin/com/yapp/web2/domain/remind/controller/RemindController.kt b/src/main/kotlin/com/yapp/web2/domain/remind/controller/RemindController.kt index a464268..a38e2e1 100644 --- a/src/main/kotlin/com/yapp/web2/domain/remind/controller/RemindController.kt +++ b/src/main/kotlin/com/yapp/web2/domain/remind/controller/RemindController.kt @@ -11,7 +11,14 @@ import io.swagger.annotations.ApiOperation import io.swagger.annotations.ApiParam import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.* +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PatchMapping +import org.springframework.web.bind.annotation.PathVariable +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 javax.servlet.http.HttpServletRequest @RestController @@ -39,15 +46,19 @@ class RemindController( ): ResponseEntity { val accessToken = ControllerUtil.extractAccessToken(servletRequest) remindService.updateRemindAlarmCycle(request, accessToken) + return ResponseEntity.status(HttpStatus.OK).body(Message.SUCCESS) } @ApiOperation(value = "리마인드 알림 삭제 API") @DeleteMapping("/remind/{bookmarkId}") fun bookmarkRemindOff( + servletRequest: HttpServletRequest, @PathVariable @ApiParam(value = "북마크 ID", required = true) bookmarkId: String ): ResponseEntity { - remindService.bookmarkRemindOff(bookmarkId) + val accessToken = ControllerUtil.extractAccessToken(servletRequest) + remindService.bookmarkRemindOff(accessToken, bookmarkId) + return ResponseEntity.status(HttpStatus.OK).body(Message.SUCCESS) } @@ -61,15 +72,12 @@ class RemindController( @ApiOperation(value = "리마인드 읽음 처리 API") @PostMapping("/remind") fun remindCheckUpdate( - @RequestBody @ApiParam(value = "리마인드 읽음으로 처리 할 북마크 ID 리스트", required = true) request: ReadRemindListRequest) - : ResponseEntity { - remindService.remindCheckUpdate(request) - return ResponseEntity.status(HttpStatus.OK).body(Message.SUCCESS) - } + servletRequest: HttpServletRequest, + @RequestBody @ApiParam(value = "리마인드 읽음으로 처리 할 북마크 ID 리스트", required = true) request: ReadRemindListRequest + ): ResponseEntity { + val accessToken = ControllerUtil.extractAccessToken(servletRequest) + remindService.remindCheckUpdate(accessToken, request) - @PostMapping("/temp") - fun temp() { - remindService.temp() + return ResponseEntity.status(HttpStatus.OK).body(Message.SUCCESS) } - } \ No newline at end of file diff --git a/src/main/kotlin/com/yapp/web2/domain/remind/service/RemindService.kt b/src/main/kotlin/com/yapp/web2/domain/remind/service/RemindService.kt index d321718..4b57afd 100644 --- a/src/main/kotlin/com/yapp/web2/domain/remind/service/RemindService.kt +++ b/src/main/kotlin/com/yapp/web2/domain/remind/service/RemindService.kt @@ -8,6 +8,7 @@ import com.yapp.web2.domain.remind.entity.dto.RemindCycleRequest import com.yapp.web2.domain.remind.entity.dto.RemindListResponse import com.yapp.web2.domain.remind.entity.dto.RemindListResponseWrapper import com.yapp.web2.domain.remind.entity.dto.RemindToggleRequest +import com.yapp.web2.exception.custom.AccountNotFoundException import com.yapp.web2.exception.custom.BookmarkNotFoundException import com.yapp.web2.infra.fcm.FirebaseService import com.yapp.web2.security.jwt.JwtProvider @@ -16,7 +17,6 @@ import com.yapp.web2.util.RemindCycleUtil import org.slf4j.LoggerFactory import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service -import org.springframework.transaction.annotation.Transactional import java.time.LocalDate import java.time.format.DateTimeFormatter @@ -33,47 +33,71 @@ class RemindService( private val log = LoggerFactory.getLogger(RemindService::class.java) } + /** + * 오늘자 기준으로 리마인드 발송 대상인 Bookmark List 조회 + */ fun getRemindBookmark(): List { val today = LocalDate.now().toString() - return bookmarkRepository.findAllByRemindTimeAndDeleteTimeIsNullAndRemindStatusIsFalse(today) + val remindBookmarkList: List = + bookmarkRepository.findAllBookmarkByRemindTime(today) + + // 리마인드 발송 시각이 오늘이 아닌 리마인드들은 제거 + remindBookmarkList.forEach { bookmark -> + bookmark.remindList.removeIf { remind -> + today != remind.remindTime + } + } + return remindBookmarkList } fun sendNotification(bookmark: Bookmark) { - val user = accountRepository.findAccountById(bookmark.userId) - - requireNotNull(user) { "Account does not exist" } - - val fcmToken: String = user.fcmToken ?: { - log.info("'${user.email}' account does not have a FCM-Token") - throw IllegalStateException("${user.email} 님은 FCM-Token이 존재하지 않습니다.") - }.toString() - - val response = firebaseService.sendMessage(fcmToken, Message.NOTIFICATION_MESSAGE, bookmark.title!!) - - log.info("Send notification to '${user.email}' succeed, Response => $response") + bookmark.remindList.forEach { remind -> + val response = firebaseService.sendMessage(remind.fcmToken, Message.NOTIFICATION_MESSAGE, bookmark.title!!) + log.info("Send notification [userId: ${remind.userId}] succeed, Response => $response") + } } - @Transactional + /** + * 프로필에서 리마인드 알람 받기 On & Off 설정 : 유저가 Off 할 경우 모든 리마인드가 삭제된다는 alert 띄어주는게 좋을 듯 함 + * request: 리마인드 알림 토글 On(true) / Off(false) 정보 + * On 일 경우: Account의 remindToggle 값만 true로 설정 + * Off 일 경우: + * 1. 유저가 Off할 Case는 별로 없을 듯 하나 로그를 남겨 사용자 분석 + * 2. Bookmark의 remindList 중 userId와 동일한 리마인드 전부 삭제 + * 3. Account의 remindToggle 값만 false로 설정 + */ + // TODO: 상용 서버에서 해당 메서드를 처리하는 로직이 느린듯한데 파악해볼 것 fun changeRemindToggle(request: RemindToggleRequest, accessToken: String) { val userId = jwtProvider.getIdFromToken(accessToken) - // 리마인드 알림을 Off 할 때, 모든 리마인드 주기 Null 처리 + // 1. logging + log.info("$userId 번 회원이 리마인드 알람 받기 설정을 ${request.remindToggle}로 변경하였습니다.") + if (isRemindOff(request.remindToggle)) { - bookmarkRepository.findAllByUserId(userId).let { - it.stream().forEach { bookmark -> - bookmark.remindOff() - bookmarkRepository.save(bookmark) + // 2. 해당 유저의 모든 Remind 삭제 + bookmarkRepository.findAllBookmarkByUserIdInRemindList(userId).forEach { bookmark -> + bookmark.remindList.removeIf { remind -> + userId == remind.userId } + bookmarkRepository.save(bookmark) } } - accountRepository.findByIdOrNull(userId)?.let { - it.remindToggle = request.remindToggle + + // 3. remindToggle 값 변경(true or false) + accountRepository.findAccountById(userId)?.let { + it.inverseRemindToggle(request.remindToggle) + accountRepository.save(it) + } ?: run { + log.info("$userId 에 해당하는 회원을 찾을 수 없습니다.") + throw AccountNotFoundException() } } private fun isRemindOff(remindToggle: Boolean) = !remindToggle - @Transactional + /** + * 프로필 -> 리마인드 주기 설정 + */ fun updateRemindAlarmCycle(request: RemindCycleRequest, accessToken: String) { RemindCycleUtil.validRemindCycle(request.remindCycle) @@ -83,48 +107,64 @@ class RemindService( } } - @Transactional - fun bookmarkRemindOff(bookmarkId: String) { + // TODO: bookmarkService.toggleOffRemindBookmark 메서드랑 동일한 로직인 듯 함, 프론트에서 어떠한 URI 사용하는지 확인필요 + fun bookmarkRemindOff(accessToken: String, bookmarkId: String) { + val accountId = jwtProvider.getIdFromToken(accessToken) + bookmarkRepository.findByIdOrNull(bookmarkId)?.let { - it.remindOff() + it.remindOff(accountId) bookmarkRepository.save(it) + } ?: run { + log.error("Remind off failed. Bookmark not exist => userId: ${accountId}, bookmarkId: $bookmarkId") + throw BookmarkNotFoundException() } + } + /** + * 도토리함 메인 화면에서 리마인드가 발송된 북마크 리스트 조회 + */ fun getRemindList(accessToken: String): RemindListResponseWrapper { val userId = jwtProvider.getIdFromToken(accessToken) + val bookmarks: List = bookmarkRepository.findAllBookmarkByUserIdAndRemindsInRemindList(userId) val responseWrapper = RemindListResponseWrapper() - val remindList = responseWrapper.contents - val bookmarks = - bookmarkRepository.findAllByUserIdAndRemindCheckIsFalseAndRemindStatusIsTrueAndRemindTimeIsNotNull(userId) - - bookmarks.stream() - .forEach { bookmark -> - val date = LocalDate.parse(bookmark.remindTime, DateTimeFormatter.ISO_DATE) // yyyy-MM-dd - val pushTime = date.atTime(13, 0, 0) - val remindResponse = RemindListResponse(bookmark.id, bookmark.title!!, pushTime!!) - remindList.add(remindResponse) - } + val contents = responseWrapper.contents + + bookmarks.forEach { bookmark -> + // bookmark의 remindList에서 userId는 중복되는 케이스가 없으므로 리마인드가 존재하면 반드시 1건만 존재 + val remind = bookmark.remindList[0] + val date = LocalDate.parse(remind.remindTime, DateTimeFormatter.ISO_DATE) + val pushTime = date.atTime(13, 0, 0) + contents.add(RemindListResponse(bookmark.id, bookmark.title!!, pushTime)) + } return responseWrapper } - fun remindCheckUpdate(request: ReadRemindListRequest) { - request.bookmarkIdList.stream() - .forEach { id -> - bookmarkRepository.findByIdOrNull(id)?.let { bookmark -> - bookmark.updateRemindCheck() - bookmarkRepository.save(bookmark) - } ?: bookmarkNotFoundException + /** + * 발송된 리마인드 중 사용자가 읽음 처리한 리마인드의 BookmarkId List + */ + fun remindCheckUpdate(accessToken: String, request: ReadRemindListRequest) { + val userId = jwtProvider.getIdFromToken(accessToken) + + // 1) bookmarkId에 해당하는 북마크 조회 + request.bookmarkIdList.stream().forEach { id -> + bookmarkRepository.findByIdOrNull(id)?.let { bookmark -> + // 2) bookmark 필드인 remindList 리스트에서 userId 동일한 remind 검색 후 update + bookmark.remindList.forEach { remind -> + if (remind.userId == userId) { + remind.updateRemindCheck() + bookmarkRepository.save(bookmark) + } + } + } ?: run { + log.info("Bookmark not exist => bookmarkId: $id") + throw bookmarkNotFoundException } + } } fun save(entity: Bookmark) { bookmarkRepository.save(entity) } - fun temp() { - val bookmark = bookmarkRepository.findBookmarkById("61d93b451af6fb65b4aa74b1") - bookmark?.remindCheck = false - bookmarkRepository.save(bookmark!!) - } } \ No newline at end of file diff --git a/src/main/kotlin/com/yapp/web2/util/ExceptionMessage.kt b/src/main/kotlin/com/yapp/web2/util/ExceptionMessage.kt index b4701e3..96b8bea 100644 --- a/src/main/kotlin/com/yapp/web2/util/ExceptionMessage.kt +++ b/src/main/kotlin/com/yapp/web2/util/ExceptionMessage.kt @@ -25,6 +25,6 @@ class ExceptionMessage { const val NOT_FOUND_EMAIL = "가입하신 이메일 주소를 찾을 수 없습니다." - const val ALREADY_EXIST_REMIND = "이미 리마인드되어 있습니다" + const val ALREADY_EXIST_REMIND = "이미 리마인드가 존재합니다." } } \ No newline at end of file diff --git a/src/test/kotlin/com/yapp/web2/domain/bookmark/repository/BookmarkRepositoryTest.kt b/src/test/kotlin/com/yapp/web2/domain/bookmark/repository/BookmarkRepositoryTest.kt index c4211ba..6c37dc6 100644 --- a/src/test/kotlin/com/yapp/web2/domain/bookmark/repository/BookmarkRepositoryTest.kt +++ b/src/test/kotlin/com/yapp/web2/domain/bookmark/repository/BookmarkRepositoryTest.kt @@ -2,13 +2,14 @@ package com.yapp.web2.domain.bookmark.repository import com.yapp.web2.domain.bookmark.entity.Bookmark import org.assertj.core.api.Assertions +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Sort -import org.junit.jupiter.api.Assertions.* @DataMongoTest internal open class BookmarkRepositoryTest { @@ -34,18 +35,6 @@ internal open class BookmarkRepositoryTest { for (page in bookmarkPages) assertEquals(1, page.folderId) } - - @Test - fun `폴더 아이디에 해당하는 북마크들 중 리마인드 시간이 설정된 북마크를 최신순으로 가져온다`() { - //when - val bookmarkPages = bookmarkRepository.findAllByFolderIdAndDeleteTimeIsNullAndRemindTimeIsNotNull(1, PageRequest.of(1, 5, Sort.by("saveTime").descending())) - - //then - for (page in bookmarkPages) { - assertEquals(1, page.folderId) - assertNotNull(page.remindTime) - } - } } @Nested diff --git a/src/test/kotlin/com/yapp/web2/domain/bookmark/service/BookmarkServiceTest.kt b/src/test/kotlin/com/yapp/web2/domain/bookmark/service/BookmarkServiceTest.kt index 8bf84e8..1c1d6df 100644 --- a/src/test/kotlin/com/yapp/web2/domain/bookmark/service/BookmarkServiceTest.kt +++ b/src/test/kotlin/com/yapp/web2/domain/bookmark/service/BookmarkServiceTest.kt @@ -303,7 +303,7 @@ internal open class BookmarkServiceTest { every { bookmarkRepository.save(any()) } returns bookmark1 // when - bookmarkService.restore(list) + bookmarkService.restoreBookmarks(list) // then assertAll( @@ -327,7 +327,7 @@ internal open class BookmarkServiceTest { every { bookmarkRepository.delete(any()) } just Runs // when - bookmarkService.permanentDelete(list) + bookmarkService.deleteBookmarkPermanently(list) // then verify(exactly = list.size) { bookmarkRepository.delete(any()) } diff --git a/src/test/kotlin/com/yapp/web2/domain/remind/service/RemindServiceTest.kt b/src/test/kotlin/com/yapp/web2/domain/remind/service/RemindServiceTest.kt index 3c35163..6e16e5c 100644 --- a/src/test/kotlin/com/yapp/web2/domain/remind/service/RemindServiceTest.kt +++ b/src/test/kotlin/com/yapp/web2/domain/remind/service/RemindServiceTest.kt @@ -1,141 +1,168 @@ -package com.yapp.web2.domain.remind.service - -import com.yapp.web2.domain.account.entity.Account -import com.yapp.web2.domain.account.repository.AccountRepository -import com.yapp.web2.domain.bookmark.entity.Bookmark -import com.yapp.web2.domain.bookmark.repository.BookmarkRepository -import com.yapp.web2.domain.remind.entity.dto.ReadRemindListRequest -import com.yapp.web2.domain.remind.entity.dto.RemindCycleRequest -import com.yapp.web2.domain.remind.entity.dto.RemindToggleRequest -import com.yapp.web2.exception.custom.RemindCycleValidException -import com.yapp.web2.infra.fcm.FirebaseService -import com.yapp.web2.security.jwt.JwtProvider -import com.yapp.web2.util.RemindCycleUtil -import io.mockk.every -import io.mockk.impl.annotations.InjectMockKs -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import io.mockk.verify -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertAll -import org.junit.jupiter.api.assertThrows -import org.junit.jupiter.api.extension.ExtendWith -import org.springframework.data.repository.findByIdOrNull - -@ExtendWith(MockKExtension::class) -internal class RemindServiceTest { - - @InjectMockKs - private lateinit var remindService: RemindService - - @MockK - private lateinit var bookmarkRepository: BookmarkRepository - - @MockK - private lateinit var accountRepository: AccountRepository - - @MockK - private lateinit var jwtProvider: JwtProvider - - @MockK - private lateinit var firebaseService: FirebaseService - - private lateinit var account: Account - private lateinit var bookmark1: Bookmark - private lateinit var bookmark2: Bookmark - private lateinit var bookmarkList: List - - @BeforeEach - fun setup() { - account = Account("test@gmail.com") - bookmark1 = Bookmark(1L, 2L, "https://www.naver.com") - bookmark2 = Bookmark(1L, 2L, "https://www.google.com") - bookmarkList = listOf(bookmark1, bookmark2) - } - - @Test - fun `리마인드 알람 설정을 OFF 한다`() { - // given - val request = RemindToggleRequest(false) - - // mock - every { bookmarkRepository.findAllByUserId(any()) } returns bookmarkList - every { bookmarkRepository.save(any()) } returns bookmark1 - every { accountRepository.findByIdOrNull(any()) } returns account - every { jwtProvider.getIdFromToken(any()) } returns 1L - - // when - remindService.changeRemindToggle(request, "token") - - // then - assertAll( - { assertThat(account.remindToggle).isEqualTo(false) }, - { bookmarkList.stream().forEach { - assertThat(it.remindTime).isNull() - } } - ) - } - - @Test - fun `리마인드 주기를 변경한다`() { - // given - val request1 = RemindCycleRequest(RemindCycleUtil.THIRTY_DAYS.days) - - // mock - every { accountRepository.findByIdOrNull(any()) } returns account - every { jwtProvider.getIdFromToken(any()) } returns 1L - - // when - remindService.updateRemindAlarmCycle(request1, "token") - - // then - assertThat(account.remindCycle).isEqualTo(30) - } - - @Test - fun `리마인드 주기가 3, 7, 14, 30일이 아니면 에러를 반환한다`() { - // given - val request1 = RemindCycleRequest(4) - val request2 = RemindCycleRequest(11) - - // mock - every { accountRepository.findByIdOrNull(any()) } returns account - every { jwtProvider.getIdFromToken(any()) } returns 1L - - // when & then - assertAll( - { assertThrows { remindService.updateRemindAlarmCycle(request1, "token") } }, - { assertThrows { remindService.updateRemindAlarmCycle(request2, "token") } } - ) - } - - @Test - fun `웹푸쉬 발송 후 Client가 확인하지 않은 리마인드 리스트를 조회한다`() { - - } - - @Test - fun `Client가 리마인드를 확인했다는 처리를 진행한다`() { - // given - val bookmarkIdList: MutableList = mutableListOf("61bdbbaa72b0f85372ad57c8", "16cdaa73j0f23785ad57c9") - val request = ReadRemindListRequest(bookmarkIdList) - - // mock - every { bookmarkRepository.findByIdOrNull("61bdbbaa72b0f85372ad57c8") } returns bookmark1 - every { bookmarkRepository.findByIdOrNull("16cdaa73j0f23785ad57c9") } returns bookmark2 - every { bookmarkRepository.save(any()) } returns bookmark1 - - // when - remindService.remindCheckUpdate(request) - - // then - assertAll( - { verify(exactly = bookmarkIdList.size) { bookmarkRepository.save(any()) } }, - { assertThat(bookmark1.remindCheck).isTrue() }, - { assertThat(bookmark2.remindCheck).isTrue() } - ) - - } -} \ No newline at end of file +//package com.yapp.web2.domain.remind.service +// +//import com.yapp.web2.domain.account.entity.Account +//import com.yapp.web2.domain.account.repository.AccountRepository +//import com.yapp.web2.domain.bookmark.entity.Bookmark +//import com.yapp.web2.domain.bookmark.entity.Remind +//import com.yapp.web2.domain.bookmark.repository.BookmarkRepository +//import com.yapp.web2.domain.remind.entity.dto.ReadRemindListRequest +//import com.yapp.web2.domain.remind.entity.dto.RemindCycleRequest +//import com.yapp.web2.domain.remind.entity.dto.RemindToggleRequest +//import com.yapp.web2.exception.custom.RemindCycleValidException +//import com.yapp.web2.infra.fcm.FirebaseService +//import com.yapp.web2.security.jwt.JwtProvider +//import com.yapp.web2.util.RemindCycleUtil +//import io.mockk.every +//import io.mockk.impl.annotations.InjectMockKs +//import io.mockk.impl.annotations.MockK +//import io.mockk.junit5.MockKExtension +//import io.mockk.verify +//import org.assertj.core.api.Assertions.assertThat +//import org.junit.jupiter.api.BeforeEach +//import org.junit.jupiter.api.Test +//import org.junit.jupiter.api.assertAll +//import org.junit.jupiter.api.assertThrows +//import org.junit.jupiter.api.extension.ExtendWith +//import org.springframework.data.repository.findByIdOrNull +//import java.time.LocalDate +// +//@ExtendWith(MockKExtension::class) +//internal class RemindServiceTest { +// +// @InjectMockKs +// private lateinit var remindService: RemindService +// +// @MockK +// private lateinit var bookmarkRepository: BookmarkRepository +// +// @MockK +// private lateinit var accountRepository: AccountRepository +// +// @MockK +// private lateinit var jwtProvider: JwtProvider +// +// @MockK +// private lateinit var firebaseService: FirebaseService +// +// private lateinit var account: Account +// private lateinit var bookmark1: Bookmark +// private lateinit var bookmark2: Bookmark +// private lateinit var bookmarkList: List +// +// @BeforeEach +// fun setup() { +// account = Account("test@gmail.com") +// bookmark1 = Bookmark(1L, 2L, "https://www.naver.com") +// bookmark2 = Bookmark(1L, 2L, "https://www.google.com") +// bookmarkList = listOf(bookmark1, bookmark2) +// } +// +// @Test +// fun `리마인드 알람 설정을 OFF 한다`() { +// // given +// val request = RemindToggleRequest(false) +// +// // mock +// every { bookmarkRepository.findAllByUserId(any()) } returns bookmarkList +// every { bookmarkRepository.save(any()) } returns bookmark1 +// every { accountRepository.findByIdOrNull(any()) } returns account +// every { jwtProvider.getIdFromToken(any()) } returns 1L +// +// // when +// remindService.changeRemindToggle(request, "token") +// +// // then +// assertAll( +// { assertThat(account.remindToggle).isEqualTo(false) }, +// { bookmarkList.stream().forEach { +// assertThat(it.remindTime).isNull() +// } } +// ) +// } +// +// @Test +// fun `리마인드 주기를 변경한다`() { +// // given +// val request1 = RemindCycleRequest(RemindCycleUtil.THIRTY_DAYS.days) +// +// // mock +// every { accountRepository.findByIdOrNull(any()) } returns account +// every { jwtProvider.getIdFromToken(any()) } returns 1L +// +// // when +// remindService.updateRemindAlarmCycle(request1, "token") +// +// // then +// assertThat(account.remindCycle).isEqualTo(30) +// } +// +// @Test +// fun `리마인드 주기가 3, 7, 14, 30일이 아니면 에러를 반환한다`() { +// // given +// val request1 = RemindCycleRequest(4) +// val request2 = RemindCycleRequest(11) +// +// // mock +// every { accountRepository.findByIdOrNull(any()) } returns account +// every { jwtProvider.getIdFromToken(any()) } returns 1L +// +// // when & then +// assertAll( +// { assertThrows { remindService.updateRemindAlarmCycle(request1, "token") } }, +// { assertThrows { remindService.updateRemindAlarmCycle(request2, "token") } } +// ) +// } +// +// @Test +// fun `웹푸쉬 발송 후 Client가 확인하지 않은 리마인드 리스트를 조회한다`() { +// +// } +// +// @Test +// fun `Client가 리마인드를 확인했다는 처리를 진행한다`() { +// // given +// val bookmarkIdList: MutableList = mutableListOf("61bdbbaa72b0f85372ad57c8", "16cdaa73j0f23785ad57c9") +// val request = ReadRemindListRequest(bookmarkIdList) +// +// // mock +// every { bookmarkRepository.findByIdOrNull("61bdbbaa72b0f85372ad57c8") } returns bookmark1 +// every { bookmarkRepository.findByIdOrNull("16cdaa73j0f23785ad57c9") } returns bookmark2 +// every { bookmarkRepository.save(any()) } returns bookmark1 +// +// // when +// remindService.remindCheckUpdate(request) +// +// // then +// assertAll( +// { verify(exactly = bookmarkIdList.size) { bookmarkRepository.save(any()) } }, +// { assertThat(bookmark1.remindCheck).isTrue() }, +// { assertThat(bookmark2.remindCheck).isTrue() } +// ) +// } +// +// @Test +// fun `리마인드 북마크 조회 시 발송 시각이 오늘이 아닌 리마인드들은 삭제한다`() { +// // given +// val reminds: MutableList = mutableListOf( +// Remind("2022-01-01"), +// Remind("2022-01-02"), +// Remind("2022-01-03"), +// Remind("2022-01-04"), +// Remind(LocalDate.now().toString()), +// ) +// val bookmark = Bookmark(1L, 1L, "test") +// bookmark.remindList = reminds +// val bookmarks: List = listOf(bookmark) +// +// every { bookmarkRepository.findAllTodayRemindBookmarks(any()) } returns bookmarks +// +// // when +// val actual: List = remindService.getRemindBookmark() +// +// // then +// assertAll( +// { assertThat(actual[0].remindList.size).isEqualTo(1) }, +// { assertThat(actual[0].remindList[0].remindTime).isEqualTo(LocalDate.now().toString()) } +// ) +// } +//} \ No newline at end of file