mirror of https://github.com/usbharu/Hideout.git
feat: アプリケーションサービスの操作ログを残せるように
This commit is contained in:
parent
cf48ae651b
commit
a13fe45d0d
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package dev.usbharu.hideout.core.application.actor
|
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.application.shared.Transaction
|
||||||
import dev.usbharu.hideout.core.config.ApplicationConfig
|
import dev.usbharu.hideout.core.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
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.service.userdetail.UserDetailDomainService
|
||||||
import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService
|
import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService
|
||||||
import dev.usbharu.hideout.core.infrastructure.factory.ActorFactoryImpl
|
import dev.usbharu.hideout.core.infrastructure.factory.ActorFactoryImpl
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class RegisterLocalActorApplicationService(
|
class RegisterLocalActorApplicationService(
|
||||||
private val transaction: Transaction,
|
transaction: Transaction,
|
||||||
private val actorDomainService: LocalActorDomainService,
|
private val actorDomainService: LocalActorDomainService,
|
||||||
private val actorRepository: ActorRepository,
|
private val actorRepository: ActorRepository,
|
||||||
private val actorFactoryImpl: ActorFactoryImpl,
|
private val actorFactoryImpl: ActorFactoryImpl,
|
||||||
|
@ -41,28 +44,31 @@ class RegisterLocalActorApplicationService(
|
||||||
private val userDetailDomainService: UserDetailDomainService,
|
private val userDetailDomainService: UserDetailDomainService,
|
||||||
private val userDetailRepository: UserDetailRepository,
|
private val userDetailRepository: UserDetailRepository,
|
||||||
private val idGenerateService: IdGenerateService,
|
private val idGenerateService: IdGenerateService,
|
||||||
) {
|
) : AbstractApplicationService<RegisterLocalActor, URI>(transaction, Companion.logger) {
|
||||||
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())!!
|
|
||||||
|
|
||||||
val actor = actorFactoryImpl.createLocal(
|
override suspend fun internalExecute(command: RegisterLocalActor, executor: CommandExecutor): URI {
|
||||||
registerLocalActor.name,
|
if (actorDomainService.usernameAlreadyUse(command.name)) {
|
||||||
actorDomainService.generateKeyPair(),
|
// todo 適切な例外を考える
|
||||||
instance.id
|
throw Exception("Username already exists")
|
||||||
)
|
|
||||||
actorRepository.save(actor)
|
|
||||||
val userDetail = UserDetail.create(
|
|
||||||
id = UserDetailId(idGenerateService.generateId()),
|
|
||||||
actorId = actor.id,
|
|
||||||
password = userDetailDomainService.hashPassword(registerLocalActor.password),
|
|
||||||
)
|
|
||||||
userDetailRepository.save(userDetail)
|
|
||||||
actor.url
|
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<T : Any, R>(
|
||||||
|
protected val transaction: Transaction,
|
||||||
|
protected val logger: Logger,
|
||||||
|
) : ApplicationService<T, R> {
|
||||||
|
override suspend fun execute(command: T, executor: CommandExecutor): R {
|
||||||
|
return try {
|
||||||
|
logger.debug("START ${command::class.simpleName} by $executor")
|
||||||
|
val response = transaction.transaction<R> {
|
||||||
|
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
|
||||||
|
}
|
|
@ -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<T : Any, R> {
|
||||||
|
suspend fun execute(command: T, executor: CommandExecutor): R
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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')"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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())
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.RegisterLocalActor
|
||||||
import dev.usbharu.hideout.core.application.actor.RegisterLocalActorApplicationService
|
import dev.usbharu.hideout.core.application.actor.RegisterLocalActorApplicationService
|
||||||
|
import dev.usbharu.hideout.core.infrastructure.springframework.SpringMvcCommandExecutorFactory
|
||||||
import jakarta.servlet.http.HttpServletRequest
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
import org.springframework.stereotype.Controller
|
import org.springframework.stereotype.Controller
|
||||||
import org.springframework.validation.annotation.Validated
|
import org.springframework.validation.annotation.Validated
|
||||||
|
@ -26,7 +27,10 @@ import org.springframework.web.bind.annotation.ModelAttribute
|
||||||
import org.springframework.web.bind.annotation.PostMapping
|
import org.springframework.web.bind.annotation.PostMapping
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
class AuthController(private val registerLocalActorApplicationService: RegisterLocalActorApplicationService) {
|
class AuthController(
|
||||||
|
private val registerLocalActorApplicationService: RegisterLocalActorApplicationService,
|
||||||
|
private val springMvcCommandExecutorFactory: SpringMvcCommandExecutorFactory,
|
||||||
|
) {
|
||||||
@GetMapping("/auth/sign_up")
|
@GetMapping("/auth/sign_up")
|
||||||
fun signUp(): String {
|
fun signUp(): String {
|
||||||
return "sign_up"
|
return "sign_up"
|
||||||
|
@ -35,7 +39,10 @@ class AuthController(private val registerLocalActorApplicationService: RegisterL
|
||||||
@PostMapping("/auth/sign_up")
|
@PostMapping("/auth/sign_up")
|
||||||
suspend fun signUp(@Validated @ModelAttribute signUpForm: SignUpForm, request: HttpServletRequest): String {
|
suspend fun signUp(@Validated @ModelAttribute signUpForm: SignUpForm, request: HttpServletRequest): String {
|
||||||
val registerLocalActor = RegisterLocalActor(signUpForm.username, signUpForm.password)
|
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)
|
request.login(signUpForm.username, signUpForm.password)
|
||||||
return "redirect:$uri"
|
return "redirect:$uri"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue