nidus-sync/platform/publicreport/notification.go

186 lines
7.3 KiB
Go
Raw Normal View History

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
}