Files
gochat/internal/repository/user_repo.go
T
2026-06-04 15:44:48 +08:00

142 lines
4.3 KiB
Go

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
}