feat: Add users create and list commands (#1111)

This allows for *extremely basic* user management.
This commit is contained in:
Kyle Carberry
2022-04-24 20:08:26 -05:00
committed by GitHub
parent 7496c3da81
commit be974cf280
21 changed files with 245 additions and 127 deletions

90
cli/usercreate.go Normal file
View File

@ -0,0 +1,90 @@
package cli
import (
"fmt"
"github.com/go-playground/validator/v10"
"github.com/spf13/cobra"
"golang.org/x/xerrors"
"github.com/coder/coder/cli/cliui"
"github.com/coder/coder/codersdk"
"github.com/coder/coder/cryptorand"
)
func userCreate() *cobra.Command {
var (
email string
username string
password string
)
cmd := &cobra.Command{
Use: "create",
RunE: func(cmd *cobra.Command, args []string) error {
client, err := createClient(cmd)
if err != nil {
return err
}
organization, err := currentOrganization(cmd, client)
if err != nil {
return err
}
if username == "" {
username, err = cliui.Prompt(cmd, cliui.PromptOptions{
Text: "Username:",
})
if err != nil {
return err
}
}
if email == "" {
email, err = cliui.Prompt(cmd, cliui.PromptOptions{
Text: "Email:",
Validate: func(s string) error {
err := validator.New().Var(s, "email")
if err != nil {
return xerrors.New("That's not a valid email address!")
}
return err
},
})
if err != nil {
return err
}
}
if password == "" {
password, err = cryptorand.StringCharset(cryptorand.Human, 12)
if err != nil {
return err
}
}
_, err = client.CreateUser(cmd.Context(), codersdk.CreateUserRequest{
Email: email,
Username: username,
Password: password,
OrganizationID: organization.ID,
})
if err != nil {
return err
}
_, _ = fmt.Fprintln(cmd.ErrOrStderr(), `A new user has been created!
Share the instructions below to get them started.
`+cliui.Styles.Placeholder.Render("—————————————————————————————————————————————————")+`
Download the Coder command line for your operating system:
https://github.com/coder/coder/releases
Run `+cliui.Styles.Code.Render("coder login "+client.URL.String())+` to authenticate.
Your email is: `+cliui.Styles.Field.Render(email)+`
Your password is: `+cliui.Styles.Field.Render(password)+`
Create a workspace `+cliui.Styles.Code.Render("coder workspaces create")+`!`)
return nil
},
}
cmd.Flags().StringVarP(&email, "email", "e", "", "Specifies an email address for the new user.")
cmd.Flags().StringVarP(&username, "username", "u", "", "Specifies a username for the new user.")
cmd.Flags().StringVarP(&password, "password", "p", "", "Specifies a password for the new user.")
return cmd
}

42
cli/usercreate_test.go Normal file
View File

@ -0,0 +1,42 @@
package cli_test
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/coder/coder/cli/clitest"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/pty/ptytest"
)
func TestUserCreate(t *testing.T) {
t.Parallel()
t.Run("Prompts", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
coderdtest.CreateFirstUser(t, client)
cmd, root := clitest.New(t, "users", "create")
clitest.SetupConfig(t, client, root)
doneChan := make(chan struct{})
pty := ptytest.New(t)
cmd.SetIn(pty.Input())
cmd.SetOut(pty.Output())
go func() {
defer close(doneChan)
err := cmd.Execute()
require.NoError(t, err)
}()
matches := []string{
"Username", "dean",
"Email", "dean@coder.com",
}
for i := 0; i < len(matches); i += 2 {
match := matches[i]
value := matches[i+1]
pty.ExpectMatch(match)
pty.WriteLine(value)
}
<-doneChan
})
}

46
cli/userlist.go Normal file
View File

@ -0,0 +1,46 @@
package cli
import (
"fmt"
"sort"
"time"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
"github.com/coder/coder/codersdk"
)
func userList() *cobra.Command {
return &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
RunE: func(cmd *cobra.Command, args []string) error {
client, err := createClient(cmd)
if err != nil {
return err
}
users, err := client.Users(cmd.Context(), codersdk.UsersRequest{})
if err != nil {
return err
}
sort.Slice(users, func(i, j int) bool {
return users[i].Username < users[j].Username
})
tableWriter := table.NewWriter()
tableWriter.SetStyle(table.StyleLight)
tableWriter.Style().Options.SeparateColumns = false
tableWriter.AppendHeader(table.Row{"Username", "Email", "Created At"})
for _, user := range users {
tableWriter.AppendRow(table.Row{
user.Username,
user.Email,
user.CreatedAt.Format(time.Stamp),
})
}
_, err = fmt.Fprintln(cmd.OutOrStdout(), tableWriter.Render())
return err
},
}
}

