Migrate contact_email and contact_phone to allow dupes

The key item here is that comms.phone and comms.email are meant to
represent a real global namespace, but comms.contact is meant to
represent an organization-specific namespace. This means the mapping,
comms.contact_phone and comms.contact_email can't key off the global
namespace. Otherwise the contact namespace would implicitly be global.
This commit is contained in:
Eli Ribble 2026-05-22 15:13:03 +00:00
parent a72f228e4e
commit f957dc6982
No known key found for this signature in database
14 changed files with 250 additions and 44 deletions

View file

@ -33,8 +33,8 @@ func NewEmailSend(ctx context.Context, txn bob.Executor, email_id int32) error {
func NewLabelStudioAudioCreate(ctx context.Context, txn bob.Executor, note_audio_id int32) error {
return newJob(ctx, txn, enums.JobtypeLabelStudioAudioCreate, note_audio_id)
}
func NewTextRespond(ctx context.Context, txn bob.Executor, text_id int32) error {
return newJob(ctx, txn, enums.JobtypeTextRespond, text_id)
func NewTextRespond(ctx context.Context, txn db.Ex, text_id int32) error {
return newJob2(ctx, txn, model.Jobtype_TextRespond, text_id)
}
func NewTextSend(ctx context.Context, txn db.Ex, job_id int32) error {
return newJob2(ctx, txn, model.Jobtype_TextSend, job_id)

View file

@ -2,12 +2,9 @@ package text
import (
"context"
"fmt"
"source.gleipnir.technology/Gleipnir/nidus-sync/db"
"source.gleipnir.technology/Gleipnir/nidus-sync/db/enums"
modelcomms "source.gleipnir.technology/Gleipnir/nidus-sync/db/gen/nidus-sync/comms/model"
"source.gleipnir.technology/Gleipnir/nidus-sync/db/models"
querycomms "source.gleipnir.technology/Gleipnir/nidus-sync/db/query/comms"
"source.gleipnir.technology/Gleipnir/nidus-sync/platform/types"
//"github.com/rs/zerolog/log"
@ -28,10 +25,11 @@ func ensureInDB(ctx context.Context, txn db.Ex, contact modelcomms.Contact, dest
_, err = querycomms.ContactPhoneInsert(ctx, txn, contact_phone)
return err
}
func phoneStatus(ctx context.Context, src types.E164) (enums.CommsPhonestatustype, error) {
phone, err := models.FindCommsPhone(ctx, db.PGInstance.BobDB, src.PhoneString())
if err != nil {
return enums.CommsPhonestatustypeUnconfirmed, fmt.Errorf("Failed to determine if '%s' is subscribed: %w", src.PhoneString(), err)
}
return phone.Status, nil
func ensurePhoneInDB(ctx context.Context, txn db.Ex, number *types.E164) (modelcomms.Phone, error) {
return querycomms.PhoneInsertIfNotExists(ctx, txn, modelcomms.Phone{
CanSms: false,
E164: number.PhoneString(),
IsSubscribed: false,
Status: modelcomms.Phonestatustype_Unconfirmed,
})
}

View file

@ -9,7 +9,6 @@ import (
"source.gleipnir.technology/Gleipnir/nidus-sync/comms/text"
"source.gleipnir.technology/Gleipnir/nidus-sync/config"
"source.gleipnir.technology/Gleipnir/nidus-sync/db"
"source.gleipnir.technology/Gleipnir/nidus-sync/db/enums"
modelcomms "source.gleipnir.technology/Gleipnir/nidus-sync/db/gen/nidus-sync/comms/model"
modelpublic "source.gleipnir.technology/Gleipnir/nidus-sync/db/gen/nidus-sync/public/model"
modelpublicreport "source.gleipnir.technology/Gleipnir/nidus-sync/db/gen/nidus-sync/publicreport/model"
@ -97,13 +96,13 @@ func sendTextComplete(ctx context.Context, job modelcomms.TextJob) error {
default:
return fmt.Errorf("incomplete switch: %s", string(job.Type))
}
status, err := phoneStatus(ctx, *dst)
destination, err := querycomms.PhoneFromE164(ctx, txn, dst.PhoneString())
if err != nil {
return fmt.Errorf("Failed to check if subscribed: %w", err)
return fmt.Errorf("destination phone from e164: %w", err)
}
log.Debug().Str("phone status", string(status)).Str("destination", job.Destination).Send()
switch status {
case enums.CommsPhonestatustypeUnconfirmed:
log.Debug().Str("phone status", string(destination.Status)).Str("destination", job.Destination).Send()
switch destination.Status {
case modelcomms.Phonestatustype_Unconfirmed:
err := ensureInitialText(ctx, txn, *dst)
if err != nil {
return fmt.Errorf("Failed to ensure initial text has been sent: %w", err)
@ -111,7 +110,7 @@ func sendTextComplete(ctx context.Context, job modelcomms.TextJob) error {
return nil
//case enums.CommsPhonestatustypeOkToSend:
// allow to drop through
case enums.CommsPhonestatustypeStopped:
case modelcomms.Phonestatustype_Stopped:
lint.LogOnErrCtx(func(ctx context.Context) error {
return resendInitialText(ctx, txn, *dst)
}, ctx, "resend initial text")

View file

@ -7,12 +7,10 @@ import (
"time"
"github.com/aarondl/opt/omit"
"github.com/aarondl/opt/omitnull"
"github.com/nyaruka/phonenumbers"
"github.com/rs/zerolog/log"
"source.gleipnir.technology/Gleipnir/nidus-sync/config"
"source.gleipnir.technology/Gleipnir/nidus-sync/db"
"source.gleipnir.technology/Gleipnir/nidus-sync/db/enums"
modelcomms "source.gleipnir.technology/Gleipnir/nidus-sync/db/gen/nidus-sync/comms/model"
modelpublicreport "source.gleipnir.technology/Gleipnir/nidus-sync/db/gen/nidus-sync/publicreport/model"
"source.gleipnir.technology/Gleipnir/nidus-sync/db/models"
@ -33,30 +31,29 @@ func HandleTextMessage(ctx context.Context, source string, destination string, c
if err != nil {
return fmt.Errorf("parse destination '%s': %w", destination, err)
}
txn, err := db.PGInstance.BobDB.BeginTx(ctx, nil)
txn, err := db.BeginTxn(ctx)
if err != nil {
return fmt.Errorf("start txn: %w", err)
}
defer lint.LogOnErrRollback(txn.Rollback, ctx, "rollback")
status, err := phoneStatus(ctx, *src)
s, err := ensurePhoneInDB(ctx, txn, src)
if err != nil {
return fmt.Errorf("Failed to get phone status")
return fmt.Errorf("ensure source in DB: %w", err)
}
is_visible_to_llm := status != enums.CommsPhonestatustypeUnconfirmed
is_visible_to_llm := s.Status != modelcomms.Phonestatustype_Unconfirmed
l, err := models.CommsTextLogs.Insert(&models.CommsTextLogSetter{
//ID:
Content: omit.From(content),
Created: omit.From(time.Now()),
Destination: omit.From(dst.PhoneString()),
IsVisibleToLLM: omit.From(is_visible_to_llm),
IsWelcome: omit.From(false),
Origin: omit.From(enums.CommsTextoriginCustomer),
Source: omit.From(src.PhoneString()),
TwilioSid: omitnull.FromPtr[string](nil),
TwilioStatus: omit.From(""),
}).One(ctx, txn)
l, err := querycomms.TextLogInsert(ctx, txn, modelcomms.TextLog{
Content: content,
Created: time.Now(),
Destination: dst.PhoneString(),
IsVisibleToLlm: is_visible_to_llm,
IsWelcome: false,
Origin: modelcomms.Textorigin_Customer,
Source: s.E164,
TwilioSid: nil,
TwilioStatus: "",
})
if err != nil {
return fmt.Errorf("insert text log: %w", err)
}