From a13fe45d0d4ff1747afe59112488dde8f90063ad Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Fri, 7 Jun 2024 00:37:34 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=E3=82=A2=E3=83=97=E3=83=AA=E3=82=B1?= =?UTF-8?q?=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=B5=E3=83=BC=E3=83=93?= =?UTF-8?q?=E3=82=B9=E3=81=AE=E6=93=8D=E4=BD=9C=E3=83=AD=E3=82=B0=E3=82=92?= =?UTF-8?q?=E6=AE=8B=E3=81=9B=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RegisterLocalActorApplicationService.kt | 50 +++++++++++-------- .../shared/AbstractApplicationService.kt | 45 +++++++++++++++++ .../application/shared/ApplicationService.kt | 21 ++++++++ .../application/shared/CommandExecutor.kt | 21 ++++++++ .../springframework/HttpCommandExecutor.kt | 29 +++++++++++ .../SpringMvcCommandExecutorFactory.kt | 32 ++++++++++++ .../interfaces/api/auth/AuthController.kt | 11 +++- 7 files changed, 185 insertions(+), 24 deletions(-) create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/AbstractApplicationService.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/ApplicationService.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/CommandExecutor.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/HttpCommandExecutor.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/SpringMvcCommandExecutorFactory.kt diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/RegisterLocalActorApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/RegisterLocalActorApplicationService.kt index 567bccde..2e172e83 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/RegisterLocalActorApplicationService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/RegisterLocalActorApplicationService.kt @@ -16,6 +16,8 @@ package dev.usbharu.hideout.core.application.actor +import dev.usbharu.hideout.core.application.shared.AbstractApplicationService +import dev.usbharu.hideout.core.application.shared.CommandExecutor import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.config.ApplicationConfig import dev.usbharu.hideout.core.domain.model.actor.ActorRepository @@ -27,12 +29,13 @@ import dev.usbharu.hideout.core.domain.service.actor.local.LocalActorDomainServi import dev.usbharu.hideout.core.domain.service.userdetail.UserDetailDomainService import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService import dev.usbharu.hideout.core.infrastructure.factory.ActorFactoryImpl +import org.slf4j.LoggerFactory import org.springframework.stereotype.Service import java.net.URI @Service class RegisterLocalActorApplicationService( - private val transaction: Transaction, + transaction: Transaction, private val actorDomainService: LocalActorDomainService, private val actorRepository: ActorRepository, private val actorFactoryImpl: ActorFactoryImpl, @@ -41,28 +44,31 @@ class RegisterLocalActorApplicationService( private val userDetailDomainService: UserDetailDomainService, private val userDetailRepository: UserDetailRepository, private val idGenerateService: IdGenerateService, -) { - suspend fun register(registerLocalActor: RegisterLocalActor): URI { - return transaction.transaction { - if (actorDomainService.usernameAlreadyUse(registerLocalActor.name)) { - // todo 適切な例外を考える - throw Exception("Username already exists") - } - val instance = instanceRepository.findByUrl(applicationConfig.url.toURI())!! +) : AbstractApplicationService(transaction, Companion.logger) { - val actor = actorFactoryImpl.createLocal( - registerLocalActor.name, - actorDomainService.generateKeyPair(), - instance.id - ) - actorRepository.save(actor) - val userDetail = UserDetail.create( - id = UserDetailId(idGenerateService.generateId()), - actorId = actor.id, - password = userDetailDomainService.hashPassword(registerLocalActor.password), - ) - userDetailRepository.save(userDetail) - actor.url + override suspend fun internalExecute(command: RegisterLocalActor, executor: CommandExecutor): URI { + if (actorDomainService.usernameAlreadyUse(command.name)) { + // todo 適切な例外を考える + throw Exception("Username already exists") } + val instance = instanceRepository.findByUrl(applicationConfig.url.toURI())!! + + val actor = actorFactoryImpl.createLocal( + command.name, + actorDomainService.generateKeyPair(), + instance.id + ) + actorRepository.save(actor) + val userDetail = UserDetail.create( + id = UserDetailId(idGenerateService.generateId()), + actorId = actor.id, + password = userDetailDomainService.hashPassword(command.password), + ) + userDetailRepository.save(userDetail) + return actor.url + } + + companion object { + val logger = LoggerFactory.getLogger(RegisterLocalActorApplicationService::class.java) } } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/AbstractApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/AbstractApplicationService.kt new file mode 100644 index 00000000..9e34cc91 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/AbstractApplicationService.kt @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dev.usbharu.hideout.core.application.shared + +import kotlinx.coroutines.CancellationException +import org.slf4j.Logger + +abstract class AbstractApplicationService( + protected val transaction: Transaction, + protected val logger: Logger, +) : ApplicationService { + override suspend fun execute(command: T, executor: CommandExecutor): R { + return try { + logger.debug("START ${command::class.simpleName} by $executor") + val response = transaction.transaction { + internalExecute(command, executor) + } + logger.info("SUCCESS ${command::class.simpleName} by ${executor.executor}") + response + } catch (e: CancellationException) { + logger.debug("Coroutine canceled", e) + throw e + } catch (e: Exception) { + logger.warn("Command execution error", e) + throw e + } + + } + + protected abstract suspend fun internalExecute(command: T, executor: CommandExecutor): R +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/ApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/ApplicationService.kt new file mode 100644 index 00000000..86f66991 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/ApplicationService.kt @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dev.usbharu.hideout.core.application.shared + +interface ApplicationService { + suspend fun execute(command: T, executor: CommandExecutor): R +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/CommandExecutor.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/CommandExecutor.kt new file mode 100644 index 00000000..d022254f --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/CommandExecutor.kt @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dev.usbharu.hideout.core.application.shared + +interface CommandExecutor { + val executor: String +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/HttpCommandExecutor.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/HttpCommandExecutor.kt new file mode 100644 index 00000000..fe315bf4 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/HttpCommandExecutor.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dev.usbharu.hideout.core.infrastructure.springframework + +import dev.usbharu.hideout.core.application.shared.CommandExecutor + +open class HttpCommandExecutor( + override val executor: String, + val ip: String, + val userAgent: String, +) : CommandExecutor { + override fun toString(): String { + return "HttpCommandExecutor(executor='$executor', ip='$ip', userAgent='$userAgent')" + } +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/SpringMvcCommandExecutorFactory.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/SpringMvcCommandExecutorFactory.kt new file mode 100644 index 00000000..63617376 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/SpringMvcCommandExecutorFactory.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dev.usbharu.hideout.core.infrastructure.springframework + +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.stereotype.Component +import org.springframework.web.context.request.RequestContextHolder +import org.springframework.web.context.request.ServletRequestAttributes + + +@Component +class SpringMvcCommandExecutorFactory { + fun getCommandExecutor(): HttpCommandExecutor { + val name = SecurityContextHolder.getContext().authentication?.name ?: "ANONYMOUS" + val request = (RequestContextHolder.currentRequestAttributes() as ServletRequestAttributes).request + return HttpCommandExecutor(name, request.remoteAddr, request.getHeader("user-agent").orEmpty()) + } +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/api/auth/AuthController.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/api/auth/AuthController.kt index d9dc8331..761dacde 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/api/auth/AuthController.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/api/auth/AuthController.kt @@ -18,6 +18,7 @@ package dev.usbharu.hideout.core.interfaces.api.auth import dev.usbharu.hideout.core.application.actor.RegisterLocalActor import dev.usbharu.hideout.core.application.actor.RegisterLocalActorApplicationService +import dev.usbharu.hideout.core.infrastructure.springframework.SpringMvcCommandExecutorFactory import jakarta.servlet.http.HttpServletRequest import org.springframework.stereotype.Controller import org.springframework.validation.annotation.Validated @@ -26,7 +27,10 @@ import org.springframework.web.bind.annotation.ModelAttribute import org.springframework.web.bind.annotation.PostMapping @Controller -class AuthController(private val registerLocalActorApplicationService: RegisterLocalActorApplicationService) { +class AuthController( + private val registerLocalActorApplicationService: RegisterLocalActorApplicationService, + private val springMvcCommandExecutorFactory: SpringMvcCommandExecutorFactory, +) { @GetMapping("/auth/sign_up") fun signUp(): String { return "sign_up" @@ -35,7 +39,10 @@ class AuthController(private val registerLocalActorApplicationService: RegisterL @PostMapping("/auth/sign_up") suspend fun signUp(@Validated @ModelAttribute signUpForm: SignUpForm, request: HttpServletRequest): String { val registerLocalActor = RegisterLocalActor(signUpForm.username, signUpForm.password) - val uri = registerLocalActorApplicationService.register(registerLocalActor) + val uri = registerLocalActorApplicationService.execute( + registerLocalActor, + springMvcCommandExecutorFactory.getCommandExecutor() + ) request.login(signUpForm.username, signUpForm.password) return "redirect:$uri" }