package repository import ( "context" "gorm.io/gorm" "github.com/gochat/gochat/internal/model" ) // UserRepo implements GORM repository for User. // Reference: Chatwoot app/models/user.rb type UserRepo struct { db *gorm.DB } // NewUserRepo creates a new User repository. func NewUserRepo(db *gorm.DB) *UserRepo { return &UserRepo{db: db} } // FindByID retrieves a user by primary key. func (r *UserRepo) FindByID(ctx context.Context, id uint) (*model.User, error) { var user model.User err := r.db.WithContext(ctx).First(&user, id).Error if err != nil { return nil, err } return &user, nil } // FindByIDs retrieves multiple users by their primary keys. func (r *UserRepo) FindByIDs(ctx context.Context, ids []uint) ([]model.User, error) { if len(ids) == 0 { return []model.User{}, nil } var users []model.User err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&users).Error return users, err } // FindByEmail retrieves a user by email address. func (r *UserRepo) FindByEmail(ctx context.Context, email string) (*model.User, error) { var user model.User err := r.db.WithContext(ctx).Where("email = ?", email).First(&user).Error if err != nil { return nil, err } return &user, nil } // Create inserts a new user. func (r *UserRepo) Create(ctx context.Context, user *model.User) error { return r.db.WithContext(ctx).Create(user).Error } // Update modifies an existing user. func (r *UserRepo) Update(ctx context.Context, user *model.User) error { return r.db.WithContext(ctx).Save(user).Error } // Delete soft-deletes a user. func (r *UserRepo) Delete(ctx context.Context, id uint) error { return r.db.WithContext(ctx).Delete(&model.User{}, id).Error } // List retrieves all users with pagination. func (r *UserRepo) List(ctx context.Context, offset, limit int) ([]model.User, int64, error) { var users []model.User var total int64 if err := r.db.WithContext(ctx).Model(&model.User{}).Count(&total).Error; err != nil { return nil, 0, err } err := r.db.WithContext(ctx).Offset(offset).Limit(limit).Order("id ASC"). Find(&users).Error return users, total, err } // Search searches users by name or email. func (r *UserRepo) Search(ctx context.Context, query string, offset, limit int) ([]model.User, int64, error) { var users []model.User var total int64 likeQuery := "%" + query + "%" condition := r.db.WithContext(ctx).Model(&model.User{}). Where("name ILIKE ? OR email ILIKE ?", likeQuery, likeQuery) if err := condition.Count(&total).Error; err != nil { return nil, 0, err } err := condition.Offset(offset).Limit(limit).Order("id ASC"). Find(&users).Error return users, total, err } // UpdateAvailability updates user availability status. // Accepts "online"/"available" → true, anything else → false. func (r *UserRepo) UpdateAvailability(ctx context.Context, id uint, availability string) error { isAvailable := availability == "online" || availability == "available" return r.db.WithContext(ctx).Model(&model.User{}).Where("id = ?", id). Update("available", isAvailable).Error } // UpdateLastSignIn updates sign-in tracking fields. func (r *UserRepo) UpdateLastSignIn(ctx context.Context, id uint, ip string) error { return r.db.WithContext(ctx).Model(&model.User{}).Where("id = ?", id). Updates(map[string]interface{}{ "last_sign_in_ip": ip, "current_sign_in_ip": ip, "sign_in_count": gorm.Expr("sign_in_count + 1"), }).Error } // FindByAccount retrieves users belonging to an account (delegated to AccountRepo). func (r *UserRepo) FindByAccount(ctx context.Context, accountID uint, offset, limit int) ([]model.User, int64, error) { var users []model.User var total int64 countDB := r.db.WithContext(ctx).Model(&model.User{}). Joins("JOIN account_users ON account_users.user_id = users.id"). Where("account_users.account_id = ?", accountID) if err := countDB.Count(&total).Error; err != nil { return nil, 0, err } err := r.db.WithContext(ctx). Joins("JOIN account_users ON account_users.user_id = users.id"). Where("account_users.account_id = ?", accountID). Offset(offset).Limit(limit).Order("id ASC"). Find(&users).Error return users, total, err } // Count returns total number of users. func (r *UserRepo) Count(ctx context.Context) (int64, error) { var total int64 err := r.db.WithContext(ctx).Model(&model.User{}).Count(&total).Error return total, err }