Files
photography/backend-old/internal/repository/postgres/user_repository_impl.go
xujiang 010fe2a8c7
Some checks failed
部署后端服务 / 🧪 测试后端 (push) Failing after 5m8s
部署后端服务 / 🚀 构建并部署 (push) Has been skipped
部署后端服务 / 🔄 回滚部署 (push) Has been skipped
fix
2025-07-10 18:09:11 +08:00

516 lines
14 KiB
Go

package postgres
import (
"context"
"errors"
"fmt"
"time"
"photography-backend/internal/model/entity"
"photography-backend/internal/repository/interfaces"
"go.uber.org/zap"
"gorm.io/gorm"
)
// userRepositoryImpl 用户仓储实现
type userRepositoryImpl struct {
db *gorm.DB
logger *zap.Logger
}
// NewUserRepository 创建用户仓储实现
func NewUserRepository(db *gorm.DB, logger *zap.Logger) interfaces.UserRepository {
return &userRepositoryImpl{
db: db,
logger: logger,
}
}
// Create 创建用户
func (r *userRepositoryImpl) Create(ctx context.Context, user *entity.User) error {
return r.db.WithContext(ctx).Create(user).Error
}
// GetByID 根据ID获取用户
func (r *userRepositoryImpl) GetByID(ctx context.Context, id uint) (*entity.User, error) {
var user entity.User
err := r.db.WithContext(ctx).First(&user, id).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("user not found")
}
return nil, err
}
return &user, nil
}
// GetByEmail 根据邮箱获取用户
func (r *userRepositoryImpl) GetByEmail(ctx context.Context, email string) (*entity.User, error) {
var user entity.User
err := r.db.WithContext(ctx).Where("email = ?", email).First(&user).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("user not found")
}
return nil, err
}
return &user, nil
}
// GetByUsername 根据用户名获取用户
func (r *userRepositoryImpl) GetByUsername(ctx context.Context, username string) (*entity.User, error) {
var user entity.User
err := r.db.WithContext(ctx).Where("username = ?", username).First(&user).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("user not found")
}
return nil, err
}
return &user, nil
}
// GetByEmailOrUsername 根据邮箱或用户名获取用户
func (r *userRepositoryImpl) GetByEmailOrUsername(ctx context.Context, emailOrUsername string) (*entity.User, error) {
var user entity.User
err := r.db.WithContext(ctx).
Where("email = ? OR username = ?", emailOrUsername, emailOrUsername).
First(&user).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("user not found")
}
return nil, err
}
return &user, nil
}
// Update 更新用户
func (r *userRepositoryImpl) Update(ctx context.Context, user *entity.User) error {
return r.db.WithContext(ctx).Save(user).Error
}
// Delete 删除用户
func (r *userRepositoryImpl) Delete(ctx context.Context, id uint) error {
return r.db.WithContext(ctx).Delete(&entity.User{}, id).Error
}
// List 获取用户列表
func (r *userRepositoryImpl) List(ctx context.Context, params *entity.UserListParams) ([]*entity.User, int64, error) {
var users []*entity.User
var total int64
query := r.db.WithContext(ctx).Model(&entity.User{})
// 应用过滤条件
if params.Role != nil {
query = query.Where("role = ?", *params.Role)
}
if params.Status != nil {
query = query.Where("status = ?", *params.Status)
}
if params.Search != "" {
query = query.Where("username ILIKE ? OR email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?",
"%"+params.Search+"%", "%"+params.Search+"%", "%"+params.Search+"%", "%"+params.Search+"%")
}
if params.CreatedFrom != nil {
query = query.Where("created_at >= ?", *params.CreatedFrom)
}
if params.CreatedTo != nil {
query = query.Where("created_at <= ?", *params.CreatedTo)
}
if params.LastLoginFrom != nil {
query = query.Where("last_login_at >= ?", *params.LastLoginFrom)
}
if params.LastLoginTo != nil {
query = query.Where("last_login_at <= ?", *params.LastLoginTo)
}
// 获取总数
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
// 应用排序
orderBy := "created_at DESC"
if params.Sort != "" {
order := "ASC"
if params.Order == "desc" {
order = "DESC"
}
orderBy = fmt.Sprintf("%s %s", params.Sort, order)
}
query = query.Order(orderBy)
// 应用分页
if params.Page > 0 && params.Limit > 0 {
offset := (params.Page - 1) * params.Limit
query = query.Offset(offset).Limit(params.Limit)
}
// 查询数据
if err := query.Find(&users).Error; err != nil {
return nil, 0, err
}
return users, total, nil
}
// ListByRole 根据角色获取用户列表
func (r *userRepositoryImpl) ListByRole(ctx context.Context, role entity.UserRole, params *entity.UserListParams) ([]*entity.User, int64, error) {
if params == nil {
params = &entity.UserListParams{}
}
params.Role = &role
return r.List(ctx, params)
}
// ListByStatus 根据状态获取用户列表
func (r *userRepositoryImpl) ListByStatus(ctx context.Context, status entity.UserStatus, params *entity.UserListParams) ([]*entity.User, int64, error) {
if params == nil {
params = &entity.UserListParams{}
}
params.Status = &status
return r.List(ctx, params)
}
// SearchUsers 搜索用户
func (r *userRepositoryImpl) SearchUsers(ctx context.Context, keyword string, params *entity.UserListParams) ([]*entity.User, int64, error) {
if params == nil {
params = &entity.UserListParams{}
}
params.Search = keyword
return r.List(ctx, params)
}
// Count 统计用户总数
func (r *userRepositoryImpl) Count(ctx context.Context) (int64, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entity.User{}).Count(&count).Error
return count, err
}
// CountByRole 根据角色统计用户数
func (r *userRepositoryImpl) CountByRole(ctx context.Context, role entity.UserRole) (int64, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entity.User{}).
Where("role = ?", role).Count(&count).Error
return count, err
}
// CountByStatus 根据状态统计用户数
func (r *userRepositoryImpl) CountByStatus(ctx context.Context, status entity.UserStatus) (int64, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entity.User{}).
Where("status = ?", status).Count(&count).Error
return count, err
}
// CountActiveUsers 统计活跃用户数
func (r *userRepositoryImpl) CountActiveUsers(ctx context.Context) (int64, error) {
return r.CountByStatus(ctx, entity.UserStatusActive)
}
// UpdateStatus 更新用户状态
func (r *userRepositoryImpl) UpdateStatus(ctx context.Context, id uint, status entity.UserStatus) error {
return r.db.WithContext(ctx).Model(&entity.User{}).
Where("id = ?", id).
Update("status", status).Error
}
// UpdateLastLogin 更新最后登录时间
func (r *userRepositoryImpl) UpdateLastLogin(ctx context.Context, id uint) error {
now := time.Now()
return r.db.WithContext(ctx).Model(&entity.User{}).
Where("id = ?", id).
Update("last_login_at", now).Error
}
// UpdatePassword 更新密码
func (r *userRepositoryImpl) UpdatePassword(ctx context.Context, id uint, hashedPassword string) error {
return r.db.WithContext(ctx).Model(&entity.User{}).
Where("id = ?", id).
Update("password", hashedPassword).Error
}
// SoftDelete 软删除用户
func (r *userRepositoryImpl) SoftDelete(ctx context.Context, id uint) error {
return r.db.WithContext(ctx).Delete(&entity.User{}, id).Error
}
// Restore 恢复软删除用户
func (r *userRepositoryImpl) Restore(ctx context.Context, id uint) error {
return r.db.WithContext(ctx).Unscoped().Model(&entity.User{}).
Where("id = ?", id).
Update("deleted_at", nil).Error
}
// BatchUpdateStatus 批量更新用户状态
func (r *userRepositoryImpl) BatchUpdateStatus(ctx context.Context, ids []uint, status entity.UserStatus) error {
if len(ids) == 0 {
return nil
}
return r.db.WithContext(ctx).Model(&entity.User{}).
Where("id IN ?", ids).
Update("status", status).Error
}
// BatchDelete 批量删除用户
func (r *userRepositoryImpl) BatchDelete(ctx context.Context, ids []uint) error {
if len(ids) == 0 {
return nil
}
return r.db.WithContext(ctx).Delete(&entity.User{}, ids).Error
}
// ValidateEmailUnique 验证邮箱唯一性
func (r *userRepositoryImpl) ValidateEmailUnique(ctx context.Context, email string, excludeID uint) error {
var count int64
query := r.db.WithContext(ctx).Model(&entity.User{}).Where("email = ?", email)
if excludeID > 0 {
query = query.Where("id != ?", excludeID)
}
if err := query.Count(&count).Error; err != nil {
return err
}
if count > 0 {
return errors.New("email already exists")
}
return nil
}
// ValidateUsernameUnique 验证用户名唯一性
func (r *userRepositoryImpl) ValidateUsernameUnique(ctx context.Context, username string, excludeID uint) error {
var count int64
query := r.db.WithContext(ctx).Model(&entity.User{}).Where("username = ?", username)
if excludeID > 0 {
query = query.Where("id != ?", excludeID)
}
if err := query.Count(&count).Error; err != nil {
return err
}
if count > 0 {
return errors.New("username already exists")
}
return nil
}
// GetUserPhotos 获取用户照片
func (r *userRepositoryImpl) GetUserPhotos(ctx context.Context, userID uint, params *entity.PhotoListParams) ([]*entity.Photo, int64, error) {
var photos []*entity.Photo
var total int64
query := r.db.WithContext(ctx).Model(&entity.Photo{}).Where("user_id = ?", userID)
// 应用过滤条件
if params != nil {
if params.Status != nil {
query = query.Where("status = ?", *params.Status)
}
if params.CategoryID != nil {
query = query.Joins("JOIN photo_categories ON photos.id = photo_categories.photo_id").
Where("photo_categories.category_id = ?", *params.CategoryID)
}
if params.TagID != nil {
query = query.Joins("JOIN photo_tags ON photos.id = photo_tags.photo_id").
Where("photo_tags.tag_id = ?", *params.TagID)
}
if params.DateFrom != nil {
query = query.Where("taken_at >= ?", *params.DateFrom)
}
if params.DateTo != nil {
query = query.Where("taken_at <= ?", *params.DateTo)
}
if params.Search != "" {
query = query.Where("title ILIKE ? OR description ILIKE ?",
"%"+params.Search+"%", "%"+params.Search+"%")
}
}
// 获取总数
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
// 应用排序和分页
if params != nil {
orderBy := "created_at DESC"
if params.Sort != "" {
order := "ASC"
if params.Order == "desc" {
order = "DESC"
}
orderBy = fmt.Sprintf("%s %s", params.Sort, order)
}
query = query.Order(orderBy)
if params.Page > 0 && params.Limit > 0 {
offset := (params.Page - 1) * params.Limit
query = query.Offset(offset).Limit(params.Limit)
}
}
// 预加载关联数据
query = query.Preload("Categories").Preload("Tags")
// 查询数据
if err := query.Find(&photos).Error; err != nil {
return nil, 0, err
}
return photos, total, nil
}
// GetUserStats 获取用户统计信息
func (r *userRepositoryImpl) GetUserStats(ctx context.Context, userID uint) (*entity.UserStats, error) {
var stats entity.UserStats
// 照片统计
var photoCount int64
if err := r.db.WithContext(ctx).Model(&entity.Photo{}).
Where("user_id = ?", userID).Count(&photoCount).Error; err != nil {
return nil, err
}
stats.PhotoCount = photoCount
// 按状态统计照片
for _, status := range []entity.PhotoStatus{
entity.PhotoStatusActive,
entity.PhotoStatusDraft,
entity.PhotoStatusArchived,
} {
var count int64
if err := r.db.WithContext(ctx).Model(&entity.Photo{}).
Where("user_id = ? AND status = ?", userID, status).
Count(&count).Error; err != nil {
return nil, err
}
switch status {
case entity.PhotoStatusActive:
stats.PublishedPhotos = count
case entity.PhotoStatusDraft:
stats.DraftPhotos = count
case entity.PhotoStatusArchived:
stats.ArchivedPhotos = count
}
}
// 总浏览数
var totalViews int64
if err := r.db.WithContext(ctx).Model(&entity.Photo{}).
Where("user_id = ?", userID).
Select("COALESCE(SUM(view_count), 0)").Row().Scan(&totalViews); err != nil {
return nil, err
}
stats.TotalViews = totalViews
// 总下载数
var totalDownloads int64
if err := r.db.WithContext(ctx).Model(&entity.Photo{}).
Where("user_id = ?", userID).
Select("COALESCE(SUM(download_count), 0)").Row().Scan(&totalDownloads); err != nil {
return nil, err
}
stats.TotalDownloads = totalDownloads
// 存储空间使用
var storageUsed int64
if err := r.db.WithContext(ctx).Model(&entity.Photo{}).
Where("user_id = ?", userID).
Select("COALESCE(SUM(file_size), 0)").Row().Scan(&storageUsed); err != nil {
return nil, err
}
stats.StorageUsed = storageUsed
// 本月新增照片
now := time.Now()
startOfMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
endOfMonth := startOfMonth.AddDate(0, 1, 0).Add(-time.Nanosecond)
var monthlyPhotos int64
if err := r.db.WithContext(ctx).Model(&entity.Photo{}).
Where("user_id = ? AND created_at >= ? AND created_at <= ?", userID, startOfMonth, endOfMonth).
Count(&monthlyPhotos).Error; err != nil {
return nil, err
}
stats.MonthlyPhotos = monthlyPhotos
return &stats, nil
}
// GetAllStats 获取全部用户统计信息
func (r *userRepositoryImpl) GetAllStats(ctx context.Context) (*entity.UserGlobalStats, error) {
var stats entity.UserGlobalStats
// 总用户数
if total, err := r.Count(ctx); err != nil {
return nil, err
} else {
stats.Total = total
}
// 活跃用户数
if active, err := r.CountActiveUsers(ctx); err != nil {
return nil, err
} else {
stats.Active = active
}
// 按角色统计
for _, role := range []entity.UserRole{
entity.UserRoleAdmin,
entity.UserRoleEditor,
entity.UserRoleUser,
} {
if count, err := r.CountByRole(ctx, role); err != nil {
return nil, err
} else {
switch role {
case entity.UserRoleAdmin:
stats.Admins = count
case entity.UserRoleEditor:
stats.Editors = count
case entity.UserRoleUser:
stats.Users = count
}
}
}
// 本月新注册用户
now := time.Now()
startOfMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
endOfMonth := startOfMonth.AddDate(0, 1, 0).Add(-time.Nanosecond)
var monthlyUsers int64
if err := r.db.WithContext(ctx).Model(&entity.User{}).
Where("created_at >= ? AND created_at <= ?", startOfMonth, endOfMonth).
Count(&monthlyUsers).Error; err != nil {
return nil, err
}
stats.MonthlyRegistrations = monthlyUsers
return &stats, nil
}