CreateUser creates a new user with a hashed password.
(input models.UserCreate)
| 83 | |
| 84 | // CreateUser creates a new user with a hashed password. |
| 85 | func (s *Store) CreateUser(input models.UserCreate) (*models.User, error) { |
| 86 | hash, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcryptCost) |
| 87 | if err != nil { |
| 88 | return nil, fmt.Errorf("hash password: %w", err) |
| 89 | } |
| 90 | |
| 91 | role := input.Role |
| 92 | if role == "" { |
| 93 | role = "member" |
| 94 | } |
| 95 | |
| 96 | id := newID() |
| 97 | ts := now() |
| 98 | |
| 99 | // Email-verification default is SAFE = verified (DR-3). Every creation path |
| 100 | // yields a verified user unless it explicitly requests unverified via |
| 101 | // UserCreate.Unverified. Today only the future cloud self-serve signup |
| 102 | // branch (PLAN-1933 Wave 3) sets that; every current call site inherits |
| 103 | // verified. A nil interface binds as a NULL column (= unverified). |
| 104 | var emailVerifiedAt interface{} |
| 105 | if !input.Unverified { |
| 106 | emailVerifiedAt = ts |
| 107 | } |
| 108 | |
| 109 | _, err = s.db.Exec(s.q(` |
| 110 | INSERT INTO users (id, email, username, name, password_hash, role, password_set, email_verified_at, created_at, updated_at) |
| 111 | VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) |
| 112 | `), id, strings.ToLower(strings.TrimSpace(input.Email)), strings.TrimSpace(input.Username), strings.TrimSpace(input.Name), string(hash), role, true, emailVerifiedAt, ts, ts) |
| 113 | if err != nil { |
| 114 | return nil, fmt.Errorf("insert user: %w", err) |
| 115 | } |
| 116 | |
| 117 | return s.GetUser(id) |
| 118 | } |
| 119 | |
| 120 | // GetUser retrieves a user by ID. |
| 121 | func (s *Store) GetUser(id string) (*models.User, error) { |