Files
gochat/backend/internal/repository/assignment_policy_repo.go
T
Rogeeandrogee 4eeb0f8957 HH-597: repair assignment policy migration parity (#156)
* fix(HH-597): repair assignment policy schema migration

* fix(HH-597): harden assignment policy migration

---------

Co-authored-by: Rogee <rogee@ipao.vip>
2026-08-24 13:09:13 +08:00

172 lines
6.6 KiB
Go

package repository
import (
"context"
"gorm.io/gorm"
"github.com/gochat/gochat/internal/model"
)
// AssignmentPolicyRepo implements GORM repository for AssignmentPolicy.
// Reference: Chatwoot app/models/assignment_policy.rb
type AssignmentPolicyRepo struct {
db *gorm.DB
}
// NewAssignmentPolicyRepo creates a new AssignmentPolicy repository.
func NewAssignmentPolicyRepo(db *gorm.DB) *AssignmentPolicyRepo {
return &AssignmentPolicyRepo{db: db}
}
// Create creates a new assignment policy.
func (r *AssignmentPolicyRepo) Create(ctx context.Context, policy *model.AssignmentPolicy) error {
return r.db.WithContext(ctx).Create(policy).Error
}
// FindByID retrieves an assignment policy by primary key.
func (r *AssignmentPolicyRepo) FindByID(ctx context.Context, id uint) (*model.AssignmentPolicy, error) {
var policy model.AssignmentPolicy
if err := r.db.WithContext(ctx).First(&policy, id).Error; err != nil {
return nil, err
}
return &policy, nil
}
// GetByID retrieves an assignment policy by primary key (alias for FindByID matching service expectations).
func (r *AssignmentPolicyRepo) GetByID(ctx context.Context, id uint) (*model.AssignmentPolicy, error) {
return r.FindByID(ctx, id)
}
// FindByAccount retrieves all assignment policies for an account.
func (r *AssignmentPolicyRepo) FindByAccount(ctx context.Context, accountID uint) ([]model.AssignmentPolicy, error) {
var policies []model.AssignmentPolicy
if err := r.db.WithContext(ctx).
Where("account_id = ?", accountID).
Order("id ASC").
Find(&policies).Error; err != nil {
return nil, err
}
return policies, nil
}
// FindByAccountAndID retrieves an account-scoped assignment policy.
func (r *AssignmentPolicyRepo) FindByAccountAndID(ctx context.Context, accountID, id uint) (*model.AssignmentPolicy, error) {
var policy model.AssignmentPolicy
if err := r.db.WithContext(ctx).
Where("account_id = ? AND id = ?", accountID, id).
First(&policy).Error; err != nil {
return nil, err
}
return &policy, nil
}
// Update updates an assignment policy.
func (r *AssignmentPolicyRepo) Update(ctx context.Context, policy *model.AssignmentPolicy) error {
return r.db.WithContext(ctx).Save(policy).Error
}
// Delete soft-deletes an assignment policy.
func (r *AssignmentPolicyRepo) Delete(ctx context.Context, id uint) error {
return r.db.WithContext(ctx).Delete(&model.AssignmentPolicy{}, id).Error
}
// CountAssignedInboxes returns how many inboxes use an assignment policy.
func (r *AssignmentPolicyRepo) CountAssignedInboxes(ctx context.Context, policyID uint) (int64, error) {
var count int64
err := r.db.WithContext(ctx).
Model(&model.InboxAssignmentPolicy{}).
Where("assignment_policy_id = ?", policyID).
Count(&count).Error
return count, err
}
// InboxAssignmentPolicyRepo implements GORM repository for InboxAssignmentPolicy.
// Reference: Chatwoot app/models/inbox_assignment_policy.rb
type InboxAssignmentPolicyRepo struct {
db *gorm.DB
}
// NewInboxAssignmentPolicyRepo creates a new InboxAssignmentPolicy repository.
func NewInboxAssignmentPolicyRepo(db *gorm.DB) *InboxAssignmentPolicyRepo {
return &InboxAssignmentPolicyRepo{db: db}
}
// FindByInbox retrieves the active assignment policy override for an inbox.
func (r *InboxAssignmentPolicyRepo) FindByInbox(ctx context.Context, accountID, inboxID uint) (*model.InboxAssignmentPolicy, error) {
var policy model.InboxAssignmentPolicy
if err := r.db.WithContext(ctx).
Joins("JOIN assignment_policies ON assignment_policies.id = inbox_assignment_policies.assignment_policy_id").
Joins("JOIN inboxes ON inboxes.id = inbox_assignment_policies.inbox_id").
Where("assignment_policies.account_id = ? AND inboxes.account_id = ? AND inbox_assignment_policies.inbox_id = ?", accountID, accountID, inboxID).
First(&policy).Error; err != nil {
return nil, err
}
return &policy, nil
}
// FindPolicyByInbox retrieves the assignment policy associated with an inbox.
func (r *InboxAssignmentPolicyRepo) FindPolicyByInbox(ctx context.Context, accountID, inboxID uint) (*model.AssignmentPolicy, error) {
var policy model.AssignmentPolicy
if err := r.db.WithContext(ctx).
Joins("JOIN inbox_assignment_policies ON inbox_assignment_policies.assignment_policy_id = assignment_policies.id").
Joins("JOIN inboxes ON inboxes.id = inbox_assignment_policies.inbox_id").
Where("assignment_policies.account_id = ? AND inboxes.account_id = ? AND inbox_assignment_policies.inbox_id = ?", accountID, accountID, inboxID).
First(&policy).Error; err != nil {
return nil, err
}
return &policy, nil
}
// FindInboxesByPolicy retrieves inboxes linked to an account-scoped policy.
func (r *InboxAssignmentPolicyRepo) FindInboxesByPolicy(ctx context.Context, accountID, policyID uint) ([]model.Inbox, error) {
var inboxes []model.Inbox
err := r.db.WithContext(ctx).
Joins("JOIN inbox_assignment_policies ON inbox_assignment_policies.inbox_id = inboxes.id").
Joins("JOIN assignment_policies ON assignment_policies.id = inbox_assignment_policies.assignment_policy_id").
Where("inboxes.account_id = ? AND assignment_policies.account_id = ? AND assignment_policies.id = ?", accountID, accountID, policyID).
Order("inboxes.id ASC").
Find(&inboxes).Error
return inboxes, err
}
// ReplaceForInbox attaches one policy to an inbox, replacing an old association.
func (r *InboxAssignmentPolicyRepo) ReplaceForInbox(ctx context.Context, accountID, inboxID, policyID uint) (*model.InboxAssignmentPolicy, error) {
var policy model.InboxAssignmentPolicy
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
var inbox model.Inbox
if err := tx.Select("id").Where("account_id = ? AND id = ?", accountID, inboxID).First(&inbox).Error; err != nil {
return err
}
var assignmentPolicy model.AssignmentPolicy
if err := tx.Select("id").Where("account_id = ? AND id = ?", accountID, policyID).First(&assignmentPolicy).Error; err != nil {
return err
}
if err := tx.Where("inbox_id = ?", inboxID).Delete(&model.InboxAssignmentPolicy{}).Error; err != nil {
return err
}
policy = model.InboxAssignmentPolicy{InboxID: inboxID, AssignmentPolicyID: policyID}
return tx.Create(&policy).Error
})
if err != nil {
return nil, err
}
return &policy, nil
}
// DeleteByInbox removes an inbox assignment policy association.
func (r *InboxAssignmentPolicyRepo) DeleteByInbox(ctx context.Context, accountID, inboxID uint) error {
result := r.db.WithContext(ctx).
Where("inbox_id = ? AND EXISTS (SELECT 1 FROM inboxes WHERE inboxes.id = inbox_assignment_policies.inbox_id AND inboxes.account_id = ?)", inboxID, accountID).
Delete(&model.InboxAssignmentPolicy{})
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return gorm.ErrRecordNotFound
}
return nil
}