9 "github.com/octo/gfitsync/app"
11 oauth2google "golang.org/x/oauth2/google"
12 fitness "google.golang.org/api/fitness/v1"
13 "google.golang.org/appengine"
14 "google.golang.org/appengine/log"
17 var oauthConfig = &oauth2.Config{
18 ClientID: "@GOOGLE_CLIENT_ID@",
19 ClientSecret: "@GOOGLE_CLIENT_SECRET@",
20 Endpoint: oauth2google.Endpoint,
21 RedirectURL: "https://fitbit-gfit-sync.appspot.com/google/grant",
23 fitness.FitnessActivityWriteScope,
24 fitness.FitnessBodyWriteScope,
28 const csrfToken = "@CSRFTOKEN@"
30 func Application(ctx context.Context) *fitness.Application {
31 return &fitness.Application{
32 Name: "Fitbit to Google Fit sync",
33 Version: appengine.VersionID(ctx),
34 DetailsUrl: "", // optional
38 func AuthURL() string {
39 return oauthConfig.AuthCodeURL(csrfToken, oauth2.AccessTypeOffline)
42 func ParseToken(ctx context.Context, r *http.Request, u *app.User) error {
43 if state := r.FormValue("state"); state != csrfToken {
44 return fmt.Errorf("invalid state parameter: %q", state)
47 tok, err := oauthConfig.Exchange(ctx, r.FormValue("code"))
52 return u.SetToken(ctx, "Google", tok)
59 func NewClient(ctx context.Context, u *app.User) (*Client, error) {
60 c, err := u.OAuthClient(ctx, "Google", oauthConfig)
65 service, err := fitness.New(c)
75 func (c *Client) SetSteps(ctx context.Context, steps int, date time.Time) error {
77 const dataTypeName = "com.google.step_count.delta"
78 dataSource := &fitness.DataSource{
79 Application: Application(ctx),
80 DataStreamName: "", // "daily summary"?
81 DataType: &fitness.DataType{
82 Field: []*fitness.DataTypeField{
83 &fitness.DataTypeField{
94 dataSource, err := c.Service.Users.DataSources.Create(userID, dataSource).Context(ctx).Do()
96 log.Errorf(ctx, "c.Service.Users.DataSources.Create() = (%+v, %v)", dataSource, err)
99 dataSourceID := dataSource.DataStreamId
101 startTimeNanos := date.UnixNano()
102 endTimeNanos := date.Add(86399999999999 * time.Nanosecond).UnixNano()
103 datasetID := fmt.Sprintf("%d-%d", startTimeNanos, endTimeNanos)
104 dataset := &fitness.Dataset{
105 MinStartTimeNs: startTimeNanos,
106 MaxEndTimeNs: endTimeNanos,
107 Point: []*fitness.DataPoint{
109 ComputationTimeMillis: time.Now().UnixNano() / 1000000,
110 DataTypeName: dataTypeName,
111 StartTimeNanos: startTimeNanos,
112 EndTimeNanos: endTimeNanos,
113 Value: []*fitness.Value{
115 IntVal: int64(steps),
122 dataset, err = c.Service.Users.DataSources.Datasets.Patch(userID, dataSourceID, datasetID, dataset).Context(ctx).Do()
124 log.Errorf(ctx, "c.Service.Users.DataSources.Datasets.Patch() = (%+v, %v)", dataset, err)