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.
198 lines
6.3 KiB
Go
198 lines
6.3 KiB
Go
package publicreport
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/Gleipnir-Technology/bob"
|
|
"github.com/Gleipnir-Technology/bob/dialect/psql"
|
|
"github.com/Gleipnir-Technology/bob/dialect/psql/sm"
|
|
"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"
|
|
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/platform/types"
|
|
//"github.com/google/uuid"
|
|
"github.com/rs/zerolog/log"
|
|
"github.com/stephenafamo/scan"
|
|
)
|
|
|
|
func ByIDCompliance(ctx context.Context, public_id string, is_public bool) (*types.PublicReportCompliance, error) {
|
|
report, err := byID(ctx, public_id, is_public)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("base report byid: %w", err)
|
|
}
|
|
if report == nil {
|
|
return nil, nil
|
|
}
|
|
return compliance(ctx, public_id, *report)
|
|
}
|
|
func ByIDNuisance(ctx context.Context, public_id string, is_public bool) (*types.PublicReportNuisance, error) {
|
|
report, err := byID(ctx, public_id, is_public)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("base report byid: %w", err)
|
|
}
|
|
if report == nil {
|
|
return nil, nil
|
|
}
|
|
return nuisance(ctx, public_id, *report)
|
|
}
|
|
func ByIDWater(ctx context.Context, public_id string, is_public bool) (*types.PublicReportWater, error) {
|
|
report, err := byID(ctx, public_id, is_public)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("base report byid: %w", err)
|
|
}
|
|
if report == nil {
|
|
return nil, nil
|
|
}
|
|
return water(ctx, public_id, *report)
|
|
}
|
|
func UnreviewedForOrganization(ctx context.Context, txn db.Ex, org_id int64, is_public bool) ([]types.PublicReport, error) {
|
|
reports, err := querypublicreport.ReportsUnreviewedForOrganization(ctx, txn, org_id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("reports unreviewed: %w", err)
|
|
}
|
|
return reportQueryToRows(ctx, reports, is_public)
|
|
}
|
|
func byID(ctx context.Context, public_id string, is_public bool) (*types.PublicReport, error) {
|
|
report, err := querypublicreport.ReportFromPublicID(ctx, db.PGInstance.PGXPool, public_id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("query report from public ID: %w", err)
|
|
}
|
|
if report == nil {
|
|
return nil, nil
|
|
}
|
|
reports, err := reportQueryToRows(ctx, []modelpublicreport.Report{*report}, is_public)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("query to rows: %w", err)
|
|
}
|
|
log.Debug().Str("public_id", public_id).Int("len", len(reports)).Msg("querying for publicreport by ID")
|
|
if len(reports) != 1 {
|
|
return nil, nil
|
|
}
|
|
return &reports[0], nil
|
|
}
|
|
func reportQueryToRows(ctx context.Context, reports []modelpublicreport.Report, is_public bool) ([]types.PublicReport, error) {
|
|
address_ids := make([]int64, 0)
|
|
report_ids := make([]int32, len(reports))
|
|
for i, report := range reports {
|
|
report_ids[i] = report.ID
|
|
if report.AddressID != nil {
|
|
address_ids = append(address_ids, int64(*report.AddressID))
|
|
} else {
|
|
log.Debug().Int32("id", report.ID).Msg("has no address")
|
|
}
|
|
}
|
|
images_by_id, err := loadImagesForReport(ctx, report_ids)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("images for report: %w", err)
|
|
}
|
|
logs_by_report_id, err := logEntriesByReportID(ctx, report_ids, is_public)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("log entries for reports: %w", err)
|
|
}
|
|
addresses, err := querypublic.AddressesFromIDs(ctx, db.PGInstance.PGXPool, address_ids)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("addresses for reports: %w", err)
|
|
}
|
|
addresses_by_id := make(map[int64]modelpublic.Address, 0)
|
|
for _, address := range addresses {
|
|
addresses_by_id[int64(address.ID)] = address
|
|
}
|
|
|
|
results := make([]types.PublicReport, len(reports))
|
|
for i, row := range reports {
|
|
var images []types.Image
|
|
images, ok := images_by_id[row.ID]
|
|
if !ok {
|
|
images = []types.Image{}
|
|
}
|
|
logs, ok := logs_by_report_id[row.ID]
|
|
if !ok {
|
|
return nil, fmt.Errorf("impossible, missing logs for %d", row.ID)
|
|
}
|
|
var location *types.Location
|
|
if row.Location == nil {
|
|
location = nil
|
|
}
|
|
var address *types.Address
|
|
if row.AddressID != nil {
|
|
addr, ok := addresses_by_id[int64(*row.AddressID)]
|
|
if !ok {
|
|
return nil, fmt.Errorf("impossible, missing address %d", row.AddressID)
|
|
}
|
|
a := types.AddressFromModel(addr)
|
|
address = &a
|
|
}
|
|
if address == nil {
|
|
address = &types.Address{
|
|
ID: row.AddressID,
|
|
GID: row.AddressGid,
|
|
Raw: row.AddressRaw,
|
|
}
|
|
}
|
|
results[i] = types.PublicReport{
|
|
Address: *address,
|
|
Concerns: nil,
|
|
Created: row.Created,
|
|
ID: row.ID,
|
|
Images: images,
|
|
Location: location,
|
|
Log: logs,
|
|
DistrictID: &row.OrganizationID,
|
|
District: nil,
|
|
PublicID: row.PublicID,
|
|
Reporter: types.Contact{
|
|
CanSMS: &row.ReporterPhoneCanSms,
|
|
Email: &row.ReporterEmail,
|
|
HasEmail: row.ReporterEmail != "",
|
|
HasPhone: row.ReporterPhone != "",
|
|
Name: row.ReporterName,
|
|
Phone: &row.ReporterPhone,
|
|
},
|
|
Status: row.Status.String(),
|
|
Type: row.ReportType.String(),
|
|
URI: "",
|
|
}
|
|
}
|
|
return results, nil
|
|
}
|
|
func Reports(ctx context.Context, org_id int64, ids []int64, is_public bool) ([]types.PublicReport, error) {
|
|
reports, err := querypublicreport.ReportsFromIDsForOrg(ctx, db.PGInstance.PGXPool, ids, org_id)
|
|
if err != nil {
|
|
return []types.PublicReport{}, fmt.Errorf("reports from ID for org: %w", err)
|
|
}
|
|
return reportQueryToRows(ctx, reports, is_public)
|
|
}
|
|
func ReportsForOrganizationCount(ctx context.Context, org_id int32) (uint, error) {
|
|
type _Row struct {
|
|
Count uint `db:"count"`
|
|
}
|
|
row, err := bob.One(ctx, db.PGInstance.BobDB, psql.Select(
|
|
sm.Columns(
|
|
"COUNT(*) AS count",
|
|
),
|
|
sm.From("publicreport.report"),
|
|
sm.Where(psql.Quote("publicreport", "report", "organization_id").EQ(psql.Arg(org_id))),
|
|
), scan.StructMapper[_Row]())
|
|
if err != nil {
|
|
return 0, fmt.Errorf("query count: %w", err)
|
|
}
|
|
return row.Count, nil
|
|
}
|
|
func copyReportContent(src types.PublicReport, dst *types.PublicReport) {
|
|
dst.Address = src.Address
|
|
dst.Created = src.Created
|
|
dst.ID = src.ID
|
|
dst.Images = src.Images
|
|
dst.Location = src.Location
|
|
dst.Log = src.Log
|
|
dst.DistrictID = src.DistrictID
|
|
dst.District = src.District
|
|
dst.PublicID = src.PublicID
|
|
dst.Reporter = src.Reporter
|
|
dst.Status = src.Status
|
|
dst.Type = src.Type
|
|
dst.URI = src.URI
|
|
}
|