ChangeUsername changes the username of the given user and updates all references to the old username. It returns ErrNameNotAllowed if the given name or pattern of the name is not allowed as a username, or ErrUserAlreadyExist when another user with same name already exists.
(ctx context.Context, userID int64, newUsername string)
| 151 | // name or pattern of the name is not allowed as a username, or |
| 152 | // ErrUserAlreadyExist when another user with same name already exists. |
| 153 | func (s *UsersStore) ChangeUsername(ctx context.Context, userID int64, newUsername string) error { |
| 154 | err := isUsernameAllowed(newUsername) |
| 155 | if err != nil { |
| 156 | return err |
| 157 | } |
| 158 | |
| 159 | if s.IsUsernameUsed(ctx, newUsername, userID) { |
| 160 | return ErrUserAlreadyExist{ |
| 161 | args: errutil.Args{ |
| 162 | "name": newUsername, |
| 163 | }, |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | user, err := s.GetByID(ctx, userID) |
| 168 | if err != nil { |
| 169 | return errors.Wrap(err, "get user") |
| 170 | } |
| 171 | |
| 172 | return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { |
| 173 | err := tx.Model(&User{}). |
| 174 | Where("id = ?", user.ID). |
| 175 | Updates(map[string]any{ |
| 176 | "lower_name": strings.ToLower(newUsername), |
| 177 | "name": newUsername, |
| 178 | "updated_unix": tx.NowFunc().Unix(), |
| 179 | }).Error |
| 180 | if err != nil { |
| 181 | return errors.Wrap(err, "update user name") |
| 182 | } |
| 183 | |
| 184 | // Stop here if it's just a case-change of the username |
| 185 | if strings.EqualFold(user.Name, newUsername) { |
| 186 | return nil |
| 187 | } |
| 188 | |
| 189 | // Update all references to the user name in pull requests |
| 190 | err = tx.Model(&PullRequest{}). |
| 191 | Where("head_user_name = ?", user.LowerName). |
| 192 | Update("head_user_name", strings.ToLower(newUsername)). |
| 193 | Error |
| 194 | if err != nil { |
| 195 | return errors.Wrap(err, `update "pull_request.head_user_name"`) |
| 196 | } |
| 197 | |
| 198 | // Delete local copies of repositories and their wikis that are owned by the user |
| 199 | rows, err := tx.Model(&Repository{}).Where("owner_id = ?", user.ID).Rows() |
| 200 | if err != nil { |
| 201 | return errors.Wrap(err, "iterate repositories") |
| 202 | } |
| 203 | defer func() { _ = rows.Close() }() |
| 204 | |
| 205 | for rows.Next() { |
| 206 | var repo struct { |
| 207 | ID int64 |
| 208 | } |
| 209 | err = tx.ScanRows(rows, &repo) |
| 210 | if err != nil { |