1
1
package coderd
2
2
3
3
import (
4
- "context"
5
4
"crypto/sha256"
6
5
"database/sql"
7
6
"errors"
@@ -11,6 +10,7 @@ import (
11
10
12
11
"github.com/go-chi/render"
13
12
"github.com/google/uuid"
13
+ "golang.org/x/xerrors"
14
14
15
15
"github.com/coder/coder/coderd/userpassword"
16
16
"github.com/coder/coder/cryptorand"
@@ -27,11 +27,12 @@ type User struct {
27
27
Username string `json:"username" validate:"required"`
28
28
}
29
29
30
- // CreateUserRequest enables callers to create a new user.
31
- type CreateUserRequest struct {
32
- Email string `json:"email" validate:"required,email"`
33
- Username string `json:"username" validate:"required,username"`
34
- Password string `json:"password" validate:"required"`
30
+ // CreateInitialUserRequest enables callers to create a new user.
31
+ type CreateInitialUserRequest struct {
32
+ Email string `json:"email" validate:"required,email"`
33
+ Username string `json:"username" validate:"required,username"`
34
+ Password string `json:"password" validate:"required"`
35
+ Organization string `json:"organization" validate:"required,username"`
35
36
}
36
37
37
38
// LoginWithPasswordRequest enables callers to authenticate with email and password.
@@ -51,7 +52,7 @@ type users struct {
51
52
52
53
// Creates the initial user for a Coder deployment.
53
54
func (users * users ) createInitialUser (rw http.ResponseWriter , r * http.Request ) {
54
- var createUser CreateUserRequest
55
+ var createUser CreateInitialUserRequest
55
56
if ! httpapi .Read (rw , r , & createUser ) {
56
57
return
57
58
}
@@ -70,19 +71,6 @@ func (users *users) createInitialUser(rw http.ResponseWriter, r *http.Request) {
70
71
})
71
72
return
72
73
}
73
- _ , err = users .Database .GetUserByEmailOrUsername (r .Context (), database.GetUserByEmailOrUsernameParams {
74
- Email : createUser .Email ,
75
- Username : createUser .Username ,
76
- })
77
- if errors .Is (err , sql .ErrNoRows ) {
78
- err = nil
79
- }
80
- if err != nil {
81
- httpapi .Write (rw , http .StatusInternalServerError , httpapi.Response {
82
- Message : fmt .Sprintf ("get user: %s" , err .Error ()),
83
- })
84
- return
85
- }
86
74
hashedPassword , err := userpassword .Hash (createUser .Password )
87
75
if err != nil {
88
76
httpapi .Write (rw , http .StatusInternalServerError , httpapi.Response {
@@ -91,28 +79,57 @@ func (users *users) createInitialUser(rw http.ResponseWriter, r *http.Request) {
91
79
return
92
80
}
93
81
94
- user , err := users .Database .InsertUser (context .Background (), database.InsertUserParams {
95
- ID : uuid .NewString (),
96
- Email : createUser .Email ,
97
- HashedPassword : []byte (hashedPassword ),
98
- Username : createUser .Username ,
99
- LoginType : database .LoginTypeBuiltIn ,
100
- CreatedAt : database .Now (),
101
- UpdatedAt : database .Now (),
82
+ // Create the user, organization, and membership to the user.
83
+ var user database.User
84
+ err = users .Database .InTx (func (s database.Store ) error {
85
+ user , err = users .Database .InsertUser (r .Context (), database.InsertUserParams {
86
+ ID : uuid .NewString (),
87
+ Email : createUser .Email ,
88
+ HashedPassword : []byte (hashedPassword ),
89
+ Username : createUser .Username ,
90
+ LoginType : database .LoginTypeBuiltIn ,
91
+ CreatedAt : database .Now (),
92
+ UpdatedAt : database .Now (),
93
+ })
94
+ if err != nil {
95
+ return xerrors .Errorf ("create user: %w" , err )
96
+ }
97
+ organization , err := users .Database .InsertOrganization (r .Context (), database.InsertOrganizationParams {
98
+ ID : uuid .NewString (),
99
+ Name : createUser .Organization ,
100
+ CreatedAt : database .Now (),
101
+ UpdatedAt : database .Now (),
102
+ })
103
+ if err != nil {
104
+ return xerrors .Errorf ("create organization: %w" , err )
105
+ }
106
+ _ , err = users .Database .InsertOrganizationMember (r .Context (), database.InsertOrganizationMemberParams {
107
+ OrganizationID : organization .ID ,
108
+ UserID : user .ID ,
109
+ CreatedAt : database .Now (),
110
+ UpdatedAt : database .Now (),
111
+ Roles : []string {"organization-admin" },
112
+ })
113
+ if err != nil {
114
+ return xerrors .Errorf ("create organization member: %w" , err )
115
+ }
116
+ return nil
102
117
})
103
118
if err != nil {
104
119
httpapi .Write (rw , http .StatusInternalServerError , httpapi.Response {
105
- Message : fmt . Sprintf ( "create user: %s" , err .Error () ),
120
+ Message : err .Error (),
106
121
})
107
122
return
108
123
}
124
+
109
125
render .Status (r , http .StatusCreated )
110
126
render .JSON (rw , r , user )
111
127
}
112
128
113
- // Returns the currently authenticated user.
114
- func (* users ) authenticatedUser (rw http.ResponseWriter , r * http.Request ) {
115
- user := httpmw .User (r )
129
+ // Returns the parameterized user requested. All validation
130
+ // is completed in the middleware for this route.
131
+ func (* users ) user (rw http.ResponseWriter , r * http.Request ) {
132
+ user := httpmw .UserParam (r )
116
133
117
134
render .JSON (rw , r , User {
118
135
ID : user .ID ,
@@ -122,6 +139,27 @@ func (*users) authenticatedUser(rw http.ResponseWriter, r *http.Request) {
122
139
})
123
140
}
124
141
142
+ // Returns organizations the parameterized user has access to.
143
+ func (users * users ) userOrganizations (rw http.ResponseWriter , r * http.Request ) {
144
+ user := httpmw .UserParam (r )
145
+
146
+ organizations , err := users .Database .GetOrganizationsByUserID (r .Context (), user .ID )
147
+ if err != nil {
148
+ httpapi .Write (rw , http .StatusInternalServerError , httpapi.Response {
149
+ Message : fmt .Sprintf ("get organizations: %s" , err .Error ()),
150
+ })
151
+ return
152
+ }
153
+
154
+ publicOrganizations := make ([]Organization , 0 , len (organizations ))
155
+ for _ , organization := range organizations {
156
+ publicOrganizations = append (publicOrganizations , convertOrganization (organization ))
157
+ }
158
+
159
+ render .Status (r , http .StatusOK )
160
+ render .JSON (rw , r , publicOrganizations )
161
+ }
162
+
125
163
// Authenticates the user with an email and password.
126
164
func (users * users ) loginWithPassword (rw http.ResponseWriter , r * http.Request ) {
127
165
var loginWithPassword LoginWithPasswordRequest
@@ -200,7 +238,7 @@ func (users *users) loginWithPassword(rw http.ResponseWriter, r *http.Request) {
200
238
}
201
239
202
240
// Clear the user's session cookie
203
- func logout (rw http.ResponseWriter , r * http.Request ) {
241
+ func ( _ * users ) logout (rw http.ResponseWriter , r * http.Request ) {
204
242
// Get a blank token cookie
205
243
cookie := & http.Cookie {
206
244
// MaxAge < 0 means to delete the cookie now
0 commit comments