Files
mce/internal/repository/user_repo.go

184 lines
5.7 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 (
"metazone.cc/metalab/internal/model"
"gorm.io/gorm"
)
// UserRepo 用户数据访问
type UserRepo struct {
db *gorm.DB
}
// NewUserRepo 构造函数
func NewUserRepo(db *gorm.DB) *UserRepo {
return &UserRepo{db: db}
}
// Create 创建用户
func (r *UserRepo) Create(user *model.User) error {
return r.db.Create(user).Error
}
// FindByEmail 按邮箱查找用户
func (r *UserRepo) FindByEmail(email string) (*model.User, error) {
var user model.User
err := r.db.Where("email = ?", email).First(&user).Error
if err != nil {
return nil, err
}
return &user, nil
}
// FindByID 按 UID 查找用户
func (r *UserRepo) FindByID(id uint) (*model.User, error) {
var user model.User
err := r.db.First(&user, id).Error
if err != nil {
return nil, err
}
return &user, nil
}
// FindByUsername 按用户名查找
func (r *UserRepo) FindByUsername(username string) (*model.User, error) {
var user model.User
err := r.db.Where("username = ?", username).First(&user).Error
if err != nil {
return nil, err
}
return &user, nil
}
// ExistsByEmail 检查邮箱是否已注册
func (r *UserRepo) ExistsByEmail(email string) (bool, error) {
var count int64
err := r.db.Model(&model.User{}).Where("email = ?", email).Count(&count).Error
return count > 0, err
}
// ExistsByUsername 检查用户名是否已存在
func (r *UserRepo) ExistsByUsername(username string) (bool, error) {
var count int64
err := r.db.Model(&model.User{}).Where("username = ?", username).Count(&count).Error
return count > 0, err
}
// ExistsByEmailExclude 检查邮箱是否被其他 active 用户占用(解锁前冲突检查)
func (r *UserRepo) ExistsByEmailExclude(email string, excludeUID uint) (bool, error) {
var count int64
err := r.db.Model(&model.User{}).
Where("email = ? AND uid != ?", email, excludeUID).
Count(&count).Error
return count > 0, err
}
// IncrementTokenVersion 递增用户令牌版本,使所有已签发的 JWT 即时失效
func (r *UserRepo) IncrementTokenVersion(userID uint) error {
return r.db.Unscoped().Model(&model.User{}).Where("uid = ?", userID).
UpdateColumn("token_version", gorm.Expr("token_version + 1")).Error
}
// FindTokenVersion 按 UID 查询当前令牌版本(轻量查询,仅 SELECT token_version
func (r *UserRepo) FindTokenVersion(userID uint) (int, error) {
var version int
err := r.db.Model(&model.User{}).
Select("token_version").
Where("uid = ?", userID).
Scan(&version).Error
return version, err
}
// FindByIDForAuth 认证专用查询:返回 uid/email/username/role/status/token_version
// 比 FindByID 轻量(不查 avatar、bio 等无用字段),避免全量 SELECT *
// 使用默认 scope排除软删除locked 用户不可持有有效 JWT
func (r *UserRepo) FindByIDForAuth(userID uint) (*model.User, error) {
var user model.User
err := r.db.Select("uid", "email", "username", "role", "status", "token_version").
First(&user, userID).Error
if err != nil {
return nil, err
}
return &user, nil
}
// FindByIDUnscoped 管理后台专用:含软删除用户,用于解锁/封禁等操作
func (r *UserRepo) FindByIDUnscoped(userID uint) (*model.User, error) {
var user model.User
err := r.db.Unscoped().Select("uid", "email", "username", "role", "status", "token_version", "deleted_at").
First(&user, userID).Error
if err != nil {
return nil, err
}
return &user, nil
}
// UpdateStatus 更新用户状态含软删除用户locked 状态变更需要)
func (r *UserRepo) UpdateStatus(uid uint, status string) error {
return r.db.Unscoped().Model(&model.User{}).Where("uid = ?", uid).Update("status", status).Error
}
// UpdateRole 更新用户角色(仅 owner 调用)
func (r *UserRepo) UpdateRole(uid uint, role string) error {
return r.db.Model(&model.User{}).Where("uid = ?", uid).Update("role", role).Error
}
// Update 全量更新用户信息
func (r *UserRepo) Update(user *model.User) error {
return r.db.Save(user).Error
}
// SoftDelete GORM 软删除(设 DeletedAt用于 locked 状态释放邮箱
func (r *UserRepo) SoftDelete(uid uint) error {
return r.db.Where("uid = ?", uid).Delete(&model.User{}).Error
}
// Restore 恢复软删除(清 DeletedAt
func (r *UserRepo) Restore(uid uint) error {
return r.db.Unscoped().Model(&model.User{}).Where("uid = ?", uid).Update("deleted_at", nil).Error
}
// SearchUsers 综合搜索(含软删除用户)
func (r *UserRepo) SearchUsers(keyword, role, status string, offset, limit int) ([]model.User, error) {
query := r.db.Unscoped().Model(&model.User{})
if keyword != "" {
like := "%" + keyword + "%"
query = query.Where("email LIKE ? OR username LIKE ?", like, like)
}
if role != "" {
query = query.Where("role = ?", role)
}
if status != "" {
query = query.Where("status = ?", status)
}
var users []model.User
err := query.Order("uid ASC").Offset(offset).Limit(limit).Find(&users).Error
return users, err
}
// CountSearchUsers 搜索结果总数(含软删除用户)
func (r *UserRepo) CountSearchUsers(keyword, role, status string) (int64, error) {
query := r.db.Unscoped().Model(&model.User{})
if keyword != "" {
like := "%" + keyword + "%"
query = query.Where("email LIKE ? OR username LIKE ?", like, like)
}
if role != "" {
query = query.Where("role = ?", role)
}
if status != "" {
query = query.Where("status = ?", status)
}
var count int64
err := query.Count(&count).Error
return count, err
}
// FindByStatus 按状态分页查询(回收站用,暂未暴露前端)
func (r *UserRepo) FindByStatus(status string, offset, limit int) ([]model.User, error) {
var users []model.User
err := r.db.Where("status = ?", status).Order("uid ASC").Offset(offset).Limit(limit).Find(&users).Error
return users, err
}