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..e0cbbeb 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 @@ -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 @@ -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) 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..4ee7306 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 @@ -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 @@ -36,8 +37,10 @@ class BookmarkPageService( fun getAllPageByEncryptFolderId(token: String, pageable: Pageable): Page { 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) } diff --git a/src/main/kotlin/com/yapp/web2/domain/bookmark/service/SharedBookmarkService.kt b/src/main/kotlin/com/yapp/web2/domain/bookmark/service/SharedBookmarkService.kt index 1b62e29..f391322 100644 --- a/src/main/kotlin/com/yapp/web2/domain/bookmark/service/SharedBookmarkService.kt +++ b/src/main/kotlin/com/yapp/web2/domain/bookmark/service/SharedBookmarkService.kt @@ -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) { diff --git a/src/main/kotlin/com/yapp/web2/domain/folder/controller/FolderController.kt b/src/main/kotlin/com/yapp/web2/domain/folder/controller/FolderController.kt index f35bc37..5e58e64 100644 --- a/src/main/kotlin/com/yapp/web2/domain/folder/controller/FolderController.kt +++ b/src/main/kotlin/com/yapp/web2/domain/folder/controller/FolderController.kt @@ -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 @@ -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 { - return ResponseEntity.status(HttpStatus.OK).body(folderService.encryptFolderId(folderId)) - } - - @ApiOperation(value = "초대를 위한 폴더 토큰 발급 API") - @GetMapping("invite/{folderId}") - fun getFolderInvitationToken(@PathVariable folderId: Long): ResponseEntity { - return ResponseEntity.status(HttpStatus.OK).body(folderService.createFolderInvitationToken(folderId)) + @ApiOperation(value = "폴더 링크 생성 API") + @GetMapping("share/{folderId}") + fun getFolderLink( + @PathVariable folderId: Long, + @RequestParam sharedType: SharedType + ): ResponseEntity { + return ResponseEntity.status(HttpStatus.OK).body(folderService.getFolderLink(folderId, sharedType)) } @ApiOperation(value = "보관함 잠금/해제 API") - @GetMapping("state/{folderId}") - fun inverseFolderShare(@PathVariable folderId: Long): ResponseEntity { - folderService.inverseSharedType(folderId) + @GetMapping("status/{folderId}") + fun changeFolderStatus(@PathVariable folderId: Long): ResponseEntity { + folderService.inverseFolderStatus(folderId) return ResponseEntity.status(HttpStatus.OK).body(Message.SUCCESS) } @@ -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 { + : ResponseEntity { return ResponseEntity.status(HttpStatus.OK).body(folderService.getFolderInfo(folderToken)) } } \ No newline at end of file diff --git a/src/main/kotlin/com/yapp/web2/domain/folder/entity/Folder.kt b/src/main/kotlin/com/yapp/web2/domain/folder/entity/Folder.kt index 0a886e0..416c450 100644 --- a/src/main/kotlin/com/yapp/web2/domain/folder/entity/Folder.kt +++ b/src/main/kotlin/com/yapp/web2/domain/folder/entity/Folder.kt @@ -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 @@ -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 } \ No newline at end of file diff --git a/src/main/kotlin/com/yapp/web2/domain/folder/entity/SharedType.kt b/src/main/kotlin/com/yapp/web2/domain/folder/entity/SharedType.kt index b129ae6..87a7c32 100644 --- a/src/main/kotlin/com/yapp/web2/domain/folder/entity/SharedType.kt +++ b/src/main/kotlin/com/yapp/web2/domain/folder/entity/SharedType.kt @@ -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 } \ No newline at end of file diff --git a/src/main/kotlin/com/yapp/web2/domain/folder/service/FolderService.kt b/src/main/kotlin/com/yapp/web2/domain/folder/service/FolderService.kt index 0650702..ae029c6 100644 --- a/src/main/kotlin/com/yapp/web2/domain/folder/service/FolderService.kt +++ b/src/main/kotlin/com/yapp/web2/domain/folder/service/FolderService.kt @@ -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 @@ -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) { @@ -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" } diff --git a/src/main/kotlin/com/yapp/web2/security/jwt/JwtProvider.kt b/src/main/kotlin/com/yapp/web2/security/jwt/JwtProvider.kt index 84f66a5..b3cf584 100644 --- a/src/main/kotlin/com/yapp/web2/security/jwt/JwtProvider.kt +++ b/src/main/kotlin/com/yapp/web2/security/jwt/JwtProvider.kt @@ -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 @@ -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() @@ -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) } @@ -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)) {