Esempio n. 1
0
func reportHandler(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("date") == "" {
		var params = map[string]interface{}{
			"Yesterday": date.NowInPdt().AddDate(0, 0, -1),
		}
		if err := templates.ExecuteTemplate(w, "report-form", params); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	c := appengine.Timeout(appengine.NewContext(r), 60*time.Second) // Default has a 5s timeout

	s, e, _ := widget.FormValueDateRange(r)
	opt := ReportOptions{
		ClassB_OnePerFlight:       widget.FormValueCheckbox(r, "classb_oneperflight"),
		ClassB_LocalDataOnly:      widget.FormValueCheckbox(r, "classb_localdataonly"),
		Skimmer_AltitudeTolerance: widget.FormValueFloat64(w, r, "skimmer_altitude_tolerance"),
		Skimmer_MinDurationNM:     widget.FormValueFloat64(w, r, "skimmer_min_duration_nm"),
	}

	if fix := strings.ToUpper(r.FormValue("waypoint")); fix != "" {
		if _, exists := sfo.KFixes[fix]; !exists {
			http.Error(w, fmt.Sprintf("Waypoint '%s' not known", fix), http.StatusInternalServerError)
			return
		}
		opt.Waypoint = fix
	}

	reportWriter(c, w, r, s, e, opt, r.FormValue("reportname"), r.FormValue("resultformat"))
}
Esempio n. 2
0
func summaryReportHandler(w http.ResponseWriter, r *http.Request) {

	if r.FormValue("date") == "" {
		var params = map[string]interface{}{
			"Title":     "Summary of disturbance reports",
			"FormUrl":   "/report/summary",
			"Yesterday": date.NowInPdt().AddDate(0, 0, -1),
		}
		//params["Message"] = "Please do not scrape this form. Instead, get in touch !"
		if err := templates.ExecuteTemplate(w, "date-report-form", params); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	if isBanned(r) {
		http.Error(w, "bad user", http.StatusUnauthorized)
		return
	}

	start, end, _ := widget.FormValueDateRange(r)
	countByUser := r.FormValue("peeps") != ""

	str, err := SummaryReport(r, start, end, countByUser)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte(str))
}
Esempio n. 3
0
func FixupComplaint(c *types.Complaint, key *datastore.Key) {
	// 0. Snag the key, so we can refer to this object later
	c.DatastoreKey = key.Encode()

	// 1. GAE datastore helpfully converts timezones to UTC upon storage; fix that
	c.Timestamp = date.InPdt(c.Timestamp)

	// 2. Compute the flight details URL, if within 24 days
	age := date.NowInPdt().Sub(c.Timestamp)
	if age < time.Hour*24 {
		// c.AircraftOverhead.Fr24Url = c.AircraftOverhead.PlaybackUrl()

		c.AircraftOverhead.Fr24Url = "http://flightaware.com/live/flight/" +
			c.AircraftOverhead.FlightNumber
		// Or: http://flightaware.com/live/flight/UAL337/history/20151215/ [0655Z/KLAX/KSFO]
		// date is UTC of departure time; might be tricky to guess :/
	}

	// 3. Compute distances, if we have an aircraft
	if c.AircraftOverhead.FlightNumber != "" {
		a := c.AircraftOverhead
		aircraftPos := geo.Latlong{a.Lat, a.Long}
		observerPos := geo.Latlong{c.Profile.Lat, c.Profile.Long}
		c.Dist2KM = observerPos.Dist(aircraftPos)
		c.Dist3KM = observerPos.Dist3(aircraftPos, a.Altitude)
	}
}
Esempio n. 4
0
func downloadHandler(w http.ResponseWriter, r *http.Request) {
	session := sessions.Get(r)
	if session.Values["email"] == nil {
		http.Error(w, "session was empty; no cookie ? is this browser in privacy mode ?",
			http.StatusInternalServerError)
		return
	}

	c := appengine.Timeout(appengine.NewContext(r), 60*time.Second)

	cdb := complaintdb.ComplaintDB{C: c}
	cap, err := cdb.GetAllByEmailAddress(session.Values["email"].(string), true)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	_ = cap

	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)",
	}

	csvWriter := csv.NewWriter(w)
	csvWriter.Write(cols)

	for _, c := range cap.Complaints {
		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),
		}

		if err := csvWriter.Write(r); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
	csvWriter.Flush()
}
Esempio n. 5
0
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()
}
Esempio n. 6
0
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()
}
Esempio n. 7
0
func (fr *Fr24) FindOverhead(observerPos geo.Latlong, overhead *Aircraft, grabAnything bool) (debug string, err error) {

	debug = fmt.Sprintf("*** FindOverhead for %s, at %s\n", observerPos,
		date.NowInPdt())

	// Create a bounding box that's ~40m square, centred on the input lat,long
	// This is a grievous fudge http://www.movable-type.co.uk/scripts/latlong.html
	lat_20miles := 0.3
	long_20miles := 0.35
	nearby := []Aircraft{}
	if err = fr.ListBbox(observerPos.Lat-lat_20miles, observerPos.Long-long_20miles,
		observerPos.Lat+lat_20miles, observerPos.Long+long_20miles, &nearby); err != nil {
		debug += fmt.Sprintf("Lookup error: %s\n", err)
		return
	}

	for i, a := range nearby {
		aircraftPos := geo.Latlong{a.Lat, a.Long}
		nearby[i].Dist = observerPos.Dist(aircraftPos)
		nearby[i].Dist3 = observerPos.Dist3(aircraftPos, a.Altitude)
		nearby[i].BearingFromObserver = observerPos.BearingTowards(aircraftPos)
	}
	sort.Sort(byDist3(nearby))
	debug += "** nearby list:-\n" + DebugFlightList(nearby)

	filtered := filterAircraft(nearby)
	if len(filtered) == 0 {
		debug += "** all empty after filtering\n"
		return
	}

	debug += "** filtered:-\n" + DebugFlightList(filtered)

	if grabAnything {
		*overhead = filtered[0]
		debug += "** grabbed 1st\n"
	} else {
		// closest plane has to be within 12 km to be 'overhead', and it has
		// to be 4km away from the next-closest
		if filtered[0].Dist3 < 12.0 {
			if (len(filtered) == 1) || (filtered[1].Dist3-filtered[0].Dist3) > 4.0 {
				*overhead = filtered[0]
				debug += "** selected 1st\n"
			} else {
				debug += "** 2nd was too close to 1st\n"
			}
		} else {
			debug += "** 1st was too far away\n"
		}
	}

	return
}
Esempio n. 8
0
func monthlySummaryTaskHandler(w http.ResponseWriter, r *http.Request) {
	month, year, err := FormValueMonthDefaultToPrev(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	countByUser := false
	now := date.NowInPdt()
	start := time.Date(int(year), time.Month(month), 1, 0, 0, 0, 0, now.Location())
	end := start.AddDate(0, 1, 0).Add(-1 * time.Second)

	bucketname := "serfr0-reports"
	filename := start.Format("summary-2006-01.txt")
	ctx := req2ctx(r)

	if exists, err := gcs.Exists(ctx, bucketname, filename); err != nil {
		http.Error(w, fmt.Sprintf("gcs.Exists=%v for gs://%s/%s (err=%v)", exists,
			bucketname, filename, err), http.StatusInternalServerError)
		return
	} else if exists {
		w.Header().Set("Content-Type", "text/plain")
		w.Write([]byte(fmt.Sprintf("OK!\nGCS file %s/%s already exists\n", bucketname, filename)))
		return
	}

	tStart := time.Now()
	str, err := SummaryReport(r, start, end, countByUser)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	gcsHandle, err := gcs.OpenRW(ctx, bucketname, filename, "text/plain")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	gcsHandle.IOWriter().Write([]byte(str))
	if err := gcsHandle.Close(); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte(fmt.Sprintf("OK!\nGCS monthly report %s/%s written, took %s",
		bucketname, filename, time.Since(tStart))))
}
Esempio n. 9
0
func publishComplaintsHandler(w http.ResponseWriter, r *http.Request) {
	tStart := time.Now()

	ctx := appengine.NewContext(r)

	foldername := "serfr0-bigquery"

	datestring := r.FormValue("datestring")
	if datestring == "yesterday" {
		datestring = date.NowInPdt().AddDate(0, 0, -1).Format("2006.01.02")
	}

	filename := "anon-" + datestring + ".json"
	log.Infof(ctx, "Starting /backend/publish-complaints: %s", filename)

	n, err := writeAnonymizedGCSFile(r, datestring, foldername, filename)
	if err != nil {
		log.Errorf(ctx, "/backend/publish-complaints: %s, err: %v", filename, err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	log.Infof(ctx, "%d entries written to gs://%s/%s\n", n, foldername, filename)
	str := fmt.Sprintf("%d entries written to gs://%s/%s\n", n, foldername, filename)

	if r.FormValue("skipload") == "" {
		if err := submitLoadJob(r, foldername, filename); err != nil {
			http.Error(w, "submitLoadJob failed: "+err.Error(), http.StatusInternalServerError)
			return
		}
		str += "file submitted to BigQuery for loading\n"
	}

	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte(fmt.Sprintf("OK! (took %s)\n\n%s", time.Since(tStart), str)))
}
Esempio n. 10
0
// Gruesome. This pseudo-widget looks at 'year' and 'month', or defaults to the previous month.
// Everything is in Pacific Time.
func FormValueMonthDefaultToPrev(r *http.Request) (month, year int, err error) {
	// Default to the previous month
	oneMonthAgo := date.NowInPdt().AddDate(0, -1, 0)
	month = int(oneMonthAgo.Month())
	year = int(oneMonthAgo.Year())

	// Override with specific values, if present
	if r.FormValue("year") != "" {
		if y, err2 := strconv.ParseInt(r.FormValue("year"), 10, 64); err2 != nil {
			err = fmt.Errorf("need arg 'year' (2015)")
			return
		} else {
			year = int(y)
		}
		if m, err2 := strconv.ParseInt(r.FormValue("month"), 10, 64); err2 != nil {
			err = fmt.Errorf("need arg 'month' (1-12)")
			return
		} else {
			month = int(m)
		}
	}

	return
}
Esempio n. 11
0
func personalReportHandler(w http.ResponseWriter, r *http.Request) {
	session := sessions.Get(r)
	if session.Values["email"] == nil {
		http.Error(w, "session was empty; no cookie ?", http.StatusInternalServerError)
		return
	}
	email := session.Values["email"].(string)

	if r.FormValue("date") == "" {
		var params = map[string]interface{}{
			"Yesterday": date.NowInPdt().AddDate(0, 0, -1),
		}
		if err := templates.ExecuteTemplate(w, "personal-report-form", params); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	start, end, _ := widget.FormValueDateRange(r)

	ctx := appengine.Timeout(appengine.NewContext(r), 60*time.Second)
	cdb := complaintdb.ComplaintDB{C: ctx}

	w.Header().Set("Content-Type", "text/plain")
	// w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", "sc.txt"))
	fmt.Fprintf(w, "Personal disturbances report for <%s>:\n From [%s]\n To   [%s]\n",
		email, start, end)

	complaintStrings := []string{}
	var countsByHour [24]int
	countsByDate := map[string]int{}
	countsByAirline := map[string]int{}

	iter := cdb.NewIter(cdb.QueryInSpanByEmailAddress(start, end, email))
	n := 0
	for {
		c := iter.Next()
		if c == nil {
			break
		}

		str := fmt.Sprintf("Time: %s, Loudness:%d, Speedbrakes:%v, Flight:%6.6s, Notes:%s",
			c.Timestamp.Format("2006.01.02 15:04:05"), c.Loudness, c.HeardSpeedbreaks,
			c.AircraftOverhead.FlightNumber, c.Description)

		n++
		complaintStrings = append(complaintStrings, str)

		countsByHour[c.Timestamp.Hour()]++
		countsByDate[c.Timestamp.Format("2006.01.02")]++
		if airline := c.AircraftOverhead.IATAAirlineCode(); airline != "" {
			countsByAirline[airline]++
		}
	}

	fmt.Fprintf(w, "\nTotal number of disturbance reports, over %d days:  %d\n",
		len(countsByDate), n)

	fmt.Fprintf(w, "\nDisturbance reports, counted by Airline (where known):\n")
	for _, k := range keysByIntValDesc(countsByAirline) {
		fmt.Fprintf(w, " %s: % 4d\n", k, countsByAirline[k])
	}

	fmt.Fprintf(w, "\nDisturbance reports, counted by date:\n")
	for _, k := range keysByKeyAsc(countsByDate) {
		fmt.Fprintf(w, " %s: % 4d\n", k, countsByDate[k])
	}
	fmt.Fprintf(w, "\nDisturbance reports, counted by hour of day (across all dates):\n")
	for i, n := range countsByHour {
		fmt.Fprintf(w, " %02d: % 4d\n", i, n)
	}
	fmt.Fprintf(w, "\nFull dump of all disturbance reports:\n\n")
	for _, s := range complaintStrings {
		fmt.Fprint(w, s+"\n")
	}
}
Esempio n. 12
0
func report3Handler(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("rep") == "" {
		var params = map[string]interface{}{
			"Yesterday": date.NowInPdt().AddDate(0, 0, -1),
			"Reports":   report.ListReports(),
			"FormUrl":   "/report/",
			"Waypoints": sfo.ListWaypoints(),
			"Title":     "Reports (DB v1)",
		}
		if err := templates.ExecuteTemplate(w, "report3-form", params); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	rep, err := report.SetupReport(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if r.FormValue("debug") != "" {
		str := fmt.Sprintf("Report Options\n\n%s\n", rep.Options)
		w.Header().Set("Content-Type", "text/plain")
		w.Write([]byte(fmt.Sprintf("OK\n\n%s\n", str)))
		return
	}

	//airframes := ref.NewAirframeCache(c)
	metars, err := metar.LookupArchive(req2ctx(r), "KSFO",
		rep.Start.AddDate(0, 0, -1), rep.End.AddDate(0, 0, 1))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	v1idspecs := []string{}
	v2idspecs := []string{}
	v1RejectByRestrict := []string{}
	v1RejectByReport := []string{}

	reportFunc := func(oldF *oldfdb.Flight) {
		newF, err := oldF.V2()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		newF.ComputeIndicatedAltitudes(metars)

		outcome, err := rep.Process(newF)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		switch outcome {
		case report.RejectedByGeoRestriction:
			v1RejectByRestrict = append(v1RejectByRestrict, oldF.UniqueIdentifier())
		case report.RejectedByReport:
			v1RejectByReport = append(v1RejectByReport, oldF.UniqueIdentifier())
		case report.Accepted:
			v1idspecs = append(v1idspecs, oldF.UniqueIdentifier())
			v2idspecs = append(v2idspecs, newF.IdSpec().String())
		}
	}

	tags := rep.Options.Tags

	for _, wp := range rep.Waypoints {
		tags = append(tags, fmt.Sprintf("%s%s", oldfdb.KWaypointTagPrefix, wp))
	}

	db := oldfgae.NewDB(r)
	s, e := rep.Start, rep.End
	if err := db.LongIterWith(db.QueryTimeRangeByTags(tags, s, e), reportFunc); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	rep.FinishSummary()

	if rep.ResultsFormat == "csv" {
		rep.OutputAsCSV(w)
		return
	}

	postButtons := ""
	url := fmt.Sprintf("/fdb/trackset2?%s", rep.ToCGIArgs())
	postButtons += maybeButtonPOST(v1RejectByRestrict, "Restriction Rejects as VectorMap", url)
	postButtons += maybeButtonPOST(v1RejectByReport, "Report Rejects as VectorMap", url)

	url = fmt.Sprintf("/fdb/descent2?%s", rep.ToCGIArgs())
	postButtons += maybeButtonPOST(v1RejectByRestrict, "Restriction Rejects as DescentGraph", url)
	postButtons += maybeButtonPOST(v1RejectByReport, "Report Rejects DescentGraph", url)

	if rep.Name == "sfoclassb" {
		url = fmt.Sprintf("/fdb/approach2?%s", rep.ToCGIArgs())
		postButtons += maybeButtonPOST(v1idspecs, "Matches as ClassB", url)
		postButtons += maybeButtonPOST(v1RejectByReport, "Report Rejects as ClassB", url)
	}

	// The only way to get embedded CGI args without them getting escaped is to submit a whole tag
	vizFormURL := "http://stop.jetnoise.net/fdb/visualize2?" + rep.ToCGIArgs()
	vizFormTag := "<form action=\"" + vizFormURL + "\" method=\"post\" target=\"_blank\">"

	var params = map[string]interface{}{
		"R":                    rep,
		"Metadata":             rep.MetadataTable(),
		"PostButtons":          template.HTML(postButtons),
		"OptStr":               template.HTML(fmt.Sprintf("<pre>%s</pre>\n", rep.Options)),
		"IdSpecs":              template.HTML(strings.Join(v1idspecs, ",")),
		"VisualizationFormTag": template.HTML(vizFormTag),
	}
	if err := templates.ExecuteTemplate(w, "report3-results", params); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}
Esempio n. 13
0
func queryHandler(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("date") == "" && r.FormValue("epoch") == "" {
		var params = map[string]interface{}{
			"TwoHoursAgo": date.NowInPdt().Add(-2 * time.Hour),
		}
		if err := templates.ExecuteTemplate(w, "fdb-queryform", params); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	db := fdb.NewDB(r)
	db.Memcache = true

	var t time.Time
	if r.FormValue("epoch") != "" {
		if epoch, err := strconv.ParseInt(r.FormValue("epoch"), 10, 64); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		} else {
			t = time.Unix(epoch, 0)
		}
	} else {
		var err2 error
		t, err2 = date.ParseInPdt("2006/01/02 15:04:05", r.FormValue("date")+" "+r.FormValue("time"))
		if err2 != nil {
			http.Error(w, err2.Error(), http.StatusInternalServerError)
			return
		}
	}

	var refPoint *geo.Latlong = nil
	if r.FormValue("lat") != "" {
		refPoint = &geo.Latlong{}
		var err error
		if refPoint.Lat, err = strconv.ParseFloat(r.FormValue("lat"), 64); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if refPoint.Long, err = strconv.ParseFloat(r.FormValue("long"), 64); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}

	if snapshots, err := db.LookupSnapshotsAtTimestampUTC(t.UTC(), refPoint, 1000); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	} else {
		var params = map[string]interface{}{
			"Legend":        buildLegend(t),
			"SearchTimeUTC": t.UTC(),
			"SearchTime":    date.InPdt(t),
			"Flights":       snapshots2params(snapshots),

			"FlightsJS":  ftype.FlightSnapshotSet(snapshots).ToJSVar(),
			"MapsAPIKey": kGoogleMapsAPIKey,
			"Center":     sfo.KLatlongSERFR1,
			"Zoom":       9,
			// "CaptureArea": fdb.KBoxSnarfingCatchment,  // comment out, as we don't want it in this view
		}

		if r.FormValue("resultformat") == "json" {
			for i, _ := range snapshots {
				snapshots[i].F.Track = nil
				snapshots[i].F.Tracks = nil
			}
			js, err := json.Marshal(snapshots)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			w.Header().Set("Content-Type", "application/json")
			w.Write(js)

		} else {
			templateName := "fdb-queryresults-map"
			if r.FormValue("resultformat") == "list" {
				templateName = "fdb-queryresults-list"
			}

			if err := templates.ExecuteTemplate(w, templateName, params); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
			}
		}
	}
}
Esempio n. 14
0
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)
	}
}
Esempio n. 15
0
func zipHandler(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("date") == "" {
		var params = map[string]interface{}{
			"Yesterday": date.NowInPdt().AddDate(0, 0, -1),
		}
		if err := templates.ExecuteTemplate(w, "zip-report-form", params); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	ctx := req2ctx(r)
	cdb := complaintdb.NewDB(ctx)

	zip := r.FormValue("zip")
	s, e, _ := widget.FormValueDateRange(r)

	var countsByHour [24]int
	countsByDate := map[string]int{}
	var uniquesByHour [24]map[string]int
	uniquesByDate := map[string]map[string]int{}
	uniquesAll := map[string]int{}

	iter := cdb.NewIter(cdb.QueryInSpanInZip(s, e, zip))
	for {
		c, err := iter.NextWithErr()
		if err != nil {
			http.Error(w, fmt.Sprintf("Zip iterator failed: %v", err), http.StatusInternalServerError)
			return
		} else if c == nil {
			break // We've hit EOF
		}

		h := c.Timestamp.Hour()
		countsByHour[h]++
		if uniquesByHour[h] == nil {
			uniquesByHour[h] = map[string]int{}
		}
		uniquesByHour[h][c.Profile.EmailAddress]++

		d := c.Timestamp.Format("2006.01.02")
		countsByDate[d]++
		if uniquesByDate[d] == nil {
			uniquesByDate[d] = map[string]int{}
		}
		uniquesByDate[d][c.Profile.EmailAddress]++

		uniquesAll[c.Profile.EmailAddress]++
	}

	dateKeys := []string{}
	for k, _ := range countsByDate {
		dateKeys = append(dateKeys, k)
	}
	sort.Strings(dateKeys)

	data := [][]string{}

	data = append(data, []string{"Date", "NumComplaints", "UniqueComplainers"})
	for _, k := range dateKeys {
		data = append(data, []string{
			k,
			fmt.Sprintf("%d", countsByDate[k]),
			fmt.Sprintf("%d", len(uniquesByDate[k])),
		})
	}
	data = append(data, []string{"------"})

	data = append(data, []string{"HourAcrossAllDays", "NumComplaints", "UniqueComplainers"})
	for i, v := range countsByHour {
		data = append(data, []string{
			fmt.Sprintf("%02d:00", i),
			fmt.Sprintf("%d", v),
			fmt.Sprintf("%d", len(uniquesByHour[i])),
		})
	}
	data = append(data, []string{"------"})
	data = append(data, []string{"UniqueComplainersAcrossAllDays", fmt.Sprintf("%d", len(uniquesAll))})

	var params = map[string]interface{}{"Data": data}
	if err := templates.ExecuteTemplate(w, "report", params); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
Esempio n. 16
0
func monthTaskHandler(w http.ResponseWriter, r *http.Request) {
	//ctx,_ := context.WithTimeout(appengine.NewContext(r), 599*time.Second)
	ctx := appengine.NewContext(r)

	cdb := complaintdb.ComplaintDB{
		//C: oldappengine.NewContext(r),
		C: oldappengine.Timeout(oldappengine.NewContext(r), 599*time.Second),
	}

	year, err := strconv.ParseInt(r.FormValue("year"), 10, 64)
	if err != nil {
		http.Error(w, "need arg 'year' (2015)", http.StatusInternalServerError)
		return
	}
	month, err := strconv.ParseInt(r.FormValue("month"), 10, 64)
	if err != nil {
		http.Error(w, "need arg 'month' (1-12)", http.StatusInternalServerError)
		return
	}

	now := date.NowInPdt()
	s := time.Date(int(year), time.Month(month), 1, 0, 0, 0, 0, now.Location())
	e := s.AddDate(0, 1, 0).Add(-1 * time.Second)
	log.Infof(ctx, "Starting /be/month: %s", s)

	// One time, at 00:00, for each day of the given month
	days := date.IntermediateMidnights(s.Add(-1*time.Second), e)

	filename := s.Format("complaints-20060102") + e.Format("-20060102.csv")

	gcsHandle, err := gcs.OpenRW(ctx, "serfr0-reports", filename, "text/plain")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	csvWriter := csv.NewWriter(gcsHandle.IOWriter())

	cols := []string{
		"CallerCode", "Name", "Address", "Zip", "Email", "HomeLat", "HomeLong",
		"UnixEpoch", "Date", "Time(PDT)", "Notes", "ActivityDisturbed", "Flightnumber",
		"Notes",
		// Column names above are incorrect, but BKSV are used to them.
		//
		//"CallerCode", "Name", "Address", "Zip", "Email", "HomeLat", "HomeLong",
		//"UnixEpoch", "Date", "Time(PDT)", "Notes", "Flightnumber",
		//"ActivityDisturbed", "CcSFO",
	}
	csvWriter.Write(cols)

	for _, dayStart := range days {
		dayEnd := dayStart.AddDate(0, 0, 1).Add(-1 * time.Second)
		log.Infof(ctx, " /be/month: %s - %s", dayStart, dayEnd)

		iter := cdb.NewIter(cdb.QueryInSpan(dayStart, dayEnd))
		for {
			c, err := iter.NextWithErr()
			if err != nil {
				http.Error(w, fmt.Sprintf("iterator failed: %v", err),
					http.StatusInternalServerError)
				return
			}
			if c == nil {
				break
			}

			r := []string{
				c.Profile.CallerCode,
				c.Profile.FullName,
				c.Profile.Address,
				c.Profile.StructuredAddress.Zip,
				c.Profile.EmailAddress,
				fmt.Sprintf("%.4f", c.Profile.Lat),
				fmt.Sprintf("%.4f", c.Profile.Long),

				fmt.Sprintf("%d", c.Timestamp.UTC().Unix()),
				c.Timestamp.Format("2006/01/02"),
				c.Timestamp.Format("15:04:05"),
				c.Description,
				c.AircraftOverhead.FlightNumber,
				c.Activity,
				fmt.Sprintf("%v", c.Profile.CcSfo),
			}

			if err := csvWriter.Write(r); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		}
	}
	csvWriter.Flush()

	if err := gcsHandle.Close(); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	log.Infof(ctx, "GCS report '%s' successfully written", filename)

	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte(fmt.Sprintf("OK!\nGCS file '%s' written to bucket", filename)))
}
Esempio n. 17
0
func reportWriter(c appengine.Context, w http.ResponseWriter, r *http.Request, s, e time.Time, opt ReportOptions, rep string, format string) {
	var rows []ReportRow
	var meta ReportMetadata
	var err error
	switch rep {
	case "classb":
		rows, meta, err = classbReport(c, s, e, opt)
	case "adsbclassb":
		rows, meta, err = adsbClassbReport(c, s, e, opt)
	case "discrep":
		rows, meta, err = discrepReport(c, s, e, opt)
	case "serfr1":
		rows, meta, err = serfr1Report(c, s, e, opt)
	case "brixx1":
		rows, meta, err = brixx1Report(c, s, e, opt)
	case "serfr1complaints":
		rows, meta, err = serfr1ComplaintsReport(c, s, e, opt)
	case "skimmer":
		rows, meta, err = skimmerReport(c, s, e, opt)
	case "brixxviolations":
		rows, meta, err = brixxViolationReport(c, s, e, opt)
	case "serfr1at":
		rows, meta, err = serfr1AtReport(c, s, e, opt)
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Should do something better for this
	filename := date.NowInPdt().AddDate(0, 0, -1).Format(rep + "-20060102.csv")
	outFunc := func(csvWriter *csv.Writer) error {
		csvWriter.Write(rows[0].ToCSVHeaders())
		for _, r := range rows {
			if err := csvWriter.Write(r.ToCSV()); err != nil {
				return err
			}
		}
		csvWriter.Flush()
		return nil
	}

	if format == "csv" {
		w.Header().Set("Content-Type", "application/csv")
		w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
		csvWriter := csv.NewWriter(w)
		if err := outFunc(csvWriter); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

	} else if format == "gcs" {
		newCtx := newappengine.NewContext(r)
		handle, err := gcs.OpenRW(newCtx, "serfr0-reports", filename, "text/plain") //?"application/csv")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		csvWriter := csv.NewWriter(handle.IOWriter())
		if err := outFunc(csvWriter); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if err := handle.Close(); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "text/plain")
		w.Write([]byte(fmt.Sprintf("OK!\nGCS file '%s' written to bucket", filename)))

	} else {
		var params = map[string]interface{}{
			"Start":    s,
			"End":      e,
			"Metadata": meta,
			"Options":  opt,
		}

		// Is there not a more elegant way to do this kind of thing ?
		switch rep {
		case "classb":
			out := []CBRow{}
			for _, r := range rows {
				out = append(out, r.(CBRow))
			}
			params["Rows"] = out
		case "adsbclassb":
			out := []ACBRow{}
			for _, r := range rows {
				out = append(out, r.(ACBRow))
			}
			params["Rows"] = out
		case "serfr1", "brixx1", "discrep":
			out := []SERFR1Row{}
			for _, r := range rows {
				out = append(out, r.(SERFR1Row))
			}
			params["Rows"] = out
			rep = "serfr1"
		case "serfr1complaints":
			out := []SCRow{}
			for _, r := range rows {
				out = append(out, r.(SCRow))
			}
			params["Rows"] = out
		case "skimmer":
			out := []SkimRow{}
			for _, r := range rows {
				out = append(out, r.(SkimRow))
			}
			params["Rows"] = out
		case "brixxviolations":
			out := []BrixxRow{}
			for _, r := range rows {
				out = append(out, r.(BrixxRow))
			}
			params["Rows"] = out
		case "serfr1at":
			out := []SERFR1AtRow{}
			for _, r := range rows {
				out = append(out, r.(SERFR1AtRow))
			}
			params["Rows"] = out
		}

		if err := templates.ExecuteTemplate(w, "report-"+rep, params); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}
Esempio n. 18
0
// Where is the version of this that does GCS via batch ?
func monthHandler(w http.ResponseWriter, r *http.Request) {
	ctx := req2ctx(r)

	year, err := strconv.ParseInt(r.FormValue("year"), 10, 64)
	if err != nil {
		http.Error(w, "need arg 'year' (2015)", http.StatusInternalServerError)
		return
	}
	month, err := strconv.ParseInt(r.FormValue("month"), 10, 64)
	if err != nil {
		http.Error(w, "need arg 'month' (1-12)", http.StatusInternalServerError)
		return
	}

	day, err := strconv.ParseInt(r.FormValue("day"), 10, 64)
	if err != nil {
		// Presume we should enqueue this for batch
		taskUrl := fmt.Sprintf("/backend/monthdump?year=%d&month=%d", year, month)
		t := taskqueue.NewPOSTTask(taskUrl, map[string][]string{
			"year":  {r.FormValue("year")},
			"month": {r.FormValue("month")},
		})
		if _, err := taskqueue.Add(ctx, t, "batch"); err != nil {
			log.Errorf(ctx, "monthHandler: enqueue: %v", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "text/plain")
		w.Write([]byte(fmt.Sprintf("OK\nHave enqueued for batch {%s}\n", taskUrl)))
		return
	}

	num, err := strconv.ParseInt(r.FormValue("num"), 10, 64)
	if err != nil {
		http.Error(w, "need arg 'num' (31 - 'day')", http.StatusInternalServerError)
		return
	}
	now := date.NowInPdt()
	firstOfMonth := time.Date(int(year), time.Month(month), 1, 0, 0, 0, 0, now.Location())
	s := firstOfMonth.AddDate(0, 0, int(day-1))
	e := s.AddDate(0, 0, int(num)).Add(-1 * time.Second)

	log.Infof(ctx, "Yow: START : %s", s)
	log.Infof(ctx, "Yow: END   : %s", e)

	cdb := complaintdb.NewDB(ctx)

	filename := s.Format("complaints-20060102") + e.Format("-20060102.csv")
	w.Header().Set("Content-Type", "application/csv")
	w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))

	cols := []string{
		"CallerCode", "Name", "Address", "Zip", "Email", "HomeLat", "HomeLong",
		"UnixEpoch", "Date", "Time(PDT)",
		"Notes", "Flightnumber", "ActivityDisturbed", "AutoSubmit",
	}
	csvWriter := csv.NewWriter(w)
	csvWriter.Write(cols)

	iter := cdb.NewIter(cdb.QueryInSpan(s, e))
	for {
		c, err := iter.NextWithErr()
		if err != nil {
			http.Error(w, fmt.Sprintf("Zip iterator failed: %v", err), http.StatusInternalServerError)
			return
		} else if c == nil {
			break // We've hit EOF
		}

		r := []string{
			c.Profile.CallerCode, c.Profile.FullName, c.Profile.Address,
			c.Profile.StructuredAddress.Zip, c.Profile.EmailAddress,
			fmt.Sprintf("%.4f", c.Profile.Lat), fmt.Sprintf("%.4f", c.Profile.Long),
			fmt.Sprintf("%d", c.Timestamp.UTC().Unix()),
			c.Timestamp.Format("2006/01/02"),
			c.Timestamp.Format("15:04:05"),
			c.Description, c.AircraftOverhead.FlightNumber, c.Activity,
			fmt.Sprintf("%v", c.Profile.CcSfo),
		}

		//r = []string{c.Timestamp.Format("15:04:05")}

		if err := csvWriter.Write(r); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
	csvWriter.Flush()
}
Esempio n. 19
0
func communityReportHandler(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("date") == "" {
		var params = map[string]interface{}{
			"Title":     "Community breakdown of disturbance reports",
			"FormUrl":   "/report/community",
			"Yesterday": date.NowInPdt().AddDate(0, 0, -1),
		}
		if err := templates.ExecuteTemplate(w, "date-report-form", params); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	start, end, _ := widget.FormValueDateRange(r)

	ctx := req2ctx(r)
	cdb := complaintdb.NewDB(ctx)

	// Use most-recent city info for all the users, not what got cached per-complaint
	userCities, err := cdb.GetEmailCityMap()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	filename := start.Format("community-20060102") + end.Format("-20060102.csv")
	w.Header().Set("Content-Type", "application/csv")
	w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))

	counts := map[string]map[string]int{} // {datestr}{city}
	users := map[string]map[string]int{}  // {datestr}{city}

	// An iterator expires after 60s, no matter what; so carve up into short-lived iterators
	n := 0

	currCounts := map[string]int{}
	currUsers := map[string]map[string]int{}
	currN := 0

	for _, dayWindow := range DayWindows(start, end) {
		//daycounts := map[string]int{}             // {city}
		//dayusers := map[string]map[string]int{}   // {city}{email}

		q := cdb.QueryInSpan(dayWindow[0], dayWindow[1])
		q = q.Project("Profile.StructuredAddress.City", "Profile.EmailAddress")
		iter := cdb.NewIter(q)
		for {
			c, err := iter.NextWithErr()
			if err != nil {
				http.Error(w, fmt.Sprintf("iterator failed at %s: %v", time.Now(), err),
					http.StatusInternalServerError)
				return
			} else if c == nil {
				break // we're all done with this iterator
			}
			n++

			//email,city := c.Profile.EmailAddress,c.Profile.StructuredAddress.City
			email := c.Profile.EmailAddress
			city := userCities[email]
			if city == "" {
				city = "Unknown"
			}

			if currUsers[city] == nil {
				currUsers[city] = map[string]int{}
			}
			currUsers[city][email]++
			currCounts[city]++
		}
		currN++ // number of days processed since last flush.

		// End of a day; should we flush the counters ?
		flushStr := ""
		if true || r.FormValue("byweek") != "" {
			if currN == 7 {
				flushStr = dayWindow[0].Format("2006.01.02")
			}
		} else {
			flushStr = dayWindow[0].Format("2006.01.02")
		}

		if flushStr != "" {
			counts[flushStr] = currCounts
			users[flushStr] = map[string]int{}
			for city, _ := range currUsers {
				users[flushStr][city] = len(currUsers[city])
			}
			currCounts = map[string]int{}
			currUsers = map[string]map[string]int{}
			currN = 0
		}
	}

	cols := []string{"Date"}
	cols = append(cols, cityCols...)
	csvWriter := csv.NewWriter(w)
	csvWriter.Write(cols)

	for _, datestr := range keysByKeyAscNested(counts) {
		row := []string{datestr}
		for _, town := range cityCols {
			n := counts[datestr][town]
			row = append(row, fmt.Sprintf("%d", n))
		}
		csvWriter.Write(row)
	}

	csvWriter.Write(cols)
	for _, datestr := range keysByKeyAscNested(users) {
		row := []string{datestr}
		for _, town := range cityCols {
			n := users[datestr][town]
			row = append(row, fmt.Sprintf("%d", n))
		}
		csvWriter.Write(row)
	}

	csvWriter.Flush()

	//fmt.Fprintf(w, "(t=%s, n=%d)\n", time.Now(), n)
}
Esempio n. 20
0
func (fr *Fr24) FindAllOverhead(observerPos geo.Latlong, overhead *flightid.Aircraft, grabAnything bool) (outAll []*Aircraft, outFilt []*Aircraft, debug string, err error) {
	outAll = []*Aircraft{}
	outFilt = []*Aircraft{}

	debug = fmt.Sprintf("*** FindOverhead for %s, at %s\n", observerPos, date.NowInPdt())
	debug += fmt.Sprintf("* url: http://%s%s?array=1&bounds=%s\n", fr.host, kListUrlPath, "...")

	// Create a bounding box that's ~40m square, centred on the input lat,long
	// This is a grievous fudge http://www.movable-type.co.uk/scripts/latlong.html
	lat_20miles := 0.3
	long_20miles := 0.35
	nearby := []Aircraft{}
	if err = fr.ListBbox(observerPos.Lat-lat_20miles, observerPos.Long-long_20miles,
		observerPos.Lat+lat_20miles, observerPos.Long+long_20miles, &nearby); err != nil {
		debug += fmt.Sprintf("Lookup error: %s\n", err)
		return
	}

	for i, a := range nearby {
		// Hack for Surf Air; promote callsigns into (invalid_ flightnumbers, so they don't get stripped
		if a.FlightNumber == "" && regexp.MustCompile("^URF\\d+$").MatchString(a.Callsign) {
			nearby[i].FlightNumber = a.Callsign
		} else if a.FlightNumber != "" {
			if _, _, err := fdb.ParseIata(a.FlightNumber); err != nil {
				debug += "** saw bad flightnumber '" + a.FlightNumber + "' from fr24\n"
				nearby[i].FlightNumber = ""
			}
		}

		aircraftPos := geo.Latlong{a.Lat, a.Long}
		nearby[i].Dist = observerPos.Dist(aircraftPos)
		nearby[i].Dist3 = observerPos.Dist3(aircraftPos, a.Altitude)
		nearby[i].BearingFromObserver = observerPos.BearingTowards(aircraftPos)
	}
	sort.Sort(byDist3(nearby))
	debug += "** nearby list:-\n" + DebugFlightList(nearby)

	filtered := filterAircraft(nearby)
	if len(filtered) == 0 {
		debug += "** all empty after filtering\n"
		return
	}

	for i, _ := range nearby {
		outAll = append(outAll, &nearby[i])
	}
	for i, _ := range filtered {
		outFilt = append(outFilt, &filtered[i])
	}

	debug += "** filtered:-\n" + DebugFlightList(filtered)

	if grabAnything {
		filtered[0].IntoFlightIdAircraft(overhead)
		debug += "** grabbed 1st\n"
	} else {
		// closest plane has to be within 12 km to be 'overhead', and it has
		// to be 4km away from the next-closest
		if filtered[0].Dist3 < 12.0 {
			if (len(filtered) == 1) || (filtered[1].Dist3-filtered[0].Dist3) > 4.0 {
				filtered[0].IntoFlightIdAircraft(overhead)
				debug += "** selected 1st\n"
			} else {
				debug += "** 2nd was too close to 1st\n"
			}
		} else {
			debug += "** 1st was too far away\n"
		}
	}

	return
}
Esempio n. 21
0
func report3Handler(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("rep") == "" {
		var params = map[string]interface{}{
			"Yesterday": date.NowInPdt().AddDate(0, 0, -1),
			"Reports":   report.ListReports(),
			"FormUrl":   "/report3/",
			"Waypoints": sfo.ListWaypoints(),
		}
		if err := templates.ExecuteTemplate(w, "report3-form", params); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	rep, err := report.SetupReport(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if r.FormValue("debug") != "" {
		str := fmt.Sprintf("Report Options\n\n%s\n", rep.Options)
		w.Header().Set("Content-Type", "text/plain")
		w.Write([]byte(fmt.Sprintf("OK\n\n%s\n", str)))
		return
	}

	//airframes := ref.NewAirframeCache(c)
	client := newurlfetch.Client(newappengine.NewContext(r))
	metars, err := metar.FetchFromNOAA(client, "KSFO",
		rep.Start.AddDate(0, 0, -1), rep.End.AddDate(0, 0, 1))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	v1idspecs := []string{}
	v2idspecs := []string{}

	v1idspecComplement := []string{}

	reportFunc := func(oldF *oldfdb.Flight) {
		newF, err := oldF.V2()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		} else {
			newF.ComputeIndicatedAltitudes(metars)
			if included, err := rep.Process(newF); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
			} else if included {
				v1idspecs = append(v1idspecs, oldF.UniqueIdentifier())
				v2idspecs = append(v2idspecs, newF.IdSpec())
			} else {
				v1idspecComplement = append(v1idspecComplement, oldF.UniqueIdentifier())
			}
		}
	}

	tags := tagList(rep.Options)

	db := oldfgae.FlightDB{C: oldappengine.Timeout(oldappengine.NewContext(r), 600*time.Second)}
	s, e := rep.Start, rep.End
	if err := db.LongIterWith(db.QueryTimeRangeByTags(tags, s, e), reportFunc); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	postButtons := ButtonPOST(fmt.Sprintf("%d Matches as a VectorMap", len(v1idspecs)),
		fmt.Sprintf("/fdb/trackset2?%s", rep.ToCGIArgs()), v1idspecs)
	postButtons += ButtonPOST(fmt.Sprintf("%d Non-matches as a VectorMap", len(v1idspecComplement)),
		fmt.Sprintf("/fdb/trackset2?%s", rep.ToCGIArgs()), v1idspecComplement)
	if rep.Name == "sfoclassb" {
		postButtons += ButtonPOST(fmt.Sprintf("%d Matches as ClassBApproaches", len(v1idspecs)),
			fmt.Sprintf("/fdb/approach2?%s", rep.ToCGIArgs()), v1idspecs)
		// This is kinda useless, as it isn't limited to SERFR1 things
		postButtons += ButtonPOST(fmt.Sprintf("%d Non-matches as ClassBApproaches", len(v1idspecComplement)),
			fmt.Sprintf("/fdb/approach2?%s", rep.ToCGIArgs()), v1idspecComplement)

		postButtons += ButtonPOST(fmt.Sprintf("%d Matches as ClassBApproaches (delta)",
			len(v1idspecs)), fmt.Sprintf("/fdb/approach2?%s&colorby=delta", rep.ToCGIArgs()), v1idspecs)
		// This is kinda useless, as it isn't limited to SERFR1 things
		postButtons += ButtonPOST(fmt.Sprintf("%d Non-matches as ClassBApproaches (delta)",
			len(v1idspecComplement)), fmt.Sprintf("/fdb/approach2?%s&colorby=delta",
			rep.ToCGIArgs()), v1idspecComplement)
	}

	var params = map[string]interface{}{
		"R":           rep,
		"Metadata":    rep.MetadataTable(),
		"PostButtons": template.HTML(postButtons),
		"OptStr":      template.HTML(fmt.Sprintf("<pre>%s</pre>\n", rep.Options)),
		"IdSpecs":     template.HTML(strings.Join(v1idspecs, ",")),
	}
	if err := templates.ExecuteTemplate(w, "report3-results", params); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}
Esempio n. 22
0
func rootHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	session := sessions.Get(r)

	// No session ? Get them to login
	if session.Values["email"] == nil {
		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
	}

	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 := complaintdb.ComplaintDB{C: c}
	cap, err := cdb.GetAllByEmailAddress(session.Values["email"].(string), 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
	}

	modes["admin"] = user.Current(c) != nil && user.Current(c).Admin
	modes["superuser"] = modes["admin"] || cap.Profile.EmailAddress == "*****@*****.**"

	// 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 := ""
	if cap.Profile.FullName == "" {
		message += "<li>We don't have your full name</li>"
	}
	if cap.Profile.StructuredAddress.Zip == "" {
		message += "<li>We don't have an accurate address</li>"
	}
	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 might be exluded, so please "+
			"<a href=\"/profile\"><b>update your profile</b></a> !</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),
	}

	if err := templates.ExecuteTemplate(w, "main", params); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
