fix delete orphan recipients when orphan is in active campaign

Signed-off-by: Ronni Skansing <rskansing@gmail.com>
This commit is contained in:
Ronni Skansing
2026-01-22 22:54:36 +01:00
parent 311df47ee1
commit f82bb16db4
2 changed files with 49 additions and 59 deletions

View File

@@ -434,45 +434,6 @@ func (r *Recipient) GetOrphaned(
return result, nil
}
// DeleteAllOrphaned deletes all recipients that are not in any group
func (r *Recipient) DeleteAllOrphaned(
ctx context.Context,
companyID *uuid.UUID,
) (int64, error) {
// build optimized LEFT JOIN delete query for orphaned recipients
var companyFilter string
var args []interface{}
if companyID != nil {
companyFilter = fmt.Sprintf("AND r.company_id = ?")
args = append(args, companyID)
} else {
companyFilter = fmt.Sprintf("AND r.company_id IS NULL")
}
// use raw SQL for optimized LEFT JOIN delete
query := fmt.Sprintf(`
DELETE FROM %s
WHERE id IN (
SELECT r.id FROM %s r
LEFT JOIN %s rgr ON r.id = rgr.recipient_id
WHERE rgr.recipient_id IS NULL %s
)`,
database.RECIPIENT_TABLE,
database.RECIPIENT_TABLE,
database.RECIPIENT_GROUP_RECIPIENT_TABLE,
companyFilter,
)
result := r.DB.Exec(query, args...)
if result.Error != nil {
return 0, result.Error
}
return result.RowsAffected, nil
}
// GetByID gets a recipient by id
func (r *Recipient) GetByID(
ctx context.Context,

View File

@@ -437,15 +437,30 @@ func (r *Recipient) DeleteAllOrphaned(
r.AuditLogNotAuthorized(ae)
return 0, errs.ErrAuthorizationFailed
}
// delete orphaned recipients
count, err := r.RecipientRepository.DeleteAllOrphaned(
// get all orphaned recipients
orphanedRecipients, err := r.RecipientRepository.GetOrphaned(
ctx,
companyID,
&repository.RecipientOption{}, // no pagination, get all
)
if err != nil {
r.Logger.Errorw("failed to delete orphaned recipients - failed to delete orphaned recipients", "error", err)
r.Logger.Errorw("failed to get orphaned recipients", "error", err)
return 0, errs.Wrap(err)
}
// delete each orphaned recipient using core deletion logic
var count int64
for _, recipient := range orphanedRecipients.Rows {
recipientID := recipient.ID.MustGet()
err = r.deleteRecipientByID(ctx, &recipientID)
if err != nil {
r.Logger.Errorw("failed to delete orphaned recipient", "error", err, "recipientID", recipientID.String())
return count, errs.Wrap(err)
}
count++
}
ae.Details["count"] = count
r.AuditLogAuthorized(ae)
return count, nil
@@ -686,26 +701,13 @@ func getStringFromOptional(field nullable.Nullable[vo.OptionalString127]) string
return ""
}
// Delete deletes a recipient
func (r *Recipient) DeleteByID(
// deleteRecipientByID is the core deletion logic without permission checks or audit logging
func (r *Recipient) deleteRecipientByID(
ctx context.Context,
session *model.Session,
id *uuid.UUID,
) error {
ae := NewAuditEvent("Recipient.DeleteByID", session)
ae.Details["id"] = id.String()
// check permissions
isAuthorized, err := IsAuthorized(session, data.PERMISSION_ALLOW_GLOBAL)
if err != nil && !errors.Is(err, errs.ErrAuthorizationFailed) {
r.LogAuthError(err)
return err
}
if !isAuthorized {
r.AuditLogNotAuthorized(ae)
return errs.ErrAuthorizationFailed
}
// remove recipient from all groups
err = r.RecipientGroupRepository.RemoveRecipientByIDFromAllGroups(ctx, id)
err := r.RecipientGroupRepository.RemoveRecipientByIDFromAllGroups(ctx, id)
if err != nil {
r.Logger.Errorw("failed to delete recipient - failed to remove recipient from all groups",
"error", err,
@@ -758,7 +760,34 @@ func (r *Recipient) DeleteByID(
r.Logger.Errorw("failed to delete recipient - failed to delete recipient", "error", err)
return err
}
r.AuditLogAuthorized(ae)
return nil
}
// DeleteByID deletes a recipient
func (r *Recipient) DeleteByID(
ctx context.Context,
session *model.Session,
id *uuid.UUID,
) error {
ae := NewAuditEvent("Recipient.DeleteByID", session)
ae.Details["id"] = id.String()
// check permissions
isAuthorized, err := IsAuthorized(session, data.PERMISSION_ALLOW_GLOBAL)
if err != nil && !errors.Is(err, errs.ErrAuthorizationFailed) {
r.LogAuthError(err)
return err
}
if !isAuthorized {
r.AuditLogNotAuthorized(ae)
return errs.ErrAuthorizationFailed
}
err = r.deleteRecipientByID(ctx, id)
if err != nil {
return err
}
r.AuditLogAuthorized(ae)
return nil
}