-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- 친구관리 기능 작업
- Loading branch information
Showing
17 changed files
with
503 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
src/main/kotlin/com/nexters/pimo/follow/adapter/in/web/FollowHandler.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package com.nexters.pimo.follow.adapter.`in`.web | ||
|
||
import com.nexters.pimo.common.constants.CommCode | ||
import com.nexters.pimo.common.dto.BaseResponse | ||
import com.nexters.pimo.common.exception.BadRequestException | ||
import com.nexters.pimo.common.filter.userId | ||
import com.nexters.pimo.follow.adapter.`in`.web.dto.RegisterInput | ||
import com.nexters.pimo.follow.application.dto.FollowAccountDto | ||
import com.nexters.pimo.follow.application.dto.FollowCntDto | ||
import com.nexters.pimo.follow.application.port.`in`.DeleteUseCase | ||
import com.nexters.pimo.follow.application.port.`in`.FindUseCase | ||
import com.nexters.pimo.follow.application.port.`in`.RegisterUseCase | ||
import org.springframework.stereotype.Component | ||
import org.springframework.web.reactive.function.server.ServerRequest | ||
import org.springframework.web.reactive.function.server.ServerResponse | ||
import reactor.core.publisher.Mono | ||
|
||
/** | ||
* @author yoonho | ||
* @since 2023.02.16 | ||
*/ | ||
@Component | ||
class FollowHandler( | ||
private val registerUseCase: RegisterUseCase, | ||
private val findUseCase: FindUseCase, | ||
private val deleteUseCase: DeleteUseCase | ||
) { | ||
/** | ||
* 친구 등록 | ||
* | ||
* @param userId [String] | ||
* @return boolean [Boolean] | ||
* @author yoonho | ||
* @since 2023.02.18 | ||
*/ | ||
fun register(request: ServerRequest): Mono<ServerResponse> = | ||
request.bodyToMono(RegisterInput::class.java) | ||
.flatMap { registerUseCase.register(it.userId, request.userId()) } | ||
.flatMap { BaseResponse().success(it) } | ||
|
||
/** | ||
* 친구 취소 | ||
* | ||
* @param userId [String] | ||
* @return boolean [Boolean] | ||
* @author yoonho | ||
* @since 2023.02.18 | ||
*/ | ||
fun delete(request: ServerRequest): Mono<ServerResponse> = | ||
request.bodyToMono(RegisterInput::class.java) | ||
.flatMap { deleteUseCase.delete(it.userId, request.userId()) } | ||
.flatMap { BaseResponse().success(it) } | ||
|
||
/** | ||
* 친구 목록수 조회 | ||
* | ||
* @return List [FollowCntDto] | ||
* @author yoonho | ||
* @since 2023.02.18 | ||
*/ | ||
fun count(request: ServerRequest): Mono<ServerResponse> = | ||
findUseCase.count(request.userId()) | ||
.flatMap { BaseResponse().success(it) } | ||
|
||
/** | ||
* 친구목록 계정정보 조회 | ||
* <pre> | ||
* 1. path Variable | ||
* - follower: 나만 친구추가한 친구목록 조회 | ||
* - followee: 상대방만 나를 친구추가한 친구목록 조회 | ||
* - followforfollow: 맞팔한 친구목록 조회 | ||
* 2. sort | ||
* - 0: 최근 친구추가한 순서 | ||
* - 1: 닉네임 가나다순 | ||
* 3. paging | ||
* - start: 시작Index | ||
* - size: 해당 페이지에서 조회할 갯수 | ||
* | ||
* @param sort [String] | ||
* @param start [String] | ||
* @param size [String] | ||
* @return List [FollowAccountDto] | ||
* @author yoonho | ||
* @since 2023.02.18 | ||
*/ | ||
fun list(request: ServerRequest): Mono<ServerResponse> = | ||
when(request.pathVariable("target")) { | ||
"follower" -> { | ||
findUseCase.follower( | ||
request.userId(), | ||
request.queryParam("sort").orElse(CommCode.DEFAULT_SORT_OPTION), | ||
request.queryParam("start").orElse(CommCode.DEFAULT_PAGING_START).toInt(), | ||
request.queryParam("size").orElse(CommCode.DEFAULT_PAGING_SIZE).toInt() | ||
) | ||
} | ||
"followee" -> { | ||
findUseCase.followee( | ||
request.userId(), | ||
request.queryParam("sort").orElse(CommCode.DEFAULT_SORT_OPTION), | ||
request.queryParam("start").orElse(CommCode.DEFAULT_PAGING_START).toInt(), | ||
request.queryParam("size").orElse(CommCode.DEFAULT_PAGING_SIZE).toInt() | ||
) | ||
} | ||
"followforfollow" -> { | ||
findUseCase.followForFollow( | ||
request.userId(), | ||
request.queryParam("sort").orElse(CommCode.DEFAULT_SORT_OPTION), | ||
request.queryParam("start").orElse(CommCode.DEFAULT_PAGING_START).toInt(), | ||
request.queryParam("size").orElse(CommCode.DEFAULT_PAGING_SIZE).toInt() | ||
) | ||
} | ||
else -> throw BadRequestException("유효한 경로가 아닙니다.") | ||
} | ||
.collectList() | ||
.flatMap { BaseResponse().success(it) } | ||
} |
29 changes: 29 additions & 0 deletions
29
src/main/kotlin/com/nexters/pimo/follow/adapter/in/web/FollowRouter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.nexters.pimo.follow.adapter.`in`.web | ||
|
||
import org.springframework.context.annotation.Bean | ||
import org.springframework.context.annotation.Configuration | ||
import org.springframework.http.MediaType | ||
import org.springframework.web.reactive.function.server.RouterFunction | ||
import org.springframework.web.reactive.function.server.ServerResponse | ||
import org.springframework.web.reactive.function.server.router | ||
|
||
/** | ||
* @author yoonho | ||
* @since 2023.02.15 | ||
*/ | ||
@Configuration | ||
class FollowRouter( | ||
private val followHandler: FollowHandler | ||
) { | ||
|
||
@Bean | ||
fun followRouterFunction(): RouterFunction<ServerResponse> = | ||
router { | ||
accept(MediaType.APPLICATION_JSON).nest { | ||
POST("/follows", followHandler::register) | ||
DELETE("/follows", followHandler::delete) | ||
GET("/follows/count", followHandler::count) | ||
GET("/follows/{target}", followHandler::list) | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/main/kotlin/com/nexters/pimo/follow/adapter/in/web/dto/RegisterInput.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.nexters.pimo.follow.adapter.`in`.web.dto | ||
|
||
import java.io.Serializable | ||
|
||
/** | ||
* @author yoonho | ||
* @since 2023.02.16 | ||
*/ | ||
data class RegisterInput( | ||
val userId: String | ||
): Serializable |
132 changes: 132 additions & 0 deletions
132
src/main/kotlin/com/nexters/pimo/follow/adapter/out/persistence/FollowPersistenceAdapter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package com.nexters.pimo.follow.adapter.out.persistence | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import com.nexters.pimo.account.adapter.out.persistence.AccountRepository | ||
import com.nexters.pimo.common.exception.BadRequestException | ||
import com.nexters.pimo.follow.application.dto.FollowAccountDto | ||
import com.nexters.pimo.follow.application.dto.FollowCntDto | ||
import com.nexters.pimo.follow.application.port.out.FindPort | ||
import com.nexters.pimo.follow.application.port.out.SavePort | ||
import com.nexters.pimo.follow.domain.Follow | ||
import org.springframework.data.domain.PageRequest | ||
import org.springframework.stereotype.Repository | ||
import reactor.core.publisher.Flux | ||
import reactor.core.publisher.Mono | ||
import reactor.kotlin.core.publisher.switchIfEmpty | ||
import java.util.* | ||
import java.util.stream.Collectors | ||
|
||
/** | ||
* @author yoonho | ||
* @since 2023.02.15 | ||
*/ | ||
@Repository | ||
class FollowPersistenceAdapter( | ||
private val followRepository: FollowRepository, | ||
private val accountRepository: AccountRepository, | ||
private val objectMapper: ObjectMapper, | ||
): SavePort, FindPort { | ||
|
||
override fun register(followeeUserId: String, followerUserId: String): Mono<Boolean> = | ||
Mono.zip( | ||
accountRepository.findByUserId(followeeUserId) | ||
.switchIfEmpty { throw BadRequestException("등록되지 않은 사용자입니다.") }, | ||
accountRepository.findByUserId(followerUserId) | ||
.switchIfEmpty { throw BadRequestException("등록되지 않은 사용자입니다.") } | ||
) | ||
.flatMap { followRepository.save( | ||
Follow( | ||
followeeUserId = followeeUserId, | ||
followeeNickName = it.t1.nickName, | ||
followerUserId = followerUserId, | ||
followerNickName = it.t2.nickName | ||
) | ||
) | ||
.flatMap { Mono.just(true) } } | ||
|
||
override fun delete(followeeUserId: String, followerUserId: String): Mono<Boolean> = | ||
followRepository.deleteByFollowerUserIdAndFolloweeUserId(followerUserId, followeeUserId) | ||
|
||
override fun count(userId: String): Mono<FollowCntDto> = | ||
Mono.zip( | ||
followRepository.findAllByFollowerUserId(userId) | ||
.filterWhen { | ||
followRepository.existsByFollowerUserIdAndFolloweeUserId(it.followeeUserId, userId) | ||
.map { !it } // not exists 조건 | ||
} | ||
.count(), | ||
followRepository.findAllByFolloweeUserId(userId) | ||
.filterWhen { | ||
followRepository.existsByFollowerUserIdAndFolloweeUserId(userId, it.followerUserId) | ||
.map { !it } // not exists 조건 | ||
} | ||
.count(), | ||
followRepository.findAllByFollowerUserId(userId) | ||
.filterWhen { | ||
followRepository.existsByFollowerUserIdAndFolloweeUserId(it.followeeUserId, userId) | ||
} | ||
.count() | ||
) | ||
.map { | ||
FollowCntDto( | ||
followerCnt = it.t1, | ||
followeeCnt = it.t2, | ||
followForFollowCnt = it.t3 | ||
) | ||
} | ||
|
||
override fun follower(userId: String, start: Int, size: Int): Flux<FollowAccountDto> = | ||
followRepository.findAllByFollowerUserIdOrderByCreatedAt(userId, PageRequest.of(start, size)) | ||
.filterWhen { | ||
followRepository.existsByFollowerUserIdAndFolloweeUserId(it.followeeUserId, userId) | ||
.map { !it } // not exists 조건 | ||
} | ||
.flatMap { findFollowAccountDto(it.followeeUserId) } | ||
|
||
override fun followee(userId: String, start: Int, size: Int): Flux<FollowAccountDto> = | ||
followRepository.findAllByFolloweeUserIdOrderByCreatedAt(userId, PageRequest.of(start, size)) | ||
.filterWhen { | ||
followRepository.existsByFollowerUserIdAndFolloweeUserId(userId, it.followerUserId) | ||
.map { !it } // not exists 조건 | ||
} | ||
.flatMap { findFollowAccountDto(it.followerUserId) } | ||
|
||
override fun followForFollow(userId: String, start: Int, size: Int): Flux<FollowAccountDto> = | ||
followRepository.findAllByFollowerUserIdOrderByCreatedAt(userId, PageRequest.of(start, size)) | ||
.filterWhen { | ||
followRepository.existsByFollowerUserIdAndFolloweeUserId(it.followeeUserId, userId) | ||
} | ||
.flatMap { findFollowAccountDto(it.followeeUserId) } | ||
|
||
override fun followerByNickname(userId: String, start: Int, size: Int): Flux<FollowAccountDto> = | ||
followRepository.findAllByFollowerUserIdOrderByFollowerNickName(userId, PageRequest.of(start, size)) | ||
.filterWhen { | ||
followRepository.existsByFollowerUserIdAndFolloweeUserId(it.followeeUserId, userId) | ||
.map { !it } // not exists 조건 | ||
} | ||
.flatMap { findFollowAccountDto(it.followeeUserId) } | ||
|
||
override fun followeeByNickname(userId: String, start: Int, size: Int): Flux<FollowAccountDto> = | ||
followRepository.findAllByFolloweeUserIdOrderByFolloweeNickName(userId, PageRequest.of(start, size)) | ||
.filterWhen { | ||
followRepository.existsByFollowerUserIdAndFolloweeUserId(userId, it.followerUserId) | ||
.map { !it } // not exists 조건 | ||
} | ||
.flatMap { findFollowAccountDto(it.followerUserId) } | ||
|
||
override fun followForFollowByNickname(userId: String, start: Int, size: Int): Flux<FollowAccountDto> = | ||
followRepository.findAllByFollowerUserIdOrderByFollowerNickName(userId, PageRequest.of(start, size)) | ||
.filterWhen { | ||
followRepository.existsByFollowerUserIdAndFolloweeUserId(it.followeeUserId, userId) | ||
} | ||
.flatMap { findFollowAccountDto(it.followeeUserId) } | ||
|
||
|
||
private fun findFollowAccountDto(userId: String): Mono<FollowAccountDto> = | ||
accountRepository.findByUserId(userId) | ||
.switchIfEmpty { throw BadRequestException("등록되지 않은 사용자입니다.") } | ||
.map { it.toDto() } | ||
.map { objectMapper.convertValue(it, FollowAccountDto::class.java) } | ||
|
||
|
||
} |
24 changes: 24 additions & 0 deletions
24
src/main/kotlin/com/nexters/pimo/follow/adapter/out/persistence/FollowRepository.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.nexters.pimo.follow.adapter.out.persistence | ||
|
||
import com.nexters.pimo.follow.domain.Follow | ||
import org.springframework.data.domain.Pageable | ||
import org.springframework.data.repository.reactive.ReactiveCrudRepository | ||
import reactor.core.publisher.Flux | ||
import reactor.core.publisher.Mono | ||
|
||
/** | ||
* @author yoonho | ||
* @since 2023.02.16 | ||
*/ | ||
interface FollowRepository: ReactiveCrudRepository<Follow, Long> { | ||
fun deleteByFollowerUserIdAndFolloweeUserId(followerUserId: String, followeeUserId: String): Mono<Boolean> | ||
|
||
fun findAllByFollowerUserId(followerUserId: String): Flux<Follow> | ||
fun findAllByFolloweeUserId(followeeUserId: String): Flux<Follow> | ||
fun existsByFollowerUserIdAndFolloweeUserId(followerUserId: String, followeeUserId: String): Mono<Boolean> | ||
|
||
fun findAllByFollowerUserIdOrderByCreatedAt(followerUserId: String, pageable: Pageable): Flux<Follow> | ||
fun findAllByFolloweeUserIdOrderByCreatedAt(followeeUserId: String, pageable: Pageable): Flux<Follow> | ||
fun findAllByFollowerUserIdOrderByFollowerNickName(followerUserId: String, pageable: Pageable): Flux<Follow> | ||
fun findAllByFolloweeUserIdOrderByFolloweeNickName(followeeUserId: String, pageable: Pageable): Flux<Follow> | ||
} |
Oops, something went wrong.