Files
kra-new/internal/data/system/business_roles.go
T

120 lines
3.5 KiB
Go

package system
import (
"fmt"
"gorm.io/gorm"
)
// The migration resolves historical IDs once. Runtime role assignment uses
// business_level and is independent of editable names and migration helpers.
func migrateBusinessRoles(db *gorm.DB) error {
if !db.Migrator().HasColumn(&authorityPO{}, "BusinessLevel") {
if err := db.Migrator().AddColumn(&authorityPO{}, "BusinessLevel"); err != nil {
return err
}
}
var roles []authorityPO
if err := db.Find(&roles).Error; err != nil {
return err
}
if len(roles) == 0 {
return ensureBusinessRoleIndex(db)
}
legacy := map[int]string{1: "2083497078545207297", 2: "2087435436573081601", 3: "2087361690139152385"}
names := map[int]string{1: "一级商务", 2: "二级商务", 3: "三级商务"}
hasMap := db.Migrator().HasTable("sw_kra_id_map")
applicable := hasMap
for _, role := range roles {
if role.BusinessLevel != nil {
applicable = true
}
for _, name := range names {
if role.AuthorityName == name {
applicable = true
}
}
}
if !applicable {
return ensureBusinessRoleIndex(db)
}
bindings := map[int]uint{}
for _, role := range roles {
if role.BusinessLevel == nil {
continue
}
level := *role.BusinessLevel
if level < 1 || level > 3 || role.AuthorityID == 888 || bindings[level] != 0 {
return fmt.Errorf("invalid or duplicate business role level %d", level)
}
bindings[level] = role.AuthorityID
}
for level := 1; level <= 3; level++ {
if bindings[level] != 0 {
continue
}
var ids []uint
if hasMap {
if err := db.Table("sw_kra_id_map m").Select("m.new_id").Joins("JOIN sys_authorities a ON a.authority_id=m.new_id AND a.deleted_at IS NULL").Where("m.entity='role' AND m.old_id=? AND m.new_id<>888", legacy[level]).Scan(&ids).Error; err != nil {
return err
}
} else {
for _, role := range roles {
if role.AuthorityID != 888 && role.AuthorityName == names[level] {
ids = append(ids, role.AuthorityID)
}
}
}
if len(ids) != 1 {
// A generic first installation can have only the administrator.
// Migrated SW databases must supply all three mapped roles.
if !hasMap && len(bindings) == 0 && len(roles) == 1 && roles[0].AuthorityID == 888 {
return ensureBusinessRoleIndex(db)
}
return fmt.Errorf("business level %d requires exactly one migration role", level)
}
for _, id := range bindings {
if id == ids[0] {
return fmt.Errorf("one role cannot represent multiple business levels")
}
}
bindings[level] = ids[0]
}
if err := db.Transaction(func(tx *gorm.DB) error {
for level, id := range bindings {
if err := tx.Model(&authorityPO{}).Where("authority_id=?", id).UpdateColumn("business_level", level).Error; err != nil {
return err
}
}
return nil
}); err != nil {
return err
}
return ensureBusinessRoleIndex(db)
}
func ensureBusinessRoleIndex(db *gorm.DB) error {
const name = "uk_authority_business_level"
if db.Migrator().HasIndex(&authorityPO{}, name) {
return nil
}
return db.Migrator().CreateIndex(&authorityPO{}, name)
}
func CheckBusinessRoles(db *gorm.DB) error {
var roles []authorityPO
if err := db.Where("business_level IS NOT NULL").Find(&roles).Error; err != nil {
return err
}
seen := map[int]bool{}
for _, role := range roles {
if *role.BusinessLevel < 1 || *role.BusinessLevel > 3 || role.AuthorityID == 888 || seen[*role.BusinessLevel] {
return fmt.Errorf("invalid business role binding")
}
seen[*role.BusinessLevel] = true
}
if len(seen) != 3 {
return fmt.Errorf("three business role bindings are required")
}
return nil
}