12 "github.com/google/uuid"
13 legacy_context "golang.org/x/net/context"
15 "google.golang.org/appengine/datastore"
16 "google.golang.org/appengine/log"
30 func NewUser(ctx context.Context, email string) (*User, error) {
32 err := datastore.RunInTransaction(ctx, func(ctx legacy_context.Context) error {
33 key := datastore.NewKey(ctx, "User", email, 0, nil)
36 err := datastore.Get(ctx, key, &u)
37 if err != nil && err != datastore.ErrNoSuchEntity {
45 id = uuid.New().String()
46 _, err = datastore.Put(ctx, key, &dbUser{
56 key: datastore.NewKey(ctx, "User", email, 0, nil),
62 func UserByID(ctx context.Context, id string) (*User, error) {
63 q := datastore.NewQuery("User").Filter("ID=", id).KeysOnly()
64 keys, err := q.GetAll(ctx, nil)
66 return nil, fmt.Errorf("datastore.Query.GetAll(): %v", err)
69 return nil, fmt.Errorf("len(keys) = %d, want 1", len(keys))
75 Email: keys[0].StringID(),
79 func (u *User) Token(ctx context.Context, svc string) (*oauth2.Token, error) {
80 key := datastore.NewKey(ctx, "Token", svc, 0, u.key)
83 if err := datastore.Get(ctx, key, &tok); err != nil {
90 func (u *User) SetToken(ctx context.Context, svc string, tok *oauth2.Token) error {
91 key := datastore.NewKey(ctx, "Token", svc, 0, u.key)
92 _, err := datastore.Put(ctx, key, tok)
96 func (u *User) DeleteToken(ctx context.Context, svc string) error {
97 key := datastore.NewKey(ctx, "Token", svc, 0, u.key)
98 return datastore.Delete(ctx, key)
101 func (u *User) OAuthClient(ctx context.Context, svc string, cfg *oauth2.Config) (*http.Client, error) {
102 key := datastore.NewKey(ctx, "Token", svc, 0, u.key)
105 if err := datastore.Get(ctx, key, &tok); err != nil {
109 src := cfg.TokenSource(ctx, &tok)
110 return oauth2.NewClient(ctx, &persistingTokenSource{
118 func (u *User) String() string {
122 func (u *User) Sign(payload string) string {
123 mac := hmac.New(sha1.New, []byte(u.ID))
124 mac.Write([]byte(payload))
126 return hex.EncodeToString(mac.Sum(nil))
129 type persistingTokenSource struct {
132 src oauth2.TokenSource
138 func (s *persistingTokenSource) Token() (*oauth2.Token, error) {
142 tok, err := s.src.Token()
147 if s.t.AccessToken != tok.AccessToken ||
148 s.t.TokenType != tok.TokenType ||
149 s.t.RefreshToken != tok.RefreshToken ||
150 !s.t.Expiry.Equal(tok.Expiry) {
151 if _, err := datastore.Put(s.ctx, s.key, tok); err != nil {
152 log.Errorf(s.ctx, "persisting OAuth token in datastore failed: %v", err)