configstore: add update user

This commit is contained in:
Simone Gotti 2019-05-03 09:53:38 +02:00
parent ab7e4b8a4b
commit 9349728997
4 changed files with 141 additions and 0 deletions

View File

@ -323,6 +323,17 @@ func (c *Client) CreateUser(ctx context.Context, req *CreateUserRequest) (*types
return user, resp, err
}
func (c *Client) UpdateUser(ctx context.Context, userID string, req *UpdateUserRequest) (*types.User, *http.Response, error) {
reqj, err := json.Marshal(req)
if err != nil {
return nil, nil, err
}
user := new(types.User)
resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/users/%s", userID), nil, jsonContent, bytes.NewReader(reqj), user)
return user, resp, err
}
func (c *Client) DeleteUser(ctx context.Context, userName string) (*http.Response, error) {
return c.getResponse(ctx, "DELETE", fmt.Sprintf("/users/%s", userName), nil, jsonContent, nil)
}

View File

@ -152,6 +152,50 @@ func (h *CreateUserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}
type UpdateUserRequest struct {
UserName string `json:"user_name"`
UpdateUserLARequest *UpdateUserLARequest `json:"create_user_la_request"`
}
type UpdateUserHandler struct {
log *zap.SugaredLogger
ch *command.CommandHandler
}
func NewUpdateUserHandler(logger *zap.Logger, ch *command.CommandHandler) *UpdateUserHandler {
return &UpdateUserHandler{log: logger.Sugar(), ch: ch}
}
func (h *UpdateUserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
userID := vars["userid"]
var req *UpdateUserRequest
d := json.NewDecoder(r.Body)
if err := d.Decode(&req); err != nil {
httpError(w, util.NewErrBadRequest(err))
return
}
creq := &command.UpdateUserRequest{
UserID: userID,
UserName: req.UserName,
}
user, err := h.ch.UpdateUser(ctx, creq)
if httpError(w, err) {
h.log.Errorf("err: %+v", err)
return
}
if err := httpResponse(w, http.StatusCreated, user); err != nil {
h.log.Errorf("err: %+v", err)
}
}
type DeleteUserHandler struct {
log *zap.SugaredLogger
ch *command.CommandHandler

View File

@ -180,6 +180,20 @@ func (s *CommandHandler) CreateProject(ctx context.Context, project *types.Proje
if pg != nil {
return util.NewErrBadRequest(errors.Errorf("project group with name %q, path %q already exists", pg.Name, pp))
}
// check that the linked account matches the remote source
user, err := s.readDB.GetUserByLinkedAccount(tx, project.LinkedAccountID)
if err != nil {
return errors.Wrapf(err, "failed to get user with linked account id %q", project.LinkedAccountID)
}
la, ok := user.LinkedAccounts[project.LinkedAccountID]
if !ok {
return util.NewErrBadRequest(errors.Errorf("linked account id %q for user %q doesn't exist", project.LinkedAccountID, user.Name))
}
if la.RemoteSourceID != project.RemoteSourceID {
return util.NewErrBadRequest(errors.Errorf("linked account id %q remote source %q different than project remote source %q", project.LinkedAccountID, la.RemoteSourceID, project.RemoteSourceID))
}
return nil
})
if err != nil {
@ -407,6 +421,76 @@ func (s *CommandHandler) DeleteUser(ctx context.Context, userName string) error
return err
}
type UpdateUserRequest struct {
UserID string
UserName string
}
func (s *CommandHandler) UpdateUser(ctx context.Context, req *UpdateUserRequest) (*types.User, error) {
var cgt *datamanager.ChangeGroupsUpdateToken
cgNames := []string{}
var user *types.User
// must do all the check in a single transaction to avoid concurrent changes
err := s.readDB.Do(func(tx *db.Tx) error {
var err error
user, err = s.readDB.GetUserByName(tx, req.UserName)
if err != nil {
return err
}
if user == nil {
return util.NewErrBadRequest(errors.Errorf("user %q doesn't exist", req.UserName))
}
cgt, err = s.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil {
return err
}
if req.UserName != "" {
// check duplicate user name
u, err := s.readDB.GetUserByName(tx, req.UserName)
if err != nil {
return err
}
if u != nil {
return util.NewErrBadRequest(errors.Errorf("user with name %q already exists", u.Name))
}
// changegroup is the username (and in future the email) to ensure no
// concurrent user creation/modification using the same name
cgNames = append(cgNames, util.EncodeSha256Hex("username-"+req.UserName))
}
return nil
})
if err != nil {
return nil, err
}
if req.UserName != "" {
user.Name = req.UserName
}
userj, err := json.Marshal(user)
if err != nil {
return nil, errors.Wrapf(err, "failed to marshal user")
}
actions := []*datamanager.Action{
{
ActionType: datamanager.ActionTypePut,
DataType: string(types.ConfigTypeUser),
ID: user.ID,
Data: userj,
},
}
_, err = s.dm.WriteWal(ctx, actions, cgt)
return user, err
}
type CreateUserLARequest struct {
UserName string
RemoteSourceName string

View File

@ -145,6 +145,7 @@ func (s *ConfigStore) Run(ctx context.Context) error {
usersHandler := api.NewUsersHandler(logger, s.readDB)
userByNameHandler := api.NewUserByNameHandler(logger, s.readDB)
createUserHandler := api.NewCreateUserHandler(logger, s.ch)
updateUserHandler := api.NewUpdateUserHandler(logger, s.ch)
deleteUserHandler := api.NewDeleteUserHandler(logger, s.ch)
createUserLAHandler := api.NewCreateUserLAHandler(logger, s.ch)
@ -196,6 +197,7 @@ func (s *ConfigStore) Run(ctx context.Context) error {
apirouter.Handle("/users", usersHandler).Methods("GET")
apirouter.Handle("/users", createUserHandler).Methods("POST")
apirouter.Handle("/users/{username}", userByNameHandler).Methods("GET")
apirouter.Handle("/users/{userid}", updateUserHandler).Methods("PUT")
apirouter.Handle("/users/{username}", deleteUserHandler).Methods("DELETE")
apirouter.Handle("/users/{username}/linkedaccounts", createUserLAHandler).Methods("POST")