// Copyright (C) 2009 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.server.account;

import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;

import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.errors.NameAlreadyUsedException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.externalids.ExternalId;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.account.externalids.ExternalIdsUpdate;
import com.google.gerrit.server.ssh.SshKeyCache;
import com.google.gwtjsonrpc.common.VoidResult;
import com.google.gwtorm.server.OrmDuplicateKeyException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.regex.Pattern;
import org.eclipse.jgit.errors.ConfigInvalidException;

/** Operation to change the username of an account. */
public class ChangeUserName implements Callable<VoidResult> {
  public static final String USERNAME_CANNOT_BE_CHANGED = "Username cannot be changed.";

  private static final Pattern USER_NAME_PATTERN = Pattern.compile(Account.USER_NAME_PATTERN);

  /** Generic factory to change any user's username. */
  public interface Factory {
    ChangeUserName create(IdentifiedUser user, String newUsername);
  }

  private final SshKeyCache sshKeyCache;
  private final ExternalIds externalIds;
  private final ExternalIdsUpdate.Server externalIdsUpdateFactory;

  private final IdentifiedUser user;
  private final String newUsername;

  @Inject
  ChangeUserName(
      SshKeyCache sshKeyCache,
      ExternalIds externalIds,
      ExternalIdsUpdate.Server externalIdsUpdateFactory,
      @Assisted IdentifiedUser user,
      @Nullable @Assisted String newUsername) {
    this.sshKeyCache = sshKeyCache;
    this.externalIds = externalIds;
    this.externalIdsUpdateFactory = externalIdsUpdateFactory;
    this.user = user;
    this.newUsername = newUsername;
  }

  @Override
  public VoidResult call()
      throws OrmException, NameAlreadyUsedException, InvalidUserNameException, IOException,
          ConfigInvalidException {
    Collection<ExternalId> old = externalIds.byAccount(user.getAccountId(), SCHEME_USERNAME);
    if (!old.isEmpty()) {
      throw new IllegalStateException(USERNAME_CANNOT_BE_CHANGED);
    }

    ExternalIdsUpdate externalIdsUpdate = externalIdsUpdateFactory.create();
    if (newUsername != null && !newUsername.isEmpty()) {
      if (!USER_NAME_PATTERN.matcher(newUsername).matches()) {
        throw new InvalidUserNameException();
      }

      ExternalId.Key key = ExternalId.Key.create(SCHEME_USERNAME, newUsername);
      try {
        String password = null;
        for (ExternalId i : old) {
          if (i.password() != null) {
            password = i.password();
          }
        }
        externalIdsUpdate.insert(ExternalId.create(key, user.getAccountId(), null, password));
      } catch (OrmDuplicateKeyException dupeErr) {
        // If we are using this identity, don't report the exception.
        //
        ExternalId other = externalIds.get(key);
        if (other != null && other.accountId().equals(user.getAccountId())) {
          return VoidResult.INSTANCE;
        }

        // Otherwise, someone else has this identity.
        //
        throw new NameAlreadyUsedException(newUsername);
      }
    }

    // If we have any older user names, remove them.
    //
    externalIdsUpdate.delete(old);
    for (ExternalId extId : old) {
      sshKeyCache.evict(extId.key().id());
    }

    sshKeyCache.evict(newUsername);
    return VoidResult.INSTANCE;
  }
}

@@ -1454,37 +1454,8 @@
 on;%0A
-import java.util.Collection;%0A
 impo
@@ -1484,24 +1484,24 @@
 t.Callable;%0A
+
 import java.
@@ -2864,37 +2864,13 @@
     
-Collection%3CExternalId%3E old = 
+if (!
 exte
@@ -2928,22 +2928,8 @@
 AME)
-;%0A    if (!old
 .isE
@@ -3360,172 +3360,8 @@
 y %7B%0A
-        String password = null;%0A        for (ExternalId i : old) %7B%0A          if (i.password() != null) %7B%0A            password = i.password();%0A          %7D%0A        %7D%0A
     
@@ -3443,16 +3443,12 @@
 ll, 
-password
+null
 ));%0A
@@ -3873,24 +3873,24 @@
 wUsername);%0A
+
       %7D%0A    
@@ -3896,188 +3896,8 @@
  %7D%0A%0A
-    // If we have any older user names, remove them.%0A    //%0A    externalIdsUpdate.delete(old);%0A    for (ExternalId extId : old) %7B%0A      sshKeyCache.evict(extId.key().id());%0A    %7D%0A%0A
     

Remove unused handling of old usernames