diff --git a/common/str.go b/common/str.go index 71391f7..d61f06b 100644 --- a/common/str.go +++ b/common/str.go @@ -87,6 +87,24 @@ func StringsContains(strs []string, str string) bool { return false } +// StringsSubtract returns elements from source that are not in exclude. +func StringsSubtract(source, exclude []string) []string { + if len(exclude) == 0 { + return source + } + excludeSet := make(map[string]struct{}, len(exclude)) + for _, s := range exclude { + excludeSet[s] = struct{}{} + } + result := make([]string, 0, len(source)) + for _, s := range source { + if _, ok := excludeSet[s]; !ok { + result = append(result, s) + } + } + return result +} + // StringToByteSlice []byte only read, panic on append func StringToByteSlice(s string) []byte { tmp1 := (*[2]uintptr)(unsafe.Pointer(&s)) diff --git a/controller/user.go b/controller/user.go index 8524291..9bfb254 100644 --- a/controller/user.go +++ b/controller/user.go @@ -270,6 +270,7 @@ func GetUser(c *gin.Context) { common.ApiErrorI18n(c, i18n.MsgUserNoPermissionSameLevel) return } + user.ApplySyncedQuota() c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", @@ -523,13 +524,16 @@ func GetUserModels(c *gin.Context) { } groups := service.GetUserUsableGroups(user.Group) var models []string + seen := make(map[string]struct{}) for group := range groups { for _, g := range model.GetGroupEnabledModels(group) { - if !common.StringsContains(models, g) { + if _, ok := seen[g]; !ok { + seen[g] = struct{}{} models = append(models, g) } } } + models = common.StringsSubtract(models, model.GetDisabledModelNames(models)) c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", diff --git a/model/model_meta.go b/model/model_meta.go index f549ec3..ce03391 100644 --- a/model/model_meta.go +++ b/model/model_meta.go @@ -98,6 +98,16 @@ func (mi *Model) Delete() error { return DB.Delete(mi).Error } +// GetDisabledModelNames returns model names that are disabled (status = 0) from the given list. +func GetDisabledModelNames(names []string) []string { + if len(names) == 0 { + return nil + } + var disabled []string + DB.Table("models").Where("model_name IN ? AND status = 0", names).Pluck("model_name", &disabled) + return disabled +} + func GetVendorModelCounts() (map[int64]int64, error) { var stats []struct { VendorID int64 diff --git a/model/user.go b/model/user.go index 89f8c7e..eeec72c 100644 --- a/model/user.go +++ b/model/user.go @@ -214,6 +214,20 @@ func GetMaxUserId() int { return user.Id } +// ApplySyncedQuota 将同步用户的 quota 替换为 synced_quota, +// 使 API 返回的 quota 对所有用户类型都表示实际可用余额。 +func (u *User) ApplySyncedQuota() { + if u.IsSyncedUser() { + u.Quota = u.SyncedQuota + } +} + +func applySyncedUserQuota(users []*User) { + for _, u := range users { + u.ApplySyncedQuota() + } +} + func GetAllUsers(pageInfo *common.PageInfo) (users []*User, total int64, err error) { // Start transaction tx := DB.Begin() @@ -245,6 +259,7 @@ func GetAllUsers(pageInfo *common.PageInfo) (users []*User, total int64, err err return nil, 0, err } + applySyncedUserQuota(users) return users, total, nil } @@ -312,6 +327,7 @@ func SearchUsers(keyword string, group string, startIdx int, num int) ([]*User, return nil, 0, err } + applySyncedUserQuota(users) return users, total, nil }