162 lines
6.0 KiB
Go
162 lines
6.0 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/gochat/gochat/internal/model"
|
|
)
|
|
|
|
// AccountUserRepo implements GORM repository for AccountUser.
|
|
// Reference: Chatwoot AccountUser (join table between Account and User)
|
|
// Used for role/availability checks in assignment logic.
|
|
type AccountUserRepo struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewAccountUserRepo creates a new AccountUser repository.
|
|
func NewAccountUserRepo(db *gorm.DB) *AccountUserRepo {
|
|
return &AccountUserRepo{db: db}
|
|
}
|
|
|
|
// FindByAccountAndUser retrieves an AccountUser by accountID and userID.
|
|
// Returns nil if not found.
|
|
func (r *AccountUserRepo) FindByAccountAndUser(ctx context.Context, accountID, userID uint) (*model.AccountUser, error) {
|
|
var au model.AccountUser
|
|
err := r.db.WithContext(ctx).
|
|
Where("account_id = ? AND user_id = ?", accountID, userID).
|
|
First(&au).Error
|
|
if err != nil {
|
|
if err == gorm.ErrRecordNotFound {
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
return &au, nil
|
|
}
|
|
|
|
// FindOnlineAgentsByAccount retrieves all AccountUsers with availability = "online"
|
|
// for a given account. Used for auto-assignment eligibility.
|
|
func (r *AccountUserRepo) FindOnlineAgentsByAccount(ctx context.Context, accountID uint) ([]model.AccountUser, error) {
|
|
var agents []model.AccountUser
|
|
err := r.db.WithContext(ctx).
|
|
Where("account_id = ? AND availability = ?", accountID, "online").
|
|
Find(&agents).Error
|
|
return agents, err
|
|
}
|
|
|
|
// FindByAccount retrieves all AccountUsers for a given account with pagination.
|
|
func (r *AccountUserRepo) FindByAccount(ctx context.Context, accountID uint, offset, limit int) ([]model.AccountUser, int64, error) {
|
|
var agents []model.AccountUser
|
|
var count int64
|
|
|
|
countDB := r.db.WithContext(ctx).Model(&model.AccountUser{}).Where("account_id = ?", accountID)
|
|
if err := countDB.Count(&count).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
err := r.db.WithContext(ctx).
|
|
Where("account_id = ?", accountID).
|
|
Offset(offset).Limit(limit).
|
|
Find(&agents).Error
|
|
return agents, count, err
|
|
}
|
|
|
|
// UpdateAvailability updates the availability status of an AccountUser.
|
|
func (r *AccountUserRepo) UpdateAvailability(ctx context.Context, accountID, userID uint, availability string) error {
|
|
return r.db.WithContext(ctx).
|
|
Model(&model.AccountUser{}).
|
|
Where("account_id = ? AND user_id = ?", accountID, userID).
|
|
Update("availability", availability).Error
|
|
}
|
|
|
|
// IsAdministrator checks if a user has administrator role in a given account.
|
|
func (r *AccountUserRepo) IsAdministrator(ctx context.Context, accountID, userID uint) (bool, error) {
|
|
var count int64
|
|
err := r.db.WithContext(ctx).
|
|
Model(&model.AccountUser{}).
|
|
Where("account_id = ? AND user_id = ? AND role = ?", accountID, userID, "administrator").
|
|
Count(&count).Error
|
|
return count > 0, err
|
|
}
|
|
|
|
// IsAgentOrAdmin checks if a user is either an agent or administrator in a given account.
|
|
func (r *AccountUserRepo) IsAgentOrAdmin(ctx context.Context, accountID, userID uint) (bool, error) {
|
|
var count int64
|
|
err := r.db.WithContext(ctx).
|
|
Model(&model.AccountUser{}).
|
|
Where("account_id = ? AND user_id = ? AND role IN ?", accountID, userID, []string{"agent", "administrator"}).
|
|
Count(&count).Error
|
|
return count > 0, err
|
|
}
|
|
|
|
// FindTeamMembersByAccount retrieves all team members belonging to teams in a given account.
|
|
// Used for team overflow logic: when all team members are offline, fall back to account-level agents.
|
|
func (r *AccountUserRepo) FindTeamMembersByAccount(ctx context.Context, accountID uint, teamID uint) ([]model.AccountUser, error) {
|
|
var members []model.AccountUser
|
|
// Join team_members to find agents belonging to a specific team in this account
|
|
err := r.db.WithContext(ctx).
|
|
Joins("JOIN team_members ON team_members.user_id = account_users.user_id").
|
|
Where("team_members.team_id = ? AND account_users.account_id = ?", teamID, accountID).
|
|
Find(&members).Error
|
|
return members, err
|
|
}
|
|
|
|
// UpdateAutoOffline updates the auto_offline setting for an AccountUser.
|
|
func (r *AccountUserRepo) UpdateAutoOffline(ctx context.Context, accountID, userID uint, autoOffline bool) error {
|
|
return r.db.WithContext(ctx).
|
|
Model(&model.AccountUser{}).
|
|
Where("account_id = ? AND user_id = ?", accountID, userID).
|
|
Update("auto_offline", autoOffline).Error
|
|
}
|
|
|
|
// UpdateActiveAt updates the active_at timestamp for an AccountUser.
|
|
func (r *AccountUserRepo) UpdateActiveAt(ctx context.Context, accountID, userID uint) error {
|
|
return r.db.WithContext(ctx).
|
|
Model(&model.AccountUser{}).
|
|
Where("account_id = ? AND user_id = ?", accountID, userID).
|
|
Update("active_at", gorm.Expr("NOW()")).Error
|
|
}
|
|
|
|
// FindByAccountAndUserOrFail retrieves an AccountUser by accountID and userID.
|
|
// Returns error if not found.
|
|
func (r *AccountUserRepo) FindByAccountAndUserOrFail(ctx context.Context, accountID, userID uint) (*model.AccountUser, error) {
|
|
var au model.AccountUser
|
|
err := r.db.WithContext(ctx).
|
|
Preload("Account").
|
|
Where("account_id = ? AND user_id = ?", accountID, userID).
|
|
First(&au).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &au, nil
|
|
}
|
|
|
|
// FindByUserWithAccounts retrieves all account memberships for a user with accounts loaded.
|
|
func (r *AccountUserRepo) FindByUserWithAccounts(ctx context.Context, userID uint) ([]model.AccountUser, error) {
|
|
var accountUsers []model.AccountUser
|
|
err := r.db.WithContext(ctx).
|
|
Preload("Account").
|
|
Where("user_id = ?", userID).
|
|
Order("active_at DESC").
|
|
Order("id ASC").
|
|
Find(&accountUsers).Error
|
|
return accountUsers, err
|
|
}
|
|
|
|
// Create inserts a new AccountUser record.
|
|
func (r *AccountUserRepo) Create(ctx context.Context, au *model.AccountUser) error {
|
|
return r.db.WithContext(ctx).Create(au).Error
|
|
}
|
|
|
|
// Delete removes an AccountUser by ID.
|
|
func (r *AccountUserRepo) Delete(ctx context.Context, id uint) error {
|
|
return r.db.WithContext(ctx).Delete(&model.AccountUser{}, id).Error
|
|
}
|
|
|
|
// UpdateRole changes the role of an AccountUser.
|
|
func (r *AccountUserRepo) UpdateRole(ctx context.Context, id uint, role string) error {
|
|
return r.db.WithContext(ctx).Model(&model.AccountUser{}).Where("id = ?", id).Update("role", role).Error
|
|
}
|