package logic import ( "context" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" v1 "tool-api/api/user/v1" "tool-api/internal/consts" "tool-api/internal/model/entity" ) // ===== 等级有效期(会员)判定 ===== // // 背景:users.level_key 是单值,无法表达「会员到期」。引入 users.level_expire_at 后, // 所有依赖等级的地方都必须先经过 EffectiveLevelKey 收敛,否则会出现「会员已过期但 // 工具仍可用」的越权问题。 // // 约定: // - level_expire_at IS NULL → 永久有效(管理员手动分配 / 种子默认等级) // - level_expire_at <= now → 已过期,回落 consts.DefaultLevelKey // - level_expire_at > now → 正常返回 users.level_key // EffectiveLevelKey 计算用户当前实际生效的等级 key。一处判定,全处复用。 func EffectiveLevelKey(user *entity.Users) string { if user == nil || user.LevelKey == "" { return consts.DefaultLevelKey } if IsLevelExpired(user) { return consts.DefaultLevelKey } return user.LevelKey } // IsLevelExpired 等级是否已过期 func IsLevelExpired(user *entity.Users) bool { if user == nil || user.LevelExpireAt == nil || user.LevelExpireAt.IsZero() { return false } return user.LevelExpireAt.Before(gtime.Now()) } // EffectiveLevelInfo 当前生效等级(含已授权模块),已过期时返回默认等级 func EffectiveLevelInfo(ctx context.Context, user *entity.Users) (*v1.LevelInfo, error) { return GetLevelByKey(ctx, EffectiveLevelKey(user)) } // levelWeight 等级权限权重,取 levels.sort(越大权限越高)。 // 查询失败时回落 0,保证不因权重查询异常而误升权。 func levelWeight(ctx context.Context, levelKey string) int { if levelKey == "" { return 0 } value, err := g.Model(consts.TableLevels). Where("level_key", levelKey). Where("is_enabled", 1). Value("sort") if err != nil || value == nil { return 0 } return value.Int() } // CanLevelAccess 判断某个等级是否包含指定模块(供发货后自检 / 管理端复用) func CanLevelAccess(ctx context.Context, levelKey, moduleKey string) bool { level, err := GetLevelByKey(ctx, levelKey) if err != nil { return false } return slicesContain(level.Modules, moduleKey) }