configstore: createuser also create linked account when requested

Useful to future user registration to create user and linked account in a unique
atomic call.
This commit is contained in:
Simone Gotti 2019-03-29 17:50:51 +01:00
parent 3e3a7a0ea5
commit 704da47afc
4 changed files with 86 additions and 13 deletions

View File

@ -314,14 +314,14 @@ func (c *Client) GetUserByLinkedAccount(ctx context.Context, linkedAccountID str
return users[0], resp, err
}
func (c *Client) CreateUser(ctx context.Context, user *types.User) (*types.User, *http.Response, error) {
uj, err := json.Marshal(user)
func (c *Client) CreateUser(ctx context.Context, req *CreateUserRequest) (*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", "/users", nil, jsonContent, bytes.NewReader(uj), user)
user := new(types.User)
resp, err := c.getParsedResponse(ctx, "PUT", "/users", nil, jsonContent, bytes.NewReader(reqj), user)
return user, resp, err
}

View File

@ -103,6 +103,12 @@ func (h *UserByNameHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}
type CreateUserRequest struct {
UserName string `json:"user_name"`
CreateUserLARequest *CreateUserLARequest `json:"create_user_la_request"`
}
type CreateUserHandler struct {
log *zap.SugaredLogger
ch *command.CommandHandler
@ -115,14 +121,28 @@ func NewCreateUserHandler(logger *zap.Logger, ch *command.CommandHandler) *Creat
func (h *CreateUserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var req types.User
var req *CreateUserRequest
d := json.NewDecoder(r.Body)
if err := d.Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
user, err := h.ch.CreateUser(ctx, &req)
creq := &command.CreateUserRequest{
UserName: req.UserName,
}
if req.CreateUserLARequest != nil {
creq.CreateUserLARequest = &command.CreateUserLARequest{
RemoteSourceName: req.CreateUserLARequest.RemoteSourceName,
RemoteUserID: req.CreateUserLARequest.RemoteUserID,
RemoteUserName: req.CreateUserLARequest.RemoteUserName,
Oauth2AccessToken: req.CreateUserLARequest.Oauth2AccessToken,
Oauth2RefreshToken: req.CreateUserLARequest.Oauth2RefreshToken,
UserAccessToken: req.CreateUserLARequest.UserAccessToken,
}
}
user, err := h.ch.CreateUser(ctx, creq)
if httpError(w, err) {
h.log.Errorf("err: %+v", err)
return

View File

@ -239,13 +239,20 @@ func (s *CommandHandler) DeleteProject(ctx context.Context, projectRef string) e
return err
}
func (s *CommandHandler) CreateUser(ctx context.Context, user *types.User) (*types.User, error) {
if user.UserName == "" {
type CreateUserRequest struct {
UserName string
CreateUserLARequest *CreateUserLARequest
}
func (s *CommandHandler) CreateUser(ctx context.Context, req *CreateUserRequest) (*types.User, error) {
if req.UserName == "" {
return nil, util.NewErrBadRequest(errors.Errorf("user name required"))
}
var cgt *wal.ChangeGroupsUpdateToken
cgNames := []string{user.UserName}
cgNames := []string{req.UserName}
var rs *types.RemoteSource
// must do all the check in a single transaction to avoid concurrent changes
err := s.readDB.Do(func(tx *db.Tx) error {
@ -256,20 +263,58 @@ func (s *CommandHandler) CreateUser(ctx context.Context, user *types.User) (*typ
}
// check duplicate user name
u, err := s.readDB.GetUserByName(tx, user.UserName)
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.UserName))
}
if req.CreateUserLARequest != nil {
rs, err = s.readDB.GetRemoteSourceByName(tx, req.CreateUserLARequest.RemoteSourceName)
if err != nil {
return err
}
if rs == nil {
return util.NewErrBadRequest(errors.Errorf("remote source %q doesn't exist", req.CreateUserLARequest.RemoteSourceName))
}
user, err := s.readDB.GetUserByLinkedAccountRemoteUserIDandSource(tx, req.CreateUserLARequest.RemoteUserID, rs.ID)
if err != nil {
return errors.Wrapf(err, "failed to get user for remote user id %q and remote source %q", req.CreateUserLARequest.RemoteUserID, rs.ID)
}
if user != nil {
return util.NewErrBadRequest(errors.Errorf("user for remote user id %q for remote source %q already exists", req.CreateUserLARequest.RemoteUserID, req.CreateUserLARequest.RemoteSourceName))
}
}
return nil
})
if err != nil {
return nil, err
}
user.ID = uuid.NewV4().String()
user := &types.User{
ID: uuid.NewV4().String(),
UserName: req.UserName,
}
if req.CreateUserLARequest != nil {
if user.LinkedAccounts == nil {
user.LinkedAccounts = make(map[string]*types.LinkedAccount)
}
la := &types.LinkedAccount{
ID: uuid.NewV4().String(),
RemoteSourceID: rs.ID,
RemoteUserID: req.CreateUserLARequest.RemoteUserID,
RemoteUserName: req.CreateUserLARequest.RemoteUserName,
UserAccessToken: req.CreateUserLARequest.UserAccessToken,
Oauth2AccessToken: req.CreateUserLARequest.Oauth2AccessToken,
Oauth2RefreshToken: req.CreateUserLARequest.Oauth2RefreshToken,
}
user.LinkedAccounts[la.ID] = la
}
userj, err := json.Marshal(user)
if err != nil {
return nil, errors.Wrapf(err, "failed to marshal user")
@ -392,6 +437,14 @@ func (s *CommandHandler) CreateUserLA(ctx context.Context, req *CreateUserLARequ
if rs == nil {
return util.NewErrBadRequest(errors.Errorf("remote source %q doesn't exist", req.RemoteSourceName))
}
user, err := s.readDB.GetUserByLinkedAccountRemoteUserIDandSource(tx, req.RemoteUserID, rs.ID)
if err != nil {
return errors.Wrapf(err, "failed to get user for remote user id %q and remote source %q", req.RemoteUserID, rs.ID)
}
if user != nil {
return util.NewErrBadRequest(errors.Errorf("user for remote user id %q for remote source %q already exists", req.RemoteUserID, req.RemoteSourceName))
}
return nil
})
if err != nil {

View File

@ -39,12 +39,12 @@ func (c *CommandHandler) CreateUser(ctx context.Context, req *CreateUserRequest)
return nil, errors.Errorf("invalid user name %q", req.UserName)
}
u := &types.User{
creq := &csapi.CreateUserRequest{
UserName: req.UserName,
}
c.log.Infof("creating user")
u, _, err := c.configstoreClient.CreateUser(ctx, u)
u, _, err := c.configstoreClient.CreateUser(ctx, creq)
if err != nil {
return nil, errors.Wrapf(err, "failed to create user")
}