169 lines
5.1 KiB
Go
169 lines
5.1 KiB
Go
package system
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
"kra/internal/biz"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type permissionRepo struct{ data Provider }
|
|
|
|
func NewPermissionRepo(data Provider) biz.PermissionRepo { return &permissionRepo{data: data} }
|
|
|
|
type menuButtonPO struct {
|
|
ID uint `gorm:"primaryKey"`
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
DeletedAt gorm.DeletedAt `gorm:"index"`
|
|
Name string
|
|
Description string `gorm:"column:desc"`
|
|
MenuID uint `gorm:"column:sys_base_menu_id"`
|
|
}
|
|
|
|
func (menuButtonPO) TableName() string { return "sys_base_menu_btns" }
|
|
|
|
type authorityButtonPO struct {
|
|
AuthorityID uint `gorm:"column:authority_id"`
|
|
MenuID uint `gorm:"column:sys_menu_id"`
|
|
ButtonID uint `gorm:"column:sys_base_menu_btn_id"`
|
|
}
|
|
|
|
func (authorityButtonPO) TableName() string { return "sys_authority_btns" }
|
|
|
|
func (r *permissionRepo) Buttons(ctx context.Context, menuID uint) ([]*biz.MenuButton, error) {
|
|
var pos []menuButtonPO
|
|
if err := r.data.DB().WithContext(ctx).Where("sys_base_menu_id = ?", menuID).Find(&pos).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
out := make([]*biz.MenuButton, 0, len(pos))
|
|
for _, po := range pos {
|
|
out = append(out, menuButtonFromPO(po))
|
|
}
|
|
return out, nil
|
|
}
|
|
func (r *permissionRepo) SetAuthorityButtons(ctx context.Context, aid uint, buttons map[uint][]uint) error {
|
|
if err := (&authorityAccessRepo{data: r.data}).checkAuthorityIDAuth(ctx, aid); err != nil {
|
|
return err
|
|
}
|
|
if err := r.checkButtonAssignmentAuth(ctx, buttons); err != nil {
|
|
return err
|
|
}
|
|
return r.data.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Where("authority_id = ?", aid).Delete(&authorityButtonPO{}).Error; err != nil {
|
|
return err
|
|
}
|
|
var links []authorityButtonPO
|
|
for menuID, ids := range buttons {
|
|
for _, id := range ids {
|
|
links = append(links, authorityButtonPO{AuthorityID: aid, MenuID: menuID, ButtonID: id})
|
|
}
|
|
}
|
|
if len(links) > 0 {
|
|
return tx.Create(&links).Error
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
func (r *permissionRepo) SelectedButtons(ctx context.Context, aid, menuID uint) ([]uint, error) {
|
|
var rows []authorityButtonPO
|
|
if err := r.data.DB().WithContext(ctx).Where("authority_id = ? AND sys_menu_id = ?", aid, menuID).Find(&rows).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
var ids []uint
|
|
for _, row := range rows {
|
|
ids = append(ids, row.ButtonID)
|
|
}
|
|
return ids, nil
|
|
}
|
|
func (r *permissionRepo) SetSelectedButtons(ctx context.Context, aid, menuID uint, ids []uint) error {
|
|
if err := (&authorityAccessRepo{data: r.data}).checkAuthorityIDAuth(ctx, aid); err != nil {
|
|
return err
|
|
}
|
|
if err := r.checkButtonAssignmentAuth(ctx, map[uint][]uint{menuID: ids}); err != nil {
|
|
return err
|
|
}
|
|
return r.data.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Where("authority_id = ? AND sys_menu_id = ?", aid, menuID).Delete(&authorityButtonPO{}).Error; err != nil {
|
|
return err
|
|
}
|
|
links := make([]authorityButtonPO, 0, len(ids))
|
|
for _, id := range ids {
|
|
links = append(links, authorityButtonPO{AuthorityID: aid, MenuID: menuID, ButtonID: id})
|
|
}
|
|
if len(links) > 0 {
|
|
return tx.Create(&links).Error
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
func (r *permissionRepo) CanRemoveButton(ctx context.Context, id string) (bool, error) {
|
|
var row authorityButtonPO
|
|
err := r.data.DB().WithContext(ctx).Where("sys_base_menu_btn_id = ?", id).First(&row).Error
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return true, nil
|
|
}
|
|
if err != nil {
|
|
return false, errors.New("此按钮正在被使用无法删除")
|
|
}
|
|
return false, nil
|
|
}
|
|
func (r *permissionRepo) AuthorityButtonIDs(ctx context.Context, aid uint) ([]uint, error) {
|
|
var ids []uint
|
|
err := r.data.DB().WithContext(ctx).Model(&authorityButtonPO{}).Where("authority_id = ?", aid).Pluck("sys_base_menu_btn_id", &ids).Error
|
|
return ids, err
|
|
}
|
|
|
|
func (r *permissionRepo) checkButtonAssignmentAuth(ctx context.Context, buttons map[uint][]uint) error {
|
|
actor, allowedAuthorities, strict, err := (&authorityAccessRepo{data: r.data}).strictAuthorityAccess(ctx)
|
|
if err != nil || !strict {
|
|
return err
|
|
}
|
|
return checkButtonAssignment(r.data.DB().WithContext(ctx), actor.AuthorityID, allowedAuthorities[actor.AuthorityID], buttons)
|
|
}
|
|
|
|
func checkButtonAssignment(db *gorm.DB, actorID uint, root bool, buttons map[uint][]uint) error {
|
|
requested := make(map[[2]uint]struct{})
|
|
buttonIDs := make([]uint, 0)
|
|
for menuID, ids := range buttons {
|
|
for _, buttonID := range ids {
|
|
key := [2]uint{menuID, buttonID}
|
|
if _, exists := requested[key]; exists {
|
|
continue
|
|
}
|
|
requested[key] = struct{}{}
|
|
buttonIDs = append(buttonIDs, buttonID)
|
|
}
|
|
}
|
|
if len(requested) == 0 {
|
|
return nil
|
|
}
|
|
allowed := make(map[[2]uint]bool, len(requested))
|
|
if root {
|
|
var rows []menuButtonPO
|
|
if err := db.Where("id IN ?", buttonIDs).Find(&rows).Error; err != nil {
|
|
return err
|
|
}
|
|
for _, row := range rows {
|
|
allowed[[2]uint{row.MenuID, row.ID}] = true
|
|
}
|
|
} else {
|
|
var rows []authorityButtonPO
|
|
if err := db.Where("authority_id = ?", actorID).Find(&rows).Error; err != nil {
|
|
return err
|
|
}
|
|
for _, row := range rows {
|
|
allowed[[2]uint{row.MenuID, row.ButtonID}] = true
|
|
}
|
|
}
|
|
for key := range requested {
|
|
if !allowed[key] {
|
|
return errors.New("添加失败,请勿跨级操作")
|
|
}
|
|
}
|
|
return nil
|
|
}
|