func (db FlightDB) LookupTimeRangeByTags(tags []string, start, end time.Time) ([]f.Flight, error) { memKey := "" todayStart, _ := date.WindowForToday() if end.Before(todayStart) || end.Equal(todayStart) { sort.Sort(f.StringsDesc(tags)) tagstr := strings.Join(tags, ",") memKey = fmt.Sprintf("fdb-tag-lookup:%s:%d-%d", tagstr, start.Unix(), end.Unix()) //db.C.Infof(" ##== fdb-tag-lookup cacheable [%s]", memKey) } q := db.QueryTimeRangeByTags(tags, start, end) return db.lookupByQuery(q, memKey) }
func (cdb ComplaintDB) GetComplaintsInSpanByEmailAddress(ea string, start, end time.Time) ([]types.Complaint, error) { //cdb.Infof(" ##== comp-in-span [%s --> %s]", start, end) memKey := "" todayStart, _ := date.WindowForToday() if end.Before(todayStart) || end.Equal(todayStart) { memKey = fmt.Sprintf("comp-in-span:%s:%d-%d", ea, start.Unix(), end.Unix()) //cdb.Infof(" ##== comp-in-span cacheable [%s]", memKey) } q := cdb.QueryInSpanByEmailAddress(start, end, ea) return cdb.getComplaintsByQuery(q, memKey) }
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) }
// Now the DB is clean, we can do this simple query instead of going user by user func (cdb ComplaintDB) GetComplaintsInSpanNew(start, end time.Time) ([]types.Complaint, error) { cdb.C.Infof(" ##== comp-in-span [%s --> %s]", start, end) memKey := "" todayStart, _ := date.WindowForToday() if end.Before(todayStart) || end.Equal(todayStart) { memKey = fmt.Sprintf("comp-in-span:__all__:%d-%d", start.Unix(), end.Unix()) //cdb.C.Infof(" ##== comp-in-span cacheable [%s]", memKey) } q := datastore. NewQuery(kComplaintKind). Filter("Timestamp >= ", start). Filter("Timestamp < ", end). Order("Timestamp"). Limit(-1) return cdb.getComplaintsByQuery(q, memKey) }
func (cdb ComplaintDB) GetComplaintsInSpanByEmailAddress(ea string, start, end time.Time) ([]types.Complaint, error) { //cdb.C.Infof(" ##== comp-in-span [%s --> %s]", start, end) memKey := "" todayStart, _ := date.WindowForToday() if end.Before(todayStart) || end.Equal(todayStart) { memKey = fmt.Sprintf("comp-in-span:%s:%d-%d", ea, start.Unix(), end.Unix()) //cdb.C.Infof(" ##== comp-in-span cacheable [%s]", memKey) } q := datastore. NewQuery(kComplaintKind). Ancestor(cdb.emailToRootKey(ea)). Filter("Timestamp >= ", start). Filter("Timestamp < ", end). Order("Timestamp") return cdb.getComplaintsByQuery(q, memKey) }
func (cdb ComplaintDB) GetAllByEmailAddress(ea string, everything bool) (*types.ComplaintsAndProfile, error) { var cap types.ComplaintsAndProfile cdb.Debugf("GABEA_001", "cdb.GetAllByEmailAddress starting (everything=%v)", everything) if cp, err := cdb.GetProfileByEmailAddress(ea); err == datastore.ErrNoSuchEntity { return nil, nil // No such profile exists } else if err != nil { return nil, err // A real problem occurred } else { cdb.Debugf("GABEA_002", "profile retrieved") cap.Profile = *cp } if everything { if c, err := cdb.GetComplaintsByEmailAddress(ea); err != nil { return nil, err } else { cdb.Debugf("GABEA_003", "EVERYTHING retrieved") cap.Complaints = c } } else { // Just today s, e := date.WindowForToday() if c, err := cdb.GetComplaintsInSpanByEmailAddress(ea, s, e); err != nil { return nil, err } else { cdb.Debugf("GABEA_004", "WindowForToday retrieved; now getting counts") cap.Complaints = c } } if counts, err := cdb.getDailyCountsByEmailAdress(ea); err != nil { return nil, err } else { cdb.Debugf("GABEA_005", "counts retrieved") cap.Counts = counts } return &cap, nil }
// This widget assumes the values 'date', 'range_from', and 'range_to' func FormValueDateRange(r *http.Request) (s, e time.Time, err error) { err = nil switch r.FormValue("date") { case "today": s, _ = date.WindowForToday() e = s case "yesterday": s, _ = date.WindowForYesterday() e = s case "range": s = date.ArbitraryDatestring2MidnightPdt(r.FormValue("range_from"), "2006/01/02") e = date.ArbitraryDatestring2MidnightPdt(r.FormValue("range_to"), "2006/01/02") if s.After(e) { s, e = e, s } } e = e.Add(23*time.Hour + 59*time.Minute + 59*time.Second) // make sure e covers its whole day return }
// We examine the tags CGI arg, which should be a pipe-delimited set of flight tags. func flightListHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) db := fdb.NewDB(r) tags := []string{} if r.FormValue("tags") != "" { tags = append(tags, strings.Split(r.FormValue("tags"), "|")...) } timeRange := regexp.MustCompile("/fdb/(.+)$").ReplaceAllString(r.URL.Path, "$1") var flights []ftype.Flight var err error switch timeRange { case "recent": flights, err = db.LookupRecentByTags(tags, 400) case "today": s, e := date.WindowForToday() flights, err = db.LookupTimeRangeByTags(tags, s, e) case "yesterday": s, e := date.WindowForYesterday() flights, err = db.LookupTimeRangeByTags(tags, s, e) } if err != nil { log.Errorf(ctx, " %s: %v", r.URL.Path, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } var params = map[string]interface{}{ "Tags": tags, "TimeRange": timeRange, "Flights": flights2params(flights), } if err := templates.ExecuteTemplate(w, "fdb-recentlist", params); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }
func (cdb ComplaintDB) GetAllByEmailAddress(ea string, everything bool) (*types.ComplaintsAndProfile, error) { var cap types.ComplaintsAndProfile if cp, err := cdb.GetProfileByEmailAddress(ea); err == datastore.ErrNoSuchEntity { return nil, nil // No such profile exists } else if err != nil { return nil, err // A real problem occurred } else { cap.Profile = *cp } if everything { if c, err := cdb.GetComplaintsByEmailAddress(ea); err != nil { return nil, err } else { cap.Complaints = c } } else { // Just today s, e := date.WindowForToday() if c, err := cdb.GetComplaintsInSpanByEmailAddress(ea, s, e); err != nil { return nil, err } else { cap.Complaints = c } } if counts, err := cdb.getDailyCountsByEmailAdress(ea); err != nil { return nil, err } else { cap.Counts = counts } return &cap, nil }
func (cdb ComplaintDB) complainByProfile(cp types.ComplainerProfile, c *types.Complaint) error { client := cdb.HTTPClient() overhead := flightid.Aircraft{} // Check we're not over a daily cap for this user cdb.Debugf("cbe_010", "doing rate limit check") s, e := date.WindowForToday() if prevKeys, err := cdb.GetComplaintKeysInSpanByEmailAddress(s, e, cp.EmailAddress); err != nil { return err } else if len(prevKeys) >= KMaxComplaintsPerDay { return fmt.Errorf("Too many complaints filed today") } else { cdb.Debugf("cbe_011", "rate limit check passed (%d); calling FindOverhead", len(prevKeys)) } elev := 0.0 pos := geo.Latlong{cp.Lat, cp.Long} algo := flightid.AlgoConservativeNoCongestion if c.Description == "ANYANY" { algo = flightid.AlgoGrabClosest } if as, err := fr24.FetchAirspace(client, pos.Box(64, 64)); err != nil { cdb.Errorf("FindOverhead failed for %s: %v", cp.EmailAddress, err) } else { oh, deb := flightid.IdentifyOverhead(as, pos, elev, algo) c.Debug = deb if oh != nil { overhead = *oh c.AircraftOverhead = overhead } } cdb.Debugf("cbe_020", "FindOverhead returned") // Contrast with the skypi pathway if cp.CallerCode == "WOR004" || cp.CallerCode == "WOR005" { asFdb, _ := airspace.Fetch(client, "", pos.Box(60, 60)) oh3, deb3 := flightid.IdentifyOverhead(asFdb, pos, elev, algo) if oh3 == nil { oh3 = &flightid.Aircraft{} } newdebug := c.Debug + "\n*** v2 / fdb testing\n" + deb3 + "\n" headline := "" if overhead.FlightNumber != oh3.FlightNumber { headline = fmt.Sprintf("** * * DIFFERS * * **\n") } else { // Agree ! Copy over the Fdb IdSpec, and pretend we're living in the future headline = fmt.Sprintf("**---- Agrees ! ----**\n") c.AircraftOverhead.Id = oh3.Id } headline += fmt.Sprintf(" * skypi: %s\n * orig : %s\n", oh3, overhead) c.Debug = headline + newdebug } c.Version = kComplaintVersion // Kill this off ? c.Profile = cp // Copy the profile fields into every complaint // Too much like the last complaint by this user ? Just update that one. cdb.Debugf("cbe_030", "retrieving prev complaint") if prev, err := cdb.GetNewestComplaintByEmailAddress(cp.EmailAddress); err != nil { cdb.Errorf("complainByProfile/GetNewest: %v", err) } else if prev != nil && ComplaintsAreEquivalent(*prev, *c) { cdb.Debugf("cbe_031", "returned, equiv; about to UpdateComlaint()") // The two complaints are in fact one complaint. Overwrite the old one with data from new one. Overwrite(prev, c) err := cdb.UpdateComplaint(*prev, cp.EmailAddress) cdb.Debugf("cbe_032", "updated in place (all done)") return err } cdb.Debugf("cbe_033", "returned, distinct/first; about to put()") key := datastore.NewIncompleteKey(cdb.Ctx(), kComplaintKind, cdb.emailToRootKey(cp.EmailAddress)) _, err := datastore.Put(cdb.Ctx(), key, c) cdb.Debugf("cbe_034", "new entity added (all done)") // TEMP /* if debug,err := bksv.PostComplaint(client, cp, *c); err != nil { cdb.Infof("BKSV Debug\n------\n%s\n------\n", debug) cdb.Infof("BKSV posting error: %v", err) } else { cdb.Infof("BKSV Debug\n------\n%s\n------\n", debug) } */ return err }
func YesterdayDebugHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) cdb := NewDB(ctx) offset := 1 start, end := date.WindowForToday() if r.FormValue("offset") != "" { offset = int(widget.FormValueInt64(r, "offset")) } start, end = start.AddDate(0, 0, -1*offset), end.AddDate(0, 0, -1*offset) keys, err := cdb.GetComplaintKeysInSpan(start, end) // complaints,err := cdb.GetComplaintsInSpanNew(start,end) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } counts := map[string]int{} problems := []types.Complaint{} good := []types.Complaint{} retries := []types.Complaint{} //for _,c := range complaints { for _, k := range keys { c, err := cdb.GetAnyComplaintByKey(k.Encode()) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } counts[fmt.Sprintf("[A] Status: %s", c.Submission.Outcome)]++ if r.FormValue("all") != "" || c.Submission.Outcome == types.SubmissionFailed { problems = append(problems, *c) } if len(good) < 5 && c.Submission.Outcome == types.SubmissionAccepted { good = append(good, *c) } if c.Submission.Outcome == types.SubmissionAccepted { counts[fmt.Sprintf("[B] AttemptsToSucceed: %02d", c.Submission.Attempts)]++ counts[fmt.Sprintf("[C] SecondsForSuccess: %02d", int(c.D.Seconds()))]++ if c.Submission.Attempts > 1 { retries = append(retries, *c) } } } str := "<html><body>\n" str += fmt.Sprintf("<pre>Start: %s\nEnd : %s\n</pre>\n", start, end) str += "<table border=0>\n" countkeys := []string{} for k, _ := range counts { countkeys = append(countkeys, k) } sort.Strings(countkeys) for _, k := range countkeys { str += fmt.Sprintf("<tr><td><b>%s</b></td><td>%d</td></tr>\n", k, counts[k]) } str += "</table>\n" url := "https://stop.jetnoise.net/cdb/comp/debug" str += "<p>\n" for _, c := range good { str += fmt.Sprintf(" <a href=\"%s?key=%s\" target=\"_blank\">Good</a>: %s", url, c.DatastoreKey, c) str += "<br/>\n" } str += "</p>\n" str += "<p>\n" for _, c := range problems { str += fmt.Sprintf(" <a href=\"%s?key=%s\" target=\"_blank\">Prob</a>: %s", url, c.DatastoreKey, c) str += "<br/>\n" } str += "</p>\n" str += "<p>\n" for _, c := range retries { str += fmt.Sprintf(" <a href=\"%s?key=%s\" target=\"_blank\">Retry</a>: %s", url, c.DatastoreKey, c) str += "<br/>\n" } str += "</p>\n" str += "</body></html>\n" w.Header().Set("Content-Type", "text/html") w.Write([]byte(str)) }