Move more logic into the "fitbit" and (new) "app" packages.
[kraftakt.git] / app / user.go
diff --git a/app/user.go b/app/user.go
new file mode 100644 (file)
index 0000000..86c033c
--- /dev/null
@@ -0,0 +1,81 @@
+package app
+
+import (
+       "context"
+       "fmt"
+
+       "github.com/google/uuid"
+       legacy_context "golang.org/x/net/context"
+       "golang.org/x/oauth2"
+       "google.golang.org/appengine/datastore"
+)
+
+type User struct {
+       key *datastore.Key
+}
+
+type dbUser struct {
+       ID string
+}
+
+func NewUser(ctx context.Context, email string) (*User, error) {
+       err := datastore.RunInTransaction(ctx, func(ctx legacy_context.Context) error {
+               key := datastore.NewKey(ctx, "User", email, 0, nil)
+               if err := datastore.Get(ctx, key, &dbUser{}); err != datastore.ErrNoSuchEntity {
+                       return err // may be nil
+               }
+
+               _, err := datastore.Put(ctx, key, &dbUser{
+                       ID: uuid.New().String(),
+               })
+               return err
+       }, nil)
+       if err != nil {
+               return nil, err
+       }
+
+       return &User{
+               key: datastore.NewKey(ctx, "User", email, 0, nil),
+       }, nil
+}
+
+func UserByID(ctx context.Context, id string) (*User, error) {
+       q := datastore.NewQuery("User").Filter("ID=", id).KeysOnly()
+       keys, err := q.GetAll(ctx, nil)
+       if err != nil {
+               return nil, fmt.Errorf("datastore.Query.GetAll(): %v", err)
+       }
+       if len(keys) != 1 {
+               return nil, fmt.Errorf("len(keys) = %d, want 1", len(keys))
+       }
+
+       return &User{
+               key: keys[0],
+       }, nil
+}
+
+func (u *User) ID(ctx context.Context) (string, error) {
+       var db dbUser
+       if err := datastore.Get(ctx, u.key, &db); err != nil {
+               return "", err
+       }
+
+       return db.ID, nil
+}
+
+func (u *User) Token(ctx context.Context, svc string) (*oauth2.Token, error) {
+       key := datastore.NewKey(ctx, "Token", svc, 0, u.key)
+
+       var tok oauth2.Token
+       if err := datastore.Get(ctx, key, &tok); err != nil {
+               return nil, err
+       }
+
+       return &tok, nil
+}
+
+func (u *User) SetToken(ctx context.Context, svc string, tok *oauth2.Token) error {
+       key := datastore.NewKey(ctx, "Token", "Fitbit", 0, u.key)
+       _, err := datastore.Put(ctx, key, tok)
+       return err
+}