Skip to content

Commit

Permalink
feat: add det user change-username to CLI [DET-3322] (#692)
Browse files Browse the repository at this point in the history
  • Loading branch information
stoksc authored Jun 11, 2020
1 parent a331567 commit 3b12c87
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 0 deletions.
14 changes: 14 additions & 0 deletions cli/determined_cli/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ def update_user(
return api.patch(master_address, "users/{}".format(username), body=request)


def update_username(current_username: str, master_address: str, new_username: str) -> Response:
request = {"username": new_username}
return api.patch(master_address, "users/{}/username".format(current_username), body=request)


@authentication_required
def list_users(args: Namespace) -> None:
render.render_objects(
Expand Down Expand Up @@ -120,6 +125,11 @@ def log_out_user(parsed_args: Namespace) -> None:
auth_inst.token_store.drop_user(auth_inst.get_session_user())


@authentication_required
def rename(parsed_args: Namespace) -> None:
update_username(parsed_args.target_user, parsed_args.master, parsed_args.new_username)


@authentication_required
def change_password(parsed_args: Namespace) -> None:
auth_inst = api.Authentication.instance()
Expand Down Expand Up @@ -206,6 +216,10 @@ def whoami(parsed_args: Namespace) -> None:
Cmd("login", log_in_user, "log in user", [
Arg("username", nargs="?", default=None, help="name of user to log in as")
]),
Cmd("rename", rename, "change username for user", [
Arg("target_user", default=None, help="name of user whose username should be changed"),
Arg("new_username", default=None, help="new username for target_user"),
]),
Cmd("change-password", change_password, "change password for user", [
Arg("target_user", nargs="?", default=None, help="name of user to change password of")
]),
Expand Down
9 changes: 9 additions & 0 deletions master/internal/db/postgres_users.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,15 @@ func (db *PgDB) UpdateUser(updated *model.User, toUpdate []string, ug *model.Age
return nil
}

// UpdateUsername updates an existing user's username.
func (db *PgDB) UpdateUsername(userID *model.UserID, newUsername string) error {
if _, err := db.sql.Exec(
"UPDATE users SET username = $1 WHERE id = $2", newUsername, userID); err != nil {
return errors.WithStack(err)
}
return nil
}

// UserList returns all of the users in the database.
func (db *PgDB) UserList() (values []model.FullUser, err error) {
err = db.Query("list_users", &values)
Expand Down
1 change: 1 addition & 0 deletions master/internal/user/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ func RegisterAPIHandler(echo *echo.Echo, m *Service, middleware ...echo.Middlewa
usersGroup.POST("", api.Route(m.postUser))
usersGroup.GET("/me", api.Route(m.getMe))
usersGroup.PATCH("/:username", api.Route(m.patchUser))
usersGroup.PATCH("/:username/username", api.Route(m.patchUsername))
}
70 changes: 70 additions & 0 deletions master/internal/user/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,76 @@ func (s *Service) patchUser(c echo.Context) (interface{}, error) {
}, nil
}

func (s *Service) patchUsername(c echo.Context) (interface{}, error) {
type (
request struct {
NewUsername *string `json:"username,omitempty"`
}
response struct {
message string
}
)

body, err := ioutil.ReadAll(c.Request().Body)
if err != nil {
return nil, err
}

args := struct {
Username string `path:"username"`
}{}
if err = api.BindArgs(&args, c); err != nil {
return nil, err
}

var params request
if err = json.Unmarshal(body, &params); err != nil {
malformedRequestError := echo.NewHTTPError(http.StatusBadRequest, "bad request")
return nil, malformedRequestError
}

forbiddenError := echo.NewHTTPError(http.StatusForbidden)
authenticatedUser := c.(*context.DetContext).MustGetUser()
if !authenticatedUser.Admin {
return nil, forbiddenError
}

user, err := s.db.UserByUsername(args.Username)
switch err {
case nil:
case db.ErrNotFound:
if authenticatedUser.Admin {
return nil, echo.NewHTTPError(
http.StatusBadRequest,
fmt.Sprintf("failed to get user '%s'", args.Username))
}
return nil, forbiddenError
default:
return nil, err
}

if params.NewUsername == nil {
malformedRequestError := echo.NewHTTPError(http.StatusBadRequest, "username is required")
return nil, malformedRequestError
}

switch u, uErr := s.db.UserByUsername(*params.NewUsername); {
case uErr == db.ErrNotFound:
case uErr != nil:
return nil, uErr
case u != nil:
return nil, echo.NewHTTPError(http.StatusBadRequest, "username is taken")
}

if err = s.db.UpdateUsername(&user.ID, *params.NewUsername); err != nil {
return nil, err
}

return response{
message: fmt.Sprintf("successfully updated %v", args.Username),
}, nil
}

func (s *Service) postUser(c echo.Context) (interface{}, error) {
type (
request struct {
Expand Down

0 comments on commit 3b12c87

Please sign in to comment.