This in a pretty huge change. At a high level we're adding the concept of a 'contact' which is a person or organization that has zero or more contact methods (email, phone). This ended up cascading a number of changes, including critically to the publicreprt schema. In the end it seemed safer to get to the point where I'm confident we aren't using any of the old fields for storing reporter information (though I haven't deleted the columns yet) so I removed the code for defining those columns. At this point I think it's not possible for me to regenerate the bob schema due to the interdependencies between my various schemas, so the migration is well-and-truly happening.
182 lines
6.5 KiB
Go
182 lines
6.5 KiB
Go
package platform
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/Gleipnir-Technology/nidus-sync/db"
|
|
modelpublic "github.com/Gleipnir-Technology/nidus-sync/db/gen/nidus-sync/public/model"
|
|
modelpublicreport "github.com/Gleipnir-Technology/nidus-sync/db/gen/nidus-sync/publicreport/model"
|
|
querycomms "github.com/Gleipnir-Technology/nidus-sync/db/query/comms"
|
|
querypublic "github.com/Gleipnir-Technology/nidus-sync/db/query/public"
|
|
querypublicreport "github.com/Gleipnir-Technology/nidus-sync/db/query/publicreport"
|
|
"github.com/Gleipnir-Technology/nidus-sync/lint"
|
|
"github.com/Gleipnir-Technology/nidus-sync/platform/event"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
type RelatedRecordType int
|
|
|
|
const (
|
|
RelatedRecordTypeUnknown RelatedRecordType = iota
|
|
RelatedRecordTypeEmail
|
|
RelatedRecordTypeReportCompliance
|
|
RelatedRecordTypeReportNuisance
|
|
RelatedRecordTypeReportWater
|
|
RelatedRecordTypeText
|
|
)
|
|
|
|
func recordTypeFromReportType(t modelpublicreport.Reporttype) RelatedRecordType {
|
|
switch t {
|
|
case modelpublicreport.Reporttype_Compliance:
|
|
return RelatedRecordTypeReportCompliance
|
|
case modelpublicreport.Reporttype_Nuisance:
|
|
return RelatedRecordTypeReportNuisance
|
|
case modelpublicreport.Reporttype_Water:
|
|
return RelatedRecordTypeReportWater
|
|
default:
|
|
return RelatedRecordTypeUnknown
|
|
}
|
|
}
|
|
|
|
type RelatedRecord struct {
|
|
Created time.Time
|
|
ID string
|
|
Type RelatedRecordType
|
|
}
|
|
|
|
func CommunicationRelatedRecords(ctx context.Context, user User, comm *modelpublic.Communication) ([]RelatedRecord, error) {
|
|
// Gather associated records
|
|
// * address
|
|
// * phone number
|
|
// * email
|
|
// * name
|
|
txn := db.PGInstance.PGXPool
|
|
result := make([]RelatedRecord, 0)
|
|
if comm.SourceEmailLogID != nil {
|
|
email_log, err := querycomms.EmailLogFromID(ctx, int64(*comm.SourceEmailLogID))
|
|
if err != nil {
|
|
return result, fmt.Errorf("email log from ID: %w", err)
|
|
}
|
|
email_logs, err := querycomms.EmailLogsFromAddress(ctx, email_log.Source)
|
|
if err != nil {
|
|
return result, fmt.Errorf("email log from ID: %w", err)
|
|
}
|
|
for _, l := range email_logs {
|
|
result = append(result, RelatedRecord{
|
|
Created: l.Created,
|
|
ID: strconv.Itoa(int(l.ID)),
|
|
Type: RelatedRecordTypeEmail,
|
|
})
|
|
}
|
|
} else if comm.SourceTextLogID != nil {
|
|
text_log, err := querycomms.TextLogFromID(ctx, txn, int64(*comm.SourceTextLogID))
|
|
if err != nil {
|
|
return result, fmt.Errorf("text log from ID: %w", err)
|
|
}
|
|
text_logs, err := querycomms.EmailLogsFromAddress(ctx, text_log.Source)
|
|
if err != nil {
|
|
return result, fmt.Errorf("text log from ID: %w", err)
|
|
}
|
|
for _, l := range text_logs {
|
|
result = append(result, RelatedRecord{
|
|
Created: l.Created,
|
|
ID: strconv.Itoa(int(l.ID)),
|
|
Type: RelatedRecordTypeText,
|
|
})
|
|
}
|
|
} else if comm.SourceReportID != nil {
|
|
report, err := querypublicreport.ReportFromID(ctx, txn, int64(*comm.SourceReportID))
|
|
if err != nil {
|
|
return result, fmt.Errorf("report from ID: %w", err)
|
|
}
|
|
if report.ReporterName != "" {
|
|
reports_by_name, err := querypublicreport.ReportsFromReporterName(ctx, db.PGInstance.PGXPool, int64(user.Organization.ID), report.ReporterName)
|
|
if err != nil {
|
|
return result, fmt.Errorf("reports from reporter name '%s': %w", report.ReporterName, err)
|
|
}
|
|
for _, r := range reports_by_name {
|
|
record_type := recordTypeFromReportType(r.ReportType)
|
|
result = append(result, RelatedRecord{
|
|
Created: r.Created,
|
|
ID: r.PublicID,
|
|
Type: record_type,
|
|
})
|
|
}
|
|
}
|
|
if report.AddressID != nil {
|
|
reports_by_address, err := querypublicreport.ReportsFromAddressID(ctx, db.PGInstance.PGXPool, int64(user.Organization.ID), int64(*report.AddressID))
|
|
if err != nil {
|
|
return result, fmt.Errorf("reports from reporter name '%s': %w", report.ReporterName, err)
|
|
}
|
|
for _, r := range reports_by_address {
|
|
record_type := recordTypeFromReportType(r.ReportType)
|
|
result = append(result, RelatedRecord{
|
|
Created: r.Created,
|
|
ID: r.PublicID,
|
|
Type: record_type,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|
|
func CommunicationsForOrganization(ctx context.Context, org_id int64) ([]modelpublic.Communication, error) {
|
|
txn := db.PGInstance.PGXPool
|
|
return querypublic.CommunicationsFromOrganization(ctx, txn, org_id)
|
|
}
|
|
func CommunicationFromID(ctx context.Context, user User, comm_id int64) (*modelpublic.Communication, error) {
|
|
txn := db.PGInstance.PGXPool
|
|
comm, err := querypublic.CommunicationFromID(ctx, txn, comm_id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if comm.OrganizationID != user.Organization.ID {
|
|
return nil, nil
|
|
}
|
|
return &comm, nil
|
|
}
|
|
func CommunicationMarkInvalid(ctx context.Context, user User, comm_id int32) error {
|
|
return communicationMark(ctx, user, comm_id, modelpublic.Communicationstatus_Invalid, modelpublic.Communicationlogentry_StatusInvalidated)
|
|
}
|
|
func CommunicationMarkPendingResponse(ctx context.Context, user User, comm_id int32) error {
|
|
return communicationMark(ctx, user, comm_id, modelpublic.Communicationstatus_Pending, modelpublic.Communicationlogentry_StatusPending)
|
|
}
|
|
func CommunicationMarkPossibleIssue(ctx context.Context, user User, comm_id int32) error {
|
|
return communicationMark(ctx, user, comm_id, modelpublic.Communicationstatus_PossibleIssue, modelpublic.Communicationlogentry_StatusPossibleIssue)
|
|
}
|
|
func CommunicationMarkPossibleResolved(ctx context.Context, user User, comm_id int32) error {
|
|
return communicationMark(ctx, user, comm_id, modelpublic.Communicationstatus_PossibleResolved, modelpublic.Communicationlogentry_StatusPossibleResolved)
|
|
}
|
|
|
|
func communicationMark(ctx context.Context, user User, comm_id int32, status modelpublic.Communicationstatus, log_type modelpublic.Communicationlogentry) error {
|
|
txn, err := db.BeginTxn(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("begin txn: %w", err)
|
|
}
|
|
defer lint.LogOnErrRollback(txn.Rollback, ctx, "rollback")
|
|
err = querypublic.CommunicationSetStatus(ctx, txn, int64(user.Organization.ID), int64(comm_id), status)
|
|
if err != nil {
|
|
return fmt.Errorf("mark: %w", err)
|
|
}
|
|
user_id := int32(user.ID)
|
|
log_entry := modelpublic.CommunicationLogEntry{
|
|
CommunicationID: comm_id,
|
|
Created: time.Now(),
|
|
Type: log_type,
|
|
User: &user_id,
|
|
}
|
|
_, err = querypublic.CommunicationLogEntryInsert(ctx, txn, log_entry)
|
|
if err != nil {
|
|
return fmt.Errorf("insert communication log entry: %w", err)
|
|
}
|
|
if err := txn.Commit(ctx); err != nil {
|
|
return fmt.Errorf("commit: %w", err)
|
|
}
|
|
log.Info().Int32("communication", comm_id).Str("status", status.String()).Msg("Marked communication")
|
|
|
|
event.Updated(event.TypeCommunication, user.Organization.ID, strconv.Itoa(int(comm_id)))
|
|
return nil
|
|
}
|