hyapp-server/server/admin/internal/repository/app_scope_repository.go
2026-07-14 17:12:39 +08:00

131 lines
3.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package repository
import (
"errors"
"sort"
"strings"
"hyapp-admin-server/internal/appctx"
"hyapp-admin-server/internal/model"
"gorm.io/gorm"
)
type AppAccess struct {
Mode string
AppCodes []string
}
func (access AppAccess) Allows(appCode string) bool {
appCode = strings.ToLower(strings.TrimSpace(appCode))
if appCode == "" {
return false
}
if access.Mode == model.UserAppScopeModeAll {
return true
}
for _, allowed := range access.AppCodes {
if allowed == appCode {
return true
}
}
return false
}
func (s *Store) AppAccessForUser(userID uint) (AppAccess, error) {
if userID == 0 {
return AppAccess{Mode: model.UserAppScopeModeNone}, nil
}
var user model.User
if err := s.db.Select("id", "app_scope_mode").First(&user, userID).Error; err != nil {
return AppAccess{}, err
}
mode := normalizeAppScopeMode(user.AppScopeMode)
if mode != model.UserAppScopeModeSelected {
return AppAccess{Mode: mode}, nil
}
var scopes []model.UserAppScope
if err := s.db.Where("user_id = ?", userID).Order("app_code ASC").Find(&scopes).Error; err != nil {
return AppAccess{}, err
}
appCodes := make([]string, 0, len(scopes))
for _, scope := range scopes {
appCodes = append(appCodes, scope.AppCode)
}
return AppAccess{Mode: mode, AppCodes: appCodes}, nil
}
func (s *Store) ReplaceUserAppScopes(userID uint, mode string, appCodes []string) (AppAccess, error) {
if userID == 0 {
return AppAccess{}, errors.New("user id is required")
}
rawMode := strings.ToLower(strings.TrimSpace(mode))
if rawMode != model.UserAppScopeModeAll && rawMode != model.UserAppScopeModeSelected && rawMode != model.UserAppScopeModeNone {
return AppAccess{}, errors.New("app scope mode must be all, selected, or none")
}
mode = rawMode
normalizedCodes := normalizeAppCodes(appCodes)
if mode == model.UserAppScopeModeSelected && len(normalizedCodes) == 0 {
return AppAccess{}, errors.New("selected app scope requires app codes")
}
if mode != model.UserAppScopeModeSelected {
normalizedCodes = nil
}
err := s.db.Transaction(func(tx *gorm.DB) error {
var user model.User
if err := tx.First(&user, userID).Error; err != nil {
return err
}
// 先删除旧明细再更新模式,使 all/none 不残留会被未来代码误读的 selected 行。
if err := tx.Where("user_id = ?", userID).Delete(&model.UserAppScope{}).Error; err != nil {
return err
}
if len(normalizedCodes) > 0 {
scopes := make([]model.UserAppScope, 0, len(normalizedCodes))
for _, appCode := range normalizedCodes {
scopes = append(scopes, model.UserAppScope{UserID: userID, AppCode: appCode})
}
if err := tx.Create(&scopes).Error; err != nil {
return err
}
}
return tx.Model(&user).Update("app_scope_mode", mode).Error
})
if err != nil {
return AppAccess{}, err
}
return AppAccess{Mode: mode, AppCodes: normalizedCodes}, nil
}
func normalizeAppScopeMode(mode string) string {
switch strings.ToLower(strings.TrimSpace(mode)) {
case model.UserAppScopeModeAll:
return model.UserAppScopeModeAll
case model.UserAppScopeModeSelected:
return model.UserAppScopeModeSelected
default:
return model.UserAppScopeModeNone
}
}
func normalizeAppCodes(appCodes []string) []string {
seen := make(map[string]struct{}, len(appCodes))
out := make([]string, 0, len(appCodes))
for _, value := range appCodes {
// appctx.Normalize 会把空值回退 laluApp scope 的空值代表无授权,必须先独立过滤。
value = strings.ToLower(strings.TrimSpace(value))
if value == "" {
continue
}
value = appctx.Normalize(value)
if _, ok := seen[value]; ok {
continue
}
seen[value] = struct{}{}
out = append(out, value)
}
sort.Strings(out)
return out
}