Esempio n. 23
0
func generateMonthlyCSV(cdb complaintdb.ComplaintDB, month, year int) (string, int, error) {
	ctx := cdb.Ctx()
	bucketname := "serfr0-reports"

	now := date.NowInPdt()
	s := time.Date(int(year), time.Month(month), 1, 0, 0, 0, 0, now.Location())
	e := s.AddDate(0, 1, 0).Add(-1 * time.Second)
	log.Infof(ctx, "Starting /be/month: %s", s)

	// One time, at 00:00, for each day of the given month
	days := date.IntermediateMidnights(s.Add(-1*time.Second), e)

	filename := s.Format("complaints-20060102") + e.Format("-20060102.csv")

	gcsName := "gs://" + bucketname + "/" + filename

	if exists, err := gcs.Exists(ctx, bucketname, filename); err != nil {
		return gcsName, 0, fmt.Errorf("gcs.Exists=%v for gs://%s/%s (err=%v)", exists, bucketname, filename, err)
	} else if exists {
		return gcsName, 0, nil
	}

	gcsHandle, err := gcs.OpenRW(ctx, bucketname, filename, "text/plain")
	if err != nil {
		return gcsName, 0, err
	}
	csvWriter := csv.NewWriter(gcsHandle.IOWriter())

	cols := []string{
		"CallerCode", "Name", "Address", "Zip", "Email", "HomeLat", "HomeLong",
		"UnixEpoch", "Date", "Time(PDT)", "Notes", "ActivityDisturbed", "Flightnumber",
		"Notes",
		// Column names above are incorrect, but BKSV are used to them.
		//
		//"CallerCode", "Name", "Address", "Zip", "Email", "HomeLat", "HomeLong",
		//"UnixEpoch", "Date", "Time(PDT)", "Notes", "Flightnumber",
		//"ActivityDisturbed", "CcSFO",
	}
	csvWriter.Write(cols)

	tStart := time.Now()
	n := 0
	for _, dayStart := range days {
		dayEnd := dayStart.AddDate(0, 0, 1).Add(-1 * time.Second)
		log.Infof(ctx, " /be/month: %s - %s", dayStart, dayEnd)

		tIter := time.Now()
		iter := cdb.NewLongBatchingIter(cdb.QueryInSpan(dayStart, dayEnd))
		for {
			c, err := iter.NextWithErr()
			if err != nil {
				return gcsName, 0, fmt.Errorf("iterator failed after %s (%s): %v", err, time.Since(tIter),
					time.Since(tStart))
			}
			if c == nil {
				break
			}

			r := []string{
				c.Profile.CallerCode,
				c.Profile.FullName,
				c.Profile.Address,
				c.Profile.StructuredAddress.Zip,
				c.Profile.EmailAddress,
				fmt.Sprintf("%.4f", c.Profile.Lat),
				fmt.Sprintf("%.4f", c.Profile.Long),

				fmt.Sprintf("%d", c.Timestamp.UTC().Unix()),
				c.Timestamp.Format("2006/01/02"),
				c.Timestamp.Format("15:04:05"),
				c.Description,
				c.AircraftOverhead.FlightNumber,
				c.Activity,
				fmt.Sprintf("%v", c.Profile.CcSfo),
			}

			if err := csvWriter.Write(r); err != nil {
				return gcsName, 0, err
			}

			n++
		}
	}
	csvWriter.Flush()

	if err := gcsHandle.Close(); err != nil {
		return gcsName, 0, err
	}

	log.Infof(ctx, "monthly CSV successfully written to %s, %d rows", gcsName, n)

	return gcsName, n, nil
}