diff --git a/api/event.go b/api/event.go index 9bf24924..d9b8094e 100644 --- a/api/event.go +++ b/api/event.go @@ -47,7 +47,7 @@ func SetEventChannel(chan_envelopes <-chan platform.Envelope) { go func() { for envelope := range chan_envelopes { for conn, _ := range connectionsSSE { - if conn.organizationID == envelope.OrganizationID { + if conn.organizationID == envelope.OrganizationID || conn.organizationID == 0 { log.Debug().Int("type", int(envelope.Event.Type)).Int32("env-org", envelope.OrganizationID).Msg("pushed event to client") conn.chanEvent <- envelope.Event } else if conn.userID == envelope.UserID { diff --git a/platform/district.go b/platform/district.go index e2336ff2..9035e7b1 100644 --- a/platform/district.go +++ b/platform/district.go @@ -40,7 +40,7 @@ func DistrictForLocation(ctx context.Context, lng float64, lat float64) (*models return nil, errors.New("too many organizations") } } -func matchDistrict(ctx context.Context, location *types.Location, images []ImageUpload) (*int32, error) { +func matchDistrict(ctx context.Context, location *types.Location, images []ImageUpload) (int32, error) { var err error var org *models.Organization for _, image := range images { @@ -56,32 +56,32 @@ func matchDistrict(ctx context.Context, location *types.Location, images []Image continue } if org != nil { - return &org.ID, nil + return org.ID, nil } } if location != nil { if location.Longitude == 0 || location.Latitude == 0 { org, err = DistrictCatchall(ctx) if err != nil { - return nil, fmt.Errorf("get catchall: %w", err) + return 0, fmt.Errorf("get catchall: %w", err) } log.Debug().Int32("id", org.ID).Msg("No location from images, no latlng for the report itself, using catchall") - return &org.ID, nil + return org.ID, nil } org, err = DistrictForLocation(ctx, location.Longitude, location.Latitude) if err != nil { log.Warn().Err(err).Msg("Failed to get district for location") - return nil, fmt.Errorf("Failed to get district for location: %w", err) + return 0, fmt.Errorf("Failed to get district for location: %w", err) } } if org == nil { org, err = DistrictCatchall(ctx) if err != nil { - return nil, fmt.Errorf("get catchall: %w", err) + return 0, fmt.Errorf("get catchall: %w", err) } log.Debug().Err(err).Int32("id", org.ID).Msg("No district match by report location, using catchall") - return &org.ID, nil + return org.ID, nil } log.Debug().Err(err).Int32("org_id", org.ID).Msg("Found district match by report location") - return &org.ID, nil + return org.ID, nil } diff --git a/platform/publicreport.go b/platform/publicreport.go index 24f04b22..aacbfd15 100644 --- a/platform/publicreport.go +++ b/platform/publicreport.go @@ -183,8 +183,8 @@ func PublicReportReporterUpdated(ctx context.Context, org_id int32, report_id st func PublicReportsForOrganization(ctx context.Context, org_id int32) ([]*types.PublicReport, error) { return publicreport.ReportsForOrganization(ctx, org_id) } -func PublicReportComplianceCreate(ctx context.Context, setter_report models.PublicreportReportSetter, setter_compliance models.PublicreportComplianceSetter) (*models.PublicreportReport, error) { - return publicReportCreate(ctx, setter_report, nil, nil, nil, func(ctx context.Context, txn bob.Executor, report_id int32) error { +func PublicReportComplianceCreate(ctx context.Context, setter_report models.PublicreportReportSetter, setter_compliance models.PublicreportComplianceSetter, org_id int32) (*models.PublicreportReport, error) { + return publicReportCreate(ctx, setter_report, nil, nil, nil, org_id, func(ctx context.Context, txn bob.Executor, report_id int32) error { setter_compliance.ReportID = omit.From(report_id) _, err := models.PublicreportCompliances.Insert(&setter_compliance).One(ctx, txn) if err != nil { @@ -226,7 +226,7 @@ func PublicReportImageCreate(ctx context.Context, public_id string, images []Ima return nil } func PublicReportNuisanceCreate(ctx context.Context, setter_report models.PublicreportReportSetter, setter_nuisance models.PublicreportNuisanceSetter, location types.Location, address Address, images []ImageUpload) (*models.PublicreportReport, error) { - return publicReportCreate(ctx, setter_report, &location, &address, images, func(ctx context.Context, txn bob.Executor, report_id int32) error { + return publicReportCreate(ctx, setter_report, &location, &address, images, 0, func(ctx context.Context, txn bob.Executor, report_id int32) error { setter_nuisance.ReportID = omit.From(report_id) _, err := models.PublicreportNuisances.Insert(&setter_nuisance).One(ctx, txn) if err != nil { @@ -237,7 +237,7 @@ func PublicReportNuisanceCreate(ctx context.Context, setter_report models.Public } func PublicReportWaterCreate(ctx context.Context, setter_report models.PublicreportReportSetter, setter_water models.PublicreportWaterSetter, location types.Location, address Address, images []ImageUpload) (*models.PublicreportReport, error) { - return publicReportCreate(ctx, setter_report, &location, &address, images, func(ctx context.Context, txn bob.Executor, report_id int32) error { + return publicReportCreate(ctx, setter_report, &location, &address, images, 0, func(ctx context.Context, txn bob.Executor, report_id int32) error { setter_water.ReportID = omit.From(report_id) _, err := models.PublicreportWaters.Insert(&setter_water).One(ctx, txn) if err != nil { @@ -258,7 +258,7 @@ func PublicReportTypeByID(ctx context.Context, public_id string) (string, error) type funcSetReportDetail = func(context.Context, bob.Executor, int32) error -func publicReportCreate(ctx context.Context, setter_report models.PublicreportReportSetter, location *types.Location, address *Address, images []ImageUpload, detail_setter funcSetReportDetail) (result *models.PublicreportReport, err error) { +func publicReportCreate(ctx context.Context, setter_report models.PublicreportReportSetter, location *types.Location, address *Address, images []ImageUpload, organization_id int32, detail_setter funcSetReportDetail) (result *models.PublicreportReport, err error) { txn, err := db.PGInstance.BobDB.BeginTx(ctx, nil) if err != nil { return nil, fmt.Errorf("create txn: %w", err) @@ -284,18 +284,17 @@ func publicReportCreate(ctx context.Context, setter_report models.PublicreportRe if err != nil { return nil, fmt.Errorf("Failed to save image uploads: %w", err) } - var organization_id *int32 - organization_id, err = matchDistrict(ctx, location, images) - if err != nil { - log.Warn().Err(err).Msg("Failed to match district") + if organization_id == 0 { + organization_id, err = matchDistrict(ctx, location, images) + if err != nil { + log.Warn().Err(err).Msg("Failed to match district") + } } + setter_report.OrganizationID = omit.From(organization_id) if addr != nil { setter_report.AddressID = omitnull.From(addr.ID) } - if organization_id != nil { - setter_report.OrganizationID = omit.FromPtr(organization_id) - } result, err = models.PublicreportReports.Insert(&setter_report).One(ctx, txn) if err != nil { return nil, fmt.Errorf("Failed to create report database record: %w", err) @@ -340,13 +339,11 @@ func publicReportCreate(ctx context.Context, setter_report models.PublicreportRe txn.Commit(ctx) - if organization_id != nil { - event.Created( - event.TypeRMOPublicReport, - *organization_id, - result.PublicID, - ) - } + event.Created( + event.TypeRMOPublicReport, + organization_id, + result.PublicID, + ) return result, nil } func publicReportFromID(ctx context.Context, public_id string) (*models.PublicreportReport, error) { diff --git a/resource/publicreport_compliance.go b/resource/publicreport_compliance.go index 91f35dba..51b70a34 100644 --- a/resource/publicreport_compliance.go +++ b/resource/publicreport_compliance.go @@ -33,6 +33,22 @@ type compliance struct { URI string `json:"uri"` } +type publicreportComplianceForm struct { + AccessInstructions omit.Val[string] `schema:"access_instructions" json:"access_instructions"` + Address omit.Val[types.Address] `schema:"address" json:"address"` + AvailabilityNotes omit.Val[string] `schema:"availability_notes" json:"availability_notes"` + ClientID uuid.UUID `schema:"client_id" json:"client_id"` + Comments omit.Val[string] `schema:"comments" json:"comments"` + District omit.Val[string] `schema:"district" json:"district"` + GateCode omit.Val[string] `schema:"gate_code" json:"gate_code"` + HasDog omitnull.Val[bool] `schema:"has_dog" json:"has_dog"` + Location omit.Val[types.Location] `schema:"location" json:"location"` + PermissionType omit.Val[enums.Permissionaccesstype] `schema:"permission_type" json:"permission_type"` + Reporter omit.Val[types.Contact] `schema:"reporter" json:"reporter"` + ReportPhoneCanSMS omitnull.Val[bool] `schema:"report_phone_can_text" json:"report_phone_can_text"` + WantsScheduled omitnull.Val[bool] `schema:"wants_scheduled" json:"wants_scheduled"` +} + func (res *complianceR) ByID(ctx context.Context, r *http.Request, query QueryParams) (*types.PublicReportCompliance, *nhttp.ErrorWithStatus) { vars := mux.Vars(r) public_id := vars["id"] @@ -48,8 +64,15 @@ func (res *complianceR) ByID(ctx context.Context, r *http.Request, query QueryPa return report, nil } func (res *complianceR) Create(ctx context.Context, r *http.Request, n publicreportComplianceForm) (*compliance, *nhttp.ErrorWithStatus) { + if n.District.IsUnset() { + return nil, nhttp.NewBadRequest("You must provide a district_id") + } + district_id, err := res.router.IDFromURI("district.ByIDGet", n.District.MustGet()) + if err != nil || district_id == nil { + return nil, nhttp.NewBadRequest("parse district ID: %w", err) + } user_agent := r.Header.Get("User-Agent") - err := platform.EnsureClient(ctx, n.ClientID, user_agent) + err = platform.EnsureClient(ctx, n.ClientID, user_agent) if err != nil { return nil, nhttp.NewError("Failed to ensure client: %w", err) } @@ -65,7 +88,7 @@ func (res *complianceR) Create(ctx context.Context, r *http.Request, n publicrep //Location: omitnull.From(fmt.Sprintf("ST_GeometryFromText(Point(%s %s))", longitude, latitude)), Location: omitnull.FromPtr[string](nil), MapZoom: omit.From(float32(0.0)), - //OrganizationID: omitnull.FromPtr(organization_id), + //OrganizationID: omit.From[int32](int32(*district_id)), //PublicID: omit.From(public_id), ReporterEmail: omit.From(""), ReporterName: omit.From(""), @@ -84,7 +107,7 @@ func (res *complianceR) Create(ctx context.Context, r *http.Request, n publicrep //ReportID omit.Val[int32] WantsScheduled: omitnull.FromPtr[bool](nil), } - report, err := platform.PublicReportComplianceCreate(ctx, setter_report, setter_compliance) + report, err := platform.PublicReportComplianceCreate(ctx, setter_report, setter_compliance, int32(*district_id)) if err != nil { return nil, nhttp.NewError("create compliance report: %w", err) } @@ -102,22 +125,6 @@ func (res *complianceR) Create(ctx context.Context, r *http.Request, n publicrep URI: uri, }, nil } - -type publicreportComplianceForm struct { - AccessInstructions omit.Val[string] `schema:"access_instructions" json:"access_instructions"` - Address omit.Val[types.Address] `schema:"address" json:"address"` - AvailabilityNotes omit.Val[string] `schema:"availability_notes" json:"availability_notes"` - ClientID uuid.UUID `schema:"client_id" json:"client_id"` - Comments omit.Val[string] `schema:"comments" json:"comments"` - GateCode omit.Val[string] `schema:"gate_code" json:"gate_code"` - HasDog omitnull.Val[bool] `schema:"has_dog" json:"has_dog"` - Location omit.Val[types.Location] `schema:"location" json:"location"` - PermissionType omit.Val[enums.Permissionaccesstype] `schema:"permission_type" json:"permission_type"` - Reporter omit.Val[types.Contact] `schema:"reporter" json:"reporter"` - ReportPhoneCanSMS omitnull.Val[bool] `schema:"report_phone_can_text" json:"report_phone_can_text"` - WantsScheduled omitnull.Val[bool] `schema:"wants_scheduled" json:"wants_scheduled"` -} - func (res *complianceR) Update(ctx context.Context, r *http.Request, prf publicreportComplianceForm) (*types.PublicReportCompliance, *nhttp.ErrorWithStatus) { vars := mux.Vars(r) public_id := vars["id"] diff --git a/resource/router.go b/resource/router.go index 180bcd30..2e4adeb1 100644 --- a/resource/router.go +++ b/resource/router.go @@ -19,6 +19,34 @@ func NewRouter(r *mux.Router) *router { router: r, } } +func (r *router) IDFromURI(route string, uri string) (*int, error) { + var match mux.RouteMatch + req, _ := http.NewRequest("GET", uri, nil) + if !r.router.Match(req, &match) { + return nil, fmt.Errorf("URI does not match any known route: %s", uri) + } + + route_name := match.Route.GetName() + if route_name != route { + return nil, fmt.Errorf("URI is not for the correct resource '%s', but for '%s'", route, route_name) + } + vars := match.Vars + id_str, ok := vars["id"] + if !ok { + entry := log.Debug() + for k, v := range vars { + entry = entry.Str(k, v) + } + entry.Msg("current URI values") + return nil, fmt.Errorf("No id found in URI %s", uri) + } + id, err := strconv.Atoi(id_str) + if err != nil { + return nil, fmt.Errorf("parse id: %w", err) + } + return &id, nil + +} func (r *router) UUIDFromURI(route string, uri string) (*uuid.UUID, error) { var match mux.RouteMatch req, _ := http.NewRequest("GET", uri, nil) diff --git a/ts/components/LoadingOverlay.vue b/ts/components/LoadingOverlay.vue index 0c02ddd5..99efc467 100644 --- a/ts/components/LoadingOverlay.vue +++ b/ts/components/LoadingOverlay.vue @@ -1,9 +1,23 @@ + - - - diff --git a/ts/rmo/view/Compliance.vue b/ts/rmo/view/Compliance.vue index d1183ff3..feac5fe8 100644 --- a/ts/rmo/view/Compliance.vue +++ b/ts/rmo/view/Compliance.vue @@ -20,12 +20,12 @@ body > .container-fluid { }