Implement Fitbit and Google Fit disconnect handlers.
[kraftakt.git] / kraftakt.go
index 69815c2..1f3ac98 100644 (file)
@@ -22,16 +22,14 @@ import (
 var delayedHandleNotifications = delay.Func("handleNotifications", handleNotifications)
 
 func init() {
-       http.HandleFunc("/fitbit/setup", fitbitSetupHandler)
+       http.Handle("/fitbit/connect", AuthenticatedHandler(fitbitConnectHandler))
        http.Handle("/fitbit/grant", AuthenticatedHandler(fitbitGrantHandler))
        http.Handle("/fitbit/notify", ContextHandler(fitbitNotifyHandler))
-       http.HandleFunc("/google/setup", googleSetupHandler)
+       http.Handle("/fitbit/disconnect", AuthenticatedHandler(fitbitDisconnectHandler))
+       http.Handle("/google/connect", AuthenticatedHandler(googleConnectHandler))
        http.Handle("/google/grant", AuthenticatedHandler(googleGrantHandler))
+       http.Handle("/google/disconnect", AuthenticatedHandler(googleDisconnectHandler))
        http.Handle("/", AuthenticatedHandler(indexHandler))
-
-       if err := app.LoadConfig(context.Background()); err != nil {
-               panic(err)
-       }
 }
 
 // ContextHandler implements http.Handler
@@ -40,6 +38,11 @@ type ContextHandler func(context.Context, http.ResponseWriter, *http.Request) er
 func (hndl ContextHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        ctx := appengine.NewContext(r)
 
+       if err := app.LoadConfig(ctx); err != nil {
+               http.Error(w, err.Error(), http.StatusInternalServerError)
+               return
+       }
+
        if err := hndl(ctx, w, r); err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return
@@ -51,6 +54,11 @@ type AuthenticatedHandler func(context.Context, http.ResponseWriter, *http.Reque
 func (hndl AuthenticatedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        ctx := appengine.NewContext(r)
 
+       if err := app.LoadConfig(ctx); err != nil {
+               http.Error(w, err.Error(), http.StatusInternalServerError)
+               return
+       }
+
        gaeUser := user.Current(ctx)
        if gaeUser == nil {
                url, err := user.LoginURL(ctx, r.URL.String())
@@ -117,8 +125,9 @@ func indexHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, u
        return nil
 }
 
-func fitbitSetupHandler(w http.ResponseWriter, r *http.Request) {
+func fitbitConnectHandler(_ context.Context, w http.ResponseWriter, r *http.Request, _ *app.User) error {
        http.Redirect(w, r, fitbit.AuthURL(), http.StatusTemporaryRedirect)
+       return nil
 }
 
 func fitbitGrantHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, u *app.User) error {
@@ -191,6 +200,7 @@ func fitbitNotifyHandler(ctx context.Context, w http.ResponseWriter, r *http.Req
        // Fitbit recommendation: "If signature verification fails, you should
        // respond with a 404"
        if !fitbit.CheckSignature(ctx, data, r.Header.Get("X-Fitbit-Signature")) {
+               log.Warningf(ctx, "signature mismatch")
                w.WriteHeader(http.StatusNotFound)
                return nil
        }
@@ -206,6 +216,10 @@ func fitbitNotifyHandler(ctx context.Context, w http.ResponseWriter, r *http.Req
 // handleNotifications parses fitbit notifications and requests the individual
 // activities from Fitbit. It is executed asynchronously via the delay package.
 func handleNotifications(ctx context.Context, payload []byte) error {
+       if err := app.LoadConfig(ctx); err != nil {
+               return err
+       }
+
        var subscriptions []fitbit.Subscription
        if err := json.Unmarshal(payload, &subscriptions); err != nil {
                return err
@@ -311,7 +325,7 @@ func handleNotification(ctx context.Context, s *fitbit.Subscription) error {
                        break
                }
                if err := gfitClient.SetDistance(ctx, distanceMeters, tm); err != nil {
-                       errs = append(errs, fmt.Errorf("gfitClient.SetDistance(%d) = %v", distanceMeters, err))
+                       errs = append(errs, fmt.Errorf("gfitClient.SetDistance(%g) = %v", distanceMeters, err))
                        return
                }
        }()