func purgeuserHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) email := r.FormValue("email") str := fmt.Sprintf("(purgeuser for %s)\n", email) q := cdb.QueryAllByEmailAddress(email).KeysOnly() keys, err := q.GetAll(cdb.Ctx(), nil) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } str += fmt.Sprintf("purge: %d complaints found\n", len(keys)) if r.FormValue("forrealz") == "1" { maxRm := 400 for len(keys) > maxRm { if err := datastore.DeleteMulti(cdb.Ctx(), keys[0:maxRm-1]); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } keys = keys[maxRm:] } str += "all deleted :O\n" } w.Header().Set("Content-Type", "text/plain") w.Write([]byte(fmt.Sprintf("OK, purge\n%s", str))) }
func isBanned(r *http.Request) bool { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) u := user.Current(cdb.Ctx()) userWhitelist := map[string]int{ "*****@*****.**": 1, "*****@*****.**": 1, "*****@*****.**": 1, "*****@*****.**": 1, } reqBytes, _ := httputil.DumpRequest(r, true) cdb.Infof("remoteAddr: '%v'", r.RemoteAddr) cdb.Infof("user: '******' (%s)", u, u.Email) cdb.Infof("inbound IP determined as: '%v'", getIP(r)) cdb.Infof("HTTP req:-\n%s", string(reqBytes)) if strings.HasPrefix(r.UserAgent(), "python") { cdb.Infof("User-Agent rejected") return true } if _, exists := userWhitelist[u.Email]; !exists { cdb.Infof("user not found in whitelist") return true } return false }
func deleteComplaintsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { cdb := complaintdb.NewDB(ctx) sesh, _ := GetUserSession(ctx) r.ParseForm() // This is so brittle; need to move away from display text if r.FormValue("act") == "CANCEL" { http.Redirect(w, r, "/", http.StatusFound) return } else if r.FormValue("act") == "UPDATE/EDIT LIST" { http.Redirect(w, r, "/edit", http.StatusFound) return } keyStrings := []string{} for k, _ := range r.Form { if len(k) < 50 { continue } keyStrings = append(keyStrings, k) } cdb.Infof("Deleting %d complaints for %s", len(keyStrings), sesh.Email) if err := cdb.DeleteComplaints(keyStrings, sesh.Email); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } http.Redirect(w, r, "/", http.StatusFound) }
func complaintUpdateFormHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { cdb := complaintdb.NewDB(ctx) sesh, _ := GetUserSession(ctx) key := r.FormValue("k") if complaint, err := cdb.GetComplaintByKey(key, sesh.Email); err != nil { cdb.Errorf("updateform, getComplaint: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) } else { cdb.Infof("Loaded complaint: %+v", complaint) var params = map[string]interface{}{ "ActivityList": kActivities, // lives in add-complaint "DefaultFlightNumber": complaint.AircraftOverhead.FlightNumber, "DefaultTimestamp": complaint.Timestamp, "DefaultActivity": complaint.Activity, "DefaultLoudness": complaint.Loudness, "DefaultSpeedbrakes": complaint.HeardSpeedbreaks, "DefaultDescription": complaint.Description, "C": complaint, } if err := templates.ExecuteTemplate(w, "complaint-updateform", params); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } }
// Grab all users, and enqueue them for batch processing func upgradeHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) var cps = []types.ComplainerProfile{} cps, err := cdb.GetAllProfiles() if err != nil { cdb.Errorf("upgradeHandler: getallprofiles: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } for _, cp := range cps { t := taskqueue.NewPOSTTask("/backend/cdb-batch-user", map[string][]string{ "email": {cp.EmailAddress}, }) if _, err := taskqueue.Add(cdb.Ctx(), t, "batch"); err != nil { cdb.Errorf("upgradeHandler: enqueue: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } cdb.Infof("enqueued %d batch", len(cps)) w.Write([]byte(fmt.Sprintf("OK, enqueued %d", len(cps)))) }
func profileButtonAddHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { cdb := complaintdb.NewDB(ctx) sesh, _ := GetUserSession(ctx) cp, _ := cdb.GetProfileByEmailAddress(sesh.Email) if r.FormValue("NewButtonId") != "" { id := sanitizeButtonId(r.FormValue("NewButtonId")) if len(id) != 16 { http.Error(w, fmt.Sprintf("Button ID must have sixteen characters; only got %d", len(id)), http.StatusInternalServerError) return } // Check we don't have the button registered already. This isn't super safe. if existingProfile, _ := cdb.GetProfileByButtonId(id); existingProfile != nil { http.Error(w, fmt.Sprintf("Button '%s' is already claimed", id), http.StatusBadRequest) return } cp.ButtonId = append(cp.ButtonId, id) if err := cdb.PutProfile(*cp); err != nil { cdb.Errorf("profileUpdate: cdb.Put: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } var params = map[string]interface{}{"Buttons": cp.ButtonId} if err := templates.ExecuteTemplate(w, "buttons", params); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }
// HandleWithSession should handle all situations where we don't have an email address func addComplaintHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { cdb := complaintdb.NewDB(ctx) cdb.Debugf("ac_001", "num cookies: %d", len(r.Cookies())) for _, c := range r.Cookies() { cdb.Debugf("ac_001", "cookie: %s", c) } cdb.Debugf("ac_001a", "Cf-Connecting-Ip: %s", r.Header.Get("Cf-Connecting-Ip")) reqBytes, _ := httputil.DumpRequest(r, true) cdb.Debugf("ac_002", "req: %s", reqBytes) sesh, _ := GetUserSession(ctx) cdb.Debugf("ac_003", "have email") complaint := form2Complaint(r) //complaint.Timestamp = complaint.Timestamp.AddDate(0,0,-3) cdb.Debugf("ac_004", "calling cdb.ComplainByEmailAddress") if err := cdb.ComplainByEmailAddress(sesh.Email, &complaint); err != nil { cdb.Errorf("cdb.Complain failed: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } cdb.Debugf("ac_900", "all done, about to redirect") http.Redirect(w, r, "/", http.StatusFound) }
func profileFormHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { // https, yay if r.URL.Host == "stop.jetnoise.net" { // We're behind cloudflare, so we always see http. This is how we can tell if the user is // using https ... if r.Header.Get("Cf-Visitor") != `{"scheme":"https"}` { safeUrl := r.URL safeUrl.Scheme = "https" http.Redirect(w, r, safeUrl.String(), http.StatusFound) return } } sesh, _ := GetUserSession(ctx) cdb := complaintdb.NewDB(ctx) cp, _ := cdb.GetProfileByEmailAddress(sesh.Email) if cp.EmailAddress == "" { // First ever visit - empty profile ! cp.EmailAddress = sesh.Email cp.CcSfo = true } var params = map[string]interface{}{ "Profile": cp, "MapsAPIKey": kGoogleMapsAPIKey, // For autocomplete & latlong goodness } params["Message"] = r.FormValue("msg") if err := templates.ExecuteTemplate(w, "profile-edit", params); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }
func SendEmailToAllUsers(r *http.Request, subject string) int { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) if cps, err := cdb.GetAllProfiles(); err != nil { cdb.Errorf("SendEmailToAllUsers/GetAllProfiles: %v", err) return 0 } else { buf := new(bytes.Buffer) params := map[string]interface{}{} if err := templates.ExecuteTemplate(buf, "email-update", params); err != nil { return 0 } n := 0 for _, cp := range cps { msg := &mail.Message{ Sender: kSenderEmail, ReplyTo: kSenderEmail, To: []string{cp.EmailAddress}, Subject: subject, HTMLBody: buf.String(), } if err := mail.Send(cdb.Ctx(), msg); err != nil { cdb.Errorf("Could not send useremail to <%s>: %v", cp.EmailAddress, err) } n++ } return n } }
func profileUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { cdb := complaintdb.NewDB(ctx) r.ParseForm() lat, err := strconv.ParseFloat(r.FormValue("Lat"), 64) if err != nil { cdb.Errorf("profileUpdate:, parse lat '%s': %v", r.FormValue("Lat"), err) http.Error(w, err.Error(), http.StatusInternalServerError) return } long, err2 := strconv.ParseFloat(r.FormValue("Long"), 64) if err2 != nil { cdb.Errorf("profileUpdate:, parse long '%s': %v", r.FormValue("Long"), err) http.Error(w, err2.Error(), http.StatusInternalServerError) return } sesh, _ := GetUserSession(ctx) // Maybe make a call to fetch the elevation ?? // https://developers.google.com/maps/documentation/elevation/intro cp := types.ComplainerProfile{ EmailAddress: sesh.Email, CallerCode: r.FormValue("CallerCode"), FullName: strings.TrimSpace(r.FormValue("FullName")), Address: strings.TrimSpace(r.FormValue("AutoCompletingMagic")), StructuredAddress: types.PostalAddress{ Number: r.FormValue("AddrNumber"), Street: r.FormValue("AddrStreet"), City: r.FormValue("AddrCity"), State: r.FormValue("AddrState"), Zip: r.FormValue("AddrZip"), Country: r.FormValue("AddrCountry"), }, CcSfo: true, //FormValueCheckbox(r, "CcSfo"), DataSharing: FormValueTriValuedCheckbox(r, "DataSharing"), ThirdPartyComms: FormValueTriValuedCheckbox(r, "ThirdPartyComms"), Lat: lat, Long: long, ButtonId: []string{}, } // Preserve some values from the old profile if origProfile, err := cdb.GetProfileByEmailAddress(sesh.Email); err == nil { cp.ButtonId = origProfile.ButtonId } if err := cdb.PutProfile(cp); err != nil { cdb.Errorf("profileUpdate: cdb.Put: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } http.Redirect(w, r, "/", http.StatusFound) }
func profileButtonsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { sesh, _ := GetUserSession(ctx) cdb := complaintdb.NewDB(ctx) cp, _ := cdb.GetProfileByEmailAddress(sesh.Email) var params = map[string]interface{}{"Buttons": cp.ButtonId} if err := templates.ExecuteTemplate(w, "buttons", params); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }
func userReportHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) profiles, err := cdb.GetAllProfiles() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if true { nOK, nNotOK, nDefault := 0, 0, 0 for _, p := range profiles { switch { case p.DataSharing < 0: nNotOK++ case p.DataSharing > 0: nOK++ case p.DataSharing == 0: nDefault++ } } w.Header().Set("Content-Type", "text/plain") fmt.Fprintf(w, "nOK=%d, nDefault=%d, nNotOk=%d\n", nOK, nDefault, nNotOK) return } filename := date.NowInPdt().Format("users-as-of-20060102.csv") w.Header().Set("Content-Type", "application/csv") w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) cols := []string{"EMAIL", "NAME", "CALLERCODE", "STREET", "CITY", "ZIP", "ALLINONELINE"} csvWriter := csv.NewWriter(w) csvWriter.Write(cols) for _, p := range profiles { street := p.StructuredAddress.Street if p.StructuredAddress.Number != "" { street = p.StructuredAddress.Number + " " + street } row := []string{ p.EmailAddress, p.FullName, p.CallerCode, street, p.StructuredAddress.City, p.StructuredAddress.Zip, p.Address, } csvWriter.Write(row) } csvWriter.Flush() }
func downloadHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { sesh, _ := GetUserSession(ctx) filename := date.NowInPdt().Format("complaints-20060102.csv") w.Header().Set("Content-Type", "application/csv") w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) cols := []string{ "Date", "Time(PDT)", "Notes", "Speedbrakes", "Loudness", "Activity", "Flightnumber", "Origin", "Destination", "Speed(Knots)", "Altitude(Feet)", "Lat", "Long", "Registration", "Callsign", "VerticalSpeed(FeetPerMin)", "Dist2(km)", "Dist3(km)", "City", } csvWriter := csv.NewWriter(w) csvWriter.Write(cols) cdb := complaintdb.NewDB(ctx) iter := cdb.NewIter(cdb.QueryAllByEmailAddress(sesh.Email)) for { c, err := iter.NextWithErr() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if c == nil { break } a := c.AircraftOverhead speedbrakes := "" if c.HeardSpeedbreaks { speedbrakes = "y" } r := []string{ c.Timestamp.Format("2006/01/02"), c.Timestamp.Format("15:04:05"), c.Description, speedbrakes, fmt.Sprintf("%d", c.Loudness), c.Activity, a.FlightNumber, a.Origin, a.Destination, fmt.Sprintf("%.0f", a.Speed), fmt.Sprintf("%.0f", a.Altitude), fmt.Sprintf("%.5f", a.Lat), fmt.Sprintf("%.5f", a.Long), a.Registration, a.Callsign, fmt.Sprintf("%.0f", a.VerticalSpeed), fmt.Sprintf("%.1f", c.Dist2KM), fmt.Sprintf("%.1f", c.Dist3KM), c.Profile.GetStructuredAddress().City, } if err := csvWriter.Write(r); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } csvWriter.Flush() }
func addHistoricalComplaintHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { cdb := complaintdb.NewDB(ctx) sesh, _ := GetUserSession(ctx) complaint := form2Complaint(r) if err := cdb.AddHistoricalComplaintByEmailAddress(sesh.Email, &complaint); err != nil { cdb.Errorf("cdb.HistoricalComplain failed: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Write([]byte(fmt.Sprintf("Added OK\n"))) }
// countHackHandler will append a new complaint total to the daily counts object. // These are sorted elsewhere, so it's OK to 'append' out of sequence. // Note no deduping is done; if you want that, add it here. func countHackHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) cdb.AddDailyCount(complaintdb.DailyCount{ Datestring: "2016.06.22", NumComplaints: 6555, NumComplainers: 630, }) w.Header().Set("Content-Type", "text/plain") w.Write([]byte("OK!\n")) }
func awsIotHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) ev := AwsIotEvent{} reqBytes, _ := httputil.DumpRequest(r, true) if false && r.FormValue("sn") != "" { // For debugging ev.ClickType = "SINGLE" ev.SerialNumber = r.FormValue("sn") } else { if err := json.NewDecoder(r.Body).Decode(&ev); err != nil { // reqBytes,_ := httputil.DumpRequest(r, true) //cdb.Errorf("decode failed: %v\n%s", err, reqBytes) http.Error(w, err.Error(), http.StatusInternalServerError) return } } expectedSecret := config.Get("awsiot.secret") if expectedSecret == "" { cdb.Errorf("secret config lookup failed ! bad config ?") http.Error(w, "bad secret config", http.StatusInternalServerError) return } else if expectedSecret != ev.Secret { cdb.Errorf("bad secret submitted") cdb.Errorf("-> %s", reqBytes) http.Error(w, "bad secret submitted", http.StatusInternalServerError) return } cdb.Infof("AWS-IoT button event received: %s", ev) if ev.ClickType == "SINGLE" { complaint := types.Complaint{ Timestamp: time.Now(), // No point setting a timezone, it gets reset to UTC } if err := cdb.ComplainByButtonId(ev.SerialNumber, &complaint); err != nil { cdb.Errorf("complain failed: %v\nev=%s", err, ev) } else { cdb.Infof("complaint made: %s", complaint) } } w.Header().Set("Content-Type", "text/plain") w.Write([]byte("OK\n" + ev.String() + "\n")) }
func debugHandler3(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) tStart := time.Now() start, end := date.WindowForYesterday() keys, err := cdb.GetComplaintKeysInSpan(start, end) str := fmt.Sprintf("OK\nret: %d\nerr: %v\nElapsed: %s\ns: %s\ne: %s\n", len(keys), err, time.Since(tStart), start, end) w.Header().Set("Content-Type", "text/plain") w.Write([]byte(str)) }
func optoutHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) users, err := cdb.GetComplainersCurrentlyOptedOut() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } str := fmt.Sprintf("OK! (%d results)\n\n", len(users)) for user, _ := range users { str += fmt.Sprintf(" %s\n", user) } w.Header().Set("Content-Type", "text/plain") w.Write([]byte(str)) }
func statsHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) if gs, err := cdb.LoadGlobalStats(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { var params = map[string]interface{}{ "GlobalStats": gs, } if err := templates.ExecuteTemplate(w, "stats", params); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } }
// This should be deprecated somehow func buttonHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) resp := "OK" cc := r.FormValue("c") complaint := types.Complaint{ Timestamp: time.Now(), // No point setting a timezone, it gets reset to UTC } if err := cdb.ComplainByCallerCode(cc, &complaint); err != nil { resp = fmt.Sprintf("fail for %s: %s\n", cc, err) } w.Write([]byte(fmt.Sprintf("%s for %s\n", resp, cc))) }
func complaintsForHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) s, e := widget.FormValueEpochTime(r, "start"), widget.FormValueEpochTime(r, "end") if r.FormValue("start") == "" { s, e = date.WindowForToday() } flightnumber := r.FormValue("flight") if e.Sub(s) > (time.Hour * 24) { http.Error(w, "time span too wide", http.StatusInternalServerError) return } else if s.Year() < 2015 { http.Error(w, "times in the past", http.StatusInternalServerError) return } else if flightnumber == "" { http.Error(w, "no flightnumber", http.StatusInternalServerError) return } cdb := complaintdb.NewDB(ctx) times, err := cdb.GetComplaintTimesInSpanByFlight(s, e, flightnumber) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if r.FormValue("debug") != "" { str := fmt.Sprintf("* %s\n* %s\n* %s\n* [%d]\n\n", s, e, flightnumber, len(times)) for i, t := range times { str += fmt.Sprintf("%3d %s\n", i, date.InPdt(t)) } w.Header().Set("Content-Type", "text/plain") w.Write([]byte(str)) return } w.Header().Set("Content-Type", "application/json") jsonBytes, err := json.Marshal(times) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Write(jsonBytes) }
func profileButtonDeleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { cdb := complaintdb.NewDB(ctx) sesh, _ := GetUserSession(ctx) cp, _ := cdb.GetProfileByEmailAddress(sesh.Email) str := "OK\n--\n" // Look for the key whose value is DELETE. This is kinda lazy. r.ParseForm() removeId := "" for key, values := range r.Form { // range over map for _, value := range values { // range over []string str += fmt.Sprintf("* {%s} : {%s}\n", key, value) if value == "DELETE" { removeId = key break } } } if removeId == "" { http.Error(w, "Could not find button ID in form ?", http.StatusBadRequest) return } newIds := []string{} for _, id := range cp.ButtonId { if id != removeId { newIds = append(newIds, id) } } cp.ButtonId = newIds if err := cdb.PutProfile(*cp); err != nil { cdb.Errorf("profileUpdate: cdb.Put: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } var params = map[string]interface{}{"Buttons": cp.ButtonId} if err := templates.ExecuteTemplate(w, "buttons", params); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }
func bksvSubmitUserHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) client := cdb.HTTPClient() start, end := date.WindowForYesterday() bksv_ok, bksv_not_ok := 0, 0 email := r.FormValue("user") if cp, err := cdb.GetProfileByEmailAddress(email); err != nil { cdb.Errorf(" /bksv/submit-user(%s): getprofile: %v", email, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } else if complaints, err := cdb.GetComplaintsInSpanByEmailAddress(email, start, end); err != nil { cdb.Errorf(" /bksv/submit-user(%s): getcomplaints: %v", email, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } else { for i, complaint := range complaints { time.Sleep(time.Millisecond * 200) if debug, err := bksv.PostComplaint(client, *cp, complaint); err != nil { //cdb.Infof("pro: %v", cp) //cdb.Infof("comp: %#v", complaint) cdb.Errorf("BKSV posting error: %v", err) cdb.Infof("BKSV Debug\n------\n%s\n------\n", debug) bksv_not_ok++ } else { if i == 0 { cdb.Infof("BKSV [OK] Debug\n------\n%s\n------\n", debug) } bksv_ok++ } } } cdb.Infof("bksv for %s, %d/%d", email, bksv_ok, bksv_not_ok) if bksv_not_ok > 0 { cdb.Errorf("bksv for %s, %d/%d", email, bksv_ok, bksv_not_ok) } w.Write([]byte("OK")) }
func monthCSVTaskHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) month, year, err := FormValueMonthDefaultToPrev(r) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } tStart := time.Now() if filename, n, err := generateMonthlyCSV(cdb, month, year); err != nil { http.Error(w, fmt.Sprintf("monthly %d.%d: %v", year, month, err), http.StatusInternalServerError) return } else { w.Header().Set("Content-Type", "text/plain") w.Write([]byte(fmt.Sprintf("OK!\nGCS file %s written, %d rows, took %s", filename, n, time.Since(tStart)))) } }
func updateComplaintHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { cdb := complaintdb.NewDB(ctx) sesh, _ := GetUserSession(ctx) new := form2Complaint(r) newFlightNumber := r.FormValue("manualflightnumber") newTimeString := r.FormValue("manualtimestring") if orig, err := cdb.GetComplaintByKey(new.DatastoreKey, sesh.Email); err != nil { cdb.Errorf("updateform, getComplaint: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) } else { // Overlay our new values orig.Description = new.Description orig.Loudness = new.Loudness orig.Activity = new.Activity orig.HeardSpeedbreaks = new.HeardSpeedbreaks // If we're manually changing a flightnumber, wipe out all the other flight data if newFlightNumber != orig.AircraftOverhead.FlightNumber { orig.AircraftOverhead = flightid.Aircraft{FlightNumber: newFlightNumber} } // Compose a new timestamp, by inserting hew HH:MM:SS fragment into the old timestamp (date+nanoseconds) newTimestamp, err2 := date.ParseInPdt("2006.01.02 .999999999 15:04:05", orig.Timestamp.Format("2006.01.02 .999999999 ")+newTimeString) if err2 != nil { http.Error(w, err2.Error(), http.StatusInternalServerError) } orig.Timestamp = newTimestamp err := cdb.UpdateComplaint(*orig, sesh.Email) if err != nil { cdb.Errorf("cdb.UpdateComplaint failed: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } http.Redirect(w, r, "/", http.StatusFound) }
// Fixup the three days where email addresses got stamped upon func fixupthing(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) email := r.FormValue("email") str := fmt.Sprintf("(lookup for %s)\n", email) // Add/remove seconds to ensure the specified dates are included as 'intermediate' for _, window := range date.DateRangeToPacificTimeWindows("2016/04/14", "2016/04/16") { s, e := window[0], window[1] //str += fmt.Sprintf("--{ %s, %s }--\n", s,e) complaints, err := cdb.GetComplaintsInSpanByEmailAddress(email, s, e) if err != nil { cdb.Errorf("fixupthing/%s: GetAll failed: %v", email, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } nOK, nBad := 0, 0 for _, comp := range complaints { if comp.Profile.EmailAddress == email { nOK++ } else { nBad++ comp.Profile.EmailAddress = email if err := cdb.UpdateComplaint(comp, email); err != nil { cdb.Errorf("fixupthing/%s: update-complaint failed: %v", email, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } } str += fmt.Sprintf("%s: ok: %4d, bad: %4d\n", s, nOK, nBad) } w.Header().Set("Content-Type", "text/plain") w.Write([]byte(fmt.Sprintf("OK, fixupthing\n%s", str))) }
// Examine all users. If they had any complaints, throw them in the queue. func bksvScanYesterdayHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) var cps = []types.ComplainerProfile{} cps, err := cdb.GetAllProfiles() if err != nil { cdb.Errorf(" /bksv/scan-yesterday: getallprofiles: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } start, end := date.WindowForYesterday() bksv_ok := 0 for _, cp := range cps { // if cp.CcSfo == false { continue } // We do not care about this value. var complaints = []types.Complaint{} complaints, err = cdb.GetComplaintsInSpanByEmailAddress(cp.EmailAddress, start, end) if err != nil { cdb.Errorf(" /bksv/scan-yesterday: getbyemail(%s): %v", cp.EmailAddress, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } if len(complaints) > 0 { t := taskqueue.NewPOSTTask("/bksv/submit-user", map[string][]string{ "user": {cp.EmailAddress}, }) if _, err := taskqueue.Add(cdb.Ctx(), t, "submitreports"); err != nil { cdb.Errorf(" /bksv/scan-yesterday: enqueue: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } bksv_ok++ } } cdb.Infof("enqueued %d bksv", bksv_ok) w.Write([]byte(fmt.Sprintf("OK, enqueued %d", bksv_ok))) }
func heatmapHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) dur := widget.FormValueDuration(r, "d") if dur == 0 { dur = 15 * time.Minute } if dur > 24*time.Hour { dur = 24 * time.Hour } e := time.Now() s := e.Add(-1 * dur) icaoid := r.FormValue("icaoid") // Might be empty string (match everything) //s,e := date.WindowForToday() w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token") w.Header().Set("Access-Control-Allow-Credentials", "true") if positions, err := cdb.GetComplaintPositionsInSpanByIcao(s, e, icaoid); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } else if jsonBytes, err := json.Marshal(positions); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } else { w.Header().Set("Content-Type", "application/json") w.Write(jsonBytes) } }
func rootHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { cdb := complaintdb.NewDB(ctx) sesh, _ := GetUserSession(ctx) cdb.Debugf("root_001", "session obtained") for _, c := range r.Cookies() { cdb.Debugf("root_002", "cookie: %s", c) } cdb.Debugf("root_002", "num cookies: %d", len(r.Cookies())) cdb.Debugf("root_002a", "Cf-Connecting-Ip: %s", r.Header.Get("Cf-Connecting-Ip")) // No session ? Get them to login if sesh.Email == "" { fb.AppId = kFacebookAppId fb.AppSecret = kFacebookAppSecret loginUrls := map[string]string{ "googlefromscratch": g.GetLoginUrl(r, true), "google": g.GetLoginUrl(r, false), "facebook": fb.GetLoginUrl(r), } if err := templates.ExecuteTemplate(w, "landing", loginUrls); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } return } if sesh.HasCreatedAt() { cdb.Debugf("root_003", "tstamp=%s, age=%s", sesh.CreatedAt, time.Since(sesh.CreatedAt)) } modes := map[string]bool{} // The rootHandler is the URL wildcard. Except Fragments, which are broken. if r.URL.Path == "/full" { modes["expanded"] = true } else if r.URL.Path == "/edit" { modes["edit"] = true } else if r.URL.Path == "/debug" { modes["debug"] = true } else if r.URL.Path != "/" { // This is a request for apple_icon or somesuch junk. Just say no. http.NotFound(w, r) return } cdb.Debugf("root_004", "about get cdb.GetAllByEmailAddress") cap, err := cdb.GetAllByEmailAddress(sesh.Email, modes["expanded"]) if cap == nil && err == nil { // No profile exists; daisy-chain into profile page http.Redirect(w, r, "/profile", http.StatusFound) return } else if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } cdb.Debugf("root_005", "cdb.GetAllByEmailAddress done") modes["admin"] = user.Current(ctx) != nil && user.Current(ctx).Admin modes["superuser"] = modes["admin"] // Default to "", unless we had a complaint in the past hour. lastActivity := "" if len(cap.Complaints) > 0 && time.Since(cap.Complaints[0].Timestamp) < time.Hour { lastActivity = cap.Complaints[0].Activity } var complaintDefaults = map[string]interface{}{ "ActivityList": kActivities, // lives in add-complaint "DefaultActivity": lastActivity, "DefaultLoudness": 1, "NewForm": true, } message := "" disableReporting := false if cap.Profile.FullName == "" { message += "<li>We don't have your full name</li>" disableReporting = true } if cap.Profile.StructuredAddress.Zip == "" { message += "<li>We don't have an accurate address</li>" disableReporting = true } if message != "" { message = fmt.Sprintf("<p><b>We've found some problems with your profile:</b></p><ul>%s</ul>"+ "<p> Without this data, your complaints won't be counted, so please "+ "<a href=\"/profile\"><b>update your profile</b></a> before submitting any more complaints !</p>", message) } var params = map[string]interface{}{ //"Message": template.HTML("Hi!"), "Cap": *cap, "Complaints": hintComplaints(cap.Complaints, modes["superuser"]), "Now": date.NowInPdt(), "Modes": modes, "ComplaintDefaults": complaintDefaults, "Message": template.HTML(message), //"Info": template.HTML("Hi!"), "DisableReporting": disableReporting, } if err := templates.ExecuteTemplate(w, "main", params); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }
// Upgrade the set of complaints for each user. func upgradeUserHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := complaintdb.NewDB(ctx) email := r.FormValue("email") cp, err := cdb.GetProfileByEmailAddress(email) if err != nil { cdb.Errorf("upgradeUserHandler/%s: GetProfile failed: %v", email, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } // Get *all* the complaints for this person, unfiltered. var data = []types.Complaint{} q := datastore. NewQuery("ComplaintKind"). Ancestor(cdb.EmailToRootKey(email)). Order("Timestamp") keys, err := q.GetAll(cdb.Ctx(), &data) if err != nil { cdb.Errorf("upgradeUserHandler/%s: GetAll failed: %v", email, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } str := fmt.Sprintf("** {%s} town1={%s}, town2={%s}\n", email, cp.StructuredAddress.City, cp.GetStructuredAddress().City) nGood, nBad := 0, 0 for i, complaint := range data { complaintdb.FixupComplaint(&complaint, keys[i]) // Put the key where cdb.* expect to find it /* str += fmt.Sprintf("BEFORE %s : {%s} {%s} {%s}\n", complaint.Timestamp.Format("2006.01.02"), cp.GetStructuredAddress().City, complaint.Profile.GetStructuredAddress().City, complaint.Profile.StructuredAddress.City) */ if complaint.Profile.GetStructuredAddress().City != cp.GetStructuredAddress().City { /* str += fmt.Sprintf("BEFORE %s : {%s} {%s} {%s}\n", complaint.Timestamp.Format("2006.01.02"), cp.GetStructuredAddress().City, complaint.Profile.GetStructuredAddress().City, complaint.Profile.StructuredAddress.City) */ complaint.Profile.StructuredAddress = cp.GetStructuredAddress() /* str += fmt.Sprintf("AFTER %s : {%s} {%s} {%s}\n\n", complaint.Timestamp.Format("2006.01.02"), cp.GetStructuredAddress().City, complaint.Profile.GetStructuredAddress().City, complaint.Profile.StructuredAddress.City) */ if err := cdb.UpdateComplaint(complaint, email); err != nil { str += fmt.Sprintf("Oh, error updating: %v\n", err) } nBad++ } else { nGood++ } } str += fmt.Sprintf("** processed {%s} [tot=%d, good=%d, bad=%d]\n", email, len(data), nGood, nBad) cdb.Infof(" -- Upgrade for %s --\n%s", email, str) w.Header().Set("Content-Type", "text/plain") w.Write([]byte(fmt.Sprintf("OK, upgraded %s\n%s", email, str))) }