This makes sense because there will naturally be cases where multiple districts have the same phone number mapped to different contacts.
185 lines
7.3 KiB
Go
185 lines
7.3 KiB
Go
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, number *types.E164, can_sms bool) error {
|
|
if number == nil {
|
|
return nil
|
|
}
|
|
_, err := querycomms.PhoneInsertIfNotExists(ctx, txn, modelcomms.Phone{
|
|
E164: number.PhoneString(),
|
|
CanSms: can_sms,
|
|
ConfirmedMessageID: nil,
|
|
StopMessageID: nil,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("insert phone if not exists: %w", err)
|
|
}
|
|
p, err := querycomms.ContactPhoneInsert(ctx, txn, modelcomms.ContactPhone{
|
|
ContactID: contact_id,
|
|
E164: number.PhoneString(),
|
|
IsSubscribed: false,
|
|
})
|
|
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
|
|
}
|