@@ -19,22 +19,31 @@ import (
19
19
"github.com/coder/coder/httpmw"
20
20
)
21
21
22
- // User is the JSON representation of a Coder user .
22
+ // User represents a user in Coder.
23
23
type User struct {
24
24
ID string `json:"id" validate:"required"`
25
25
Email string `json:"email" validate:"required"`
26
26
CreatedAt time.Time `json:"created_at" validate:"required"`
27
27
Username string `json:"username" validate:"required"`
28
28
}
29
29
30
- // CreateInitialUserRequest enables callers to create a new user.
30
+ // CreateInitialUserRequest provides options to create the initial
31
+ // user for a Coder deployment. The organization provided will be
32
+ // created as well.
31
33
type CreateInitialUserRequest struct {
32
34
Email string `json:"email" validate:"required,email"`
33
35
Username string `json:"username" validate:"required,username"`
34
36
Password string `json:"password" validate:"required"`
35
37
Organization string `json:"organization" validate:"required,username"`
36
38
}
37
39
40
+ // CreateUserRequest provides options for creating a new user.
41
+ type CreateUserRequest struct {
42
+ Email string `json:"email" validate:"required,email"`
43
+ Username string `json:"username" validate:"required,username"`
44
+ Password string `json:"password" validate:"required"`
45
+ }
46
+
38
47
// LoginWithPasswordRequest enables callers to authenticate with email and password.
39
48
type LoginWithPasswordRequest struct {
40
49
Email string `json:"email" validate:"required,email"`
@@ -123,20 +132,65 @@ func (users *users) createInitialUser(rw http.ResponseWriter, r *http.Request) {
123
132
}
124
133
125
134
render .Status (r , http .StatusCreated )
126
- render .JSON (rw , r , user )
135
+ render .JSON (rw , r , convertUser (user ))
136
+ }
137
+
138
+ func (users * users ) createUser (rw http.ResponseWriter , r * http.Request ) {
139
+ var createUser CreateUserRequest
140
+ if ! httpapi .Read (rw , r , & createUser ) {
141
+ return
142
+ }
143
+ _ , err := users .Database .GetUserByEmailOrUsername (r .Context (), database.GetUserByEmailOrUsernameParams {
144
+ Username : createUser .Username ,
145
+ Email : createUser .Email ,
146
+ })
147
+ if err == nil {
148
+ httpapi .Write (rw , http .StatusConflict , httpapi.Response {
149
+ Message : "user already exists" ,
150
+ })
151
+ return
152
+ }
153
+ if ! errors .Is (err , sql .ErrNoRows ) {
154
+ httpapi .Write (rw , http .StatusInternalServerError , httpapi.Response {
155
+ Message : fmt .Sprintf ("get user: %s" , err ),
156
+ })
157
+ return
158
+ }
159
+
160
+ hashedPassword , err := userpassword .Hash (createUser .Password )
161
+ if err != nil {
162
+ httpapi .Write (rw , http .StatusInternalServerError , httpapi.Response {
163
+ Message : fmt .Sprintf ("hash password: %s" , err .Error ()),
164
+ })
165
+ return
166
+ }
167
+
168
+ user , err := users .Database .InsertUser (r .Context (), database.InsertUserParams {
169
+ ID : uuid .NewString (),
170
+ Email : createUser .Email ,
171
+ HashedPassword : []byte (hashedPassword ),
172
+ Username : createUser .Username ,
173
+ LoginType : database .LoginTypeBuiltIn ,
174
+ CreatedAt : database .Now (),
175
+ UpdatedAt : database .Now (),
176
+ })
177
+ if err != nil {
178
+ httpapi .Write (rw , http .StatusInternalServerError , httpapi.Response {
179
+ Message : fmt .Sprintf ("create user: %s" , err .Error ()),
180
+ })
181
+ return
182
+ }
183
+
184
+ render .Status (r , http .StatusCreated )
185
+ render .JSON (rw , r , convertUser (user ))
127
186
}
128
187
129
188
// Returns the parameterized user requested. All validation
130
189
// is completed in the middleware for this route.
131
190
func (* users ) user (rw http.ResponseWriter , r * http.Request ) {
132
191
user := httpmw .UserParam (r )
133
192
134
- render .JSON (rw , r , User {
135
- ID : user .ID ,
136
- Email : user .Email ,
137
- CreatedAt : user .CreatedAt ,
138
- Username : user .Username ,
139
- })
193
+ render .JSON (rw , r , convertUser (user ))
140
194
}
141
195
142
196
// Returns organizations the parameterized user has access to.
@@ -265,3 +319,12 @@ func generateAPIKeyIDSecret() (id string, secret string, err error) {
265
319
}
266
320
return id , secret , nil
267
321
}
322
+
323
+ func convertUser (user database.User ) User {
324
+ return User {
325
+ ID : user .ID ,
326
+ Email : user .Email ,
327
+ CreatedAt : user .CreatedAt ,
328
+ Username : user .Username ,
329
+ }
330
+ }
0 commit comments