diff --git a/rmo/error.go b/rmo/error.go deleted file mode 100644 index 7b18aad5..00000000 --- a/rmo/error.go +++ /dev/null @@ -1,32 +0,0 @@ -package rmo - -import ( - "net/http" - - //"github.com/Gleipnir-Technology/nidus-sync/config" - "github.com/Gleipnir-Technology/nidus-sync/html" -) - -type ContentError struct { - Code string - District *ContentDistrict - URL ContentURL -} - -func getError(w http.ResponseWriter, r *http.Request) { - code := r.FormValue("code") - district, err := districtBySlug(r) - if err != nil { - //respondError(w, "Failed to lookup organization", err, http.StatusBadRequest) - district = nil - } - html.RenderOrError( - w, - "rmo/error.html", - ContentError{ - Code: code, - District: newContentDistrict(district), - URL: makeContentURL(nil), - }, - ) -} diff --git a/rmo/notification.go b/rmo/notification.go deleted file mode 100644 index 90f9f7ad..00000000 --- a/rmo/notification.go +++ /dev/null @@ -1 +0,0 @@ -package rmo diff --git a/rmo/nuisance.go b/rmo/nuisance.go deleted file mode 100644 index 6673c291..00000000 --- a/rmo/nuisance.go +++ /dev/null @@ -1,64 +0,0 @@ -package rmo - -import ( - "fmt" - "net/http" - - "github.com/Gleipnir-Technology/nidus-sync/html" - "github.com/Gleipnir-Technology/nidus-sync/platform/report" - //"github.com/rs/zerolog/log" -) - -type ContentNuisance struct { - District *ContentDistrict - MapboxToken string - URL ContentURL -} -type ContentNuisanceSubmitComplete struct { - District *ContentDistrict - ReportID string - URL ContentURL -} - -func getNuisance(w http.ResponseWriter, r *http.Request) { - html.RenderOrError( - w, - "rmo/nuisance.html", - ContentNuisance{ - District: nil, - URL: makeContentURL(nil), - }, - ) -} -func getNuisanceDistrict(w http.ResponseWriter, r *http.Request) { - district, err := districtBySlug(r) - if err != nil { - respondError(w, "Failed to lookup organization", err, http.StatusBadRequest) - return - } - html.RenderOrError( - w, - "rmo/nuisance.html", - ContentNuisance{ - District: newContentDistrict(district), - URL: makeContentURL(nil), - }, - ) -} -func getSubmitComplete(w http.ResponseWriter, r *http.Request) { - report_id := r.URL.Query().Get("report") - district, err := report.DistrictForReport(r.Context(), report_id) - if err != nil { - respondError(w, fmt.Sprintf("Failed to get district for report '%s'", report_id, err), err, http.StatusInternalServerError) - return - } - html.RenderOrError( - w, - "rmo/submit-complete.html", - ContentNuisanceSubmitComplete{ - District: newContentDistrict(district), - ReportID: report_id, - URL: makeContentURL(nil), - }, - ) -} diff --git a/rmo/quick.go b/rmo/quick.go deleted file mode 100644 index 67343ec1..00000000 --- a/rmo/quick.go +++ /dev/null @@ -1,26 +0,0 @@ -package rmo - -import ( - "net/http" - - "github.com/Gleipnir-Technology/nidus-sync/html" -) - -type ContentRegisterNotificationsComplete struct { - ReportID string -} -type District struct { - LogoURL string - Name string -} - -func getRegisterNotificationsComplete(w http.ResponseWriter, r *http.Request) { - report := r.URL.Query().Get("report") - html.RenderOrError( - w, - "rmo/register-notifications-complete.html", - ContentRegisterNotificationsComplete{ - ReportID: report, - }, - ) -} diff --git a/rmo/report.go b/rmo/report.go deleted file mode 100644 index 4499c222..00000000 --- a/rmo/report.go +++ /dev/null @@ -1,89 +0,0 @@ -package rmo - -import ( - "encoding/json" - "net/http" - "strings" - - //"github.com/Gleipnir-Technology/nidus-sync/config" - "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" - "github.com/Gleipnir-Technology/nidus-sync/lint" - //"github.com/gorilla/mux" - "github.com/stephenafamo/scan" - //"github.com/rs/zerolog/log" -) - -type ReportSuggestion struct { - ID string `json:"id"` - //Type string `json:"type"` - //Location string -} -type ReportSuggestionResponse struct { - Reports []ReportSuggestion `json:"reports"` -} - -func getReportSuggestion(w http.ResponseWriter, r *http.Request) { - partial_report_id := r.FormValue("r") - if partial_report_id == "" { - respondError(w, "You need at least a bit of an 'r'", nil, http.StatusBadRequest) - return - } - p := partialSearchParam(partial_report_id) - ctx := r.Context() - /* - rows, err := sql.PublicreportPublicIDSuggestion(p).All(ctx, db.PGInstance.BobDB) - if err != nil { - respondError(w, "Failed to query DB: %w", err, http.StatusInternalServerError) - return - } - */ - type _Row struct { - Location string `db:"location"` - PublicID string `db:"public_id"` - } - rows, err := bob.All(ctx, db.PGInstance.BobDB, psql.Select( - sm.Columns("public_id", "location"), - sm.From("publicreport.report"), - sm.Where( - psql.Quote("public_id").Like(psql.Arg(p)), - ), - ), scan.StructMapper[_Row]()) - - var result ReportSuggestionResponse - for _, row := range rows { - /* - value, err := row.Location.Value() - if err != nil { - log.Warn().Err(err).Msg("Failed to get value") - continue - } - value_str, ok := value.(string) - if !ok { - log.Warn().Msg("Failed to get location as string") - continue - } - log.Debug().Str("location", value_str).Msg("Looking at row") - */ - result.Reports = append(result.Reports, ReportSuggestion{ - //Type: row.TableName, - ID: row.PublicID, - //Location: "", - }) - } - jsonBody, err := json.Marshal(result) - if err != nil { - respondError(w, "Failed to marshal JSON: %w", err, http.StatusInternalServerError) - return - } - w.Header().Set("Content-Type", "application/json") - lint.Write(w, jsonBody) -} - -func partialSearchParam(p string) string { - result := strings.ReplaceAll(p, "-", "") - result = strings.ToUpper(result) - return result + "%" -} diff --git a/rmo/root.go b/rmo/root.go deleted file mode 100644 index 4b7589af..00000000 --- a/rmo/root.go +++ /dev/null @@ -1,123 +0,0 @@ -package rmo - -import ( - "net/http" - - "github.com/Gleipnir-Technology/nidus-sync/config" - "github.com/Gleipnir-Technology/nidus-sync/db/models" - "github.com/Gleipnir-Technology/nidus-sync/lint" - "github.com/Gleipnir-Technology/nidus-sync/html" - "github.com/rs/zerolog/log" -) - -type ContentPrivacy struct { - Address string - Company string - Site string - URLReport string -} -type ContentRoot struct { - District *ContentDistrict - URL ContentURL -} -type ContentURL struct { - Nuisance string - NuisanceSubmit string - SubmitComplete string - Status string - Tegola string - Water string - WaterSubmit string -} - -func boolFromForm(r *http.Request, k string) bool { - s := r.PostFormValue(k) - if s == "on" { - return true - } - return false -} - -func getPrivacy(w http.ResponseWriter, r *http.Request) { - html.RenderOrError( - w, - "rmo/privacy.html", - ContentPrivacy{ - Address: "2726 S Quinn Ave, Gilbert, AZ, USA", - Company: "Gleipnir LLC", - Site: "Report Mosquitoes Online", - URLReport: config.MakeURLReport("/"), - }, - ) -} -func getRoot(w http.ResponseWriter, r *http.Request) { - html.RenderOrError( - w, - "rmo/root.html", - ContentRoot{ - URL: makeContentURL(nil), - }, - ) -} -func getRootDistrict(w http.ResponseWriter, r *http.Request) { - district, err := districtBySlug(r) - if err != nil { - respondError(w, "Failed to lookup organization", err, http.StatusBadRequest) - return - } - html.RenderOrError( - w, - "rmo/root.html", - ContentRoot{ - District: newContentDistrict(district), - URL: makeContentURL(district), - }, - ) -} - -func getRobots(w http.ResponseWriter, r *http.Request) { - lint.Fprint(w, "User-agent: *\n") - lint.Fprint(w, "Allow: /\n") -} -func getTerms(w http.ResponseWriter, r *http.Request) { - html.RenderOrError( - w, - "rmo/terms.html", - ContentRoot{ - URL: makeContentURL(nil), - }, - ) -} - -func makeContentURL(district *models.Organization) ContentURL { - if district == nil || district.Slug.IsNull() { - return ContentURL{ - Nuisance: makeURL("/nuisance"), - NuisanceSubmit: makeURL("/nuisance"), - Status: makeURL("/status"), - Tegola: config.MakeURLTegola("/"), - Water: makeURL("/water"), - WaterSubmit: makeURL("/water"), - } - } else { - slug := district.Slug.MustGet() - return ContentURL{ - Nuisance: makeURL("/district/%s/nuisance", slug), - NuisanceSubmit: makeURL("/nuisance", slug), - Status: makeURL("/status"), - Tegola: config.MakeURLTegola("/"), - Water: makeURL("/district/%s/water", slug), - WaterSubmit: makeURL("/water"), - } - } -} - -func makeURL(f string, args ...string) string { - return config.MakeURLReport(f, args...) -} - -// Respond with an error that is visible to the user -func respondError(w http.ResponseWriter, m string, e error, s int) { - log.Warn().Int("status", s).Err(e).Str("user message", m).Msg("Responding with an error") - http.Error(w, m, s) -} diff --git a/rmo/status.go b/rmo/status.go deleted file mode 100644 index 65b3d0c8..00000000 --- a/rmo/status.go +++ /dev/null @@ -1,305 +0,0 @@ -package rmo - -import ( - "context" - "fmt" - "net/http" - "strconv" - "strings" - "time" - - "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" - "github.com/Gleipnir-Technology/nidus-sync/db/models" - "github.com/Gleipnir-Technology/nidus-sync/html" - "github.com/google/uuid" - "github.com/gorilla/mux" - //"github.com/rs/zerolog/log" - "github.com/stephenafamo/scan" - "golang.org/x/text/cases" - "golang.org/x/text/language" -) - -type ContentStatus struct { - District *ContentDistrict - Error string - ReportID string - URL ContentURL -} -type ContentStatusByID struct { - District *ContentDistrict - Report Report - Timeline []TimelineEntry - URL ContentURL -} -type DetailEntry struct { - Name string - Value string -} -type Report struct { - Address string - Comments string - Created time.Time - Details []DetailEntry - ID string - ImageCount int - Location string // GeoJSON - Status string - Type string -} -type TimelineEntry struct { - At time.Time - Detail string - Title string -} - -func formatReportID(s string) string { - // truncate down if too long - if len(s) > 12 { - s = s[:12] - } - - // If less than 4 characters, return as is - if len(s) < 4 { - return s - } - - // If at least 8 characters, add hyphens at positions 4 and 8 - if len(s) >= 8 { - return s[0:4] + "-" + s[4:8] + "-" + s[8:] - } - - // If at least 4 characters but less than 8, add hyphen only at position 4 - return s[0:4] + "-" + s[4:] -} - -func getStatus(w http.ResponseWriter, r *http.Request) { - report_id_str := r.URL.Query().Get("report") - content := ContentStatus{ - Error: "", - ReportID: "", - URL: makeContentURL(nil), - } - if report_id_str == "" { - html.RenderOrError(w, "rmo/status.html", content) - return - } - report_id := sanitizeReportID(report_id_str) - report_id_str = formatReportID(report_id) - //some_report, e := report.FindSomeReport(r.Context(), report_id) - content.Error = "Sorry, we can't find that report" - html.RenderOrError(w, "rmo/status.html", content) -} -func contentFromReport(ctx context.Context, report *models.PublicreportReport) (result ContentStatusByID, err error) { - org, err := models.FindOrganization(ctx, db.PGInstance.BobDB, report.OrganizationID) - if err != nil { - return result, fmt.Errorf("Failed to get district information: %w", err) - } - - type _Row struct { - ID int32 `db:"id"` - ContentType string `db:"content_type"` - Created time.Time `db:"created"` - Location string `db:"location"` - LocationJSON string `db:"location_json"` - ResolutionX int32 `db:"resolution_x"` - ResolutionY int32 `db:"resolution_y"` - StorageUUID uuid.UUID `db:"storage_uuid"` - StorageSize int32 `db:"storage_size"` - UploadedFilename string `db:"uploaded_filename"` - } - images, err := bob.All(ctx, db.PGInstance.BobDB, psql.Select( - sm.Columns( - "id", - "content_type", - "created", - "location", - "COALESCE(ST_AsGeoJSON(location), '{}') AS location_json", - "resolution_x", - "resolution_y", - "storage_uuid", - "storage_size", - "uploaded_filename", - ), - sm.From("publicreport.image"), - sm.InnerJoin("publicreport.report_image").OnEQ( - psql.Quote("publicreport", "image", "id"), - psql.Quote("publicreport", "report_image", "image_id"), - ), - sm.Where( - psql.Quote("publicreport", "report_image", "report_id").EQ(psql.Arg(report.ID)), - ), - ), scan.StructMapper[_Row]()) - if err != nil { - return result, fmt.Errorf("Failed to get images: %w", err) - } - result.District = newContentDistrict(org) - result.Report.ID = report.PublicID - result.Report.Address = report.AddressRaw - result.Report.Created = report.Created - result.Report.ImageCount = len(images) - result.Report.Status = cases.Title(language.AmericanEnglish).String(report.Status.String()) - result.Timeline = []TimelineEntry{ - TimelineEntry{ - At: report.Created, - Detail: "Initial report was submitted", - Title: "Created", - }, - } - - type LocationGeoJSON struct { - Location string - } - location, err := bob.One(ctx, db.PGInstance.BobDB, psql.Select( - sm.Columns( - psql.F("ST_AsGeoJSON", "location"), - ), - sm.From("publicreport.report"), - sm.Where(psql.Quote("id").EQ(psql.Arg(report.ID))), - ), scan.SingleColumnMapper[string]) - if err != nil { - return result, fmt.Errorf("Failed to query location of report %d: %w", report.ID, err) - } - result.Report.Location = location - nuisance, err := models.PublicreportNuisances.Query( - models.SelectWhere.PublicreportNuisances.ReportID.EQ(report.ID), - ).One(ctx, db.PGInstance.BobDB) - if err == nil { - result.Report.Type = "Mosquito Nuisance" - addContentFromNuisance(&result, nuisance) - } - water, err := models.PublicreportWaters.Query( - models.SelectWhere.PublicreportWaters.ReportID.EQ(report.ID), - ).One(ctx, db.PGInstance.BobDB) - if err == nil { - result.Report.Type = "Standing Water" - addContentFromWater(&result, water) - } - return result, nil -} -func addContentFromNuisance(result *ContentStatusByID, nuisance *models.PublicreportNuisance) { - result.Report.Type = "Mosquito Nuisance" - result.Report.Details = []DetailEntry{ - DetailEntry{ - Name: "Active early morning (5a-8a)?", - Value: strconv.FormatBool(nuisance.TodEarly), - }, - DetailEntry{ - Name: "Active daytime (8a-5p)?", - Value: strconv.FormatBool(nuisance.TodDay), - }, - DetailEntry{ - Name: "Active evening (5p-9p)?", - Value: strconv.FormatBool(nuisance.TodEvening), - }, - DetailEntry{ - Name: "Active night (9p-5a)?", - Value: strconv.FormatBool(nuisance.TodNight), - }, - DetailEntry{ - Name: "Duration", - Value: nuisance.Duration.String(), - }, - DetailEntry{ - Name: "Active in backyard?", - Value: strconv.FormatBool(nuisance.IsLocationBackyard), - }, - DetailEntry{ - Name: "Active in frontyard?", - Value: strconv.FormatBool(nuisance.IsLocationFrontyard), - }, - DetailEntry{ - Name: "Active in garden?", - Value: strconv.FormatBool(nuisance.IsLocationGarden), - }, - DetailEntry{ - Name: "Active in other location?", - Value: strconv.FormatBool(nuisance.IsLocationOther), - }, - DetailEntry{ - Name: "Active in pool area?", - Value: strconv.FormatBool(nuisance.IsLocationPool), - }, - DetailEntry{ - Name: "Stagnant Water", - Value: strconv.FormatBool(nuisance.SourceStagnant), - }, - DetailEntry{ - Name: "Container", - Value: strconv.FormatBool(nuisance.SourceContainer), - }, - DetailEntry{ - Name: "Sprinklers & Gutters", - Value: strconv.FormatBool(nuisance.SourceGutter), - }, - } -} -func addContentFromWater(result *ContentStatusByID, water *models.PublicreportWater) { - result.Report.Details = []DetailEntry{ - DetailEntry{ - Name: "Has a gate that affects access?", - Value: strconv.FormatBool(water.AccessGate), - }, - DetailEntry{ - Name: "Has dog that affects access?", - Value: strconv.FormatBool(water.AccessDog), - }, - DetailEntry{ - Name: "Has a fence that affects access?", - Value: strconv.FormatBool(water.AccessFence), - }, - DetailEntry{ - Name: "Has a locked entrace that affects access?", - Value: strconv.FormatBool(water.AccessLocked), - }, - DetailEntry{ - Name: "Reporter observed larvae (wigglers)?", - Value: strconv.FormatBool(water.HasLarvae), - }, - DetailEntry{ - Name: "Reporter observed pupae (tumblers)?", - Value: strconv.FormatBool(water.HasPupae), - }, - DetailEntry{ - Name: "Reporter observed adult mosquitoes?", - Value: strconv.FormatBool(water.HasAdult), - }, - } -} - -func getStatusByID(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - report_id := vars["report_id"] - ctx := r.Context() - - report, err := models.PublicreportReports.Query( - models.SelectWhere.PublicreportReports.PublicID.EQ(report_id), - ).One(ctx, db.PGInstance.BobDB) - if err != nil { - respondError(w, "Failed to find report", err, http.StatusBadRequest) - return - } - content, err := contentFromReport(ctx, report) - if err != nil { - respondError(w, "Failed to generate report content", err, http.StatusInternalServerError) - return - } - content.URL = makeContentURL(nil) - html.RenderOrError( - w, - "rmo/status-by-id.html", - content, - ) -} - -func sanitizeReportID(r string) string { - result := "" - for _, char := range r { - if char != '-' { - result += string(char) - } - } - return strings.ToUpper(result) -}