diff --git a/api/publicreport.go b/api/publicreport.go index 65f64483..fc69d381 100644 --- a/api/publicreport.go +++ b/api/publicreport.go @@ -10,17 +10,20 @@ import ( "github.com/Gleipnir-Technology/nidus-sync/platform" ) -type formPublicreportLead struct { +type formPublicreportSignal struct { ReportID string `json:"reportID"` } +type createdSignal struct { + ID int32 `json:"id"` +} -func postPublicreportLead(ctx context.Context, r *http.Request, user platform.User, req formPublicreportLead) (*createdLead, *nhttp.ErrorWithStatus) { - lead_id, err := platform.LeadCreateFromPublicreport(ctx, user, req.ReportID) +func postPublicreportSignal(ctx context.Context, r *http.Request, user platform.User, req formPublicreportSignal) (*createdSignal, *nhttp.ErrorWithStatus) { + signal_id, err := platform.SignalCreateFromPublicreport(ctx, user, req.ReportID) if err != nil { - return nil, nhttp.NewError("create lead: %w", err) + return nil, nhttp.NewError("create signal: %w", err) } - return &createdLead{ - ID: *lead_id, + return &createdSignal{ + ID: *signal_id, }, nil } @@ -31,10 +34,10 @@ type createdReport struct { URI string `json:"uri"` } -func postPublicreportInvalid(ctx context.Context, r *http.Request, user platform.User, req formPublicreportLead) (*createdReport, *nhttp.ErrorWithStatus) { +func postPublicreportInvalid(ctx context.Context, r *http.Request, user platform.User, req formPublicreportSignal) (*createdReport, *nhttp.ErrorWithStatus) { err := platform.PublicreportInvalid(ctx, user, req.ReportID) if err != nil { - return nil, nhttp.NewError("create lead: %w", err) + return nil, nhttp.NewError("create signal: %w", err) } return &createdReport{ URI: config.MakeURLNidus("/publicreport/%s", req.ReportID), diff --git a/api/routes.go b/api/routes.go index a458b6b9..25c9b43f 100644 --- a/api/routes.go +++ b/api/routes.go @@ -22,7 +22,7 @@ func AddRoutes(r chi.Router) { r.Method("POST", "/leads", authenticatedHandlerJSONPost(postLeads)) r.Method("GET", "/mosquito-source", auth.NewEnsureAuth(apiMosquitoSource)) r.Method("POST", "/publicreport/invalid", authenticatedHandlerJSONPost(postPublicreportInvalid)) - r.Method("POST", "/publicreport/lead", authenticatedHandlerJSONPost(postPublicreportLead)) + r.Method("POST", "/publicreport/signal", authenticatedHandlerJSONPost(postPublicreportSignal)) r.Method("POST", "/publicreport/message", authenticatedHandlerJSONPost(postPublicreportMessage)) r.Method("POST", "/review/pool", authenticatedHandlerJSONPost(postReviewPool)) r.Method("GET", "/review-task/pool", authenticatedHandlerJSON(listReviewTaskPool)) diff --git a/db/dbinfo/signal.bob.go b/db/dbinfo/signal.bob.go index c4f3c930..bffd3f25 100644 --- a/db/dbinfo/signal.bob.go +++ b/db/dbinfo/signal.bob.go @@ -96,6 +96,15 @@ var Signals = Table[ Generated: false, AutoIncr: false, }, + SiteID: column{ + Name: "site_id", + DBType: "integer", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, }, Indexes: signalIndexes{ SignalPkey: index{ @@ -149,6 +158,15 @@ var Signals = Table[ ForeignTable: "organization", ForeignColumns: []string{"id"}, }, + SignalSignalSiteIDFkey: foreignKey{ + constraint: constraint{ + Name: "signal.signal_site_id_fkey", + Columns: []string{"site_id"}, + Comment: "", + }, + ForeignTable: "site", + ForeignColumns: []string{"id"}, + }, }, Comment: "", @@ -164,11 +182,12 @@ type signalColumns struct { Species column Title column Type column + SiteID column } func (c signalColumns) AsSlice() []column { return []column{ - c.Addressed, c.Addressor, c.Created, c.Creator, c.ID, c.OrganizationID, c.Species, c.Title, c.Type, + c.Addressed, c.Addressor, c.Created, c.Creator, c.ID, c.OrganizationID, c.Species, c.Title, c.Type, c.SiteID, } } @@ -186,11 +205,12 @@ type signalForeignKeys struct { SignalSignalAddressorFkey foreignKey SignalSignalCreatorFkey foreignKey SignalSignalOrganizationIDFkey foreignKey + SignalSignalSiteIDFkey foreignKey } func (f signalForeignKeys) AsSlice() []foreignKey { return []foreignKey{ - f.SignalSignalAddressorFkey, f.SignalSignalCreatorFkey, f.SignalSignalOrganizationIDFkey, + f.SignalSignalAddressorFkey, f.SignalSignalCreatorFkey, f.SignalSignalOrganizationIDFkey, f.SignalSignalSiteIDFkey, } } diff --git a/db/migrations/00119_signal_from_publicreport.sql b/db/migrations/00119_signal_from_publicreport.sql new file mode 100644 index 00000000..6cbe8521 --- /dev/null +++ b/db/migrations/00119_signal_from_publicreport.sql @@ -0,0 +1,4 @@ +-- +goose Up +ALTER TABLE signal ADD COLUMN site_id INTEGER REFERENCES site(id); +-- +goose Down +ALTER TABLE signal DROP COLUMN site_id; diff --git a/db/models/signal.bob.go b/db/models/signal.bob.go index fa3c2610..732ffa4a 100644 --- a/db/models/signal.bob.go +++ b/db/models/signal.bob.go @@ -35,6 +35,7 @@ type Signal struct { Species null.Val[enums.Mosquitospecies] `db:"species" ` Title string `db:"title" ` Type enums.Signaltype `db:"type_" ` + SiteID null.Val[int32] `db:"site_id" ` R signalR `db:"-" ` } @@ -54,12 +55,13 @@ type signalR struct { AddressorUser *User // signal.signal_addressor_fkey CreatorUser *User // signal.signal_creator_fkey Organization *Organization // signal.signal_organization_id_fkey + Site *Site // signal.signal_site_id_fkey } func buildSignalColumns(alias string) signalColumns { return signalColumns{ ColumnsExpr: expr.NewColumnsExpr( - "addressed", "addressor", "created", "creator", "id", "organization_id", "species", "title", "type_", + "addressed", "addressor", "created", "creator", "id", "organization_id", "species", "title", "type_", "site_id", ).WithParent("signal"), tableAlias: alias, Addressed: psql.Quote(alias, "addressed"), @@ -71,6 +73,7 @@ func buildSignalColumns(alias string) signalColumns { Species: psql.Quote(alias, "species"), Title: psql.Quote(alias, "title"), Type: psql.Quote(alias, "type_"), + SiteID: psql.Quote(alias, "site_id"), } } @@ -86,6 +89,7 @@ type signalColumns struct { Species psql.Expression Title psql.Expression Type psql.Expression + SiteID psql.Expression } func (c signalColumns) Alias() string { @@ -109,10 +113,11 @@ type SignalSetter struct { Species omitnull.Val[enums.Mosquitospecies] `db:"species" ` Title omit.Val[string] `db:"title" ` Type omit.Val[enums.Signaltype] `db:"type_" ` + SiteID omitnull.Val[int32] `db:"site_id" ` } func (s SignalSetter) SetColumns() []string { - vals := make([]string, 0, 9) + vals := make([]string, 0, 10) if !s.Addressed.IsUnset() { vals = append(vals, "addressed") } @@ -140,6 +145,9 @@ func (s SignalSetter) SetColumns() []string { if s.Type.IsValue() { vals = append(vals, "type_") } + if !s.SiteID.IsUnset() { + vals = append(vals, "site_id") + } return vals } @@ -171,6 +179,9 @@ func (s SignalSetter) Overwrite(t *Signal) { if s.Type.IsValue() { t.Type = s.Type.MustGet() } + if !s.SiteID.IsUnset() { + t.SiteID = s.SiteID.MustGetNull() + } } func (s *SignalSetter) Apply(q *dialect.InsertQuery) { @@ -179,7 +190,7 @@ func (s *SignalSetter) Apply(q *dialect.InsertQuery) { }) q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { - vals := make([]bob.Expression, 9) + vals := make([]bob.Expression, 10) if !s.Addressed.IsUnset() { vals[0] = psql.Arg(s.Addressed.MustGetNull()) } else { @@ -234,6 +245,12 @@ func (s *SignalSetter) Apply(q *dialect.InsertQuery) { vals[8] = psql.Raw("DEFAULT") } + if !s.SiteID.IsUnset() { + vals[9] = psql.Arg(s.SiteID.MustGetNull()) + } else { + vals[9] = psql.Raw("DEFAULT") + } + return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "") })) } @@ -243,7 +260,7 @@ func (s SignalSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] { } func (s SignalSetter) Expressions(prefix ...string) []bob.Expression { - exprs := make([]bob.Expression, 0, 9) + exprs := make([]bob.Expression, 0, 10) if !s.Addressed.IsUnset() { exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ @@ -308,6 +325,13 @@ func (s SignalSetter) Expressions(prefix ...string) []bob.Expression { }}) } + if !s.SiteID.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "site_id")...), + psql.Arg(s.SiteID), + }}) + } + return exprs } @@ -606,6 +630,30 @@ func (os SignalSlice) Organization(mods ...bob.Mod[*dialect.SelectQuery]) Organi )...) } +// Site starts a query for related objects on site +func (o *Signal) Site(mods ...bob.Mod[*dialect.SelectQuery]) SitesQuery { + return Sites.Query(append(mods, + sm.Where(Sites.Columns.ID.EQ(psql.Arg(o.SiteID))), + )...) +} + +func (os SignalSlice) Site(mods ...bob.Mod[*dialect.SelectQuery]) SitesQuery { + pkSiteID := make(pgtypes.Array[null.Val[int32]], 0, len(os)) + for _, o := range os { + if o == nil { + continue + } + pkSiteID = append(pkSiteID, o.SiteID) + } + PKArgExpr := psql.Select(sm.Columns( + psql.F("unnest", psql.Cast(psql.Arg(pkSiteID), "integer[]")), + )) + + return Sites.Query(append(mods, + sm.Where(psql.Group(Sites.Columns.ID).OP("IN", PKArgExpr)), + )...) +} + func attachSignalAddressorUser0(ctx context.Context, exec bob.Executor, count int, signal0 *Signal, user1 *User) (*Signal, error) { setter := &SignalSetter{ Addressor: omitnull.From(user1.ID), @@ -750,6 +798,54 @@ func (signal0 *Signal) AttachOrganization(ctx context.Context, exec bob.Executor return nil } +func attachSignalSite0(ctx context.Context, exec bob.Executor, count int, signal0 *Signal, site1 *Site) (*Signal, error) { + setter := &SignalSetter{ + SiteID: omitnull.From(site1.ID), + } + + err := signal0.Update(ctx, exec, setter) + if err != nil { + return nil, fmt.Errorf("attachSignalSite0: %w", err) + } + + return signal0, nil +} + +func (signal0 *Signal) InsertSite(ctx context.Context, exec bob.Executor, related *SiteSetter) error { + var err error + + site1, err := Sites.Insert(related).One(ctx, exec) + if err != nil { + return fmt.Errorf("inserting related objects: %w", err) + } + + _, err = attachSignalSite0(ctx, exec, 1, signal0, site1) + if err != nil { + return err + } + + signal0.R.Site = site1 + + site1.R.Signals = append(site1.R.Signals, signal0) + + return nil +} + +func (signal0 *Signal) AttachSite(ctx context.Context, exec bob.Executor, site1 *Site) error { + var err error + + _, err = attachSignalSite0(ctx, exec, 1, signal0, site1) + if err != nil { + return err + } + + signal0.R.Site = site1 + + site1.R.Signals = append(site1.R.Signals, signal0) + + return nil +} + type signalWhere[Q psql.Filterable] struct { Addressed psql.WhereNullMod[Q, time.Time] Addressor psql.WhereNullMod[Q, int32] @@ -760,6 +856,7 @@ type signalWhere[Q psql.Filterable] struct { Species psql.WhereNullMod[Q, enums.Mosquitospecies] Title psql.WhereMod[Q, string] Type psql.WhereMod[Q, enums.Signaltype] + SiteID psql.WhereNullMod[Q, int32] } func (signalWhere[Q]) AliasedAs(alias string) signalWhere[Q] { @@ -777,6 +874,7 @@ func buildSignalWhere[Q psql.Filterable](cols signalColumns) signalWhere[Q] { Species: psql.WhereNull[Q, enums.Mosquitospecies](cols.Species), Title: psql.Where[Q, string](cols.Title), Type: psql.Where[Q, enums.Signaltype](cols.Type), + SiteID: psql.WhereNull[Q, int32](cols.SiteID), } } @@ -818,6 +916,18 @@ func (o *Signal) Preload(name string, retrieved any) error { o.R.Organization = rel + if rel != nil { + rel.R.Signals = SignalSlice{o} + } + return nil + case "Site": + rel, ok := retrieved.(*Site) + if !ok { + return fmt.Errorf("signal cannot load %T as %q", retrieved, name) + } + + o.R.Site = rel + if rel != nil { rel.R.Signals = SignalSlice{o} } @@ -831,6 +941,7 @@ type signalPreloader struct { AddressorUser func(...psql.PreloadOption) psql.Preloader CreatorUser func(...psql.PreloadOption) psql.Preloader Organization func(...psql.PreloadOption) psql.Preloader + Site func(...psql.PreloadOption) psql.Preloader } func buildSignalPreloader() signalPreloader { @@ -874,6 +985,19 @@ func buildSignalPreloader() signalPreloader { }, }, Organizations.Columns.Names(), opts...) }, + Site: func(opts ...psql.PreloadOption) psql.Preloader { + return psql.Preload[*Site, SiteSlice](psql.PreloadRel{ + Name: "Site", + Sides: []psql.PreloadSide{ + { + From: Signals, + To: Sites, + FromColumns: []string{"site_id"}, + ToColumns: []string{"id"}, + }, + }, + }, Sites.Columns.Names(), opts...) + }, } } @@ -881,6 +1005,7 @@ type signalThenLoader[Q orm.Loadable] struct { AddressorUser func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] CreatorUser func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] Organization func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + Site func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] } func buildSignalThenLoader[Q orm.Loadable]() signalThenLoader[Q] { @@ -893,6 +1018,9 @@ func buildSignalThenLoader[Q orm.Loadable]() signalThenLoader[Q] { type OrganizationLoadInterface interface { LoadOrganization(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } + type SiteLoadInterface interface { + LoadSite(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } return signalThenLoader[Q]{ AddressorUser: thenLoadBuilder[Q]( @@ -913,6 +1041,12 @@ func buildSignalThenLoader[Q orm.Loadable]() signalThenLoader[Q] { return retrieved.LoadOrganization(ctx, exec, mods...) }, ), + Site: thenLoadBuilder[Q]( + "Site", + func(ctx context.Context, exec bob.Executor, retrieved SiteLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadSite(ctx, exec, mods...) + }, + ), } } @@ -1074,3 +1208,58 @@ func (os SignalSlice) LoadOrganization(ctx context.Context, exec bob.Executor, m return nil } + +// LoadSite loads the signal's Site into the .R struct +func (o *Signal) LoadSite(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + // Reset the relationship + o.R.Site = nil + + related, err := o.Site(mods...).One(ctx, exec) + if err != nil { + return err + } + + related.R.Signals = SignalSlice{o} + + o.R.Site = related + return nil +} + +// LoadSite loads the signal's Site into the .R struct +func (os SignalSlice) LoadSite(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + sites, err := os.Site(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, o := range os { + if o == nil { + continue + } + + for _, rel := range sites { + if !o.SiteID.IsValue() { + continue + } + + if !(o.SiteID.IsValue() && o.SiteID.MustGet() == rel.ID) { + continue + } + + rel.R.Signals = append(rel.R.Signals, o) + + o.R.Site = rel + break + } + } + + return nil +} diff --git a/db/models/site.bob.go b/db/models/site.bob.go index 66af17a0..d8c39986 100644 --- a/db/models/site.bob.go +++ b/db/models/site.bob.go @@ -57,6 +57,7 @@ type siteR struct { Features FeatureSlice // feature.feature_site_id_fkey Leads LeadSlice // lead.lead_site_id_fkey Residents ResidentSlice // resident.resident_site_id_fkey + Signals SignalSlice // signal.signal_site_id_fkey Address *Address // site.site_address_id_fkey CreatorUser *User // site.site_creator_id_fkey File *FileuploadFile // site.site_file_id_fkey @@ -701,6 +702,30 @@ func (os SiteSlice) Residents(mods ...bob.Mod[*dialect.SelectQuery]) ResidentsQu )...) } +// Signals starts a query for related objects on signal +func (o *Site) Signals(mods ...bob.Mod[*dialect.SelectQuery]) SignalsQuery { + return Signals.Query(append(mods, + sm.Where(Signals.Columns.SiteID.EQ(psql.Arg(o.ID))), + )...) +} + +func (os SiteSlice) Signals(mods ...bob.Mod[*dialect.SelectQuery]) SignalsQuery { + pkID := make(pgtypes.Array[int32], 0, len(os)) + for _, o := range os { + if o == nil { + continue + } + pkID = append(pkID, o.ID) + } + PKArgExpr := psql.Select(sm.Columns( + psql.F("unnest", psql.Cast(psql.Arg(pkID), "integer[]")), + )) + + return Signals.Query(append(mods, + sm.Where(psql.Group(Signals.Columns.SiteID).OP("IN", PKArgExpr)), + )...) +} + // Address starts a query for related objects on address func (o *Site) Address(mods ...bob.Mod[*dialect.SelectQuery]) AddressesQuery { return Addresses.Query(append(mods, @@ -1001,6 +1026,74 @@ func (site0 *Site) AttachResidents(ctx context.Context, exec bob.Executor, relat return nil } +func insertSiteSignals0(ctx context.Context, exec bob.Executor, signals1 []*SignalSetter, site0 *Site) (SignalSlice, error) { + for i := range signals1 { + signals1[i].SiteID = omitnull.From(site0.ID) + } + + ret, err := Signals.Insert(bob.ToMods(signals1...)).All(ctx, exec) + if err != nil { + return ret, fmt.Errorf("insertSiteSignals0: %w", err) + } + + return ret, nil +} + +func attachSiteSignals0(ctx context.Context, exec bob.Executor, count int, signals1 SignalSlice, site0 *Site) (SignalSlice, error) { + setter := &SignalSetter{ + SiteID: omitnull.From(site0.ID), + } + + err := signals1.UpdateAll(ctx, exec, *setter) + if err != nil { + return nil, fmt.Errorf("attachSiteSignals0: %w", err) + } + + return signals1, nil +} + +func (site0 *Site) InsertSignals(ctx context.Context, exec bob.Executor, related ...*SignalSetter) error { + if len(related) == 0 { + return nil + } + + var err error + + signals1, err := insertSiteSignals0(ctx, exec, related, site0) + if err != nil { + return err + } + + site0.R.Signals = append(site0.R.Signals, signals1...) + + for _, rel := range signals1 { + rel.R.Site = site0 + } + return nil +} + +func (site0 *Site) AttachSignals(ctx context.Context, exec bob.Executor, related ...*Signal) error { + if len(related) == 0 { + return nil + } + + var err error + signals1 := SignalSlice(related) + + _, err = attachSiteSignals0(ctx, exec, len(related), signals1, site0) + if err != nil { + return err + } + + site0.R.Signals = append(site0.R.Signals, signals1...) + + for _, rel := range related { + rel.R.Site = site0 + } + + return nil +} + func attachSiteAddress0(ctx context.Context, exec bob.Executor, count int, site0 *Site, address1 *Address) (*Site, error) { setter := &SiteSetter{ AddressID: omit.From(address1.ID), @@ -1273,6 +1366,20 @@ func (o *Site) Preload(name string, retrieved any) error { o.R.Residents = rels + for _, rel := range rels { + if rel != nil { + rel.R.Site = o + } + } + return nil + case "Signals": + rels, ok := retrieved.(SignalSlice) + if !ok { + return fmt.Errorf("site cannot load %T as %q", retrieved, name) + } + + o.R.Signals = rels + for _, rel := range rels { if rel != nil { rel.R.Site = o @@ -1400,6 +1507,7 @@ type siteThenLoader[Q orm.Loadable] struct { Features func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] Leads func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] Residents func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + Signals func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] Address func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] CreatorUser func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] File func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] @@ -1416,6 +1524,9 @@ func buildSiteThenLoader[Q orm.Loadable]() siteThenLoader[Q] { type ResidentsLoadInterface interface { LoadResidents(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } + type SignalsLoadInterface interface { + LoadSignals(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } type AddressLoadInterface interface { LoadAddress(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } @@ -1448,6 +1559,12 @@ func buildSiteThenLoader[Q orm.Loadable]() siteThenLoader[Q] { return retrieved.LoadResidents(ctx, exec, mods...) }, ), + Signals: thenLoadBuilder[Q]( + "Signals", + func(ctx context.Context, exec bob.Executor, retrieved SignalsLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadSignals(ctx, exec, mods...) + }, + ), Address: thenLoadBuilder[Q]( "Address", func(ctx context.Context, exec bob.Executor, retrieved AddressLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { @@ -1661,6 +1778,70 @@ func (os SiteSlice) LoadResidents(ctx context.Context, exec bob.Executor, mods . return nil } +// LoadSignals loads the site's Signals into the .R struct +func (o *Site) LoadSignals(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + // Reset the relationship + o.R.Signals = nil + + related, err := o.Signals(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, rel := range related { + rel.R.Site = o + } + + o.R.Signals = related + return nil +} + +// LoadSignals loads the site's Signals into the .R struct +func (os SiteSlice) LoadSignals(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + signals, err := os.Signals(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, o := range os { + if o == nil { + continue + } + + o.R.Signals = nil + } + + for _, o := range os { + if o == nil { + continue + } + + for _, rel := range signals { + + if !rel.SiteID.IsValue() { + continue + } + if !(rel.SiteID.IsValue() && o.ID == rel.SiteID.MustGet()) { + continue + } + + rel.R.Site = o + + o.R.Signals = append(o.R.Signals, rel) + } + } + + return nil +} + // LoadAddress loads the site's Address into the .R struct func (o *Site) LoadAddress(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if o == nil { diff --git a/html/template/sync/communication-root.html b/html/template/sync/communication-root.html index 2a9efc12..95bbf2bf 100644 --- a/html/template/sync/communication-root.html +++ b/html/template/sync/communication-root.html @@ -154,12 +154,12 @@ } }, - async createLead() { + async createSignal() { try { const payload = { reportID: this.selectedCommunication.id, }; - const response = await fetch(`api/publicreport/lead`, { + const response = await fetch(`api/publicreport/signal`, { method: "POST", headers: { "Content-Type": "application/json", @@ -167,7 +167,7 @@ body: JSON.stringify(payload), }); if (!response.ok) { - throw new Error("Failed to submit lead"); + throw new Error("Failed to submit signal"); } // Remove from list after creating lead this.removeCurrentFromList(); @@ -759,13 +759,16 @@