diff options
Diffstat (limited to 'app/models/account.go')
-rw-r--r-- | app/models/account.go | 95 |
1 files changed, 64 insertions, 31 deletions
diff --git a/app/models/account.go b/app/models/account.go index 0ae1821..61b144d 100644 --- a/app/models/account.go +++ b/app/models/account.go | |||
@@ -2,10 +2,11 @@ package models | |||
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "context" | 4 | "context" |
5 | "fmt" | ||
6 | "time" | 5 | "time" |
7 | 6 | ||
8 | "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" | ||
9 | ) | 10 | ) |
10 | 11 | ||
11 | const accountCol = "accounts" | 12 | const accountCol = "accounts" |
@@ -20,43 +21,48 @@ type AccountStore interface { | |||
20 | } | 21 | } |
21 | 22 | ||
22 | type Account struct { | 23 | type Account struct { |
23 | ShortName string `bson:"_id"` | 24 | ShortName string `bson:"_id" json:"short_name"` |
24 | AccountType string | 25 | AccountType string `json:"account_type"` |
25 | AccountNumber int | 26 | AccountNumber int `json:"account_number"` |
26 | Name string | 27 | Name string `json:"name"` |
27 | ConsoleSessionDuration time.Duration | 28 | ConsoleSessionDuration time.Duration `json:"console_session_duration, omitempty"` |
28 | VaultMaterial string | 29 | VaultMaterial string `json:"vault_material,omitempty"` |
29 | DefaultRegion string | 30 | DefaultRegion string `json:"default_region"` |
30 | Users []string | 31 | Users []string `json:"users,omitempty"` |
32 | Deleted *time.Time `json:"deleted,omitempty" bson:"deleted,omitempty"` | ||
31 | } | 33 | } |
32 | 34 | ||
33 | func (a *Account) ConsoleSessionDurationSecs() int64 { | 35 | func (a *Account) ConsoleSessionDurationSecs() int64 { |
34 | return int64(a.ConsoleSessionDuration.Seconds()) | 36 | return int64(a.ConsoleSessionDuration.Seconds()) |
35 | } | 37 | } |
36 | 38 | ||
37 | func (a *Account) CanAccess(u *User) bool { | 39 | func (a *Account) CanBeModifiedBy(u *User) bool { |
38 | if u.IsAdmin { | 40 | return u.IsAdmin |
39 | return true | ||
40 | } | ||
41 | // Linear search should be fine for now, these lists are pretty small | ||
42 | for _, n := range a.Users { | ||
43 | if n == u.Username { | ||
44 | return true | ||
45 | } | ||
46 | } | ||
47 | return false | ||
48 | } | 41 | } |
49 | 42 | ||
50 | type MongoDbAccountStore struct { | 43 | type MongoDbAccountStore struct { |
51 | Db *mongodb.Mongo | 44 | Db *mongodb.Mongo |
45 | |||
46 | // ReturnDeleted will allow all methods to return deleted items. By default | ||
47 | // items where the Deleted field is set will not be returned. This should | ||
48 | // be the common cast for most code using this store but in some Admin | ||
49 | // use-cases it would be useful to show deleted accounts. | ||
50 | ReturnDeleted bool | ||
52 | } | 51 | } |
53 | 52 | ||
54 | // List returns all accounts in the system. | 53 | // List returns all accounts in the system. |
55 | func (s *MongoDbAccountStore) List(ctx context.Context) ([]*Account, error) { | 54 | func (s *MongoDbAccountStore) List(ctx context.Context) ([]*Account, error) { |
56 | var out []*Account | 55 | var out []*Account |
57 | if err := s.Db.FindAll(ctx, accountCol, &out); err != nil { | 56 | |
57 | filter := bson.M{} | ||
58 | if !s.ReturnDeleted { | ||
59 | filter["deleted"] = primitive.Null{} | ||
60 | } | ||
61 | |||
62 | if err := s.Db.FindAllByFilter(ctx, accountCol, filter, &out); err != nil { | ||
58 | return nil, err | 63 | return nil, err |
59 | } | 64 | } |
65 | |||
60 | return out, nil | 66 | return out, nil |
61 | } | 67 | } |
62 | 68 | ||
@@ -68,34 +74,56 @@ func (s *MongoDbAccountStore) List(ctx context.Context) ([]*Account, error) { | |||
68 | // just use List directly. | 74 | // just use List directly. |
69 | func (s *MongoDbAccountStore) ListForUser(ctx context.Context, u *User) ([]*Account, error) { | 75 | func (s *MongoDbAccountStore) ListForUser(ctx context.Context, u *User) ([]*Account, error) { |
70 | var out []*Account | 76 | var out []*Account |
71 | filter := mongodb.AnyInTopLevelArray("Users", u.Username) | 77 | |
78 | filter := mongodb.AnyInTopLevelArray("users", u.Username) | ||
79 | if !s.ReturnDeleted { | ||
80 | filter["deleted"] = primitive.Null{} | ||
81 | } | ||
82 | |||
72 | if err := s.Db.FindAllByFilter(ctx, accountCol, filter, &out); err != nil { | 83 | if err := s.Db.FindAllByFilter(ctx, accountCol, filter, &out); err != nil { |
73 | return nil, err | 84 | return nil, err |
74 | } | 85 | } |
86 | |||
75 | return out, nil | 87 | return out, nil |
76 | } | 88 | } |
77 | 89 | ||
78 | func (s *MongoDbAccountStore) Get(ctx context.Context, id string) (*Account, error) { | 90 | func (s *MongoDbAccountStore) Get(ctx context.Context, id string) (*Account, error) { |
79 | var a Account | 91 | var a Account |
80 | if err := s.Db.FindOneById(ctx, accountCol, id, &a); err != nil { | 92 | |
93 | filter := bson.M{"_id": id} | ||
94 | if !s.ReturnDeleted { | ||
95 | filter["deleted"] = primitive.Null{} | ||
96 | } | ||
97 | |||
98 | if err := s.Db.FindOneByFilter(ctx, accountCol, filter, &a); err != nil { | ||
81 | return nil, err | 99 | return nil, err |
82 | } | 100 | } |
101 | |||
83 | return &a, nil | 102 | return &a, nil |
84 | } | 103 | } |
85 | 104 | ||
86 | // GetForUser returns an account if the user has access to this account, | 105 | // GetForUser returns an account if the user has access to this account, |
87 | // otherwise it returns an error. This is the authorized version of Get. | 106 | // otherwise it returns an error. This is the authorized version of Get. |
88 | func (s *MongoDbAccountStore) GetForUser(ctx context.Context, id string, u *User) (*Account, error) { | 107 | func (s *MongoDbAccountStore) GetForUser(ctx context.Context, id string, u *User) (*Account, error) { |
89 | a, err := s.Get(ctx, id) | 108 | var a Account |
90 | if err != nil { | 109 | var filter bson.M |
91 | return nil, err | 110 | |
111 | if u.IsAdmin { | ||
112 | filter = bson.M{"_id": id} | ||
113 | } else { | ||
114 | filter = mongodb.AnyInTopLevelArray("users", u.Username) | ||
115 | filter["_id"] = id | ||
92 | } | 116 | } |
93 | 117 | ||
94 | if !a.CanAccess(u) { | 118 | if !s.ReturnDeleted { |
95 | return nil, fmt.Errorf("User does not have access to account") | 119 | filter["deleted"] = primitive.Null{} |
96 | } | 120 | } |
97 | 121 | ||
98 | return a, nil | 122 | if err := s.Db.FindOneByFilter(ctx, accountCol, filter, &a); err != nil { |
123 | return nil, err | ||
124 | } | ||
125 | |||
126 | return &a, nil | ||
99 | } | 127 | } |
100 | 128 | ||
101 | func (s *MongoDbAccountStore) Put(ctx context.Context, a *Account) error { | 129 | func (s *MongoDbAccountStore) Put(ctx context.Context, a *Account) error { |
@@ -106,10 +134,15 @@ func (s *MongoDbAccountStore) Put(ctx context.Context, a *Account) error { | |||
106 | } | 134 | } |
107 | 135 | ||
108 | func (s *MongoDbAccountStore) Delete(ctx context.Context, a *Account) error { | 136 | func (s *MongoDbAccountStore) Delete(ctx context.Context, a *Account) error { |
109 | if err := s.Db.DeleteOneById(ctx, accountCol, a.ShortName); err != nil { | 137 | a, err := s.Get(ctx, a.ShortName) |
138 | if err != nil { | ||
110 | return err | 139 | return err |
111 | } | 140 | } |
112 | return nil | 141 | |
142 | now := time.Now() | ||
143 | a.Deleted = &now | ||
144 | |||
145 | return s.Put(ctx, a) | ||
113 | } | 146 | } |
114 | 147 | ||
115 | var _ AccountStore = (*MongoDbAccountStore)(nil) | 148 | var _ AccountStore = (*MongoDbAccountStore)(nil) |