From 2057322b57f6137867645c345d6283fd36c8a7d9 Mon Sep 17 00:00:00 2001 From: Shiina Kin Date: Fri, 13 Sep 2024 18:18:02 +0800 Subject: [PATCH] feat: unified management of service instantiation --- .../main/kotlin/io/sakurasou/Application.kt | 2 + .../io/sakurasou/config/InstanceCenter.kt | 32 ++++++++++ .../io/sakurasou/controller/AuthController.kt | 12 ++-- .../sakurasou/controller/CommonController.kt | 4 +- .../io/sakurasou/controller/UserController.kt | 3 +- .../kotlin/io/sakurasou/plugins/Routing.kt | 9 ++- .../sakurasou/service/album/AlbumService.kt | 10 +++ .../service/album/AlbumServiceImpl.kt | 28 +++++++++ .../io/sakurasou/service/auth/AuthService.kt | 2 - .../sakurasou/service/auth/AuthServiceImpl.kt | 22 ------- .../sakurasou/service/common/CommonService.kt | 11 ++++ .../service/common/CommonServiceImpl.kt | 63 +++++++++++++++++++ .../sakurasou/service/group/GroupService.kt | 9 +++ .../io/sakurasou/service/user/UserService.kt | 4 +- .../sakurasou/service/user/UserServiceImpl.kt | 33 +++++++++- 15 files changed, 205 insertions(+), 39 deletions(-) create mode 100644 app/src/main/kotlin/io/sakurasou/service/album/AlbumService.kt create mode 100644 app/src/main/kotlin/io/sakurasou/service/album/AlbumServiceImpl.kt create mode 100644 app/src/main/kotlin/io/sakurasou/service/common/CommonService.kt create mode 100644 app/src/main/kotlin/io/sakurasou/service/common/CommonServiceImpl.kt create mode 100644 app/src/main/kotlin/io/sakurasou/service/group/GroupService.kt diff --git a/app/src/main/kotlin/io/sakurasou/Application.kt b/app/src/main/kotlin/io/sakurasou/Application.kt index a210c4d4..9cda2514 100644 --- a/app/src/main/kotlin/io/sakurasou/Application.kt +++ b/app/src/main/kotlin/io/sakurasou/Application.kt @@ -1,6 +1,7 @@ package io.sakurasou import io.ktor.server.application.* +import io.sakurasou.config.InstanceCenter import io.sakurasou.config.configureDatabase import io.sakurasou.config.configureJwt import io.sakurasou.plugins.* @@ -17,6 +18,7 @@ fun Application.module() { val redisPort = environment.config.property("ktor.application.cache.redis.port").getString() configureDatabase() + InstanceCenter.initService() configureCache(redisHost, redisPort) configureJwt() configureSecurity() diff --git a/app/src/main/kotlin/io/sakurasou/config/InstanceCenter.kt b/app/src/main/kotlin/io/sakurasou/config/InstanceCenter.kt index 577ca735..6a055835 100644 --- a/app/src/main/kotlin/io/sakurasou/config/InstanceCenter.kt +++ b/app/src/main/kotlin/io/sakurasou/config/InstanceCenter.kt @@ -18,6 +18,17 @@ import io.sakurasou.model.dao.strategy.StrategyDao import io.sakurasou.model.dao.strategy.StrategyDaoImpl import io.sakurasou.model.dao.user.UserDao import io.sakurasou.model.dao.user.UserDaoImpl +import io.sakurasou.service.album.AlbumService +import io.sakurasou.service.album.AlbumServiceImpl +import io.sakurasou.service.auth.AuthService +import io.sakurasou.service.auth.AuthServiceImpl +import io.sakurasou.service.common.CommonService +import io.sakurasou.service.common.CommonServiceImpl +import io.sakurasou.service.image.ImageService +import io.sakurasou.service.setting.SettingService +import io.sakurasou.service.setting.SettingServiceImpl +import io.sakurasou.service.user.UserService +import io.sakurasou.service.user.UserServiceImpl /** * @author Shiina Kin @@ -34,6 +45,18 @@ object InstanceCenter { lateinit var permissionDao: PermissionDao lateinit var relationDao: RelationDao + lateinit var authService: AuthService + lateinit var userService: UserService + lateinit var imageService: ImageService + lateinit var albumService: AlbumService + // lateinit var strategyService: UserService + lateinit var settingService: SettingService + lateinit var commonService: CommonService + // lateinit var roleService: UserService + // lateinit var permissionService: UserService + // lateinit var relationService: UserService + + fun initDao() { userDao = UserDaoImpl() imageDao = ImageDaoImpl() @@ -45,4 +68,13 @@ object InstanceCenter { permissionDao = PermissionDaoImpl() relationDao = RelationDaoImpl() } + + fun initService() { + albumService = AlbumServiceImpl(albumDao) + settingService = SettingServiceImpl(settingDao) + authService = AuthServiceImpl(userDao, relationDao) + + userService = UserServiceImpl(userDao, albumService, settingService) + commonService = CommonServiceImpl(userDao, albumService, settingService) + } } \ No newline at end of file diff --git a/app/src/main/kotlin/io/sakurasou/controller/AuthController.kt b/app/src/main/kotlin/io/sakurasou/controller/AuthController.kt index a31a3db7..27b47039 100644 --- a/app/src/main/kotlin/io/sakurasou/controller/AuthController.kt +++ b/app/src/main/kotlin/io/sakurasou/controller/AuthController.kt @@ -8,18 +8,15 @@ import io.ktor.server.response.* import io.ktor.server.routing.* import io.sakurasou.controller.request.UserInsertRequest import io.sakurasou.controller.request.UserLoginRequest -import io.sakurasou.model.dao.relation.RelationDao -import io.sakurasou.model.dao.user.UserDao import io.sakurasou.service.auth.AuthService -import io.sakurasou.service.auth.AuthServiceImpl +import io.sakurasou.service.user.UserService /** * @author Shiina Kin * 2024/9/12 10:14 */ -fun Route.authRoute(userDao: UserDao, relationDao: RelationDao) { - val authService = AuthServiceImpl(userDao, relationDao) - val authController = AuthController(authService) +fun Route.authRoute(authService: AuthService, userService: UserService) { + val authController = AuthController(authService, userService) route("user", { protected = false }) { @@ -49,7 +46,8 @@ fun Route.authRoute(userDao: UserDao, relationDao: RelationDao) { } class AuthController( - private val authService: AuthService + private val authService: AuthService, + private val userService: UserService ) { suspend fun handleLogin(loginRequest: UserLoginRequest): String { return authService.login(loginRequest) diff --git a/app/src/main/kotlin/io/sakurasou/controller/CommonController.kt b/app/src/main/kotlin/io/sakurasou/controller/CommonController.kt index 2b007c6a..7e89fc57 100644 --- a/app/src/main/kotlin/io/sakurasou/controller/CommonController.kt +++ b/app/src/main/kotlin/io/sakurasou/controller/CommonController.kt @@ -6,12 +6,14 @@ import io.github.smiley4.ktorswaggerui.dsl.routing.route import io.ktor.http.* import io.ktor.server.routing.* import io.sakurasou.controller.request.SiteInitRequest +import io.sakurasou.service.common.CommonService /** * @author Shiina Kin * 2024/9/9 09:03 */ -fun Route.commonRoute() { +fun Route.commonRoute(commonService: CommonService) { + val commonController = CommonController(commonService) route("site") { post("init", { request { diff --git a/app/src/main/kotlin/io/sakurasou/controller/UserController.kt b/app/src/main/kotlin/io/sakurasou/controller/UserController.kt index c0c1fcad..99725111 100644 --- a/app/src/main/kotlin/io/sakurasou/controller/UserController.kt +++ b/app/src/main/kotlin/io/sakurasou/controller/UserController.kt @@ -24,8 +24,7 @@ import io.sakurasou.service.user.UserServiceImpl * 2024/9/5 15:35 */ -fun Route.userRoute(userDao: UserDao) { - val userService = UserServiceImpl(userDao) +fun Route.userRoute(userService: UserService) { val userController = UserController(userService) route("user", { protected = true diff --git a/app/src/main/kotlin/io/sakurasou/plugins/Routing.kt b/app/src/main/kotlin/io/sakurasou/plugins/Routing.kt index 3375ec90..c8bf81fd 100644 --- a/app/src/main/kotlin/io/sakurasou/plugins/Routing.kt +++ b/app/src/main/kotlin/io/sakurasou/plugins/Routing.kt @@ -13,8 +13,11 @@ import io.ktor.server.resources.* import io.ktor.server.response.* import io.ktor.server.routing.* import io.ktor.util.* +import io.sakurasou.config.InstanceCenter.authService +import io.sakurasou.config.InstanceCenter.commonService import io.sakurasou.config.InstanceCenter.relationDao import io.sakurasou.config.InstanceCenter.userDao +import io.sakurasou.config.InstanceCenter.userService import io.sakurasou.controller.* import io.sakurasou.exception.FileSizeException import io.sakurasou.exception.UnauthorizedAccessException @@ -45,8 +48,8 @@ fun Application.configureRouting() { install(DoubleReceive) routing { route("api") { - authRoute(userDao, relationDao) - cacheOutput { commonRoute() } + authRoute(authService, userService) + cacheOutput { commonRoute(commonService) } authenticate("auth-jwt") { intercept(ApplicationCallPipeline.Call) { val principal = call.principal() @@ -62,7 +65,7 @@ fun Application.configureRouting() { albumRoute() strategyRoute() settingRoute() - userRoute(userDao) + userRoute(userService) groupRoute() roleRoute() } diff --git a/app/src/main/kotlin/io/sakurasou/service/album/AlbumService.kt b/app/src/main/kotlin/io/sakurasou/service/album/AlbumService.kt new file mode 100644 index 00000000..427607bf --- /dev/null +++ b/app/src/main/kotlin/io/sakurasou/service/album/AlbumService.kt @@ -0,0 +1,10 @@ +package io.sakurasou.service.album + +/** + * @author Shiina Kin + * 2024/9/13 14:48 + */ +interface AlbumService { + suspend fun initAlbumForUser(userId: Long) + suspend fun saveAlbum() +} \ No newline at end of file diff --git a/app/src/main/kotlin/io/sakurasou/service/album/AlbumServiceImpl.kt b/app/src/main/kotlin/io/sakurasou/service/album/AlbumServiceImpl.kt new file mode 100644 index 00000000..b08c260d --- /dev/null +++ b/app/src/main/kotlin/io/sakurasou/service/album/AlbumServiceImpl.kt @@ -0,0 +1,28 @@ +package io.sakurasou.service.album + +import io.sakurasou.model.DatabaseSingleton.dbQuery +import io.sakurasou.model.dao.album.AlbumDao +import io.sakurasou.model.dto.AlbumInsertDTO +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime + +/** + * @author Shiina Kin + * 2024/9/13 14:48 + */ +class AlbumServiceImpl( + private val albumDao: AlbumDao +) : AlbumService { + override suspend fun initAlbumForUser(userId: Long) { + val now = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) + val uncategorizedAlbum = AlbumInsertDTO(userId, "uncategorized", "default, cannot delete", 0, now) + dbQuery { + albumDao.saveAlbum(uncategorizedAlbum) + } + } + + override suspend fun saveAlbum() { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/io/sakurasou/service/auth/AuthService.kt b/app/src/main/kotlin/io/sakurasou/service/auth/AuthService.kt index 58ad4541..58fa737c 100644 --- a/app/src/main/kotlin/io/sakurasou/service/auth/AuthService.kt +++ b/app/src/main/kotlin/io/sakurasou/service/auth/AuthService.kt @@ -1,6 +1,5 @@ package io.sakurasou.service.auth -import io.sakurasou.controller.request.UserInsertRequest import io.sakurasou.controller.request.UserLoginRequest /** @@ -9,5 +8,4 @@ import io.sakurasou.controller.request.UserLoginRequest */ interface AuthService { suspend fun login(loginRequest: UserLoginRequest): String - suspend fun saveUser(userInsertRequest: UserInsertRequest) } \ No newline at end of file diff --git a/app/src/main/kotlin/io/sakurasou/service/auth/AuthServiceImpl.kt b/app/src/main/kotlin/io/sakurasou/service/auth/AuthServiceImpl.kt index b8555571..646877e0 100644 --- a/app/src/main/kotlin/io/sakurasou/service/auth/AuthServiceImpl.kt +++ b/app/src/main/kotlin/io/sakurasou/service/auth/AuthServiceImpl.kt @@ -6,18 +6,14 @@ import com.auth0.jwt.algorithms.Algorithm import io.sakurasou.config.JwtConfig.audience import io.sakurasou.config.JwtConfig.issuer import io.sakurasou.config.JwtConfig.jwkProvider -import io.sakurasou.controller.request.UserInsertRequest import io.sakurasou.controller.request.UserLoginRequest import io.sakurasou.exception.UnauthorizedAccessException import io.sakurasou.exception.UserNotFoundException import io.sakurasou.model.DatabaseSingleton.dbQuery import io.sakurasou.model.dao.relation.RelationDao import io.sakurasou.model.dao.user.UserDao -import io.sakurasou.model.dto.UserInsertDTO import kotlinx.datetime.Clock -import kotlinx.datetime.TimeZone import kotlinx.datetime.toJavaInstant -import kotlinx.datetime.toLocalDateTime import java.security.KeyFactory import java.security.interfaces.RSAPrivateKey import java.security.interfaces.RSAPublicKey @@ -56,22 +52,4 @@ class AuthServiceImpl( .sign(Algorithm.RSA256(publicKey as RSAPublicKey, privateKey as RSAPrivateKey)) return token } - - override suspend fun saveUser(userInsertRequest: UserInsertRequest) { - val rowPassword = userInsertRequest.password - val encodePassword = BCrypt.withDefaults().hashToString(12, rowPassword.toCharArray()) - - val now = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) - val userInsertDTO = UserInsertDTO( - userInsertRequest.groupId, - userInsertRequest.username, - encodePassword, - userInsertRequest.email, - now, - now - ) - dbQuery { - userDao.saveUser(userInsertDTO) - } - } } \ No newline at end of file diff --git a/app/src/main/kotlin/io/sakurasou/service/common/CommonService.kt b/app/src/main/kotlin/io/sakurasou/service/common/CommonService.kt new file mode 100644 index 00000000..f75b7b69 --- /dev/null +++ b/app/src/main/kotlin/io/sakurasou/service/common/CommonService.kt @@ -0,0 +1,11 @@ +package io.sakurasou.service.common + +import io.sakurasou.controller.request.SiteInitRequest + +/** + * @author Shiina Kin + * 2024/9/13 16:23 + */ +interface CommonService { + suspend fun initSite(siteInitRequest: SiteInitRequest) +} \ No newline at end of file diff --git a/app/src/main/kotlin/io/sakurasou/service/common/CommonServiceImpl.kt b/app/src/main/kotlin/io/sakurasou/service/common/CommonServiceImpl.kt new file mode 100644 index 00000000..378b82d9 --- /dev/null +++ b/app/src/main/kotlin/io/sakurasou/service/common/CommonServiceImpl.kt @@ -0,0 +1,63 @@ +package io.sakurasou.service.common + +import at.favre.lib.crypto.bcrypt.BCrypt +import io.sakurasou.controller.request.SiteInitRequest +import io.sakurasou.exception.SiteRepeatedInitializationException +import io.sakurasou.model.DatabaseSingleton.dbQuery +import io.sakurasou.model.dao.user.UserDao +import io.sakurasou.model.dto.UserInsertDTO +import io.sakurasou.model.setting.SiteSetting +import io.sakurasou.model.setting.SystemStatus +import io.sakurasou.service.album.AlbumService +import io.sakurasou.service.setting.SettingService +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime + +/** + * @author Shiina Kin + * 2024/9/13 15:34 + */ +class CommonServiceImpl( + private val userDao: UserDao, + private val albumService: AlbumService, + private val settingService: SettingService +) : CommonService { + override suspend fun initSite(siteInitRequest: SiteInitRequest) { + val status = settingService.getSystemStatus() + if (status.isInit) throw SiteRepeatedInitializationException() + + val rawPassword = siteInitRequest.password + val encodePassword = BCrypt.withDefaults().hashToString(12, rawPassword.toCharArray()) + + val now = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) + val userInsertDTO = UserInsertDTO( + groupId = 1, + username = siteInitRequest.username, + password = encodePassword, + email = siteInitRequest.email, + createTime = now, + updateTime = now + ) + + val oldSiteSetting = settingService.getSiteSetting() + val siteSettingConfig = SiteSetting( + siteTitle = siteInitRequest.siteTitle, + siteSubtitle = siteInitRequest.siteSubtitle, + siteDescription = siteInitRequest.siteDescription, + siteKeyword = oldSiteSetting.siteKeyword, + homePageRandomPicDisplay = oldSiteSetting.homePageRandomPicDisplay + ) + + val systemStatus = SystemStatus( + isInit = true + ) + + dbQuery { + val userId = userDao.saveUser(userInsertDTO) + albumService.initAlbumForUser(userId) + settingService.updateSiteSetting(siteSettingConfig) + settingService.updateSystemStatus(systemStatus) + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/io/sakurasou/service/group/GroupService.kt b/app/src/main/kotlin/io/sakurasou/service/group/GroupService.kt new file mode 100644 index 00000000..ea260b86 --- /dev/null +++ b/app/src/main/kotlin/io/sakurasou/service/group/GroupService.kt @@ -0,0 +1,9 @@ +package io.sakurasou.service.group + +/** + * @author Shiina Kin + * 2024/9/13 14:47 + */ +interface GroupService { + fun saveGroup() +} \ No newline at end of file diff --git a/app/src/main/kotlin/io/sakurasou/service/user/UserService.kt b/app/src/main/kotlin/io/sakurasou/service/user/UserService.kt index 05c67582..eff197c3 100644 --- a/app/src/main/kotlin/io/sakurasou/service/user/UserService.kt +++ b/app/src/main/kotlin/io/sakurasou/service/user/UserService.kt @@ -1,9 +1,11 @@ package io.sakurasou.service.user +import io.sakurasou.controller.request.UserInsertRequest + /** * @author ShiinaKin * 2024/9/5 15:30 */ interface UserService { - + suspend fun saveUser(userInsertRequest: UserInsertRequest) } \ No newline at end of file diff --git a/app/src/main/kotlin/io/sakurasou/service/user/UserServiceImpl.kt b/app/src/main/kotlin/io/sakurasou/service/user/UserServiceImpl.kt index eb50cc31..62b24e2c 100644 --- a/app/src/main/kotlin/io/sakurasou/service/user/UserServiceImpl.kt +++ b/app/src/main/kotlin/io/sakurasou/service/user/UserServiceImpl.kt @@ -1,13 +1,44 @@ package io.sakurasou.service.user +import at.favre.lib.crypto.bcrypt.BCrypt +import io.sakurasou.controller.request.UserInsertRequest +import io.sakurasou.model.DatabaseSingleton.dbQuery import io.sakurasou.model.dao.user.UserDao +import io.sakurasou.model.dto.UserInsertDTO +import io.sakurasou.service.album.AlbumService +import io.sakurasou.service.setting.SettingService +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime /** * @author ShiinaKin * 2024/9/5 15:30 */ class UserServiceImpl( - private val userDao: UserDao + private val userDao: UserDao, + private val albumService: AlbumService, + private val settingService: SettingService ) : UserService { + override suspend fun saveUser(userInsertRequest: UserInsertRequest) { + val rawPassword = userInsertRequest.password + val encodePassword = BCrypt.withDefaults().hashToString(12, rawPassword.toCharArray()) + + val systemSetting = settingService.getSystemSetting() + + val now = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) + val userInsertDTO = UserInsertDTO( + groupId = systemSetting.defaultGroupId, + username = userInsertRequest.username, + password = encodePassword, + email = userInsertRequest.email, + createTime = now, + updateTime = now + ) + dbQuery { + val userId = userDao.saveUser(userInsertDTO) + albumService.initAlbumForUser(userId) + } + } } \ No newline at end of file