Skip to content

Commit

Permalink
Merge branch 'feature/#168-공유_관련_수정' of https://github.com/YAPP-19th/…
Browse files Browse the repository at this point in the history
…Web-Team-2-Backend into feature/#176-공유_보관함_잠금_기능
  • Loading branch information
Ji-Ha committed Aug 16, 2022
2 parents e508844 + 0a580de commit b737e04
Show file tree
Hide file tree
Showing 41 changed files with 831 additions and 917 deletions.
1 change: 1 addition & 0 deletions Dockerfile-dev
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
FROM openjdk:11-jdk-slim
EXPOSE 8080
ARG JAR_FILE=/build/libs/Web-Team-2-Backend-0.0.1-SNAPSHOT.jar
VOLUME ["/var/log"]
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","-Dspring.profiles.active=dev","/app.jar"]
1 change: 1 addition & 0 deletions Dockerfile-prod
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
FROM openjdk:14-jdk-slim
EXPOSE 8080
ARG JAR_FILE=/build/libs/Web-Team-2-Backend-0.0.1-SNAPSHOT.jar
VOLUME ["/var/log"]
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","-Dspring.profiles.active=prod","/app.jar"]
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
<br>

## API 문서
- http://3.39.95.212:8080/swagger-ui/index.html#/

<br>

Expand Down
30 changes: 28 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,34 @@ sourceSets {
srcDirs(listOf("src/main/resources", "src/main/resources/profiles"))
}
}

create("intTest") {
compileClasspath += sourceSets.main.get().output
runtimeClasspath += sourceSets.main.get().output
}
}

// https://docs.gradle.org/current/userguide/java_testing.html#sec:configuring_java_integration_tests
val intTestImplementation by configurations.getting {
// all the declared dependencies of the production code also become dependencies of the integration tests
extendsFrom(configurations.implementation.get())
}

configurations["intTestRuntimeOnly"].extendsFrom(configurations.runtimeOnly.get())
configurations["intTestImplementation"].extendsFrom(configurations.testImplementation.get())

val integrationTest = task<Test>("integrationTest") {
description = "Runs integration tests."
group = "verification"

testClassesDirs = sourceSets["intTest"].output.classesDirs
classpath = sourceSets["intTest"].runtimeClasspath
shouldRunAfter("test")
}

// execute integrationTest after test
tasks.test { dependsOn(integrationTest) }

jacoco {
toolVersion = "0.8.7"
}
Expand Down Expand Up @@ -131,8 +157,8 @@ tasks.jacocoTestCoverageVerification {
// 측정한 커버리지를 어떠한 방식으로 보여줄 것인지 설정, Default: "COVEREDRATIO"
value = "COVEREDRATIO" // 커버된 비율(0 ~ 1)

// 테스트 커버리지 최솟값(0.80 -> 80%)
minimum = "0.80".toBigDecimal()
// // 테스트 커버리지 최솟값(0.80 -> 80%)
// minimum = "0.80".toBigDecimal()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
@AutoConfigureMockMvc(addFilters = false)
@TestPropertySource(properties = ["extension.version=4.0.3"])
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class AccountControllerTest: AbstractControllerTest() {
class AccountControllerTest : AbstractControllerTest() {

@Test
fun `현재 회원의 프로필을 조회한다`() {
Expand Down Expand Up @@ -97,7 +97,7 @@ class AccountControllerTest: AbstractControllerTest() {
fun `토큰을 재발급 한다`() {
// given
val tokenDto = TokenDto("Re-AccessToken", "Re-RefreshToken")
every { accountService.reIssuedAccessToken(any(), any()) } returns tokenDto
every { accountService.reIssuedAccessToken(any(), any()) } returns tokenDto // slow?

// when
val resultAction = util.getResultAction("/api/v1/user/reIssuanceAccessToken", mockMvc)
Expand Down Expand Up @@ -172,7 +172,6 @@ class AccountControllerTest: AbstractControllerTest() {
fun `현재 회원의 익스텐션 버전을 조회한다`() {
// given
every { accountService.checkExtension(any()) } returns extensionVersion
println("exten: $extensionVersion")

// when
val resultAction = util.getResultAction("/api/v1/user/$extensionVersion", mockMvc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
@AutoConfigureMockMvc(addFilters = false)
@TestPropertySource(properties = ["extension.version=4.0.3"])
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
internal class FolderControllerTest: AbstractControllerTest() {
internal class FolderControllerTest : AbstractControllerTest() {

@Test
fun `폴더를 생성한다`() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,20 @@ class AccountController(
return ResponseEntity.status(HttpStatus.OK).body(accountService.checkExtension(extensionVersion))
}

@ApiOperation(value = "폴더 토큰을 통하여 공유 폴더에 초대받는 API")
@GetMapping("/invite/{folderToken}")
fun acceptInvitation(request: HttpServletRequest, @PathVariable folderToken: String): ResponseEntity<String> {
fun acceptInvitation(request: HttpServletRequest, @ApiParam(value = "폴더 토큰") @PathVariable folderToken: String): ResponseEntity<String> {
val token = ControllerUtil.extractAccessToken(request)
accountService.acceptInvitation(token, folderToken)
return ResponseEntity.status(HttpStatus.OK).body("good")
return ResponseEntity.status(HttpStatus.OK).body(Message.SUCCESS)
}

@ApiOperation(value = "folderId를 통하여 공유 폴더에서 나가는 API")
@GetMapping("/exit/{folderId}")
fun exitSharedFolder(request: HttpServletRequest, @ApiParam(value = "폴더 아이디") @PathVariable folderId: Long): ResponseEntity<String> {
val token = ControllerUtil.extractAccessToken(request)
accountService.exitSharedFolder(folderId, token)
return ResponseEntity.status(HttpStatus.OK).body(Message.SUCCESS)
}

@ApiOperation("회원가입 API")
Expand Down
69 changes: 35 additions & 34 deletions src/main/kotlin/com/yapp/web2/domain/account/entity/Account.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.yapp.web2.domain.account.entity

import com.yapp.web2.domain.BaseTimeEntity
import com.yapp.web2.domain.folder.entity.AccountFolder
import com.yapp.web2.domain.folder.entity.Folder
import com.yapp.web2.security.jwt.TokenDto
import io.swagger.annotations.ApiModel
import io.swagger.annotations.ApiModelProperty
Expand Down Expand Up @@ -42,34 +43,6 @@ class Account(
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
}

constructor(email: String, encryptPassword: String, fcmToken: String, name: String) : this(email) {
this.password = encryptPassword
this.fcmToken = fcmToken
this.name = name
}

constructor(email: String, image: String, nickname: String, socialType: String, fcmToken: String) : this(email) {
this.image = image
this.name = nickname
this.socialType = socialType
this.fcmToken = fcmToken
}

fun addAccountFolder(accountFolder: AccountFolder) {
this.accountFolderList.add(accountFolder)
}

@Transactional
fun isInsideAccountFolder(accountFolder: AccountFolder): Boolean {
accountFolderList.forEach {
if (it.folder.id == accountFolder.folder.id) return true
}
return false
}

@Column(nullable = true)
var password: String? = null
Expand Down Expand Up @@ -98,9 +71,38 @@ class Account(
@Column
var deleted: Boolean = false

@OneToMany(mappedBy = "account")
@OneToMany(mappedBy = "account", cascade = [CascadeType.ALL], orphanRemoval = true)
var accountFolderList: MutableList<AccountFolder> = mutableListOf()

constructor(email: String, password: String) : this(email) {
this.password = password
}

constructor(email: String, encryptPassword: String, fcmToken: String, name: String) : this(email) {
this.password = encryptPassword
this.fcmToken = fcmToken
this.name = name
}

constructor(email: String, image: String, nickname: String, socialType: String, fcmToken: String) : this(email) {
this.image = image
this.name = nickname
this.socialType = socialType
this.fcmToken = fcmToken
}

fun addAccountFolder(accountFolder: AccountFolder) {
this.accountFolderList.add(accountFolder)
}

@Transactional
fun isInsideAccountFolder(accountFolder: AccountFolder): Boolean {
accountFolderList.forEach {
if (it.folder.id == accountFolder.folder.id) return true
}
return false
}

@ApiModel(description = "소셜로그인 DTO")
class AccountProfile(
@ApiModelProperty(value = "이메일", required = true, example = "[email protected]")
Expand Down Expand Up @@ -166,11 +168,10 @@ class Account(
val nickName: String
)

fun hasAccountFolder(accountFolder: AccountFolder): Boolean {
for (af in this.accountFolderList)
if (accountFolder == af) return true

return false
fun removeFolderInAccountFolder(folder: Folder) {
this.accountFolderList.let {
it.removeIf { af -> af.folder == folder }
}
}

fun softDeleteAccount() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class AccountRequestDto {

@ApiModelProperty(value = "비밀번호", required = true, example = "!1234567")
@field: NotBlank(message = "비밀번호를 입력해주세요")
// @field: CustomPassword
@field: CustomPassword
val password: String,

@ApiModelProperty(value = "FCM 토큰", required = true, example = "dOOUnnp-iBs:APA91bF1i7mobIF7kEhi3aVlFuv6A5--P1S...")
Expand All @@ -41,7 +41,7 @@ class AccountRequestDto {
val email: String,

@ApiModelProperty(value = "비밀번호", required = true, example = "!1234567")
// @field: CustomPassword
@field: CustomPassword
val password: String
)

Expand All @@ -56,12 +56,12 @@ class AccountRequestDto {
class PasswordChangeRequest(
@ApiModelProperty(value = "기존 비밀번호", required = true, example = "1234567!")
@field: NotBlank(message = "기존 비밀번호를 입력해주세요")
// @field: CustomPassword
@field: CustomPassword
val currentPassword: String,

@ApiModelProperty(value = "새 비밀번호", required = true, example = "12345678!")
@field: NotBlank(message = "새 비밀번호를 입력해주세요")
// @field: CustomPassword
@field: CustomPassword
val newPassword: String
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
package com.yapp.web2.domain.account.service

import com.yapp.web2.config.S3Uploader
import com.yapp.web2.domain.account.entity.Account
import com.yapp.web2.domain.account.entity.AccountRequestDto
import com.yapp.web2.domain.account.repository.AccountRepository
import com.yapp.web2.security.jwt.JwtProvider
import com.yapp.web2.security.jwt.TokenDto
import com.yapp.web2.config.S3Uploader
import com.yapp.web2.domain.folder.entity.AccountFolder
import com.yapp.web2.domain.folder.entity.Authority
import com.yapp.web2.domain.account.entity.AccountRequestDto
import com.yapp.web2.domain.folder.service.FolderService
import com.yapp.web2.exception.BusinessException
import com.yapp.web2.exception.custom.AlreadyInvitedException
import com.yapp.web2.exception.custom.EmailNotFoundException
import com.yapp.web2.exception.custom.ExistNameException
import com.yapp.web2.exception.custom.FolderNotRootException
import com.yapp.web2.exception.custom.ImageNotFoundException
import com.yapp.web2.util.AES256Util
import com.yapp.web2.exception.custom.PasswordMismatchException
import com.yapp.web2.security.jwt.JwtProvider
import com.yapp.web2.security.jwt.TokenDto
import com.yapp.web2.util.Message
import org.apache.commons.lang3.RandomStringUtils
import org.slf4j.LoggerFactory
Expand All @@ -26,7 +25,6 @@ import org.springframework.mail.javamail.JavaMailSender
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Service
import org.springframework.web.multipart.MultipartFile
import java.lang.IllegalStateException
import javax.transaction.Transactional

@Service
Expand All @@ -35,7 +33,6 @@ class AccountService(
private val folderService: FolderService,
private val accountRepository: AccountRepository,
private val jwtProvider: JwtProvider,
private val aes256Util: AES256Util,
private val s3Uploader: S3Uploader,
private val passwordEncoder: PasswordEncoder,
private val mailSender: JavaMailSender
Expand Down Expand Up @@ -195,30 +192,46 @@ class AccountService(
@Transactional
fun acceptInvitation(token: String, folderToken: String) {
val account = jwtProvider.getAccountFromToken(token)
val folderId = aes256Util.decrypt(folderToken).toLong()
val folderId = jwtProvider.getIdFromToken(folderToken)
val rootFolder = folderService.findByFolderId(folderId)

if(rootFolder.rootFolderId != null) throw FolderNotRootException()
if (rootFolder.rootFolderId != folderId) throw FolderNotRootException()

val accountFolder = AccountFolder(account, rootFolder)
accountFolder.changeAuthority(Authority.INVITEE)
// account에 굳이 추가하지 않아도 account-folder에 추가가 된다.
// 왜???
if(account.isInsideAccountFolder(accountFolder)) throw AlreadyInvitedException()
if (account.isInsideAccountFolder(accountFolder)) throw AlreadyInvitedException()
// account.addAccountFolder(accountFolder)
rootFolder.folders?.add(accountFolder)
}

@Transactional
fun exitSharedFolder(folderId: Long, token: String) {
val account = jwtProvider.getAccountFromToken(token)
val folder = folderService.findByFolderId(folderId)
var exitFolder = folder.rootFolderId?.let {
folderService.findByFolderId(it)
} ?: folder

exitFolder.folders?.let {
it.removeIf { x -> x.account == account }
}

account.removeFolderInAccountFolder(exitFolder)
}

fun signIn(request: AccountRequestDto.SignInRequest): Account.AccountLoginSuccess? {
val account = accountRepository.findByEmail(request.email) ?: throw IllegalStateException(Message.NOT_EXIST_EMAIL)
val account =
accountRepository.findByEmail(request.email) ?: throw IllegalStateException(Message.NOT_EXIST_EMAIL)

if (!passwordEncoder.matches(request.password, account.password)) {
throw IllegalStateException(Message.USER_PASSWORD_MISMATCH)
}

log.info("base login => ${account.email} succeed")

return Account.AccountLoginSuccess(jwtProvider.createToken(account), account, false)
return Account.AccountLoginSuccess(jwtProvider.createToken(account), account, true)
}

fun comparePassword(token: String, dto: AccountRequestDto.CurrentPassword): String {
Expand Down Expand Up @@ -254,7 +267,7 @@ class AccountService(
return Message.SUCCESS_EXIST_EMAIL
}

internal fun createTempPassword(): String {
fun createTempPassword(): String {
return RandomStringUtils.randomAlphanumeric(12) + "!"
}

Expand Down
Loading

0 comments on commit b737e04

Please sign in to comment.