PermissionServiceImpl.kt

package io.github.lishangbu.avalon.auth.service.impl

import io.github.lishangbu.avalon.auth.entity.Permission
import io.github.lishangbu.avalon.auth.entity.dto.PermissionSpecification
import io.github.lishangbu.avalon.auth.entity.dto.PermissionView
import io.github.lishangbu.avalon.auth.entity.dto.SavePermissionInput
import io.github.lishangbu.avalon.auth.entity.dto.UpdatePermissionInput
import io.github.lishangbu.avalon.auth.repository.AuthorizationFetchers
import io.github.lishangbu.avalon.auth.repository.MenuRepository
import io.github.lishangbu.avalon.auth.repository.PermissionRepository
import io.github.lishangbu.avalon.auth.service.PermissionService
import io.github.lishangbu.avalon.jimmer.support.readOrNull
import org.babyfish.jimmer.sql.ast.mutation.SaveMode
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

/** 权限点服务实现。 */
@Service
class PermissionServiceImpl(
    private val permissionRepository: PermissionRepository,
    private val menuRepository: MenuRepository,
) : PermissionService {
    override fun listByCondition(specification: PermissionSpecification): List<PermissionView> = permissionRepository.listViews(specification)

    override fun getById(id: Long): PermissionView? = permissionRepository.loadViewById(id)

    @Transactional(rollbackFor = [Exception::class])
    override fun save(command: SavePermissionInput): PermissionView {
        val permission = bindMenu(command.toEntity())
        return permissionRepository.save(permission, SaveMode.INSERT_ONLY).let(::reloadView)
    }

    @Transactional(rollbackFor = [Exception::class])
    override fun update(command: UpdatePermissionInput): PermissionView {
        val permission = bindMenu(command.toEntity())
        return permissionRepository.save(permission).let(::reloadView)
    }

    @Transactional(rollbackFor = [Exception::class])
    override fun removeById(id: Long) {
        permissionRepository.deleteById(id)
    }

    private fun bindMenu(permission: Permission): Permission {
        val menuId =
            permission.readOrNull { menu }?.id
                ?: throw IllegalArgumentException("权限点必须绑定所属菜单")

        val menu =
            menuRepository.findNullable(menuId, AuthorizationFetchers.MENU)
                ?: throw IllegalArgumentException("所属菜单不存在")

        return Permission(permission) {
            this.menu = menu
        }
    }

    private fun reloadView(permission: Permission): PermissionView =
        requireNotNull(permissionRepository.loadViewById(permission.id)) {
            "未找到 ID=${permission.id} 对应的权限点"
        }
}