Merge pull request #256 from usbharu/feature/controller-login-user-id

Feature/controller login user
This commit is contained in:
usbharu 2024-01-26 12:54:29 +09:00 committed by GitHub
commit da0f38a608
8 changed files with 71 additions and 65 deletions

View File

@ -0,0 +1,5 @@
package dev.usbharu.hideout.core.infrastructure.springframework.security
interface LoginUserContextHolder {
fun getLoginUserId(): Long
}

View File

@ -0,0 +1,14 @@
package dev.usbharu.hideout.core.infrastructure.springframework.security
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.oauth2.jwt.Jwt
import org.springframework.stereotype.Component
@Component
class OAuth2JwtLoginUserContextHolder : LoginUserContextHolder {
override fun getLoginUserId(): Long {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt
return principal.getClaim<String>("uid").toLong()
}
}

View File

@ -2,6 +2,7 @@ package dev.usbharu.hideout.mastodon.interfaces.api.account
import dev.usbharu.hideout.application.external.Transaction import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.controller.mastodon.generated.AccountApi import dev.usbharu.hideout.controller.mastodon.generated.AccountApi
import dev.usbharu.hideout.core.infrastructure.springframework.security.LoginUserContextHolder
import dev.usbharu.hideout.core.service.user.UserCreateDto import dev.usbharu.hideout.core.service.user.UserCreateDto
import dev.usbharu.hideout.domain.mastodon.model.generated.* import dev.usbharu.hideout.domain.mastodon.model.generated.*
import dev.usbharu.hideout.mastodon.service.account.AccountApiService import dev.usbharu.hideout.mastodon.service.account.AccountApiService
@ -11,37 +12,32 @@ import kotlinx.coroutines.runBlocking
import org.springframework.http.HttpHeaders import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.oauth2.jwt.Jwt
import org.springframework.stereotype.Controller import org.springframework.stereotype.Controller
import java.net.URI import java.net.URI
@Controller @Controller
class MastodonAccountApiController( class MastodonAccountApiController(
private val accountApiService: AccountApiService, private val accountApiService: AccountApiService,
private val transaction: Transaction private val transaction: Transaction,
private val loginUserContextHolder: LoginUserContextHolder
) : AccountApi { ) : AccountApi {
override suspend fun apiV1AccountsIdFollowPost( override suspend fun apiV1AccountsIdFollowPost(
id: String, id: String,
followRequestBody: FollowRequestBody? followRequestBody: FollowRequestBody?
): ResponseEntity<Relationship> { ): ResponseEntity<Relationship> {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
return ResponseEntity.ok(accountApiService.follow(principal.getClaim<String>("uid").toLong(), id.toLong())) return ResponseEntity.ok(accountApiService.follow(userid, id.toLong()))
} }
override suspend fun apiV1AccountsIdGet(id: String): ResponseEntity<Account> = override suspend fun apiV1AccountsIdGet(id: String): ResponseEntity<Account> =
ResponseEntity.ok(accountApiService.account(id.toLong())) ResponseEntity.ok(accountApiService.account(id.toLong()))
override suspend fun apiV1AccountsVerifyCredentialsGet(): ResponseEntity<CredentialAccount> { override suspend fun apiV1AccountsVerifyCredentialsGet(): ResponseEntity<CredentialAccount> = ResponseEntity(
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt accountApiService.verifyCredentials(loginUserContextHolder.getLoginUserId()),
return ResponseEntity(
accountApiService.verifyCredentials(principal.getClaim<String>("uid").toLong()),
HttpStatus.OK HttpStatus.OK
) )
}
override suspend fun apiV1AccountsPost( override suspend fun apiV1AccountsPost(
username: String, username: String,
@ -71,9 +67,7 @@ class MastodonAccountApiController(
pinned: Boolean, pinned: Boolean,
tagged: String? tagged: String?
): ResponseEntity<Flow<Status>> = runBlocking { ): ResponseEntity<Flow<Status>> = runBlocking {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
val userid = principal.getClaim<String>("uid").toLong()
val statusFlow = accountApiService.accountsStatuses( val statusFlow = accountApiService.accountsStatuses(
userid = id.toLong(), userid = id.toLong(),
maxId = maxId?.toLongOrNull(), maxId = maxId?.toLongOrNull(),
@ -94,9 +88,7 @@ class MastodonAccountApiController(
id: List<String>?, id: List<String>?,
withSuspended: Boolean withSuspended: Boolean
): ResponseEntity<Flow<Relationship>> = runBlocking { ): ResponseEntity<Flow<Relationship>> = runBlocking {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
val userid = principal.getClaim<String>("uid").toLong()
ResponseEntity.ok( ResponseEntity.ok(
accountApiService.relationships(userid, id.orEmpty().mapNotNull { it.toLongOrNull() }, withSuspended) accountApiService.relationships(userid, id.orEmpty().mapNotNull { it.toLongOrNull() }, withSuspended)
@ -105,9 +97,7 @@ class MastodonAccountApiController(
} }
override suspend fun apiV1AccountsIdBlockPost(id: String): ResponseEntity<Relationship> { override suspend fun apiV1AccountsIdBlockPost(id: String): ResponseEntity<Relationship> {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
val userid = principal.getClaim<String>("uid").toLong()
val block = accountApiService.block(userid, id.toLong()) val block = accountApiService.block(userid, id.toLong())
@ -115,9 +105,7 @@ class MastodonAccountApiController(
} }
override suspend fun apiV1AccountsIdUnblockPost(id: String): ResponseEntity<Relationship> { override suspend fun apiV1AccountsIdUnblockPost(id: String): ResponseEntity<Relationship> {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
val userid = principal.getClaim<String>("uid").toLong()
val unblock = accountApiService.unblock(userid, id.toLong()) val unblock = accountApiService.unblock(userid, id.toLong())
@ -125,9 +113,7 @@ class MastodonAccountApiController(
} }
override suspend fun apiV1AccountsIdUnfollowPost(id: String): ResponseEntity<Relationship> { override suspend fun apiV1AccountsIdUnfollowPost(id: String): ResponseEntity<Relationship> {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
val userid = principal.getClaim<String>("uid").toLong()
val unfollow = accountApiService.unfollow(userid, id.toLong()) val unfollow = accountApiService.unfollow(userid, id.toLong())
@ -135,9 +121,7 @@ class MastodonAccountApiController(
} }
override suspend fun apiV1AccountsIdRemoveFromFollowersPost(id: String): ResponseEntity<Relationship> { override suspend fun apiV1AccountsIdRemoveFromFollowersPost(id: String): ResponseEntity<Relationship> {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
val userid = principal.getClaim<String>("uid").toLong()
val removeFromFollowers = accountApiService.removeFromFollowers(userid, id.toLong()) val removeFromFollowers = accountApiService.removeFromFollowers(userid, id.toLong())
@ -146,9 +130,7 @@ class MastodonAccountApiController(
override suspend fun apiV1AccountsUpdateCredentialsPatch(updateCredentials: UpdateCredentials?): override suspend fun apiV1AccountsUpdateCredentialsPatch(updateCredentials: UpdateCredentials?):
ResponseEntity<Account> { ResponseEntity<Account> {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
val userid = principal.getClaim<String>("uid").toLong()
val removeFromFollowers = accountApiService.updateProfile(userid, updateCredentials) val removeFromFollowers = accountApiService.updateProfile(userid, updateCredentials)
@ -156,9 +138,7 @@ class MastodonAccountApiController(
} }
override suspend fun apiV1FollowRequestsAccountIdAuthorizePost(accountId: String): ResponseEntity<Relationship> { override suspend fun apiV1FollowRequestsAccountIdAuthorizePost(accountId: String): ResponseEntity<Relationship> {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
val userid = principal.getClaim<String>("uid").toLong()
val acceptFollowRequest = accountApiService.acceptFollowRequest(userid, accountId.toLong()) val acceptFollowRequest = accountApiService.acceptFollowRequest(userid, accountId.toLong())
@ -166,9 +146,7 @@ class MastodonAccountApiController(
} }
override suspend fun apiV1FollowRequestsAccountIdRejectPost(accountId: String): ResponseEntity<Relationship> { override suspend fun apiV1FollowRequestsAccountIdRejectPost(accountId: String): ResponseEntity<Relationship> {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
val userid = principal.getClaim<String>("uid").toLong()
val rejectFollowRequest = accountApiService.rejectFollowRequest(userid, accountId.toLong()) val rejectFollowRequest = accountApiService.rejectFollowRequest(userid, accountId.toLong())
@ -177,9 +155,7 @@ class MastodonAccountApiController(
override fun apiV1FollowRequestsGet(maxId: String?, sinceId: String?, limit: Int?): ResponseEntity<Flow<Account>> = override fun apiV1FollowRequestsGet(maxId: String?, sinceId: String?, limit: Int?): ResponseEntity<Flow<Account>> =
runBlocking { runBlocking {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
val userid = principal.getClaim<String>("uid").toLong()
val accountFlow = val accountFlow =
accountApiService.followRequests(userid, maxId?.toLong(), sinceId?.toLong(), limit ?: 20, false) accountApiService.followRequests(userid, maxId?.toLong(), sinceId?.toLong(), limit ?: 20, false)
@ -188,9 +164,7 @@ class MastodonAccountApiController(
} }
override suspend fun apiV1AccountsIdMutePost(id: String): ResponseEntity<Relationship> { override suspend fun apiV1AccountsIdMutePost(id: String): ResponseEntity<Relationship> {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
val userid = principal.getClaim<String>("uid").toLong()
val mute = accountApiService.mute(userid, id.toLong()) val mute = accountApiService.mute(userid, id.toLong())
@ -198,9 +172,7 @@ class MastodonAccountApiController(
} }
override suspend fun apiV1AccountsIdUnmutePost(id: String): ResponseEntity<Relationship> { override suspend fun apiV1AccountsIdUnmutePost(id: String): ResponseEntity<Relationship> {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
val userid = principal.getClaim<String>("uid").toLong()
val unmute = accountApiService.unmute(userid, id.toLong()) val unmute = accountApiService.unmute(userid, id.toLong())
@ -209,9 +181,7 @@ class MastodonAccountApiController(
override fun apiV1MutesGet(maxId: String?, sinceId: String?, limit: Int?): ResponseEntity<Flow<Account>> = override fun apiV1MutesGet(maxId: String?, sinceId: String?, limit: Int?): ResponseEntity<Flow<Account>> =
runBlocking { runBlocking {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
val userid = principal.getClaim<String>("uid").toLong()
val unmute = val unmute =
accountApiService.mutesAccount(userid, maxId?.toLong(), sinceId?.toLong(), limit ?: 20).asFlow() accountApiService.mutesAccount(userid, maxId?.toLong(), sinceId?.toLong(), limit ?: 20).asFlow()

View File

@ -1,25 +1,27 @@
package dev.usbharu.hideout.mastodon.interfaces.api.status package dev.usbharu.hideout.mastodon.interfaces.api.status
import dev.usbharu.hideout.controller.mastodon.generated.StatusApi import dev.usbharu.hideout.controller.mastodon.generated.StatusApi
import dev.usbharu.hideout.core.infrastructure.springframework.security.LoginUserContextHolder
import dev.usbharu.hideout.domain.mastodon.model.generated.Status import dev.usbharu.hideout.domain.mastodon.model.generated.Status
import dev.usbharu.hideout.mastodon.service.status.StatusesApiService import dev.usbharu.hideout.mastodon.service.status.StatusesApiService
import org.springframework.http.HttpStatus import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.oauth2.jwt.Jwt
import org.springframework.stereotype.Controller import org.springframework.stereotype.Controller
@Controller @Controller
class MastodonStatusesApiContoller(private val statusesApiService: StatusesApiService) : StatusApi { class MastodonStatusesApiContoller(
private val statusesApiService: StatusesApiService,
private val loginUserContextHolder: LoginUserContextHolder
) : StatusApi {
override suspend fun apiV1StatusesPost( override suspend fun apiV1StatusesPost(
devUsbharuHideoutDomainModelMastodonStatusesRequest: StatusesRequest devUsbharuHideoutDomainModelMastodonStatusesRequest: StatusesRequest
): ResponseEntity<Status> { ): ResponseEntity<Status> {
val jwt = SecurityContextHolder.getContext().authentication.principal as Jwt val userid = loginUserContextHolder.getLoginUserId()
return ResponseEntity( return ResponseEntity(
statusesApiService.postStatus( statusesApiService.postStatus(
devUsbharuHideoutDomainModelMastodonStatusesRequest, devUsbharuHideoutDomainModelMastodonStatusesRequest,
jwt.getClaim<String>("uid").toLong() userid
), ),
HttpStatus.OK HttpStatus.OK
) )
@ -27,14 +29,14 @@ class MastodonStatusesApiContoller(private val statusesApiService: StatusesApiSe
override suspend fun apiV1StatusesIdEmojiReactionsEmojiDelete(id: String, emoji: String): ResponseEntity<Status> { override suspend fun apiV1StatusesIdEmojiReactionsEmojiDelete(id: String, emoji: String): ResponseEntity<Status> {
val uid = val uid =
(SecurityContextHolder.getContext().authentication.principal as Jwt).getClaim<String>("uid").toLong() loginUserContextHolder.getLoginUserId()
return ResponseEntity.ok(statusesApiService.removeEmojiReactions(id.toLong(), uid, emoji)) return ResponseEntity.ok(statusesApiService.removeEmojiReactions(id.toLong(), uid, emoji))
} }
override suspend fun apiV1StatusesIdEmojiReactionsEmojiPut(id: String, emoji: String): ResponseEntity<Status> { override suspend fun apiV1StatusesIdEmojiReactionsEmojiPut(id: String, emoji: String): ResponseEntity<Status> {
val uid = val uid =
(SecurityContextHolder.getContext().authentication.principal as Jwt).getClaim<String>("uid").toLong() loginUserContextHolder.getLoginUserId()
return ResponseEntity.ok(statusesApiService.emojiReactions(id.toLong(), uid, emoji)) return ResponseEntity.ok(statusesApiService.emojiReactions(id.toLong(), uid, emoji))
} }

View File

@ -1,6 +1,7 @@
package dev.usbharu.hideout.mastodon.interfaces.api.timeline package dev.usbharu.hideout.mastodon.interfaces.api.timeline
import dev.usbharu.hideout.controller.mastodon.generated.TimelineApi import dev.usbharu.hideout.controller.mastodon.generated.TimelineApi
import dev.usbharu.hideout.core.infrastructure.springframework.security.LoginUserContextHolder
import dev.usbharu.hideout.domain.mastodon.model.generated.Status import dev.usbharu.hideout.domain.mastodon.model.generated.Status
import dev.usbharu.hideout.mastodon.service.timeline.TimelineApiService import dev.usbharu.hideout.mastodon.service.timeline.TimelineApiService
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -8,21 +9,21 @@ import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.springframework.http.HttpStatus import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.oauth2.jwt.Jwt
import org.springframework.stereotype.Controller import org.springframework.stereotype.Controller
@Controller @Controller
class MastodonTimelineApiController(private val timelineApiService: TimelineApiService) : TimelineApi { class MastodonTimelineApiController(
private val timelineApiService: TimelineApiService,
private val loginUserContextHolder: LoginUserContextHolder
) : TimelineApi {
override fun apiV1TimelinesHomeGet( override fun apiV1TimelinesHomeGet(
maxId: String?, maxId: String?,
sinceId: String?, sinceId: String?,
minId: String?, minId: String?,
limit: Int? limit: Int?
): ResponseEntity<Flow<Status>> = runBlocking { ): ResponseEntity<Flow<Status>> = runBlocking {
val jwt = SecurityContextHolder.getContext().authentication.principal as Jwt
val homeTimeline = timelineApiService.homeTimeline( val homeTimeline = timelineApiService.homeTimeline(
userId = jwt.getClaim<String>("uid").toLong(), userId = loginUserContextHolder.getLoginUserId(),
maxId = maxId?.toLongOrNull(), maxId = maxId?.toLongOrNull(),
minId = minId?.toLongOrNull(), minId = minId?.toLongOrNull(),
sinceId = sinceId?.toLongOrNull(), sinceId = sinceId?.toLongOrNull(),

View File

@ -1,6 +1,7 @@
package dev.usbharu.hideout.mastodon.interfaces.api.account package dev.usbharu.hideout.mastodon.interfaces.api.account
import dev.usbharu.hideout.application.config.ActivityPubConfig import dev.usbharu.hideout.application.config.ActivityPubConfig
import dev.usbharu.hideout.core.infrastructure.springframework.security.OAuth2JwtLoginUserContextHolder
import dev.usbharu.hideout.domain.mastodon.model.generated.AccountSource import dev.usbharu.hideout.domain.mastodon.model.generated.AccountSource
import dev.usbharu.hideout.domain.mastodon.model.generated.CredentialAccount import dev.usbharu.hideout.domain.mastodon.model.generated.CredentialAccount
import dev.usbharu.hideout.domain.mastodon.model.generated.Role import dev.usbharu.hideout.domain.mastodon.model.generated.Role
@ -31,6 +32,9 @@ class MastodonAccountApiControllerTest {
private lateinit var mockMvc: MockMvc private lateinit var mockMvc: MockMvc
@Spy
private val loginUserContextHolder = OAuth2JwtLoginUserContextHolder()
@Spy @Spy
private lateinit var testTransaction: TestTransaction private lateinit var testTransaction: TestTransaction

View File

@ -1,6 +1,7 @@
package dev.usbharu.hideout.mastodon.interfaces.api.status package dev.usbharu.hideout.mastodon.interfaces.api.status
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import dev.usbharu.hideout.core.infrastructure.springframework.security.OAuth2JwtLoginUserContextHolder
import dev.usbharu.hideout.domain.mastodon.model.generated.Account import dev.usbharu.hideout.domain.mastodon.model.generated.Account
import dev.usbharu.hideout.domain.mastodon.model.generated.Status import dev.usbharu.hideout.domain.mastodon.model.generated.Status
import dev.usbharu.hideout.generate.JsonOrFormModelMethodProcessor import dev.usbharu.hideout.generate.JsonOrFormModelMethodProcessor
@ -11,6 +12,7 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.InjectMocks import org.mockito.InjectMocks
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Spy
import org.mockito.junit.jupiter.MockitoExtension import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.doReturn import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq import org.mockito.kotlin.eq
@ -30,6 +32,9 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBody
@ExtendWith(MockitoExtension::class) @ExtendWith(MockitoExtension::class)
class MastodonStatusesApiControllerTest { class MastodonStatusesApiControllerTest {
@Spy
private val loginUserContextHolder = OAuth2JwtLoginUserContextHolder()
@Mock @Mock
private lateinit var statusesApiService: StatusesApiService private lateinit var statusesApiService: StatusesApiService

View File

@ -1,6 +1,7 @@
package dev.usbharu.hideout.mastodon.interfaces.api.timeline package dev.usbharu.hideout.mastodon.interfaces.api.timeline
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import dev.usbharu.hideout.core.infrastructure.springframework.security.OAuth2JwtLoginUserContextHolder
import dev.usbharu.hideout.domain.mastodon.model.generated.Account import dev.usbharu.hideout.domain.mastodon.model.generated.Account
import dev.usbharu.hideout.domain.mastodon.model.generated.Status import dev.usbharu.hideout.domain.mastodon.model.generated.Status
import dev.usbharu.hideout.mastodon.service.timeline.TimelineApiService import dev.usbharu.hideout.mastodon.service.timeline.TimelineApiService
@ -10,6 +11,7 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.InjectMocks import org.mockito.InjectMocks
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Spy
import org.mockito.junit.jupiter.MockitoExtension import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.* import org.mockito.kotlin.*
import org.springframework.security.core.context.SecurityContextHolder import org.springframework.security.core.context.SecurityContextHolder
@ -23,6 +25,9 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders
@ExtendWith(MockitoExtension::class) @ExtendWith(MockitoExtension::class)
class MastodonTimelineApiControllerTest { class MastodonTimelineApiControllerTest {
@Spy
private val loginUserContextHolder = OAuth2JwtLoginUserContextHolder()
@Mock @Mock
private lateinit var timelineApiService: TimelineApiService private lateinit var timelineApiService: TimelineApiService