aboutsummaryrefslogtreecommitdiff
path: root/app/models/user.go
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/user.go')
-rw-r--r--app/models/user.go56
1 files changed, 44 insertions, 12 deletions
diff --git a/app/models/user.go b/app/models/user.go
index 0cbd92d..2871380 100644
--- a/app/models/user.go
+++ b/app/models/user.go
@@ -2,8 +2,11 @@ package models
2 2
3import ( 3import (
4 "context" 4 "context"
5 "time"
5 6
6 "code.crute.us/mcrute/golib/db/mongodb" 7 "code.crute.us/mcrute/golib/db/mongodb"
8 "go.mongodb.org/mongo-driver/bson"
9 "go.mongodb.org/mongo-driver/bson/primitive"
7) 10)
8 11
9const userCol = "users" 12const userCol = "users"
@@ -16,17 +19,21 @@ type UserStore interface {
16} 19}
17 20
18type AuthToken struct { 21type AuthToken struct {
19 Kind string 22 Kind string `json:"kind"`
20 Token string 23 Token string `json:"token"`
21 RefreshToken string 24
25 // Do not expose refresh tokens in JSON as they are long-lived tokens that
26 // are harder to invalidate and thus rather security sensitive.
27 RefreshToken string `json:"-"`
22} 28}
23 29
24type User struct { 30type User struct {
25 Username string `bson:"_id"` 31 Username string `bson:"_id" json:"key_id"`
26 IsAdmin bool 32 IsAdmin bool `json:"is_admin"`
27 IsService bool 33 IsService bool `json:"is_service"`
28 Keys map[string]*SessionKey // kid -> key 34 Keys map[string]*SessionKey `json:"keys,omitempty"` // kid -> key
29 AuthTokens map[string]*AuthToken // kind -> token 35 AuthTokens map[string]*AuthToken `json:"auth_tokens,omitempty"` // kind -> token
36 Deleted *time.Time `json:"deleted,omitempty"`
30} 37}
31 38
32// GCKeys garbage collects keys that are no longer valid 39// GCKeys garbage collects keys that are no longer valid
@@ -64,21 +71,41 @@ func (u *User) AddToken(t *AuthToken) {
64 71
65type MongoDbUserStore struct { 72type MongoDbUserStore struct {
66 Db *mongodb.Mongo 73 Db *mongodb.Mongo
74
75 // ReturnDeleted will allow all methods to return deleted items. By default
76 // items where the Deleted field is set will not be returned. This should
77 // be the common cast for most code using this store but in some Admin
78 // use-cases it would be useful to show deleted accounts.
79 ReturnDeleted bool
67} 80}
68 81
69func (s *MongoDbUserStore) List(ctx context.Context) ([]*User, error) { 82func (s *MongoDbUserStore) List(ctx context.Context) ([]*User, error) {
70 var out []*User 83 var out []*User
71 if err := s.Db.FindAll(ctx, userCol, &out); err != nil { 84
85 filter := bson.M{}
86 if !s.ReturnDeleted {
87 filter["deleted"] = primitive.Null{}
88 }
89
90 if err := s.Db.FindAllByFilter(ctx, userCol, filter, &out); err != nil {
72 return nil, err 91 return nil, err
73 } 92 }
93
74 return out, nil 94 return out, nil
75} 95}
76 96
77func (s *MongoDbUserStore) Get(ctx context.Context, username string) (*User, error) { 97func (s *MongoDbUserStore) Get(ctx context.Context, username string) (*User, error) {
78 var u User 98 var u User
79 if err := s.Db.FindOneById(ctx, userCol, username, &u); err != nil { 99
100 filter := bson.M{"_id": username}
101 if !s.ReturnDeleted {
102 filter["deleted"] = primitive.Null{}
103 }
104
105 if err := s.Db.FindOneByFilter(ctx, userCol, filter, &u); err != nil {
80 return nil, err 106 return nil, err
81 } 107 }
108
82 return &u, nil 109 return &u, nil
83} 110}
84 111
@@ -90,10 +117,15 @@ func (s *MongoDbUserStore) Put(ctx context.Context, u *User) error {
90} 117}
91 118
92func (s *MongoDbUserStore) Delete(ctx context.Context, u *User) error { 119func (s *MongoDbUserStore) Delete(ctx context.Context, u *User) error {
93 if err := s.Db.DeleteOneById(ctx, userCol, u.Username); err != nil { 120 u, err := s.Get(ctx, u.Username)
121 if err != nil {
94 return err 122 return err
95 } 123 }
96 return nil 124
125 now := time.Now()
126 u.Deleted = &now
127
128 return s.Put(ctx, u)
97} 129}
98 130
99var _ UserStore = (*MongoDbUserStore)(nil) 131var _ UserStore = (*MongoDbUserStore)(nil)