diff --git a/app/src/main/kotlin/io/sakurasou/config/InstanceCenter.kt b/app/src/main/kotlin/io/sakurasou/config/InstanceCenter.kt index a2dea2b0..485774a0 100644 --- a/app/src/main/kotlin/io/sakurasou/config/InstanceCenter.kt +++ b/app/src/main/kotlin/io/sakurasou/config/InstanceCenter.kt @@ -89,8 +89,8 @@ object InstanceCenter { authService = AuthServiceImpl(userDao, relationDao) groupService = GroupServiceImpl(groupDao, relationDao) - userService = UserServiceImpl(userDao, albumDao, settingService) commonService = CommonServiceImpl(userDao, albumDao, settingService) + userService = UserServiceImpl(userDao, groupDao, albumDao, imageDao, settingService) roleService = RoleServiceImpl(roleDao, permissionDao, relationDao) } diff --git a/app/src/main/kotlin/io/sakurasou/model/dao/image/ImageDao.kt b/app/src/main/kotlin/io/sakurasou/model/dao/image/ImageDao.kt index 8fa5f618..bd8af0c5 100644 --- a/app/src/main/kotlin/io/sakurasou/model/dao/image/ImageDao.kt +++ b/app/src/main/kotlin/io/sakurasou/model/dao/image/ImageDao.kt @@ -1,5 +1,6 @@ package io.sakurasou.model.dao.image +import io.sakurasou.model.dto.ImageCountAndTotalSizeDTO import io.sakurasou.model.dto.ImageInsertDTO import io.sakurasou.model.entity.Image @@ -8,7 +9,9 @@ import io.sakurasou.model.entity.Image * 2024/9/5 15:33 */ interface ImageDao { + fun saveImage(insertDTO: ImageInsertDTO): Long + fun updateImageGroupIdByUserId(userId: Long, groupId: Long): Int fun listImageByAlbumId(albumId: Long): List + fun getImageCountAndTotalSizeOfUser(userId: Long): ImageCountAndTotalSizeDTO fun getImageById(imageId: Long): Image? - fun saveImage(insertDTO: ImageInsertDTO): Long } \ No newline at end of file diff --git a/app/src/main/kotlin/io/sakurasou/model/dao/image/ImageDaoImpl.kt b/app/src/main/kotlin/io/sakurasou/model/dao/image/ImageDaoImpl.kt index d8b394df..6d39ddc3 100644 --- a/app/src/main/kotlin/io/sakurasou/model/dao/image/ImageDaoImpl.kt +++ b/app/src/main/kotlin/io/sakurasou/model/dao/image/ImageDaoImpl.kt @@ -1,29 +1,15 @@ package io.sakurasou.model.dao.image +import io.sakurasou.model.dto.ImageCountAndTotalSizeDTO import io.sakurasou.model.dto.ImageInsertDTO import io.sakurasou.model.entity.Image -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.insertAndGetId -import org.jetbrains.exposed.sql.selectAll +import org.jetbrains.exposed.sql.* /** * @author ShiinaKin * 2024/9/5 15:35 */ class ImageDaoImpl : ImageDao { - override fun listImageByAlbumId(albumId: Long): List { - return Images.selectAll() - .where { Images.albumId eq albumId } - .map { toImage(it) } - } - - override fun getImageById(imageId: Long): Image? { - return Images.selectAll() - .where { Images.id eq imageId } - .map { toImage(it) } - .firstOrNull() - } - override fun saveImage(insertDTO: ImageInsertDTO): Long { val entityID = Images.insertAndGetId { it[userId] = insertDTO.userId @@ -47,6 +33,38 @@ class ImageDaoImpl : ImageDao { return entityID.value } + override fun updateImageGroupIdByUserId(userId: Long, groupId: Long): Int { + return Images.update({ Images.userId eq userId }) { + it[Images.groupId] = groupId + } + } + + override fun listImageByAlbumId(albumId: Long): List { + return Images.selectAll() + .where { Images.albumId eq albumId } + .map { toImage(it) } + } + + override fun getImageCountAndTotalSizeOfUser(userId: Long): ImageCountAndTotalSizeDTO { + return Images + .select(Images.id.count(), Images.size.sum()) + .where { Images.userId eq userId } + .first() + .let { + ImageCountAndTotalSizeDTO( + count = it[Images.id.count()], + totalSize = it[Images.size.sum()] ?: 0.0 + ) + } + } + + override fun getImageById(imageId: Long): Image? { + return Images.selectAll() + .where { Images.id eq imageId } + .map { toImage(it) } + .firstOrNull() + } + private fun toImage(it: ResultRow) = Image( it[Images.id].value, it[Images.userId], diff --git a/app/src/main/kotlin/io/sakurasou/model/dao/user/UserDao.kt b/app/src/main/kotlin/io/sakurasou/model/dao/user/UserDao.kt index 8906f4b9..95b47333 100644 --- a/app/src/main/kotlin/io/sakurasou/model/dao/user/UserDao.kt +++ b/app/src/main/kotlin/io/sakurasou/model/dao/user/UserDao.kt @@ -1,6 +1,11 @@ package io.sakurasou.model.dao.user +import io.sakurasou.controller.request.PageRequest +import io.sakurasou.controller.vo.PageResult +import io.sakurasou.controller.vo.UserPageVO import io.sakurasou.model.dto.UserInsertDTO +import io.sakurasou.model.dto.UserManageUpdateDTO +import io.sakurasou.model.dto.UserSelfUpdateDTO import io.sakurasou.model.entity.User /** @@ -10,7 +15,11 @@ import io.sakurasou.model.entity.User interface UserDao { fun saveUser(user: UserInsertDTO): Long fun deleteUserById(id: Long): Int + fun updateSelfById(selfUpdateDTO: UserSelfUpdateDTO): Int + fun updateUserById(manageUpdateDTO: UserManageUpdateDTO): Int + fun updateUserBanStatusById(id: Long, isBan: Boolean): Int fun updateUserDefaultAlbumId(userId: Long, defaultAlbumId: Long): Int fun findUserById(id: Long): User? fun findUserByName(name: String): User? + fun pagination(pageRequest: PageRequest): PageResult } \ No newline at end of file diff --git a/app/src/main/kotlin/io/sakurasou/model/dao/user/UserDaoImpl.kt b/app/src/main/kotlin/io/sakurasou/model/dao/user/UserDaoImpl.kt index 528c94cb..99b61660 100644 --- a/app/src/main/kotlin/io/sakurasou/model/dao/user/UserDaoImpl.kt +++ b/app/src/main/kotlin/io/sakurasou/model/dao/user/UserDaoImpl.kt @@ -1,12 +1,17 @@ package io.sakurasou.model.dao.user +import io.sakurasou.controller.request.PageRequest +import io.sakurasou.controller.vo.PageResult +import io.sakurasou.controller.vo.UserPageVO +import io.sakurasou.exception.controller.param.PagingParameterWrongException +import io.sakurasou.model.dao.group.Groups +import io.sakurasou.model.dao.image.Images import io.sakurasou.model.dto.UserInsertDTO +import io.sakurasou.model.dto.UserManageUpdateDTO +import io.sakurasou.model.dto.UserSelfUpdateDTO import io.sakurasou.model.entity.User +import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.insertAndGetId -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.update /** * @author ShiinaKin @@ -32,6 +37,33 @@ class UserDaoImpl : UserDao { return Users.deleteWhere { Users.id eq id } } + override fun updateSelfById(selfUpdateDTO: UserSelfUpdateDTO): Int { + return Users.update({ Users.id eq selfUpdateDTO.id }) { + it[password] = selfUpdateDTO.password + it[email] = selfUpdateDTO.email + it[isDefaultImagePrivate] = selfUpdateDTO.isDefaultImagePrivate + it[defaultAlbumId] = selfUpdateDTO.defaultAlbumId + it[updateTime] = selfUpdateDTO.updateTime + } + } + + override fun updateUserById(manageUpdateDTO: UserManageUpdateDTO): Int { + return Users.update({ Users.id eq manageUpdateDTO.id }) { + it[groupId] = manageUpdateDTO.groupId + it[password] = manageUpdateDTO.password + it[email] = manageUpdateDTO.email + it[isDefaultImagePrivate] = manageUpdateDTO.isDefaultImagePrivate + it[defaultAlbumId] = manageUpdateDTO.defaultAlbumId + it[updateTime] = manageUpdateDTO.updateTime + } + } + + override fun updateUserBanStatusById(id: Long, isBan: Boolean): Int { + return Users.update({ Users.id eq id }) { + it[isBanned] = isBan + } + } + override fun updateUserDefaultAlbumId(userId: Long, defaultAlbumId: Long): Int { return Users.update({ Users.id eq userId }) { it[Users.defaultAlbumId] = defaultAlbumId @@ -41,36 +73,87 @@ class UserDaoImpl : UserDao { override fun findUserById(id: Long): User? { return Users.selectAll() .where { Users.id eq id } - .map { row -> - User( - row[Users.id].value, - row[Users.groupId], - row[Users.name], - row[Users.password], - row[Users.email], - row[Users.isDefaultImagePrivate], - row[Users.defaultAlbumId]!!, - row[Users.createTime], - row[Users.updateTime] - ) - }.firstOrNull() + .map { row -> toUser(row) } + .firstOrNull() } override fun findUserByName(name: String): User? { return Users.selectAll() .where { Users.name eq name } - .map { row -> - User( - row[Users.id].value, - row[Users.groupId], - row[Users.name], - row[Users.password], - row[Users.email], - row[Users.isDefaultImagePrivate], - row[Users.defaultAlbumId]!!, - row[Users.createTime], - row[Users.updateTime] - ) - }.firstOrNull() + .map { row -> toUser(row) } + .firstOrNull() } + + override fun pagination(pageRequest: PageRequest): PageResult { + val page = pageRequest.page + val pageSize = pageRequest.pageSize + + val offset = (page - 1) * pageSize + + val totalRecords: Long = Users.selectAll().count() + val query = Users + .join(Groups, JoinType.INNER, Users.groupId, Groups.id) + .join(Images, JoinType.INNER, Users.id, Images.userId) + .select( + Users.id, Users.name, Users.isBanned, + Groups.name, Images.id.count(), Images.size.sum() + ) + .groupBy(Users.id, Users.name, Users.isBanned, Groups.name) + .limit(pageSize, offset) + + val finalQuery = pageRequest.orderBy?.let { + val sortOrder = SortOrder.valueOf(pageRequest.order?.uppercase() ?: "DESC") + setPageQueryCondition(query, it, sortOrder) + } ?: query + + val data = finalQuery.map { + UserPageVO( + id = it[Users.id].value, + username = it[Users.name], + groupName = it[Groups.name], + isBanned = it[Users.isBanned], + imageCount = it[Images.id.count()], + totalImageSize = it[Images.size.sum()] ?: 0.0 + ) + }.toList() + + val pageResult = PageResult( + page = page, + pageSize = pageSize, + total = totalRecords, + data = data + ) + return pageResult + } + + private val columnMap: Map> = mapOf( + "id" to Users.id, + "name" to Users.name, + "isBanned" to Users.isBanned, + "groupName" to Groups.name, + ) + + private fun setPageQueryCondition(query: Query, columnName: String, order: SortOrder): Query { + val column = columnMap[columnName] ?: run { + when (columnName) { + "imageCount" -> Images.id.count() + "totalImageSize" -> Images.size.sum() + else -> throw PagingParameterWrongException("Column $columnName not found in user pagination params") + } + } + return query.orderBy(column, order) + } + + private fun toUser(row: ResultRow) = User( + id = row[Users.id].value, + groupId = row[Users.groupId], + name = row[Users.name], + password = row[Users.password], + email = row[Users.email], + isDefaultImagePrivate = row[Users.isDefaultImagePrivate], + defaultAlbumId = row[Users.defaultAlbumId]!!, + isBanned = row[Users.isBanned], + updateTime = row[Users.updateTime], + createTime = row[Users.createTime] + ) } \ No newline at end of file diff --git a/app/src/main/kotlin/io/sakurasou/model/dto/ImageDTO.kt b/app/src/main/kotlin/io/sakurasou/model/dto/ImageDTO.kt index b54ffb64..8f6611c4 100644 --- a/app/src/main/kotlin/io/sakurasou/model/dto/ImageDTO.kt +++ b/app/src/main/kotlin/io/sakurasou/model/dto/ImageDTO.kt @@ -24,4 +24,9 @@ data class ImageInsertDTO( val sha1: String, val isPrivate: Boolean, val createTime: LocalDateTime +) + +data class ImageCountAndTotalSizeDTO( + val count: Long, + val totalSize: Double ) \ No newline at end of file diff --git a/app/src/main/kotlin/io/sakurasou/model/dto/UserDTO.kt b/app/src/main/kotlin/io/sakurasou/model/dto/UserDTO.kt index e9dc2df5..df3d61fc 100644 --- a/app/src/main/kotlin/io/sakurasou/model/dto/UserDTO.kt +++ b/app/src/main/kotlin/io/sakurasou/model/dto/UserDTO.kt @@ -17,5 +17,22 @@ data class UserInsertDTO( val updateTime: LocalDateTime, val createTime: LocalDateTime ) + +data class UserSelfUpdateDTO( + val id: Long, + val password: String, + val email: String?, + val isDefaultImagePrivate: Boolean, + val defaultAlbumId: Long?, + val updateTime: LocalDateTime +) + +data class UserManageUpdateDTO( + val id: Long, + val groupId: Long, + val password: String, + val email: String?, + val isDefaultImagePrivate: Boolean, + val defaultAlbumId: Long?, val updateTime: LocalDateTime ) \ 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 2140e435..5b645254 100644 --- a/app/src/main/kotlin/io/sakurasou/service/user/UserServiceImpl.kt +++ b/app/src/main/kotlin/io/sakurasou/service/user/UserServiceImpl.kt @@ -5,6 +5,8 @@ import io.sakurasou.controller.request.UserInsertRequest import io.sakurasou.exception.controller.access.SignupNotAllowedException import io.sakurasou.model.DatabaseSingleton.dbQuery import io.sakurasou.model.dao.album.AlbumDao +import io.sakurasou.model.dao.group.GroupDao +import io.sakurasou.model.dao.image.ImageDao import io.sakurasou.model.dao.user.UserDao import io.sakurasou.model.dto.UserInsertDTO import io.sakurasou.service.setting.SettingService @@ -18,7 +20,9 @@ import kotlinx.datetime.toLocalDateTime */ class UserServiceImpl( private val userDao: UserDao, + private val groupDao: GroupDao, private val albumDao: AlbumDao, + private val imageDao: ImageDao, private val settingService: SettingService ) : UserService { override suspend fun saveUser(userInsertRequest: UserInsertRequest) {