Skip to content

Commit

Permalink
[#176] fix(보관함 잠금/해제)
Browse files Browse the repository at this point in the history
- SharedType 구성 변경
- 보관함 잠금/해제 로직 변경
- ENUM 타입에 맞게 공유 링크 생성하도록 변경
- 링크를 통한 북마크 조회 변경
- 초대링크를 통한 공유보관함 초대 로직 변경
  • Loading branch information
Ji-Ha committed Sep 20, 2022
1 parent 66f7d22 commit 5e8948f
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.yapp.web2.domain.account.entity.AccountRequestDto
import com.yapp.web2.domain.account.repository.AccountRepository
import com.yapp.web2.domain.folder.entity.AccountFolder
import com.yapp.web2.domain.folder.entity.Authority
import com.yapp.web2.domain.folder.entity.SharedType
import com.yapp.web2.domain.folder.service.FolderService
import com.yapp.web2.exception.BusinessException
import com.yapp.web2.exception.custom.AlreadyInvitedException
Expand Down Expand Up @@ -197,10 +198,11 @@ class AccountService(
fun acceptInvitation(token: String, folderToken: String) {
val account = jwtProvider.getAccountFromToken(token)
val folderId = jwtProvider.getIdFromToken(folderToken)
val sharedType = jwtProvider.getSharedTypeFromToken(folderToken)
val rootFolder = folderService.findByFolderId(folderId)

if(sharedType != SharedType.EDIT) throw RuntimeException("초대 링크가 아닙니다.")
if (rootFolder.rootFolderId != folderId) throw FolderNotRootException()
if(!rootFolder.isInviteState()) throw RuntimeException("보관함이 초대잠금상태입니다. 가입할 수 없습니다.")

val accountFolder = AccountFolder(account, rootFolder)
accountFolder.changeAuthority(Authority.INVITEE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.yapp.web2.domain.bookmark.BookmarkDto
import com.yapp.web2.domain.bookmark.entity.Bookmark
import com.yapp.web2.domain.bookmark.repository.BookmarkRepository
import com.yapp.web2.domain.folder.entity.Folder
import com.yapp.web2.domain.folder.entity.SharedType
import com.yapp.web2.domain.folder.service.FolderService
import com.yapp.web2.security.jwt.JwtProvider
import org.springframework.data.domain.Page
Expand Down Expand Up @@ -36,8 +37,10 @@ class BookmarkPageService(

fun getAllPageByEncryptFolderId(token: String, pageable: Pageable): Page<Bookmark> {
val folderId = jwtProvider.getIdFromToken(token)
val sharedType = jwtProvider.getSharedTypeFromToken(token)
val folder = folderService.findByFolderId(folderId)
if(!folder.isOpenState()) throw RuntimeException("보관함이 조회잠금상태입니다. 조회할 수 없습니다!")

if(sharedType >= SharedType.CLOSED_EDIT) throw RuntimeException("보관함이 잠금상태입니다.")
return bookmarkRepository.findAllByFolderIdAndDeletedIsFalse(folderId, pageable)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class SharedBookmarkService(
val beforeFolder = folderRepository.findFolderById(beforeFolderId) ?: throw FolderNotFoundException()
val nextFolder = folderRepository.findFolderById(nextFolderId) ?: throw FolderNotFoundException()

if(!beforeFolder.isFolderSameRootFolder(nextFolder)) throw NotSameRootFolderException()
// if(!beforeFolder.isFolderSameRootFolder(nextFolder)) throw NotSameRootFolderException()
}

fun deleteBookmarkInfoAtFolder(bookmark: Bookmark) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.yapp.web2.domain.folder.controller
import com.yapp.web2.domain.account.AccountDto
import com.yapp.web2.domain.folder.FolderDto
import com.yapp.web2.domain.folder.entity.Folder
import com.yapp.web2.domain.folder.entity.SharedType

import com.yapp.web2.domain.folder.service.FolderService
import com.yapp.web2.util.ControllerUtil
Expand Down Expand Up @@ -112,23 +113,19 @@ class FolderController(
return ResponseEntity.status(HttpStatus.OK).body(folderService.findAllParentFolderList(folderId))
}

// TODO: 2022/06/22 유저 정보 확인
@ApiOperation(value = "폴더 토큰 발급 API")
@GetMapping("encrypt/{folderId}")
fun getEncryptFolderId(@PathVariable folderId: Long): ResponseEntity<FolderTokenDto> {
return ResponseEntity.status(HttpStatus.OK).body(folderService.encryptFolderId(folderId))
}

@ApiOperation(value = "초대를 위한 폴더 토큰 발급 API")
@GetMapping("invite/{folderId}")
fun getFolderInvitationToken(@PathVariable folderId: Long): ResponseEntity<FolderTokenDto> {
return ResponseEntity.status(HttpStatus.OK).body(folderService.createFolderInvitationToken(folderId))
@ApiOperation(value = "폴더 링크 생성 API")
@GetMapping("share/{folderId}")
fun getFolderLink(
@PathVariable folderId: Long,
@RequestParam sharedType: SharedType
): ResponseEntity<FolderTokenDto> {
return ResponseEntity.status(HttpStatus.OK).body(folderService.getFolderLink(folderId, sharedType))
}

@ApiOperation(value = "보관함 잠금/해제 API")
@GetMapping("state/{folderId}")
fun inverseFolderShare(@PathVariable folderId: Long): ResponseEntity<String> {
folderService.inverseSharedType(folderId)
@GetMapping("status/{folderId}")
fun changeFolderStatus(@PathVariable folderId: Long): ResponseEntity<String> {
folderService.inverseFolderStatus(folderId)
return ResponseEntity.status(HttpStatus.OK).body(Message.SUCCESS)
}

Expand All @@ -142,7 +139,7 @@ class FolderController(
@ApiOperation(value = "폴더의 이름 조회 API")
@GetMapping("name/{folderToken}")
fun getFolderName(@PathVariable @ApiParam(value = "폴더 ID", example = "2", required = true) folderToken: String)
: ResponseEntity<FolderDto.FolderInfoDto> {
: ResponseEntity<FolderDto.FolderInfoDto> {
return ResponseEntity.status(HttpStatus.OK).body(folderService.getFolderInfo(folderToken))
}
}
29 changes: 5 additions & 24 deletions src/main/kotlin/com/yapp/web2/domain/folder/entity/Folder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class Folder(

// 공유 상태 저장
@Enumerated(value = EnumType.STRING)
var sharedType: SharedType = SharedType.ALL_CLOSED
var sharedType: SharedType = SharedType.CLOSED_BLOCK_EDIT

var rootFolderId: Long? = null

Expand Down Expand Up @@ -182,36 +182,17 @@ class Folder(
}

fun isRootFolder(): Boolean {
if(parentFolder == null) return true
if (parentFolder == null) return true
return false
}

fun isFolderSameRootFolder(folder: Folder): Boolean {
if(folder.rootFolderId == this.rootFolderId) return true
return false
}

fun changeSharedTypeToOpen() {
if(this.sharedType == SharedType.INVITE) this.sharedType = SharedType.INVITE_AND_OPEN
else this.sharedType = SharedType.OPEN
}

fun changeSharedTypeToInvite() {
if(this.sharedType == SharedType.OPEN) this.sharedType = SharedType.INVITE_AND_OPEN
else this.sharedType = SharedType.INVITE
fun updateSharedType(sharedType: SharedType) {
this.sharedType = sharedType
}

fun inverseShareType() {
this.sharedType = this.sharedType.inversionState()
}

fun isInviteState(): Boolean {
if(this.sharedType == SharedType.INVITE || this.sharedType == SharedType.INVITE_AND_OPEN) return true
return false
}

fun isOpenState(): Boolean {
if(this.sharedType == SharedType.OPEN || this.sharedType == SharedType.INVITE_AND_OPEN) return true
return false
}
fun isSharedFolder(): Boolean = rootFolderId != null
}
28 changes: 9 additions & 19 deletions src/main/kotlin/com/yapp/web2/domain/folder/entity/SharedType.kt
Original file line number Diff line number Diff line change
@@ -1,36 +1,26 @@
package com.yapp.web2.domain.folder.entity

enum class SharedType {
INVITE {
EDIT {
override fun inversionState(): SharedType {
return CLOSED_INVITE
return CLOSED_EDIT
}
},
OPEN {
BLOCK_EDIT {
override fun inversionState(): SharedType {
return CLOSED_OPEN
return CLOSED_BLOCK_EDIT
}
},
INVITE_AND_OPEN {
CLOSED_EDIT {
override fun inversionState(): SharedType {
return ALL_CLOSED
return EDIT
}
},
CLOSED_INVITE {
CLOSED_BLOCK_EDIT {
override fun inversionState(): SharedType {
return INVITE
return BLOCK_EDIT
}
},
CLOSED_OPEN {
override fun inversionState(): SharedType {
return OPEN
}
},
ALL_CLOSED {
override fun inversionState(): SharedType {
return INVITE_AND_OPEN
}
};
} ;

abstract fun inversionState(): SharedType
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.yapp.web2.domain.folder.FolderDto
import com.yapp.web2.domain.folder.entity.AccountFolder
import com.yapp.web2.domain.folder.entity.Authority
import com.yapp.web2.domain.folder.entity.Folder
import com.yapp.web2.domain.folder.entity.SharedType
import com.yapp.web2.domain.folder.repository.FolderRepository
import com.yapp.web2.domain.folder.service.move.factory.FolderMoveFactory
import com.yapp.web2.domain.folder.service.move.inner.FolderMoveInnerStrategy
Expand Down Expand Up @@ -343,22 +344,26 @@ class FolderService(
return childList
}

fun createFolderInvitationToken(rootFolderId: Long): FolderTokenDto {
//그냥 재귀를 돌면서 Folder 리스트들을 다 받고, 그 후에 폴더들에 rootFolder 추가, 북마크 shared 변경 하면 되지 않을까? 굳이 재귀?
val folder = folderRepository.findFolderById(rootFolderId) ?: throw FolderNotFoundException()
if(!folder.isRootFolder()) throw RuntimeException("보관함이 아닙니다! 공유를 할 수 없습니다.")
fun inverseFolderStatus(folderId: Long) {
val folder = folderRepository.findFolderById(folderId) ?: throw FolderNotFoundException()
folder.inverseShareType()
}

// 폴더의 공유 상태 변경하기
folder.changeSharedTypeToInvite()
fun getFolderLink(folderId: Long, sharedType: SharedType): FolderTokenDto {
val folder = folderRepository.findFolderById(folderId) ?: throw FolderNotFoundException()
folder.updateSharedType(sharedType)

// 하위 폴더들 모두 rootFolderId 추가해주기
val sharedFolderIdList = changeFolderToShared(folder, rootFolderId)
// 사용자가 folder의 링크를 edit이 가능한 상태로 받으려고 할 때, folder가 공유 상태가 아니라면 공유로 바꾼다.
if (sharedType == SharedType.EDIT && !folder.isSharedFolder()) changeRootFolderToShared(folder, folderId)

// 하위 북마크들 모두 shared가 true인 상태로 변경해주기
changeBookmarkToShared(sharedFolderIdList)
return FolderTokenDto(jwtProvider.createFolderToken(folderId, sharedType))
}

private fun changeRootFolderToShared(folder: Folder, rootFolderId: Long) {
if (!folder.isRootFolder()) throw RuntimeException("보관함이 아닙니다! 공유를 할 수 없습니다.")

// 토큰 발급
return FolderTokenDto(jwtProvider.createFolderToken(rootFolderId))
val sharedFolderIdList = changeFolderToShared(folder, rootFolderId)
changeBookmarkToShared(sharedFolderIdList)
}

private fun changeBookmarkToShared(sharedFolderIdList: List<Long?>) {
Expand All @@ -382,19 +387,6 @@ class FolderService(
return folderIdList
}

fun encryptFolderId(folderId: Long): FolderTokenDto {
require(folderId > 0) { "folderId must be greater than zero" }

val folder = folderRepository.findFolderById(folderId) ?: throw FolderNotFoundException()
folder.changeSharedTypeToOpen()
return FolderTokenDto(jwtProvider.createFolderToken(folderId = folder.id!!))
}

fun inverseSharedType(folderId: Long) {
val folder = folderRepository.findFolderById(folderId) ?: throw FolderNotFoundException()
folder.inverseShareType()
}

fun getAccountListAtRootFolder(folderId: Long): AccountDto.FolderBelongAccountListDto {
require(folderId > 0) { "folderId must be greater than zero" }

Expand Down
29 changes: 21 additions & 8 deletions src/main/kotlin/com/yapp/web2/security/jwt/JwtProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import com.yapp.web2.exception.custom.NoRefreshTokenException
import com.yapp.web2.exception.custom.TokenMisMatchException
import com.yapp.web2.domain.account.entity.Account
import com.yapp.web2.domain.account.repository.AccountRepository
import com.yapp.web2.domain.folder.entity.SharedType
import com.yapp.web2.exception.custom.AccountNotFoundException
import io.jsonwebtoken.Claims
import io.jsonwebtoken.Jwt
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import org.springframework.beans.factory.annotation.Autowired
Expand Down Expand Up @@ -45,14 +47,6 @@ class JwtProvider(
return TokenDto(accessToken, refreshToken)
}

fun createFolderToken(folderId: Long): String {
return Jwts.builder()
.setSubject(folderId.toString())
.setIssuedAt(Date())
.signWith(SignatureAlgorithm.HS512, secretKey)
.compact()
}

fun reIssuedAccessToken(accessToken: String, refreshToken: String): TokenDto {
val refreshToken = removePrefix(refreshToken)
val idFromToken = getIdFromToken(refreshToken).toString()
Expand Down Expand Up @@ -97,6 +91,19 @@ class JwtProvider(
return refreshToken
}

fun createFolderToken(folderId: Long, sharedType: SharedType): String {
val claims = Jwts.claims()
claims.id = folderId.toString()
claims["sharedType"] = sharedType

return Jwts.builder()
.setSubject(folderId.toString())
.claim("sharedType", sharedType)
.setIssuedAt(Date())
.signWith(SignatureAlgorithm.HS512, secretKey)
.compact()
}

private fun saveRefreshToken(compact: String, id: String) {
redisTemplate.opsForValue().set(id, compact, redisExpiration, TimeUnit.DAYS)
}
Expand All @@ -112,6 +119,12 @@ class JwtProvider(
return getClaimFromToken(token) { obj: Claims -> obj.expiration }
}

fun getSharedTypeFromToken(token: String): SharedType {
val sharedType = getClaimFromToken(token) { obj -> obj["sharedType"] }

return SharedType.valueOf(sharedType.toString())
}

fun getAccountFromToken(token: String): Account {
val idFromToken = getIdFromToken(token)
return when(val account = accountRepository.findAccountById(idFromToken)) {
Expand Down

0 comments on commit 5e8948f

Please sign in to comment.