MCPcopy Create free account
hub / github.com/bytebase/bytebase / CreateUser

Method CreateUser

backend/api/v1/user_service.go:206–280  ·  view source on GitHub ↗

CreateUser creates a user in the caller's workspace (admin action, self-hosted only). In SaaS mode, admins should add users via workspace IAM policy instead.

(ctx context.Context, request *connect.Request[v1pb.CreateUserRequest])

Source from the content-addressed store, hash-verified

204// CreateUser creates a user in the caller's workspace (admin action, self-hosted only).
205// In SaaS mode, admins should add users via workspace IAM policy instead.
206func (s *UserService) CreateUser(ctx context.Context, request *connect.Request[v1pb.CreateUserRequest]) (*connect.Response[v1pb.User], error) {
207 if s.profile.SaaS {
208 return nil, connect.NewError(connect.CodeUnimplemented, errors.Errorf("CreateUser is not available in SaaS mode, add users via workspace IAM policy instead"))
209 }
210
211 if request.Msg.User == nil {
212 return nil, connect.NewError(connect.CodeInvalidArgument, errors.Errorf("user must be set"))
213 }
214 if request.Msg.User.Email == "" {
215 return nil, connect.NewError(connect.CodeInvalidArgument, errors.Errorf("email must be set"))
216 }
217 if request.Msg.User.Title == "" {
218 return nil, connect.NewError(connect.CodeInvalidArgument, errors.Errorf("user title must be set"))
219 }
220 if request.Msg.User.Phone != "" {
221 if err := common.ValidatePhone(request.Msg.User.Phone); err != nil {
222 return nil, connect.NewError(connect.CodeInvalidArgument, errors.Wrapf(err, "invalid phone %q", request.Msg.User.Phone))
223 }
224 }
225
226 workspaceID := common.GetWorkspaceIDFromContext(ctx)
227 email := request.Msg.User.Email
228
229 if err := validateEmailWithDomains(ctx, s.licenseService, s.store, workspaceID, email, false); err != nil {
230 return nil, err
231 }
232
233 existingUser, err := s.store.GetUserByEmail(ctx, email)
234 if err != nil {
235 return nil, connect.NewError(connect.CodeInternal, errors.Wrapf(err, "failed to find user by email"))
236 }
237 if existingUser != nil {
238 return nil, connect.NewError(connect.CodeAlreadyExists, errors.Errorf("email %s exists", email))
239 }
240
241 // Validate password.
242 password := request.Msg.User.Password
243 if password != "" {
244 if err := s.validatePassword(ctx, workspaceID, password); err != nil {
245 return nil, err
246 }
247 } else {
248 pwd, err := common.RandomString(20)
249 if err != nil {
250 return nil, connect.NewError(connect.CodeInternal, errors.Errorf("failed to generate random password for user"))
251 }
252 password = pwd
253 }
254 passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
255 if err != nil {
256 return nil, connect.NewError(connect.CodeInternal, errors.Wrapf(err, "failed to generate password hash"))
257 }
258
259 if err := s.preAddUserGuard(ctx, workspaceID); err != nil {
260 return nil, err
261 }
262
263 user, err := s.store.CreateUser(ctx, &store.UserMessage{

Callers 1

UpdateUserMethod · 0.95

Calls 11

validatePasswordMethod · 0.95
preAddUserGuardMethod · 0.95
ValidatePhoneFunction · 0.92
RandomStringFunction · 0.92
FormatWorkspaceFunction · 0.92
validateEmailWithDomainsFunction · 0.85
convertToUserFunction · 0.85
ErrorfMethod · 0.80
GetUserByEmailMethod · 0.80
CreateUserMethod · 0.65

Tested by

no test coverage detected