package publicreport import ( "context" "fmt" "time" "github.com/rs/zerolog/log" "source.gleipnir.technology/Gleipnir/nidus-sync/db" 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" querycomms "source.gleipnir.technology/Gleipnir/nidus-sync/db/query/comms" querypublic "source.gleipnir.technology/Gleipnir/nidus-sync/db/query/public" querypublicreport "source.gleipnir.technology/Gleipnir/nidus-sync/db/query/publicreport" "source.gleipnir.technology/Gleipnir/nidus-sync/platform/email" "source.gleipnir.technology/Gleipnir/nidus-sync/platform/text" "source.gleipnir.technology/Gleipnir/nidus-sync/platform/types" ) func DistrictForReport(ctx context.Context, report_id string) (modelpublic.Organization, error) { report, err := querypublicreport.ReportFromPublicID(ctx, db.PGInstance.PGXPool, report_id) if err != nil { return modelpublic.Organization{}, fmt.Errorf("Failed to find report %s: %w", report_id, err) } result, e := querypublic.OrganizationFromID(ctx, db.PGInstance.PGXPool, int64(report.OrganizationID)) if e != nil { return modelpublic.Organization{}, fmt.Errorf("Failed to load organization %d: %w", report.OrganizationID, e) } return result, nil } func RegisterNotificationEmail(ctx context.Context, txn db.Ex, report modelpublicreport.Report, contact modelcomms.Contact, destination string) error { err := email.EnsureInDB(ctx, txn, contact, destination) if err != nil { return fmt.Errorf("Failed to ensure phone is in DB: %w", err) } _, err = querypublicreport.NotifyEmailCreate(ctx, txn, report.ID, destination) if err != nil { return err } return email.SendReportConfirmation(ctx, txn, contact, destination, report.PublicID) } func RegisterNotificationPhone(ctx context.Context, txn db.Ex, report modelpublicreport.Report, contact modelcomms.Contact, phone types.E164) error { err := text.EnsureInDB(ctx, txn, contact, phone) if err != nil { return fmt.Errorf("Failed to ensure phone is in DB: %w", err) } _, err = querypublicreport.NotifyPhoneCreate(ctx, txn, report.ID, phone.PhoneString()) if err != nil { return err } return text.ReportSubscriptionConfirmationText(ctx, db.PGInstance.PGXPool, phone, report.PublicID) } func RegisterSubscriptionEmail(ctx context.Context, txn db.Ex, contact modelcomms.Contact, destination string) error { _, err := querypublicreport.SubscribeEmailInsert(ctx, txn, modelpublicreport.SubscribeEmail{ Created: time.Now(), Deleted: nil, EmailAddress: destination, }) if err != nil { return fmt.Errorf("Failed to save new subscription email row: %w", err) } return nil } func RegisterSubscriptionPhone(ctx context.Context, txn db.Ex, contact modelcomms.Contact, phone types.E164) error { _, err := querypublicreport.SubscribePhoneInsert(ctx, txn, modelpublicreport.SubscribePhone{ Created: time.Now(), Deleted: nil, PhoneE164: phone.PhoneString(), }) if err != nil { return fmt.Errorf("Failed to save new subscription phone row: %w", err) } return nil } func SaveReporter(ctx context.Context, txn db.Ex, report modelpublicreport.Report, name string, email_address string, phone *types.E164, can_sms bool) (contact modelcomms.Contact, err error) { report_contact, err := querycomms.ContactFromID(ctx, txn, int64(report.ReporterContactID)) if err != nil { return contact, fmt.Errorf("contact query: %w", err) } email_contact, err := querycomms.ContactFromEmail(ctx, txn, email_address) if err != nil { return contact, fmt.Errorf("contact query: %w", err) } phone_contact, err := querycomms.ContactFromPhone(ctx, txn, phone.PhoneString()) if err != nil { return contact, fmt.Errorf("contact query: %w", err) } var new_contact_name string new_contact_id := report_contact.ID if phone_contact != nil { // Whether or not the contacts match, we're going to pick the phone contact // as the authoritative one, for no particular reason. new_contact_id = phone_contact.ID if phone_contact.Name != "" { new_contact_name = phone_contact.Name } if email_contact != nil && email_contact.ID != phone_contact.ID { err = querycomms.ContactEmailUpdateContactID(ctx, txn, email_address, int64(phone_contact.ID)) if err != nil { return contact, fmt.Errorf("update email contact %d (%d) to %d: %w", email_contact.ID, email_contact.ID, phone_contact.ID, err) } log.Info().Str("address", email_address).Str("e164", phone.PhoneString()).Int32("from-id", email_contact.ID).Int32("to-id", phone_contact.ID).Msg("merged email contact with phone contact") } } else if email_contact != nil { new_contact_id = email_contact.ID if email_contact.Name != "" { new_contact_name = email_contact.Name } } if name != "" { new_contact_name = name } if new_contact_id != 0 && new_contact_id != report_contact.ID { err = querypublicreport.ReportUpdateReporterContactID(ctx, txn, int64(report.ID), int64(new_contact_id)) if err != nil { return contact, fmt.Errorf("update report %d reporter contact from %d to %d: %w", report.ID, report.ReporterContactID, new_contact_id, err) } } if new_contact_name != "" { err = querycomms.ContactUpdateName(ctx, txn, int64(new_contact_id), new_contact_name) if err != nil { return contact, fmt.Errorf("update contact %d to name %s: %w", new_contact_id, new_contact_name, err) } } log.Debug().Str("name", name).Str("old name", contact.Name).Int32("id", contact.ID).Msg("contact updated") if email_address != "" && email_contact == nil { err = saveReporterEmail(ctx, txn, new_contact_id, email_address) if err != nil { return contact, fmt.Errorf("new contact email for '%s' on %d: %w", email_address, new_contact_id, err) } } if phone != nil && phone_contact == nil { err = saveReporterPhone(ctx, txn, new_contact_id, phone, can_sms) if err != nil { return contact, fmt.Errorf("new contact phone for '%s' on %d: %w", phone.PhoneString(), new_contact_id, err) } } return contact, nil } func saveReporterEmail(ctx context.Context, txn db.Ex, contact_id int32, email_address string) error { e, err := querycomms.ContactEmailInsert(ctx, txn, modelcomms.ContactEmail{ Address: email_address, Confirmed: false, ContactID: contact_id, IsSubscribed: false, }) if err != nil { return fmt.Errorf("contact add email: %w", err) } log.Info().Str("address", e.Address).Int32("contact_id", contact_id).Msg("Created contact email") return nil } func saveReporterPhone(ctx context.Context, txn db.Ex, contact_id int32, phone *types.E164, can_sms bool) error { if phone == nil { return nil } p, err := querycomms.ContactPhoneInsert(ctx, txn, modelcomms.ContactPhone{ CanSms: can_sms, ConfirmedMessageID: nil, ContactID: contact_id, E164: phone.PhoneString(), IsSubscribed: false, StopMessageID: nil, }) if err != nil { return fmt.Errorf("contact add phone: %w", err) } log.Info().Str("e164", p.E164).Int32("contact_id", contact_id).Msg("Created contact phone") return nil }