"github.com/octo/gfitsync/app"
"github.com/octo/gfitsync/fitbit"
+ "github.com/octo/gfitsync/gfit"
"google.golang.org/appengine"
"google.golang.org/appengine/datastore"
"google.golang.org/appengine/delay"
var delayedHandleNotifications = delay.Func("handleNotifications", handleNotifications)
func init() {
- http.HandleFunc("/setup", setupHandler)
+ http.HandleFunc("/fitbit/setup", fitbitSetupHandler)
http.Handle("/fitbit/grant", AuthenticatedHandler(fitbitGrantHandler))
http.Handle("/fitbit/notify", ContextHandler(fitbitNotifyHandler))
+ http.HandleFunc("/google/setup", googleSetupHandler)
+ http.Handle("/google/grant", AuthenticatedHandler(googleGrantHandler))
http.Handle("/", AuthenticatedHandler(indexHandler))
}
type AuthenticatedHandler func(context.Context, http.ResponseWriter, *http.Request, *app.User) error
-type User struct {
- ID string
-}
-
func (hndl AuthenticatedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
if err != nil && err != datastore.ErrNoSuchEntity {
return err
}
- haveToken := err == nil
+ haveFitbitToken := err == nil
+
+ _, err = u.Token(ctx, "Google")
+ if err != nil && err != datastore.ErrNoSuchEntity {
+ return err
+ }
+ haveGoogleToken := err == nil
fmt.Fprintln(w, "<html><body><h1>Fitbit to Google Fit sync</h1>")
fmt.Fprintf(w, "<p>Hello %s</p>\n", user.Current(ctx).Email)
- fmt.Fprint(w, "<p>Fitbit: ")
- if haveToken {
+ fmt.Fprintln(w, "<ul>")
+
+ fmt.Fprint(w, "<li>Fitbit: ")
+ if haveFitbitToken {
fmt.Fprint(w, `<strong style="color: DarkGreen;">Authorized</strong>`)
} else {
- fmt.Fprint(w, `<strong style="color: DarkRed;">Not authorized</strong> (<a href="/setup">Authorize</a>)`)
+ fmt.Fprint(w, `<strong style="color: DarkRed;">Not authorized</strong> (<a href="/fitbit/setup">Authorize</a>)`)
}
- fmt.Fprintln(w, "</p>")
+ fmt.Fprintln(w, "</li>")
+
+ fmt.Fprint(w, "<li>Google: ")
+ if haveGoogleToken {
+ fmt.Fprint(w, `<strong style="color: DarkGreen;">Authorized</strong>`)
+ } else {
+ fmt.Fprint(w, `<strong style="color: DarkRed;">Not authorized</strong> (<a href="/google/setup">Authorize</a>)`)
+ }
+ fmt.Fprintln(w, "</li>")
+
+ fmt.Fprintln(w, "</ul>")
fmt.Fprintln(w, "</body></html>")
return nil
}
-func setupHandler(w http.ResponseWriter, r *http.Request) {
- url := fitbit.AuthURL()
- http.Redirect(w, r, url, http.StatusTemporaryRedirect)
+func fitbitSetupHandler(w http.ResponseWriter, r *http.Request) {
+ http.Redirect(w, r, fitbit.AuthURL(), http.StatusTemporaryRedirect)
}
func fitbitGrantHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, u *app.User) error {
return nil
}
+func googleSetupHandler(w http.ResponseWriter, r *http.Request) {
+ http.Redirect(w, r, gfit.AuthURL(), http.StatusTemporaryRedirect)
+}
+
+func googleGrantHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, u *app.User) error {
+ if err := gfit.ParseToken(ctx, r, u); err != nil {
+ return err
+ }
+
+ redirectURL := r.URL
+ redirectURL.Path = "/"
+ redirectURL.RawQuery = ""
+ redirectURL.Fragment = ""
+ http.Redirect(w, r, redirectURL.String(), http.StatusTemporaryRedirect)
+ return nil
+}
+
// fitbitNotifyHandler is called by Fitbit whenever there are updates to a
// subscription. It verifies the payload, splits it into individual
// notifications and adds it to the taskqueue service.
if err != nil {
return err
}
- c, err := fitbit.NewClient(ctx, s.OwnerID, u)
+
+ fitbitClient, err := fitbit.NewClient(ctx, s.OwnerID, u)
if err != nil {
return err
}
- tm, err := time.Parse("2006-01-02", s.Date)
+ profile, err := fitbitClient.Profile(ctx)
if err != nil {
return err
}
+ log.Debugf(ctx, "profile = %+v", profile)
- summary, err := c.ActivitySummary(tm)
+ tm, err := time.ParseInLocation("2006-01-02", s.Date, profile.Timezone)
if err != nil {
return err
}
- log.Debugf(ctx, "ActivitySummary for %s = %+v", u.Email, summary)
+ summary, err := fitbitClient.ActivitySummary(tm)
+ if err != nil {
+ return err
+ }
+ log.Debugf(ctx, "%s (%s) took %d steps on %s",
+ profile.Name, u.Email, summary.Summary.Steps, s.Date)
+
+ gfitClient, err := gfit.NewClient(ctx, u)
+ if err != nil {
+ return err
+ }
+
+ if err := gfitClient.SetSteps(ctx, summary.Summary.Steps, tm); err != nil {
+ return fmt.Errorf("gfitClient.SetSteps(%d) = %v", summary.Summary.Steps, err)
+ }
+
+ if err := gfitClient.SetCalories(ctx, summary.Summary.CaloriesOut, tm); err != nil {
+ return fmt.Errorf("gfitClient.SetCalories(%d) = %v", summary.Summary.CaloriesOut, err)
+ }
+
return nil
}