// Package admin 提供后台 RBAC 相关表的数据访问。 // 包含管理员(admin_users)、角色(admin_roles)、权限(admin_permissions) // 及其多对多关联表的读写。所有查询均参数化,杜绝 SQL 注入。 package admin import ( "context" "gorm.io/gorm" "portal-mini-go/internal/model/admin" "portal-mini-go/internal/pkg/errors" ) // UserRepository 管理员账号与角色关联的数据访问。 type UserRepository struct { db *gorm.DB } func NewUserRepository(db *gorm.DB) *UserRepository { return &UserRepository{db: db} } // GetByUsername 按用户名查询管理员,不存在返回 ErrNotFound。 func (r *UserRepository) GetByUsername(ctx context.Context, username string) (*admin.User, error) { var u admin.User if err := r.db.WithContext(ctx).Where("username = ?", username).First(&u).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.ErrNotFound } return nil, errors.Wrap(50000, "query admin user", err) } return &u, nil } // GetByID 按 ID 查询管理员,不存在返回 ErrNotFound。 func (r *UserRepository) GetByID(ctx context.Context, id uint64) (*admin.User, error) { var u admin.User if err := r.db.WithContext(ctx).Where("id = ?", id).First(&u).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.ErrNotFound } return nil, errors.Wrap(50000, "query admin user", err) } return &u, nil } // Create 新建管理员。 func (r *UserRepository) Create(ctx context.Context, u *admin.User) error { if err := r.db.WithContext(ctx).Create(u).Error; err != nil { return errors.Wrap(50000, "create admin user", err) } return nil } // Count 统计管理员总数。 func (r *UserRepository) Count(ctx context.Context) (int64, error) { var n int64 if err := r.db.WithContext(ctx).Model(&admin.User{}).Count(&n).Error; err != nil { return 0, errors.Wrap(50000, "count admin user", err) } return n, nil } // UserListFilter 管理员列表过滤条件。 type UserListFilter struct { Keyword string Status int8 // <0 表示不过滤 Page int Size int } // List 分页查询管理员,支持关键字(用户名 / 昵称)与状态过滤。 func (r *UserRepository) List(ctx context.Context, f UserListFilter) ([]admin.User, int64, error) { q := r.db.WithContext(ctx).Model(&admin.User{}) if f.Status >= 0 { q = q.Where("status = ?", f.Status) } if f.Keyword != "" { kw := "%" + f.Keyword + "%" q = q.Where("username LIKE ? OR nickname LIKE ?", kw, kw) } var total int64 if err := q.Count(&total).Error; err != nil { return nil, 0, errors.Wrap(50000, "count admin user", err) } var list []admin.User if err := q.Order("id DESC").Offset((f.Page - 1) * f.Size).Limit(f.Size).Find(&list).Error; err != nil { return nil, 0, errors.Wrap(50000, "list admin user", err) } return list, total, nil } // Update 按 ID 局部更新管理员非零值字段(cols 为待更新列)。 func (r *UserRepository) Update(ctx context.Context, id uint64, cols map[string]interface{}) error { res := r.db.WithContext(ctx).Model(&admin.User{}).Where("id = ?", id).Updates(cols) if res.Error != nil { return errors.Wrap(50000, "update admin user", res.Error) } if res.RowsAffected == 0 { return errors.ErrNotFound } return nil } // Delete 删除管理员,并清理其角色关联。 func (r *UserRepository) Delete(ctx context.Context, id uint64) error { if err := r.db.WithContext(ctx).Where("admin_id = ?", id).Delete(&admin.UserRole{}).Error; err != nil { return errors.Wrap(50000, "delete admin user roles", err) } res := r.db.WithContext(ctx).Where("id = ?", id).Delete(&admin.User{}) if res.Error != nil { return errors.Wrap(50000, "delete admin user", res.Error) } if res.RowsAffected == 0 { return errors.ErrNotFound } return nil } // SetRoles 全量替换管理员所属角色(先删后插)。 func (r *UserRepository) SetRoles(ctx context.Context, adminID uint64, roleIDs []uint64) error { if err := r.db.WithContext(ctx).Where("admin_id = ?", adminID).Delete(&admin.UserRole{}).Error; err != nil { return errors.Wrap(50000, "reset admin roles", err) } if len(roleIDs) == 0 { return nil } rows := make([]admin.UserRole, 0, len(roleIDs)) for _, rid := range roleIDs { rows = append(rows, admin.UserRole{AdminID: adminID, RoleID: rid}) } if err := r.db.WithContext(ctx).Create(&rows).Error; err != nil { return errors.Wrap(50000, "assign admin roles", err) } return nil } // RoleCodesOf 返回管理员所属角色 code 列表(经 admin_user_roles 关联)。 func (r *UserRepository) RoleCodesOf(ctx context.Context, adminID uint64) ([]string, error) { var codes []string if err := r.db.WithContext(ctx). Table("admin_user_roles"). Joins("JOIN admin_roles ON admin_roles.id = admin_user_roles.role_id"). Where("admin_user_roles.admin_id = ?", adminID). Pluck("admin_roles.code", &codes).Error; err != nil { return nil, errors.Wrap(50000, "query admin role codes", err) } return codes, nil } // PermissionCodesOf 返回管理员经角色聚合后的全部权限 code 列表(去重)。 func (r *UserRepository) PermissionCodesOf(ctx context.Context, adminID uint64) ([]string, error) { var codes []string if err := r.db.WithContext(ctx). Table("admin_user_roles ur"). Joins("JOIN admin_role_permissions rp ON rp.role_id = ur.role_id"). Joins("JOIN admin_permissions p ON p.id = rp.permission_id"). Where("ur.admin_id = ?", adminID). Pluck("p.code", &codes).Error; err != nil { return nil, errors.Wrap(50000, "query admin permission codes", err) } return codes, nil }