Package gfit: Implement initial client code for Google Fit.
[kraftakt.git] / gfit / gfit.go
1 package gfit
2
3 import (
4         "context"
5         "fmt"
6         "net/http"
7
8         "github.com/octo/gfitsync/app"
9         "golang.org/x/oauth2"
10         oauth2google "golang.org/x/oauth2/google"
11         fitness "google.golang.org/api/fitness/v1"
12 )
13
14 var oauthConfig = &oauth2.Config{
15         ClientID:     "@GOOGLE_CLIENT_ID@",
16         ClientSecret: "@GOOGLE_CLIENT_SECRET@",
17         Endpoint:     oauth2google.Endpoint,
18         RedirectURL:  "https://fitbit-gfit-sync.appspot.com/google/grant",
19         Scopes: []string{
20                 fitness.FitnessActivityWriteScope,
21                 fitness.FitnessBodyWriteScope,
22         },
23 }
24
25 const csrfToken = "@CSRFTOKEN@"
26
27 func AuthURL() string {
28         return oauthConfig.AuthCodeURL(csrfToken, oauth2.AccessTypeOffline)
29 }
30
31 func ParseToken(ctx context.Context, r *http.Request, u *app.User) error {
32         if state := r.FormValue("state"); state != csrfToken {
33                 return fmt.Errorf("invalid state parameter: %q", state)
34         }
35
36         tok, err := oauthConfig.Exchange(ctx, r.FormValue("code"))
37         if err != nil {
38                 return err
39         }
40
41         return u.SetToken(ctx, "Google", tok)
42 }
43
44 type Client struct {
45         *fitness.Service
46 }
47
48 func NewClient(ctx context.Context, u *app.User) (*Client, error) {
49         c, err := u.OAuthClient(ctx, "Google", oauthConfig)
50         if err != nil {
51                 return nil, err
52         }
53
54         service, err := fitness.New(c)
55         if err != nil {
56                 return nil, err
57         }
58
59         return &Client{
60                 Service: service,
61         }, nil
62 }