Example #1
0
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)))
}
Example #2
0
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
}
Example #3
0
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)
}
Example #4
0
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)
		}
	}
}
Example #5
0
// 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))))
}
Example #6
0
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)
	}
}
Example #7
0
// 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)
}
Example #8
0
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)
	}
}
Example #9
0
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
	}
}
Example #10
0
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)
}
Example #11
0
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)
	}
}
Example #12
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()
}
Example #13
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()
}
Example #14
0
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")))
}
Example #15
0
// 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"))
}
Example #16
0
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"))
}
Example #17
0
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))
}
Example #18
0
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))
}
Example #19
0
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)
		}
	}
}
Example #20
0
// 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)))
}
Example #21
0
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)
}
Example #22
0
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)
	}
}
Example #23
0
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"))
}
Example #24
0
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))))
	}
}
Example #25
0
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)
}
Example #26
0
// 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)))
}
Example #27
0
// 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)))
}
Example #28
0
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)
	}
}
Example #29
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)
	}
}
Example #30
0
// 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)))
}