215 lines
6.6 KiB
Go
215 lines
6.6 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/gochat/gochat/internal/model"
|
|
)
|
|
|
|
// AccountRepo implements GORM repository for Account.
|
|
// Reference: Chatwoot app/models/account.rb + AccountUser join
|
|
type AccountRepo struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewAccountRepo creates a new Account repository.
|
|
func NewAccountRepo(db *gorm.DB) *AccountRepo {
|
|
return &AccountRepo{db: db}
|
|
}
|
|
|
|
// FindByID retrieves an account by primary key.
|
|
func (r *AccountRepo) FindByID(ctx context.Context, id uint) (*model.Account, error) {
|
|
var account model.Account
|
|
err := r.db.WithContext(ctx).First(&account, id).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &account, nil
|
|
}
|
|
|
|
// FindByUser retrieves all accounts accessible by a user via AccountUser join.
|
|
func (r *AccountRepo) FindByUser(ctx context.Context, userID uint, offset, limit int) ([]model.Account, int64, error) {
|
|
var accounts []model.Account
|
|
var total int64
|
|
|
|
// Count total accounts for this user
|
|
countDB := r.db.WithContext(ctx).Model(&model.Account{}).
|
|
Joins("JOIN account_users ON account_users.account_id = accounts.id").
|
|
Where("account_users.user_id = ?", userID)
|
|
if err := countDB.Count(&total).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
// Fetch paginated accounts
|
|
err := r.db.WithContext(ctx).
|
|
Joins("JOIN account_users ON account_users.account_id = accounts.id").
|
|
Where("account_users.user_id = ?", userID).
|
|
Offset(offset).Limit(limit).
|
|
Find(&accounts).Error
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
return accounts, total, nil
|
|
}
|
|
|
|
// Create inserts a new account.
|
|
func (r *AccountRepo) Create(ctx context.Context, account *model.Account) error {
|
|
return r.db.WithContext(ctx).Create(account).Error
|
|
}
|
|
|
|
// Update modifies an existing account.
|
|
func (r *AccountRepo) Update(ctx context.Context, account *model.Account) error {
|
|
return r.db.WithContext(ctx).Save(account).Error
|
|
}
|
|
|
|
// Delete soft-deletes an account.
|
|
func (r *AccountRepo) Delete(ctx context.Context, id uint) error {
|
|
return r.db.WithContext(ctx).Delete(&model.Account{}, id).Error
|
|
}
|
|
|
|
// FindUsersByAccount retrieves all users belonging to an account.
|
|
func (r *AccountRepo) FindUsersByAccount(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).
|
|
Find(&users).Error
|
|
return users, total, err
|
|
}
|
|
|
|
// AddUserToAccount creates an AccountUser association.
|
|
func (r *AccountRepo) AddUserToAccount(ctx context.Context, accountID, userID uint, role string) error {
|
|
au := model.AccountUser{
|
|
AccountID: accountID,
|
|
UserID: userID,
|
|
Role: role,
|
|
}
|
|
return r.db.WithContext(ctx).Create(&au).Error
|
|
}
|
|
|
|
// UpsertAccountUser creates or updates an AccountUser membership.
|
|
// Reference: Chatwoot Platform::Api::V1::AccountUsersController#create uses
|
|
// account.account_users.find_or_initialize_by(user_id: ...).update!(params).
|
|
func (r *AccountRepo) UpsertAccountUser(ctx context.Context, accountID, userID uint, role *string) (*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 && err != gorm.ErrRecordNotFound {
|
|
return nil, err
|
|
}
|
|
|
|
if err == gorm.ErrRecordNotFound {
|
|
au = model.AccountUser{
|
|
AccountID: accountID,
|
|
UserID: userID,
|
|
Role: "agent",
|
|
Availability: "offline",
|
|
AutoOffline: true,
|
|
}
|
|
}
|
|
if role != nil && *role != "" {
|
|
au.Role = *role
|
|
}
|
|
|
|
if err == gorm.ErrRecordNotFound {
|
|
if err := r.db.WithContext(ctx).Create(&au).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &au, nil
|
|
}
|
|
|
|
if role != nil {
|
|
if err := r.db.WithContext(ctx).Model(&au).Update("role", au.Role).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return &au, nil
|
|
}
|
|
|
|
// RemoveUserFromAccount deletes an AccountUser association.
|
|
func (r *AccountRepo) RemoveUserFromAccount(ctx context.Context, accountID, userID uint) error {
|
|
return r.db.WithContext(ctx).Exec(
|
|
"DELETE FROM account_users WHERE account_id = ? AND user_id = ?", accountID, userID,
|
|
).Error
|
|
}
|
|
|
|
// Count returns total number of accounts.
|
|
func (r *AccountRepo) Count(ctx context.Context) (int64, error) {
|
|
var total int64
|
|
err := r.db.WithContext(ctx).Model(&model.Account{}).Count(&total).Error
|
|
return total, err
|
|
}
|
|
|
|
// FindAll retrieves all accounts with pagination.
|
|
func (r *AccountRepo) FindAll(ctx context.Context, offset, limit int) ([]model.Account, int64, error) {
|
|
var accounts []model.Account
|
|
var total int64
|
|
|
|
if err := r.db.WithContext(ctx).Model(&model.Account{}).Count(&total).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
err := r.db.WithContext(ctx).Offset(offset).Limit(limit).Find(&accounts).Error
|
|
return accounts, total, err
|
|
}
|
|
|
|
// FindAgentsByAccount retrieves AccountUser records for an account with pagination.
|
|
// Reference: Chatwoot app/controllers/api/v1/accounts/agents_controller.rb#index
|
|
func (r *AccountRepo) FindAgentsByAccount(ctx context.Context, accountID uint, offset, limit int) ([]model.AccountUser, int64, error) {
|
|
var agents []model.AccountUser
|
|
var total int64
|
|
|
|
countDB := r.db.WithContext(ctx).Model(&model.AccountUser{}).
|
|
Where("account_id = ?", accountID)
|
|
if err := countDB.Count(&total).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, total, err
|
|
}
|
|
|
|
// UpdateActiveAt updates the active_at timestamp for a user in an account.
|
|
// Reference: Chatwoot accounts_controller.rb#update_active_at
|
|
func (r *AccountRepo) UpdateActiveAt(ctx context.Context, accountID, userID uint, activeAt time.Time) error {
|
|
result := r.db.WithContext(ctx).Model(&model.AccountUser{}).
|
|
Where("account_id = ? AND user_id = ?", accountID, userID).
|
|
Update("active_at", activeAt)
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
if result.RowsAffected == 0 {
|
|
return gorm.ErrRecordNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// FindAccountUserByUserAndAccount retrieves the AccountUser record for a specific user-account pair.
|
|
func (r *AccountRepo) FindAccountUserByUserAndAccount(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 {
|
|
return nil, err
|
|
}
|
|
return &au, nil
|
|
}
|