30
cli/userlist_test.go Normal file
View File

@ -0,0 +1,30 @@
package cli_test
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/coder/coder/cli/clitest"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/pty/ptytest"
)
func TestUserList(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
coderdtest.CreateFirstUser(t, client)
cmd, root := clitest.New(t, "users", "list")
clitest.SetupConfig(t, client, root)
doneChan := make(chan struct{})
pty := ptytest.New(t)
cmd.SetIn(pty.Input())
cmd.SetOut(pty.Output())
go func() {
defer close(doneChan)
err := cmd.Execute()
require.NoError(t, err)
}()
pty.ExpectMatch("coder.com")
<-doneChan
}

View File

@ -6,5 +6,6 @@ func users() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "users", Use: "users",
} }
cmd.AddCommand(userCreate(), userList())
return cmd return cmd
} }

View File

@ -207,8 +207,6 @@ func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams
tmp = append(tmp, users[i]) tmp = append(tmp, users[i])
} else if strings.Contains(user.Username, params.Search) { } else if strings.Contains(user.Username, params.Search) {
tmp = append(tmp, users[i]) tmp = append(tmp, users[i])
} else if strings.Contains(user.Name, params.Search) {
tmp = append(tmp, users[i])
} }
} }
users = tmp users = tmp
@ -1116,8 +1114,6 @@ func (q *fakeQuerier) InsertUser(_ context.Context, arg database.InsertUserParam
user := database.User{ user := database.User{
ID: arg.ID, ID: arg.ID,
Email: arg.Email, Email: arg.Email,
Name: arg.Name,
LoginType: arg.LoginType,
HashedPassword: arg.HashedPassword, HashedPassword: arg.HashedPassword,
CreatedAt: arg.CreatedAt, CreatedAt: arg.CreatedAt,
UpdatedAt: arg.UpdatedAt, UpdatedAt: arg.UpdatedAt,
@ -1135,7 +1131,6 @@ func (q *fakeQuerier) UpdateUserProfile(_ context.Context, arg database.UpdateUs
if user.ID != arg.ID { if user.ID != arg.ID {
continue continue
} }
user.Name = arg.Name
user.Email = arg.Email user.Email = arg.Email
user.Username = arg.Username user.Username = arg.Username
q.users[index] = user q.users[index] = user

View File

@ -218,13 +218,10 @@ CREATE TABLE templates (
CREATE TABLE users ( CREATE TABLE users (
id uuid NOT NULL, id uuid NOT NULL,
email text NOT NULL, email text NOT NULL,
name text NOT NULL, username text DEFAULT ''::text NOT NULL,
revoked boolean NOT NULL,
login_type login_type NOT NULL,
hashed_password bytea NOT NULL, hashed_password bytea NOT NULL,
created_at timestamp with time zone NOT NULL, created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL, updated_at timestamp with time zone NOT NULL
username text DEFAULT ''::text NOT NULL
); );
CREATE TABLE workspace_agents ( CREATE TABLE workspace_agents (

View File

@ -12,13 +12,10 @@ CREATE TYPE login_type AS ENUM (
CREATE TABLE IF NOT EXISTS users ( CREATE TABLE IF NOT EXISTS users (
id uuid NOT NULL, id uuid NOT NULL,
email text NOT NULL, email text NOT NULL,
name text NOT NULL, username text DEFAULT ''::text NOT NULL,
revoked boolean NOT NULL,
login_type login_type NOT NULL,
hashed_password bytea NOT NULL, hashed_password bytea NOT NULL,
created_at timestamp with time zone NOT NULL, created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL, updated_at timestamp with time zone NOT NULL,
username text DEFAULT ''::text NOT NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
); );

View File

@ -374,13 +374,10 @@ type TemplateVersion struct {
type User struct { type User struct {
ID uuid.UUID `db:"id" json:"id"` ID uuid.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"` Email string `db:"email" json:"email"`
Name string `db:"name" json:"name"` Username string `db:"username" json:"username"`
Revoked bool `db:"revoked" json:"revoked"`
LoginType LoginType `db:"login_type" json:"login_type"`
HashedPassword []byte `db:"hashed_password" json:"hashed_password"` HashedPassword []byte `db:"hashed_password" json:"hashed_password"`
CreatedAt time.Time `db:"created_at" json:"created_at"` CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
Username string `db:"username" json:"username"`
} }
type Workspace struct { type Workspace struct {

View File

@ -1782,7 +1782,7 @@ func (q *sqlQuerier) UpdateTemplateVersionByID(ctx context.Context, arg UpdateTe
const getUserByEmailOrUsername = `-- name: GetUserByEmailOrUsername :one const getUserByEmailOrUsername = `-- name: GetUserByEmailOrUsername :one
SELECT SELECT
id, email, name, revoked, login_type, hashed_password, created_at, updated_at, username id, email, username, hashed_password, created_at, updated_at
FROM FROM
users users
WHERE WHERE
@ -1803,20 +1803,17 @@ func (q *sqlQuerier) GetUserByEmailOrUsername(ctx context.Context, arg GetUserBy
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.Email, &i.Email,
&i.Name, &i.Username,
&i.Revoked,
&i.LoginType,
&i.HashedPassword, &i.HashedPassword,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.Username,
) )
return i, err return i, err
} }
const getUserByID = `-- name: GetUserByID :one const getUserByID = `-- name: GetUserByID :one
SELECT SELECT
id, email, name, revoked, login_type, hashed_password, created_at, updated_at, username id, email, username, hashed_password, created_at, updated_at
FROM FROM
users users
WHERE WHERE
@ -1831,13 +1828,10 @@ func (q *sqlQuerier) GetUserByID(ctx context.Context, id uuid.UUID) (User, error
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.Email, &i.Email,
&i.Name, &i.Username,
&i.Revoked,
&i.LoginType,
&i.HashedPassword, &i.HashedPassword,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.Username,
) )
return i, err return i, err
} }
@ -1858,7 +1852,7 @@ func (q *sqlQuerier) GetUserCount(ctx context.Context) (int64, error) {
const getUsers = `-- name: GetUsers :many const getUsers = `-- name: GetUsers :many
SELECT SELECT
id, email, name, revoked, login_type, hashed_password, created_at, updated_at, username id, email, username, hashed_password, created_at, updated_at
FROM FROM
users users
WHERE WHERE
@ -1888,7 +1882,6 @@ WHERE
WHEN $2 :: text != '' THEN ( WHEN $2 :: text != '' THEN (
email LIKE concat('%', $2, '%') email LIKE concat('%', $2, '%')
OR username LIKE concat('%', $2, '%') OR username LIKE concat('%', $2, '%')
OR 'name' LIKE concat('%', $2, '%')
) )
ELSE true ELSE true
END END
@ -1925,13 +1918,10 @@ func (q *sqlQuerier) GetUsers(ctx context.Context, arg GetUsersParams) ([]User,
if err := rows.Scan( if err := rows.Scan(
&i.ID, &i.ID,
&i.Email, &i.Email,
&i.Name, &i.Username,
&i.Revoked,
&i.LoginType,
&i.HashedPassword, &i.HashedPassword,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.Username,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
@ -1951,51 +1941,41 @@ INSERT INTO
users ( users (
id, id,
email, email,
"name", username,
login_type,
revoked,
hashed_password, hashed_password,
created_at, created_at,
updated_at, updated_at
username
) )
VALUES VALUES
($1, $2, $3, $4, FALSE, $5, $6, $7, $8) RETURNING id, email, name, revoked, login_type, hashed_password, created_at, updated_at, username ($1, $2, $3, $4, $5, $6) RETURNING id, email, username, hashed_password, created_at, updated_at
` `
type InsertUserParams struct { type InsertUserParams struct {
ID uuid.UUID `db:"id" json:"id"` ID uuid.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"` Email string `db:"email" json:"email"`
Name string `db:"name" json:"name"` Username string `db:"username" json:"username"`
LoginType LoginType `db:"login_type" json:"login_type"`
HashedPassword []byte `db:"hashed_password" json:"hashed_password"` HashedPassword []byte `db:"hashed_password" json:"hashed_password"`
CreatedAt time.Time `db:"created_at" json:"created_at"` CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
Username string `db:"username" json:"username"`
} }
func (q *sqlQuerier) InsertUser(ctx context.Context, arg InsertUserParams) (User, error) { func (q *sqlQuerier) InsertUser(ctx context.Context, arg InsertUserParams) (User, error) {
row := q.db.QueryRowContext(ctx, insertUser, row := q.db.QueryRowContext(ctx, insertUser,
arg.ID, arg.ID,
arg.Email, arg.Email,
arg.Name, arg.Username,
arg.LoginType,
arg.HashedPassword, arg.HashedPassword,
arg.CreatedAt, arg.CreatedAt,
arg.UpdatedAt, arg.UpdatedAt,
arg.Username,
) )
var i User var i User
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.Email, &i.Email,
&i.Name, &i.Username,
&i.Revoked,
&i.LoginType,
&i.HashedPassword, &i.HashedPassword,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.Username,
) )
return i, err return i, err
} }
@ -2005,17 +1985,15 @@ UPDATE
users users
SET SET
email = $2, email = $2,
"name" = $3, username = $3,
username = $4, updated_at = $4
updated_at = $5
WHERE WHERE
id = $1 RETURNING id, email, name, revoked, login_type, hashed_password, created_at, updated_at, username id = $1 RETURNING id, email, username, hashed_password, created_at, updated_at
` `
type UpdateUserProfileParams struct { type UpdateUserProfileParams struct {
ID uuid.UUID `db:"id" json:"id"` ID uuid.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"` Email string `db:"email" json:"email"`
Name string `db:"name" json:"name"`
Username string `db:"username" json:"username"` Username string `db:"username" json:"username"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
} }
@ -2024,7 +2002,6 @@ func (q *sqlQuerier) UpdateUserProfile(ctx context.Context, arg UpdateUserProfil
row := q.db.QueryRowContext(ctx, updateUserProfile, row := q.db.QueryRowContext(ctx, updateUserProfile,
arg.ID, arg.ID,
arg.Email, arg.Email,
arg.Name,
arg.Username, arg.Username,
arg.UpdatedAt, arg.UpdatedAt,
) )
@ -2032,13 +2009,10 @@ func (q *sqlQuerier) UpdateUserProfile(ctx context.Context, arg UpdateUserProfil
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.Email, &i.Email,
&i.Name, &i.Username,
&i.Revoked,
&i.LoginType,
&i.HashedPassword, &i.HashedPassword,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.Username,
) )
return i, err return i, err
} }

View File

@ -30,25 +30,21 @@ INSERT INTO
users ( users (
id, id,
email, email,
"name", username,
login_type,
revoked,
hashed_password, hashed_password,
created_at, created_at,
updated_at, updated_at
username
) )
VALUES VALUES
($1, $2, $3, $4, FALSE, $5, $6, $7, $8) RETURNING *; ($1, $2, $3, $4, $5, $6) RETURNING *;
-- name: UpdateUserProfile :one -- name: UpdateUserProfile :one
UPDATE UPDATE
users users
SET SET
email = $2, email = $2,
"name" = $3, username = $3,
username = $4, updated_at = $4
updated_at = $5
WHERE WHERE
id = $1 RETURNING *; id = $1 RETURNING *;
@ -84,7 +80,6 @@ WHERE
WHEN @search :: text != '' THEN ( WHEN @search :: text != '' THEN (
email LIKE concat('%', @search, '%') email LIKE concat('%', @search, '%')
OR username LIKE concat('%', @search, '%') OR username LIKE concat('%', @search, '%')
OR 'name' LIKE concat('%', @search, '%')
) )
ELSE true ELSE true
END END

View File

@ -40,8 +40,6 @@ func TestOrganizationParam(t *testing.T) {
user, err := db.InsertUser(r.Context(), database.InsertUserParams{ user, err := db.InsertUser(r.Context(), database.InsertUserParams{
ID: userID, ID: userID,
Email: "testaccount@coder.com", Email: "testaccount@coder.com",
Name: "example",
LoginType: database.LoginTypePassword,
HashedPassword: hashed[:], HashedPassword: hashed[:],
Username: username, Username: username,
CreatedAt: database.Now(), CreatedAt: database.Now(),

View File

@ -39,8 +39,6 @@ func TestTemplateParam(t *testing.T) {
user, err := db.InsertUser(r.Context(), database.InsertUserParams{ user, err := db.InsertUser(r.Context(), database.InsertUserParams{
ID: userID, ID: userID,
Email: "testaccount@coder.com", Email: "testaccount@coder.com",
Name: "example",
LoginType: database.LoginTypePassword,
HashedPassword: hashed[:], HashedPassword: hashed[:],
Username: username, Username: username,
CreatedAt: database.Now(), CreatedAt: database.Now(),

View File

@ -39,8 +39,6 @@ func TestTemplateVersionParam(t *testing.T) {
user, err := db.InsertUser(r.Context(), database.InsertUserParams{ user, err := db.InsertUser(r.Context(), database.InsertUserParams{
ID: userID, ID: userID,
Email: "testaccount@coder.com", Email: "testaccount@coder.com",
Name: "example",
LoginType: database.LoginTypePassword,
HashedPassword: hashed[:], HashedPassword: hashed[:],
Username: username, Username: username,
CreatedAt: database.Now(), CreatedAt: database.Now(),

View File

@ -39,8 +39,6 @@ func TestWorkspaceAgentParam(t *testing.T) {
user, err := db.InsertUser(r.Context(), database.InsertUserParams{ user, err := db.InsertUser(r.Context(), database.InsertUserParams{
ID: userID, ID: userID,
Email: "testaccount@coder.com", Email: "testaccount@coder.com",
Name: "example",
LoginType: database.LoginTypePassword,
HashedPassword: hashed[:], HashedPassword: hashed[:],
Username: username, Username: username,
CreatedAt: database.Now(), CreatedAt: database.Now(),

View File

@ -39,8 +39,6 @@ func TestWorkspaceBuildParam(t *testing.T) {
user, err := db.InsertUser(r.Context(), database.InsertUserParams{ user, err := db.InsertUser(r.Context(), database.InsertUserParams{
ID: userID, ID: userID,
Email: "testaccount@coder.com", Email: "testaccount@coder.com",
Name: "example",
LoginType: database.LoginTypePassword,
HashedPassword: hashed[:], HashedPassword: hashed[:],
Username: username, Username: username,
CreatedAt: database.Now(), CreatedAt: database.Now(),

View File

@ -39,8 +39,6 @@ func TestWorkspaceParam(t *testing.T) {
user, err := db.InsertUser(r.Context(), database.InsertUserParams{ user, err := db.InsertUser(r.Context(), database.InsertUserParams{
ID: userID, ID: userID,
Email: "testaccount@coder.com", Email: "testaccount@coder.com",
Name: "example",
LoginType: database.LoginTypePassword,
HashedPassword: hashed[:], HashedPassword: hashed[:],
Username: username, Username: username,
CreatedAt: database.Now(), CreatedAt: database.Now(),

View File

@ -233,11 +233,6 @@ func (api *api) putUserProfile(rw http.ResponseWriter, r *http.Request) {
if !httpapi.Read(rw, r, &params) { if !httpapi.Read(rw, r, &params) {
return return
} }
if params.Name == nil {
params.Name = &user.Name
}
existentUser, err := api.Database.GetUserByEmailOrUsername(r.Context(), database.GetUserByEmailOrUsernameParams{ existentUser, err := api.Database.GetUserByEmailOrUsername(r.Context(), database.GetUserByEmailOrUsernameParams{
Email: params.Email, Email: params.Email,
Username: params.Username, Username: params.Username,
@ -273,7 +268,6 @@ func (api *api) putUserProfile(rw http.ResponseWriter, r *http.Request) {
updatedUserProfile, err := api.Database.UpdateUserProfile(r.Context(), database.UpdateUserProfileParams{ updatedUserProfile, err := api.Database.UpdateUserProfile(r.Context(), database.UpdateUserProfileParams{
ID: user.ID, ID: user.ID,
Name: *params.Name,
Email: params.Email, Email: params.Email,
Username: params.Username, Username: params.Username,
UpdatedAt: database.Now(), UpdatedAt: database.Now(),
@ -896,7 +890,6 @@ func (api *api) createUser(ctx context.Context, req codersdk.CreateUserRequest)
ID: uuid.New(), ID: uuid.New(),
Email: req.Email, Email: req.Email,
Username: req.Username, Username: req.Username,
LoginType: database.LoginTypePassword,
CreatedAt: database.Now(), CreatedAt: database.Now(),
UpdatedAt: database.Now(), UpdatedAt: database.Now(),
} }
@ -949,7 +942,6 @@ func convertUser(user database.User) codersdk.User {
Email: user.Email, Email: user.Email,
CreatedAt: user.CreatedAt, CreatedAt: user.CreatedAt,
Username: user.Username, Username: user.Username,
Name: user.Name,
} }
} }

View File

@ -283,28 +283,6 @@ func TestUpdateUserProfile(t *testing.T) {
require.Equal(t, userProfile.Username, me.Username) require.Equal(t, userProfile.Username, me.Username)
require.Equal(t, userProfile.Email, "newemail@coder.com") require.Equal(t, userProfile.Email, "newemail@coder.com")
}) })
t.Run("KeepUserName", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
coderdtest.CreateFirstUser(t, client)
me, _ := client.User(context.Background(), codersdk.Me)
newName := "New Name"
firstProfile, _ := client.UpdateUserProfile(context.Background(), codersdk.Me, codersdk.UpdateUserProfileRequest{
Username: me.Username,
Email: me.Email,
Name: &newName,
})
t.Log(firstProfile)
userProfile, err := client.UpdateUserProfile(context.Background(), codersdk.Me, codersdk.UpdateUserProfileRequest{
Username: "newusername",
Email: "newemail@coder.com",
})
require.NoError(t, err)
require.Equal(t, userProfile.Username, "newusername")
require.Equal(t, userProfile.Email, "newemail@coder.com")
require.Equal(t, userProfile.Name, newName)
})
} }
func TestUserByName(t *testing.T) { func TestUserByName(t *testing.T) {

View File

@ -34,7 +34,6 @@ type User struct {
Email string `json:"email" validate:"required"` Email string `json:"email" validate:"required"`
CreatedAt time.Time `json:"created_at" validate:"required"` CreatedAt time.Time `json:"created_at" validate:"required"`
Username string `json:"username" validate:"required"` Username string `json:"username" validate:"required"`
Name string `json:"name"`
} }
type CreateFirstUserRequest struct { type CreateFirstUserRequest struct {
@ -60,7 +59,6 @@ type CreateUserRequest struct {
type UpdateUserProfileRequest struct { type UpdateUserProfileRequest struct {
Email string `json:"email" validate:"required,email"` Email string `json:"email" validate:"required,email"`
Username string `json:"username" validate:"required,username"` Username string `json:"username" validate:"required,username"`
Name *string `json:"name"`
} }
// LoginWithPasswordRequest enables callers to authenticate with email and password. // LoginWithPasswordRequest enables callers to authenticate with email and password.

View File

@ -81,10 +81,9 @@ export interface UsersRequest {
export interface User { export interface User {
readonly email: string readonly email: string
readonly username: string readonly username: string
readonly name: string
} }
// From codersdk/users.go:40:6. // From codersdk/users.go:39:6.
export interface CreateFirstUserRequest { export interface CreateFirstUserRequest {
readonly email: string readonly email: string
readonly username: string readonly username: string
@ -92,47 +91,46 @@ export interface CreateFirstUserRequest {
readonly organization: string readonly organization: string
} }
// From codersdk/users.go:53:6. // From codersdk/users.go:52:6.
export interface CreateUserRequest { export interface CreateUserRequest {
readonly email: string readonly email: string
readonly username: string readonly username: string
readonly password: string readonly password: string
} }
// From codersdk/users.go:60:6. // From codersdk/users.go:59:6.
export interface UpdateUserProfileRequest { export interface UpdateUserProfileRequest {
readonly email: string readonly email: string
readonly username: string readonly username: string
readonly name?: string
} }
// From codersdk/users.go:67:6. // From codersdk/users.go:65:6.
export interface LoginWithPasswordRequest { export interface LoginWithPasswordRequest {
readonly email: string readonly email: string
readonly password: string readonly password: string
} }
// From codersdk/users.go:73:6. // From codersdk/users.go:71:6.
export interface LoginWithPasswordResponse { export interface LoginWithPasswordResponse {
readonly session_token: string readonly session_token: string
} }
// From codersdk/users.go:78:6. // From codersdk/users.go:76:6.
export interface GenerateAPIKeyResponse { export interface GenerateAPIKeyResponse {
readonly key: string readonly key: string
} }
// From codersdk/users.go:82:6. // From codersdk/users.go:80:6.
export interface CreateOrganizationRequest { export interface CreateOrganizationRequest {
readonly name: string readonly name: string
} }
// From codersdk/users.go:87:6. // From codersdk/users.go:85:6.
export interface CreateWorkspaceRequest { export interface CreateWorkspaceRequest {
readonly name: string readonly name: string
} }
// From codersdk/users.go:96:6. // From codersdk/users.go:94:6.
export interface AuthMethods { export interface AuthMethods {
readonly password: boolean readonly password: boolean
readonly github: boolean readonly github: boolean