Пример #1
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))
}
Пример #2
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"))
}
Пример #3
0
// Writes them all into a batch queue
func publishAllComplaintsHandler(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)
	str := ""

	s, e, _ := widget.FormValueDateRange(r)
	days := date.IntermediateMidnights(s.Add(-1*time.Second), e) // decrement start, to include it
	url := "/backend/publish-complaints"

	for i, day := range days {
		dayStr := day.Format("2006.01.02")

		thisUrl := fmt.Sprintf("%s?datestring=%s", url, dayStr)
		if r.FormValue("skipload") != "" {
			thisUrl += "&skipload=" + r.FormValue("skipload")
		}

		t := taskqueue.NewPOSTTask(thisUrl, map[string][]string{})
		// Give ourselves time to get all these tasks posted, and stagger them out a bit
		t.Delay = time.Minute + time.Duration(i)*15*time.Second

		if _, err := taskqueue.Add(ctx, t, "batch"); err != nil {
			log.Errorf(ctx, "publishAllComplaintsHandler: enqueue: %v", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		str += " * posting for " + thisUrl + "\n"
	}

	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte(fmt.Sprintf("OK, enqueued %d\n--\n%s", len(days), str)))
}
Пример #4
0
// This enqueues tasks for each individual day, or flight
func batchFlightScanHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	tags := []string{} //"ADSB"} // Maybe make this configurable ...

	n := 0
	str := ""
	s, e, _ := widget.FormValueDateRange(r)
	job := r.FormValue("job")
	if job == "" {
		http.Error(w, "Missing argument: &job=foo", http.StatusInternalServerError)
	}

	days := date.IntermediateMidnights(s.Add(-1*time.Second), e) // decrement start, to include it
	for _, day := range days {
		// Get the keys for all the flights on this day.
		fdb := oldfgae.FlightDB{C: oldappengine.NewContext(r)}

		dStart, dEnd := date.WindowForTime(day)
		dEnd = dEnd.Add(-1 * time.Second)
		keys, err := fdb.KeysInTimeRangeByTags(tags, dStart, dEnd)
		if err != nil {
			log.Errorf(c, "upgradeHandler: enqueue: %v", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		singleFlightUrl := "/backend/fdb-batch/flight"
		for _, key := range keys {
			str += fmt.Sprintf("Enqueing day=%s: %s?job=%s&key=%s\n",
				day.Format("2006.01.02"), singleFlightUrl, job, key.Encode())

			t := taskqueue.NewPOSTTask(singleFlightUrl, map[string][]string{
				"date": {day.Format("2006.01.02")},
				"key":  {key.Encode()},
				"job":  {job},
			})

			if _, err := taskqueue.Add(c, t, "batch"); err != nil {
				log.Errorf(c, "upgradeHandler: enqueue: %v", err)
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			n++
		}
	}

	log.Infof(c, "enqueued %d batch items for '%s'", n, job)

	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte(fmt.Sprintf("OK, batch, enqueued %d tasks for %s\n%s", n, job, str)))
}
Пример #5
0
// Enqueues one 'day' task per day in the range
func batchFlightDateRangeHandler(w http.ResponseWriter, r *http.Request) {
	ctx := req2ctx(r)

	n := 0
	str := ""
	s, e, _ := widget.FormValueDateRange(r)
	job := r.FormValue("job")
	if job == "" {
		http.Error(w, "Missing argument: &job=foo", http.StatusInternalServerError)
		return
	}

	str += fmt.Sprintf("** s: %s\n** e: %s\n", s, e)

	days := date.IntermediateMidnights(s.Add(-1*time.Second), e) // decrement start, to include it
	for _, day := range days {

		dayUrl := "/backend/fdb-batch/day"
		dayStr := day.Format("2006/01/02")

		str += fmt.Sprintf(" * adding %s, %s via %s\n", job, dayStr, dayUrl)

		if r.FormValue("dryrun") == "" {
			t := taskqueue.NewPOSTTask(dayUrl, map[string][]string{
				"day": {dayStr},
				"job": {job},
			})

			if _, err := taskqueue.Add(ctx, t, "batch"); err != nil {
				log.Errorf(ctx, "upgradeHandler: enqueue: %v", err)
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		}

		n++
	}

	log.Infof(ctx, "enqueued %d batch items for '%s'", n, job)

	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte(fmt.Sprintf("OK, batch, enqueued %d tasks for %s\n%s", n, job, str)))
}
Пример #6
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")
	}
}
Пример #7
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)
}
Пример #8
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)
	}
}