Reindex account whenever account is evicted from cache
Change-Id: I025cabc9be98628777066cda7aa97186f5a0da15 Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
		@@ -66,6 +66,7 @@ import org.junit.After;
 | 
				
			|||||||
import org.junit.Before;
 | 
					import org.junit.Before;
 | 
				
			||||||
import org.junit.Test;
 | 
					import org.junit.Test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.Arrays;
 | 
					import java.util.Arrays;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
@@ -154,7 +155,7 @@ public class GerritPublicKeyCheckerTest {
 | 
				
			|||||||
    return userFactory.create(id);
 | 
					    return userFactory.create(id);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private IdentifiedUser reloadUser() {
 | 
					  private IdentifiedUser reloadUser() throws IOException {
 | 
				
			||||||
    accountCache.evict(userId);
 | 
					    accountCache.evict(userId);
 | 
				
			||||||
    user = userFactory.create(userId);
 | 
					    user = userFactory.create(userId);
 | 
				
			||||||
    return user;
 | 
					    return user;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -219,7 +219,7 @@ class BecomeAnyAccountLoginServlet extends HttpServlet {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private AuthResult create() {
 | 
					  private AuthResult create() throws IOException {
 | 
				
			||||||
    String fakeId = AccountExternalId.SCHEME_UUID + UUID.randomUUID();
 | 
					    String fakeId = AccountExternalId.SCHEME_UUID + UUID.randomUUID();
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      return accountManager.authenticate(new AuthRequest(fakeId));
 | 
					      return accountManager.authenticate(new AuthRequest(fakeId));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -153,7 +153,7 @@ class HttpLoginServlet extends HttpServlet {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private void updateRemoteExternalId(AuthResult arsp, String remoteAuthToken)
 | 
					  private void updateRemoteExternalId(AuthResult arsp, String remoteAuthToken)
 | 
				
			||||||
      throws AccountException, OrmException {
 | 
					      throws AccountException, OrmException, IOException {
 | 
				
			||||||
    AccountExternalId remoteAuthExtId =
 | 
					    AccountExternalId remoteAuthExtId =
 | 
				
			||||||
        new AccountExternalId(arsp.getAccountId(), new AccountExternalId.Key(
 | 
					        new AccountExternalId(arsp.getAccountId(), new AccountExternalId.Key(
 | 
				
			||||||
            SCHEME_EXTERNAL, remoteAuthToken));
 | 
					            SCHEME_EXTERNAL, remoteAuthToken));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,8 @@ import com.google.gwtorm.server.OrmException;
 | 
				
			|||||||
import com.google.gwtorm.server.OrmRuntimeException;
 | 
					import com.google.gwtorm.server.OrmRuntimeException;
 | 
				
			||||||
import com.google.inject.Provider;
 | 
					import com.google.inject.Provider;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Support for services which require a {@link ReviewDb} instance. */
 | 
					/** Support for services which require a {@link ReviewDb} instance. */
 | 
				
			||||||
public class BaseServiceImplementation {
 | 
					public class BaseServiceImplementation {
 | 
				
			||||||
  private final Provider<ReviewDb> schema;
 | 
					  private final Provider<ReviewDb> schema;
 | 
				
			||||||
@@ -86,6 +88,8 @@ public class BaseServiceImplementation {
 | 
				
			|||||||
      handleOrmException(callback, ex);
 | 
					      handleOrmException(callback, ex);
 | 
				
			||||||
    } catch (OrmException e) {
 | 
					    } catch (OrmException e) {
 | 
				
			||||||
      handleOrmException(callback, e);
 | 
					      handleOrmException(callback, e);
 | 
				
			||||||
 | 
					    } catch (IOException e) {
 | 
				
			||||||
 | 
					      callback.onFailure(e);
 | 
				
			||||||
    } catch (Failure e) {
 | 
					    } catch (Failure e) {
 | 
				
			||||||
      if (e.getCause() instanceof NoSuchProjectException
 | 
					      if (e.getCause() instanceof NoSuchProjectException
 | 
				
			||||||
          || e.getCause() instanceof NoSuchChangeException) {
 | 
					          || e.getCause() instanceof NoSuchChangeException) {
 | 
				
			||||||
@@ -132,6 +136,6 @@ public class BaseServiceImplementation {
 | 
				
			|||||||
     * @throws InvalidQueryException
 | 
					     * @throws InvalidQueryException
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    T run(ReviewDb db) throws OrmException, Failure, NoSuchProjectException,
 | 
					    T run(ReviewDb db) throws OrmException, Failure, NoSuchProjectException,
 | 
				
			||||||
        NoSuchGroupException, InvalidQueryException;
 | 
					        NoSuchGroupException, InvalidQueryException, IOException;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,6 +40,7 @@ import com.google.gwtorm.server.OrmException;
 | 
				
			|||||||
import com.google.inject.Inject;
 | 
					import com.google.inject.Inject;
 | 
				
			||||||
import com.google.inject.Provider;
 | 
					import com.google.inject.Provider;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Set;
 | 
					import java.util.Set;
 | 
				
			||||||
@@ -98,7 +99,8 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
 | 
				
			|||||||
      final AsyncCallback<Account> callback) {
 | 
					      final AsyncCallback<Account> callback) {
 | 
				
			||||||
    run(callback, new Action<Account>() {
 | 
					    run(callback, new Action<Account>() {
 | 
				
			||||||
      @Override
 | 
					      @Override
 | 
				
			||||||
      public Account run(ReviewDb db) throws OrmException, Failure {
 | 
					      public Account run(ReviewDb db)
 | 
				
			||||||
 | 
					          throws OrmException, Failure, IOException {
 | 
				
			||||||
        IdentifiedUser self = user.get();
 | 
					        IdentifiedUser self = user.get();
 | 
				
			||||||
        final Account me = db.accounts().get(self.getAccountId());
 | 
					        final Account me = db.accounts().get(self.getAccountId());
 | 
				
			||||||
        final String oldEmail = me.getPreferredEmail();
 | 
					        final String oldEmail = me.getPreferredEmail();
 | 
				
			||||||
@@ -133,7 +135,8 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
 | 
				
			|||||||
      final AsyncCallback<VoidResult> callback) {
 | 
					      final AsyncCallback<VoidResult> callback) {
 | 
				
			||||||
    run(callback, new Action<VoidResult>() {
 | 
					    run(callback, new Action<VoidResult>() {
 | 
				
			||||||
      @Override
 | 
					      @Override
 | 
				
			||||||
      public VoidResult run(final ReviewDb db) throws OrmException, Failure {
 | 
					      public VoidResult run(final ReviewDb db)
 | 
				
			||||||
 | 
					          throws OrmException, Failure, IOException {
 | 
				
			||||||
        ContributorAgreement ca = projectCache.getAllProjects().getConfig()
 | 
					        ContributorAgreement ca = projectCache.getAllProjects().getConfig()
 | 
				
			||||||
            .getContributorAgreement(agreementName);
 | 
					            .getContributorAgreement(agreementName);
 | 
				
			||||||
        if (ca == null) {
 | 
					        if (ca == null) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@ import com.google.gwtorm.server.OrmException;
 | 
				
			|||||||
import com.google.inject.Inject;
 | 
					import com.google.inject.Inject;
 | 
				
			||||||
import com.google.inject.assistedinject.Assisted;
 | 
					import com.google.inject.assistedinject.Assisted;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.HashSet;
 | 
					import java.util.HashSet;
 | 
				
			||||||
@@ -60,7 +61,7 @@ class DeleteExternalIds extends Handler<Set<AccountExternalId.Key>> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public Set<AccountExternalId.Key> call() throws OrmException {
 | 
					  public Set<AccountExternalId.Key> call() throws OrmException, IOException {
 | 
				
			||||||
    final Map<AccountExternalId.Key, AccountExternalId> have = have();
 | 
					    final Map<AccountExternalId.Key, AccountExternalId> have = have();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    List<AccountExternalId> toDelete = new ArrayList<>();
 | 
					    List<AccountExternalId> toDelete = new ArrayList<>();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,8 @@ package com.google.gerrit.server.account;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import com.google.gerrit.reviewdb.client.Account;
 | 
					import com.google.gerrit.reviewdb.client.Account;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Caches important (but small) account state to avoid database hits. */
 | 
					/** Caches important (but small) account state to avoid database hits. */
 | 
				
			||||||
public interface AccountCache {
 | 
					public interface AccountCache {
 | 
				
			||||||
  AccountState get(Account.Id accountId);
 | 
					  AccountState get(Account.Id accountId);
 | 
				
			||||||
@@ -24,7 +26,7 @@ public interface AccountCache {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  AccountState getByUsername(String username);
 | 
					  AccountState getByUsername(String username);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void evict(Account.Id accountId);
 | 
					  void evict(Account.Id accountId) throws IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void evictByUsername(String username);
 | 
					  void evictByUsername(String username);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,8 @@ import com.google.gerrit.reviewdb.client.AccountGroup;
 | 
				
			|||||||
import com.google.gerrit.reviewdb.client.AccountGroupMember;
 | 
					import com.google.gerrit.reviewdb.client.AccountGroupMember;
 | 
				
			||||||
import com.google.gerrit.reviewdb.server.ReviewDb;
 | 
					import com.google.gerrit.reviewdb.server.ReviewDb;
 | 
				
			||||||
import com.google.gerrit.server.cache.CacheModule;
 | 
					import com.google.gerrit.server.cache.CacheModule;
 | 
				
			||||||
 | 
					import com.google.gerrit.server.index.Index;
 | 
				
			||||||
 | 
					import com.google.gerrit.server.index.account.AccountIndexCollection;
 | 
				
			||||||
import com.google.gwtorm.server.OrmException;
 | 
					import com.google.gwtorm.server.OrmException;
 | 
				
			||||||
import com.google.gwtorm.server.SchemaFactory;
 | 
					import com.google.gwtorm.server.SchemaFactory;
 | 
				
			||||||
import com.google.inject.Inject;
 | 
					import com.google.inject.Inject;
 | 
				
			||||||
@@ -74,12 +76,15 @@ public class AccountCacheImpl implements AccountCache {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  private final LoadingCache<Account.Id, AccountState> byId;
 | 
					  private final LoadingCache<Account.Id, AccountState> byId;
 | 
				
			||||||
  private final LoadingCache<String, Optional<Account.Id>> byName;
 | 
					  private final LoadingCache<String, Optional<Account.Id>> byName;
 | 
				
			||||||
 | 
					  private final AccountIndexCollection indexes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Inject
 | 
					  @Inject
 | 
				
			||||||
  AccountCacheImpl(@Named(BYID_NAME) LoadingCache<Account.Id, AccountState> byId,
 | 
					  AccountCacheImpl(@Named(BYID_NAME) LoadingCache<Account.Id, AccountState> byId,
 | 
				
			||||||
      @Named(BYUSER_NAME) LoadingCache<String, Optional<Account.Id>> byUsername) {
 | 
					      @Named(BYUSER_NAME) LoadingCache<String, Optional<Account.Id>> byUsername,
 | 
				
			||||||
 | 
					      AccountIndexCollection indexes) {
 | 
				
			||||||
    this.byId = byId;
 | 
					    this.byId = byId;
 | 
				
			||||||
    this.byName = byUsername;
 | 
					    this.byName = byUsername;
 | 
				
			||||||
 | 
					    this.indexes = indexes;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
@@ -109,9 +114,16 @@ public class AccountCacheImpl implements AccountCache {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public void evict(Account.Id accountId) {
 | 
					  public void evict(Account.Id accountId) throws IOException {
 | 
				
			||||||
    if (accountId != null) {
 | 
					    if (accountId != null) {
 | 
				
			||||||
      byId.invalidate(accountId);
 | 
					      byId.invalidate(accountId);
 | 
				
			||||||
 | 
					      index(accountId);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private void index(Account.Id id) throws IOException {
 | 
				
			||||||
 | 
					    for (Index<?, AccountState> i : indexes.getWriteIndexes()) {
 | 
				
			||||||
 | 
					      i.replace(get(id));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,7 @@ import com.google.inject.Singleton;
 | 
				
			|||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
@@ -101,7 +102,8 @@ public class AccountManager {
 | 
				
			|||||||
   * @throws AccountException the account does not exist, and cannot be created,
 | 
					   * @throws AccountException the account does not exist, and cannot be created,
 | 
				
			||||||
   *         or exists, but cannot be located, or is inactive.
 | 
					   *         or exists, but cannot be located, or is inactive.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  public AuthResult authenticate(AuthRequest who) throws AccountException {
 | 
					  public AuthResult authenticate(AuthRequest who)
 | 
				
			||||||
 | 
					      throws AccountException, IOException {
 | 
				
			||||||
    who = realm.authenticate(who);
 | 
					    who = realm.authenticate(who);
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      try (ReviewDb db = schema.open()) {
 | 
					      try (ReviewDb db = schema.open()) {
 | 
				
			||||||
@@ -152,7 +154,8 @@ public class AccountManager {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private void update(ReviewDb db, AuthRequest who, AccountExternalId extId)
 | 
					  private void update(ReviewDb db, AuthRequest who, AccountExternalId extId)
 | 
				
			||||||
      throws OrmException, NameAlreadyUsedException, InvalidUserNameException {
 | 
					      throws OrmException, NameAlreadyUsedException, InvalidUserNameException,
 | 
				
			||||||
 | 
					      IOException {
 | 
				
			||||||
    IdentifiedUser user = userFactory.create(extId.getAccountId());
 | 
					    IdentifiedUser user = userFactory.create(extId.getAccountId());
 | 
				
			||||||
    Account toUpdate = null;
 | 
					    Account toUpdate = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -214,7 +217,7 @@ public class AccountManager {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private AuthResult create(ReviewDb db, AuthRequest who)
 | 
					  private AuthResult create(ReviewDb db, AuthRequest who)
 | 
				
			||||||
      throws OrmException, AccountException {
 | 
					      throws OrmException, AccountException, IOException {
 | 
				
			||||||
    Account.Id newId = new Account.Id(db.nextAccountId());
 | 
					    Account.Id newId = new Account.Id(db.nextAccountId());
 | 
				
			||||||
    Account account = new Account(newId, TimeUtil.nowTs());
 | 
					    Account account = new Account(newId, TimeUtil.nowTs());
 | 
				
			||||||
    AccountExternalId extId = createId(newId, who);
 | 
					    AccountExternalId extId = createId(newId, who);
 | 
				
			||||||
@@ -340,7 +343,7 @@ public class AccountManager {
 | 
				
			|||||||
   *         cannot be linked at this time.
 | 
					   *         cannot be linked at this time.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  public AuthResult link(Account.Id to, AuthRequest who)
 | 
					  public AuthResult link(Account.Id to, AuthRequest who)
 | 
				
			||||||
      throws AccountException, OrmException {
 | 
					      throws AccountException, OrmException, IOException {
 | 
				
			||||||
    try (ReviewDb db = schema.open()) {
 | 
					    try (ReviewDb db = schema.open()) {
 | 
				
			||||||
      AccountExternalId.Key key = id(who);
 | 
					      AccountExternalId.Key key = id(who);
 | 
				
			||||||
      AccountExternalId extId = getAccountExternalId(db, key);
 | 
					      AccountExternalId extId = getAccountExternalId(db, key);
 | 
				
			||||||
@@ -392,7 +395,7 @@ public class AccountManager {
 | 
				
			|||||||
   *         cannot be linked at this time.
 | 
					   *         cannot be linked at this time.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  public AuthResult updateLink(Account.Id to, AuthRequest who) throws OrmException,
 | 
					  public AuthResult updateLink(Account.Id to, AuthRequest who) throws OrmException,
 | 
				
			||||||
      AccountException {
 | 
					      AccountException, IOException {
 | 
				
			||||||
    try (ReviewDb db = schema.open()) {
 | 
					    try (ReviewDb db = schema.open()) {
 | 
				
			||||||
      AccountExternalId.Key key = id(who);
 | 
					      AccountExternalId.Key key = id(who);
 | 
				
			||||||
      List<AccountExternalId.Key> filteredKeysByScheme =
 | 
					      List<AccountExternalId.Key> filteredKeysByScheme =
 | 
				
			||||||
@@ -429,7 +432,7 @@ public class AccountManager {
 | 
				
			|||||||
   *         cannot be unlinked at this time.
 | 
					   *         cannot be unlinked at this time.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  public AuthResult unlink(Account.Id from, AuthRequest who)
 | 
					  public AuthResult unlink(Account.Id from, AuthRequest who)
 | 
				
			||||||
      throws AccountException, OrmException {
 | 
					      throws AccountException, OrmException, IOException {
 | 
				
			||||||
    try (ReviewDb db = schema.open()) {
 | 
					    try (ReviewDb db = schema.open()) {
 | 
				
			||||||
      AccountExternalId.Key key = id(who);
 | 
					      AccountExternalId.Key key = id(who);
 | 
				
			||||||
      AccountExternalId extId = getAccountExternalId(db, key);
 | 
					      AccountExternalId extId = getAccountExternalId(db, key);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,7 @@ import com.google.gwtorm.server.OrmException;
 | 
				
			|||||||
import com.google.inject.Inject;
 | 
					import com.google.inject.Inject;
 | 
				
			||||||
import com.google.inject.assistedinject.Assisted;
 | 
					import com.google.inject.assistedinject.Assisted;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.Collection;
 | 
					import java.util.Collection;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
@@ -71,7 +72,7 @@ public class ChangeUserName implements Callable<VoidResult> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public VoidResult call() throws OrmException, NameAlreadyUsedException,
 | 
					  public VoidResult call() throws OrmException, NameAlreadyUsedException,
 | 
				
			||||||
      InvalidUserNameException {
 | 
					      InvalidUserNameException, IOException {
 | 
				
			||||||
    final Collection<AccountExternalId> old = old();
 | 
					    final Collection<AccountExternalId> old = old();
 | 
				
			||||||
    if (!old.isEmpty()) {
 | 
					    if (!old.isEmpty()) {
 | 
				
			||||||
      throw new IllegalStateException(USERNAME_CANNOT_BE_CHANGED);
 | 
					      throw new IllegalStateException(USERNAME_CANNOT_BE_CHANGED);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,6 +39,8 @@ import org.apache.commons.validator.routines.EmailValidator;
 | 
				
			|||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class CreateEmail implements RestModifyView<AccountResource, EmailInput> {
 | 
					public class CreateEmail implements RestModifyView<AccountResource, EmailInput> {
 | 
				
			||||||
  private static final Logger log = LoggerFactory.getLogger(CreateEmail.class);
 | 
					  private static final Logger log = LoggerFactory.getLogger(CreateEmail.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -75,7 +77,7 @@ public class CreateEmail implements RestModifyView<AccountResource, EmailInput>
 | 
				
			|||||||
  public Response<EmailInfo> apply(AccountResource rsrc, EmailInput input)
 | 
					  public Response<EmailInfo> apply(AccountResource rsrc, EmailInput input)
 | 
				
			||||||
      throws AuthException, BadRequestException, ResourceConflictException,
 | 
					      throws AuthException, BadRequestException, ResourceConflictException,
 | 
				
			||||||
      ResourceNotFoundException, OrmException, EmailException,
 | 
					      ResourceNotFoundException, OrmException, EmailException,
 | 
				
			||||||
      MethodNotAllowedException {
 | 
					      MethodNotAllowedException, IOException {
 | 
				
			||||||
    if (self.get() != rsrc.getUser()
 | 
					    if (self.get() != rsrc.getUser()
 | 
				
			||||||
        && !self.get().getCapabilities().canModifyAccount()) {
 | 
					        && !self.get().getCapabilities().canModifyAccount()) {
 | 
				
			||||||
      throw new AuthException("not allowed to add email address");
 | 
					      throw new AuthException("not allowed to add email address");
 | 
				
			||||||
@@ -104,7 +106,7 @@ public class CreateEmail implements RestModifyView<AccountResource, EmailInput>
 | 
				
			|||||||
  public Response<EmailInfo> apply(IdentifiedUser user, EmailInput input)
 | 
					  public Response<EmailInfo> apply(IdentifiedUser user, EmailInput input)
 | 
				
			||||||
      throws AuthException, BadRequestException, ResourceConflictException,
 | 
					      throws AuthException, BadRequestException, ResourceConflictException,
 | 
				
			||||||
      ResourceNotFoundException, OrmException, EmailException,
 | 
					      ResourceNotFoundException, OrmException, EmailException,
 | 
				
			||||||
      MethodNotAllowedException {
 | 
					      MethodNotAllowedException, IOException {
 | 
				
			||||||
    if (input.email != null && !email.equals(input.email)) {
 | 
					    if (input.email != null && !email.equals(input.email)) {
 | 
				
			||||||
      throw new BadRequestException("email address must match URL");
 | 
					      throw new BadRequestException("email address must match URL");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,7 @@ import com.google.inject.Inject;
 | 
				
			|||||||
import com.google.inject.Provider;
 | 
					import com.google.inject.Provider;
 | 
				
			||||||
import com.google.inject.Singleton;
 | 
					import com.google.inject.Singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RequiresCapability(GlobalCapability.MODIFY_ACCOUNT)
 | 
					@RequiresCapability(GlobalCapability.MODIFY_ACCOUNT)
 | 
				
			||||||
@@ -46,7 +47,7 @@ public class DeleteActive implements RestModifyView<AccountResource, Input> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public Response<?> apply(AccountResource rsrc, Input input)
 | 
					  public Response<?> apply(AccountResource rsrc, Input input)
 | 
				
			||||||
      throws ResourceNotFoundException, OrmException {
 | 
					      throws ResourceNotFoundException, OrmException, IOException {
 | 
				
			||||||
    Account a = dbProvider.get().accounts().get(rsrc.getUser().getAccountId());
 | 
					    Account a = dbProvider.get().accounts().get(rsrc.getUser().getAccountId());
 | 
				
			||||||
    if (a == null) {
 | 
					    if (a == null) {
 | 
				
			||||||
      throw new ResourceNotFoundException("account not found");
 | 
					      throw new ResourceNotFoundException("account not found");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,8 @@ import com.google.inject.Inject;
 | 
				
			|||||||
import com.google.inject.Provider;
 | 
					import com.google.inject.Provider;
 | 
				
			||||||
import com.google.inject.Singleton;
 | 
					import com.google.inject.Singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Singleton
 | 
					@Singleton
 | 
				
			||||||
public class DeleteEmail implements RestModifyView<AccountResource.Email, Input> {
 | 
					public class DeleteEmail implements RestModifyView<AccountResource.Email, Input> {
 | 
				
			||||||
  public static class Input {
 | 
					  public static class Input {
 | 
				
			||||||
@@ -53,7 +55,8 @@ public class DeleteEmail implements RestModifyView<AccountResource.Email, Input>
 | 
				
			|||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public Response<?> apply(AccountResource.Email rsrc, Input input)
 | 
					  public Response<?> apply(AccountResource.Email rsrc, Input input)
 | 
				
			||||||
      throws AuthException, ResourceNotFoundException,
 | 
					      throws AuthException, ResourceNotFoundException,
 | 
				
			||||||
      ResourceConflictException, MethodNotAllowedException, OrmException {
 | 
					      ResourceConflictException, MethodNotAllowedException, OrmException,
 | 
				
			||||||
 | 
					      IOException {
 | 
				
			||||||
    if (self.get() != rsrc.getUser()
 | 
					    if (self.get() != rsrc.getUser()
 | 
				
			||||||
        && !self.get().getCapabilities().canModifyAccount()) {
 | 
					        && !self.get().getCapabilities().canModifyAccount()) {
 | 
				
			||||||
      throw new AuthException("not allowed to delete email address");
 | 
					      throw new AuthException("not allowed to delete email address");
 | 
				
			||||||
@@ -63,7 +66,7 @@ public class DeleteEmail implements RestModifyView<AccountResource.Email, Input>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  public Response<?> apply(IdentifiedUser user, String email)
 | 
					  public Response<?> apply(IdentifiedUser user, String email)
 | 
				
			||||||
      throws ResourceNotFoundException, ResourceConflictException,
 | 
					      throws ResourceNotFoundException, ResourceConflictException,
 | 
				
			||||||
      MethodNotAllowedException, OrmException {
 | 
					      MethodNotAllowedException, OrmException, IOException {
 | 
				
			||||||
    if (!realm.allowsEdit(FieldName.REGISTER_NEW_EMAIL)) {
 | 
					    if (!realm.allowsEdit(FieldName.REGISTER_NEW_EMAIL)) {
 | 
				
			||||||
      throw new MethodNotAllowedException("realm does not allow deleting emails");
 | 
					      throw new MethodNotAllowedException("realm does not allow deleting emails");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,7 @@ import com.google.inject.Inject;
 | 
				
			|||||||
import com.google.inject.Provider;
 | 
					import com.google.inject.Provider;
 | 
				
			||||||
import com.google.inject.Singleton;
 | 
					import com.google.inject.Singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RequiresCapability(GlobalCapability.MODIFY_ACCOUNT)
 | 
					@RequiresCapability(GlobalCapability.MODIFY_ACCOUNT)
 | 
				
			||||||
@@ -46,7 +47,7 @@ public class PutActive implements RestModifyView<AccountResource, Input> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public Response<String> apply(AccountResource rsrc, Input input)
 | 
					  public Response<String> apply(AccountResource rsrc, Input input)
 | 
				
			||||||
      throws ResourceNotFoundException, OrmException {
 | 
					      throws ResourceNotFoundException, OrmException, IOException {
 | 
				
			||||||
    Account a = dbProvider.get().accounts().get(rsrc.getUser().getAccountId());
 | 
					    Account a = dbProvider.get().accounts().get(rsrc.getUser().getAccountId());
 | 
				
			||||||
    if (a == null) {
 | 
					    if (a == null) {
 | 
				
			||||||
      throw new ResourceNotFoundException("account not found");
 | 
					      throw new ResourceNotFoundException("account not found");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,7 @@ import com.google.inject.Singleton;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import org.apache.commons.codec.binary.Base64;
 | 
					import org.apache.commons.codec.binary.Base64;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.security.NoSuchAlgorithmException;
 | 
					import java.security.NoSuchAlgorithmException;
 | 
				
			||||||
import java.security.SecureRandom;
 | 
					import java.security.SecureRandom;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
@@ -69,8 +70,9 @@ public class PutHttpPassword implements RestModifyView<AccountResource, Input> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public Response<String> apply(AccountResource rsrc, Input input) throws AuthException,
 | 
					  public Response<String> apply(AccountResource rsrc, Input input)
 | 
				
			||||||
      ResourceNotFoundException, ResourceConflictException, OrmException {
 | 
					      throws AuthException, ResourceNotFoundException,
 | 
				
			||||||
 | 
					      ResourceConflictException, OrmException, IOException {
 | 
				
			||||||
    if (input == null) {
 | 
					    if (input == null) {
 | 
				
			||||||
      input = new Input();
 | 
					      input = new Input();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -101,7 +103,8 @@ public class PutHttpPassword implements RestModifyView<AccountResource, Input> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public Response<String> apply(IdentifiedUser user, String newPassword)
 | 
					  public Response<String> apply(IdentifiedUser user, String newPassword)
 | 
				
			||||||
      throws ResourceNotFoundException, ResourceConflictException, OrmException {
 | 
					      throws ResourceNotFoundException, ResourceConflictException, OrmException,
 | 
				
			||||||
 | 
					      IOException {
 | 
				
			||||||
    if (user.getUserName() == null) {
 | 
					    if (user.getUserName() == null) {
 | 
				
			||||||
      throw new ResourceConflictException("username must be set");
 | 
					      throw new ResourceConflictException("username must be set");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,7 @@ import com.google.inject.Inject;
 | 
				
			|||||||
import com.google.inject.Provider;
 | 
					import com.google.inject.Provider;
 | 
				
			||||||
import com.google.inject.Singleton;
 | 
					import com.google.inject.Singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Singleton
 | 
					@Singleton
 | 
				
			||||||
@@ -62,7 +63,7 @@ public class PutName implements RestModifyView<AccountResource, Input> {
 | 
				
			|||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public Response<String> apply(AccountResource rsrc, Input input)
 | 
					  public Response<String> apply(AccountResource rsrc, Input input)
 | 
				
			||||||
      throws AuthException, MethodNotAllowedException,
 | 
					      throws AuthException, MethodNotAllowedException,
 | 
				
			||||||
      ResourceNotFoundException, OrmException {
 | 
					      ResourceNotFoundException, OrmException, IOException {
 | 
				
			||||||
    if (self.get() != rsrc.getUser()
 | 
					    if (self.get() != rsrc.getUser()
 | 
				
			||||||
        && !self.get().getCapabilities().canModifyAccount()) {
 | 
					        && !self.get().getCapabilities().canModifyAccount()) {
 | 
				
			||||||
      throw new AuthException("not allowed to change name");
 | 
					      throw new AuthException("not allowed to change name");
 | 
				
			||||||
@@ -71,7 +72,8 @@ public class PutName implements RestModifyView<AccountResource, Input> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public Response<String> apply(IdentifiedUser user, Input input)
 | 
					  public Response<String> apply(IdentifiedUser user, Input input)
 | 
				
			||||||
      throws MethodNotAllowedException, ResourceNotFoundException, OrmException {
 | 
					      throws MethodNotAllowedException, ResourceNotFoundException, OrmException,
 | 
				
			||||||
 | 
					      IOException {
 | 
				
			||||||
    if (input == null) {
 | 
					    if (input == null) {
 | 
				
			||||||
      input = new Input();
 | 
					      input = new Input();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,7 @@ import com.google.inject.Inject;
 | 
				
			|||||||
import com.google.inject.Provider;
 | 
					import com.google.inject.Provider;
 | 
				
			||||||
import com.google.inject.Singleton;
 | 
					import com.google.inject.Singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Singleton
 | 
					@Singleton
 | 
				
			||||||
@@ -50,7 +51,8 @@ public class PutPreferred implements
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public Response<String> apply(AccountResource.Email rsrc, Input input)
 | 
					  public Response<String> apply(AccountResource.Email rsrc, Input input)
 | 
				
			||||||
      throws AuthException, ResourceNotFoundException, OrmException {
 | 
					      throws AuthException, ResourceNotFoundException, OrmException,
 | 
				
			||||||
 | 
					      IOException {
 | 
				
			||||||
    if (self.get() != rsrc.getUser()
 | 
					    if (self.get() != rsrc.getUser()
 | 
				
			||||||
        && !self.get().getCapabilities().canModifyAccount()) {
 | 
					        && !self.get().getCapabilities().canModifyAccount()) {
 | 
				
			||||||
      throw new AuthException("not allowed to set preferred email address");
 | 
					      throw new AuthException("not allowed to set preferred email address");
 | 
				
			||||||
@@ -59,7 +61,7 @@ public class PutPreferred implements
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public Response<String> apply(IdentifiedUser user, String email)
 | 
					  public Response<String> apply(IdentifiedUser user, String email)
 | 
				
			||||||
      throws ResourceNotFoundException, OrmException {
 | 
					      throws ResourceNotFoundException, OrmException, IOException {
 | 
				
			||||||
    Account a = dbProvider.get().accounts().get(user.getAccountId());
 | 
					    Account a = dbProvider.get().accounts().get(user.getAccountId());
 | 
				
			||||||
    if (a == null) {
 | 
					    if (a == null) {
 | 
				
			||||||
      throw new ResourceNotFoundException("account not found");
 | 
					      throw new ResourceNotFoundException("account not found");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,8 @@ import com.google.inject.Inject;
 | 
				
			|||||||
import com.google.inject.Provider;
 | 
					import com.google.inject.Provider;
 | 
				
			||||||
import com.google.inject.Singleton;
 | 
					import com.google.inject.Singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Singleton
 | 
					@Singleton
 | 
				
			||||||
public class PutUsername implements RestModifyView<AccountResource, Input> {
 | 
					public class PutUsername implements RestModifyView<AccountResource, Input> {
 | 
				
			||||||
  public static class Input {
 | 
					  public static class Input {
 | 
				
			||||||
@@ -56,7 +58,7 @@ public class PutUsername implements RestModifyView<AccountResource, Input> {
 | 
				
			|||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public String apply(AccountResource rsrc, Input input) throws AuthException,
 | 
					  public String apply(AccountResource rsrc, Input input) throws AuthException,
 | 
				
			||||||
      MethodNotAllowedException, UnprocessableEntityException,
 | 
					      MethodNotAllowedException, UnprocessableEntityException,
 | 
				
			||||||
      ResourceConflictException, OrmException {
 | 
					      ResourceConflictException, OrmException, IOException {
 | 
				
			||||||
    if (self.get() != rsrc.getUser()
 | 
					    if (self.get() != rsrc.getUser()
 | 
				
			||||||
        && !self.get().getCapabilities().canAdministrateServer()) {
 | 
					        && !self.get().getCapabilities().canAdministrateServer()) {
 | 
				
			||||||
      throw new AuthException("not allowed to set username");
 | 
					      throw new AuthException("not allowed to set username");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -311,7 +311,7 @@ public class AccountApiImpl implements AccountApi {
 | 
				
			|||||||
        new AccountResource.Email(account.getUser(), input.email);
 | 
					        new AccountResource.Email(account.getUser(), input.email);
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      createEmailFactory.create(input.email).apply(rsrc, input);
 | 
					      createEmailFactory.create(input.email).apply(rsrc, input);
 | 
				
			||||||
    } catch (EmailException | OrmException e) {
 | 
					    } catch (EmailException | OrmException | IOException e) {
 | 
				
			||||||
      throw new RestApiException("Cannot add email", e);
 | 
					      throw new RestApiException("Cannot add email", e);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,6 +44,7 @@ import com.google.gwtorm.server.OrmException;
 | 
				
			|||||||
import com.google.inject.assistedinject.Assisted;
 | 
					import com.google.inject.assistedinject.Assisted;
 | 
				
			||||||
import com.google.inject.assistedinject.AssistedInject;
 | 
					import com.google.inject.assistedinject.AssistedInject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.Arrays;
 | 
					import java.util.Arrays;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -217,7 +218,7 @@ class GroupApiImpl implements GroupApi {
 | 
				
			|||||||
    try {
 | 
					    try {
 | 
				
			||||||
      addMembers.apply(
 | 
					      addMembers.apply(
 | 
				
			||||||
          rsrc, AddMembers.Input.fromMembers(Arrays.asList(members)));
 | 
					          rsrc, AddMembers.Input.fromMembers(Arrays.asList(members)));
 | 
				
			||||||
    } catch (OrmException e) {
 | 
					    } catch (OrmException | IOException e) {
 | 
				
			||||||
      throw new RestApiException("Cannot add group members", e);
 | 
					      throw new RestApiException("Cannot add group members", e);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -227,7 +228,7 @@ class GroupApiImpl implements GroupApi {
 | 
				
			|||||||
    try {
 | 
					    try {
 | 
				
			||||||
      deleteMembers.apply(
 | 
					      deleteMembers.apply(
 | 
				
			||||||
          rsrc, AddMembers.Input.fromMembers(Arrays.asList(members)));
 | 
					          rsrc, AddMembers.Input.fromMembers(Arrays.asList(members)));
 | 
				
			||||||
    } catch (OrmException e) {
 | 
					    } catch (OrmException | IOException e) {
 | 
				
			||||||
      throw new RestApiException("Cannot remove group members", e);
 | 
					      throw new RestApiException("Cannot remove group members", e);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -90,7 +90,7 @@ class GroupsImpl implements Groups {
 | 
				
			|||||||
      GroupInfo info = createGroup.create(in.name)
 | 
					      GroupInfo info = createGroup.create(in.name)
 | 
				
			||||||
          .apply(TopLevelResource.INSTANCE, in);
 | 
					          .apply(TopLevelResource.INSTANCE, in);
 | 
				
			||||||
      return id(info.id);
 | 
					      return id(info.id);
 | 
				
			||||||
    } catch (OrmException e) {
 | 
					    } catch (OrmException | IOException e) {
 | 
				
			||||||
      throw new RestApiException("Cannot create group " + in.name, e);
 | 
					      throw new RestApiException("Cannot create group " + in.name, e);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,6 +32,8 @@ import org.kohsuke.args4j.spi.OptionHandler;
 | 
				
			|||||||
import org.kohsuke.args4j.spi.Parameters;
 | 
					import org.kohsuke.args4j.spi.Parameters;
 | 
				
			||||||
import org.kohsuke.args4j.spi.Setter;
 | 
					import org.kohsuke.args4j.spi.Setter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class AccountIdHandler extends OptionHandler<Account.Id> {
 | 
					public class AccountIdHandler extends OptionHandler<Account.Id> {
 | 
				
			||||||
  private final AccountResolver accountResolver;
 | 
					  private final AccountResolver accountResolver;
 | 
				
			||||||
  private final AccountManager accountManager;
 | 
					  private final AccountManager accountManager;
 | 
				
			||||||
@@ -76,7 +78,7 @@ public class AccountIdHandler extends OptionHandler<Account.Id> {
 | 
				
			|||||||
            throw new CmdLineException(owner, "user \"" + token + "\" not found");
 | 
					            throw new CmdLineException(owner, "user \"" + token + "\" not found");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } catch (OrmException e) {
 | 
					    } catch (OrmException | IOException e) {
 | 
				
			||||||
      throw new CmdLineException(owner, "database is down");
 | 
					      throw new CmdLineException(owner, "database is down");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    setter.addValue(accountId);
 | 
					    setter.addValue(accountId);
 | 
				
			||||||
@@ -84,7 +86,7 @@ public class AccountIdHandler extends OptionHandler<Account.Id> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private Account.Id createAccountByLdap(String user)
 | 
					  private Account.Id createAccountByLdap(String user)
 | 
				
			||||||
      throws CmdLineException {
 | 
					      throws CmdLineException, IOException {
 | 
				
			||||||
    if (!user.matches(Account.USER_NAME_PATTERN)) {
 | 
					    if (!user.matches(Account.USER_NAME_PATTERN)) {
 | 
				
			||||||
      throw new CmdLineException(owner, "user \"" + user + "\" not found");
 | 
					      throw new CmdLineException(owner, "user \"" + user + "\" not found");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,8 @@ import com.google.inject.Inject;
 | 
				
			|||||||
import com.google.inject.Provider;
 | 
					import com.google.inject.Provider;
 | 
				
			||||||
import com.google.inject.Singleton;
 | 
					import com.google.inject.Singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Singleton
 | 
					@Singleton
 | 
				
			||||||
public class ConfirmEmail implements RestModifyView<ConfigResource, Input> {
 | 
					public class ConfirmEmail implements RestModifyView<ConfigResource, Input> {
 | 
				
			||||||
  public static class Input {
 | 
					  public static class Input {
 | 
				
			||||||
@@ -53,7 +55,7 @@ public class ConfirmEmail implements RestModifyView<ConfigResource, Input> {
 | 
				
			|||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public Response<?> apply(ConfigResource rsrc, Input input)
 | 
					  public Response<?> apply(ConfigResource rsrc, Input input)
 | 
				
			||||||
      throws AuthException, UnprocessableEntityException, AccountException,
 | 
					      throws AuthException, UnprocessableEntityException, AccountException,
 | 
				
			||||||
      OrmException {
 | 
					      OrmException, IOException {
 | 
				
			||||||
    CurrentUser user = self.get();
 | 
					    CurrentUser user = self.get();
 | 
				
			||||||
    if (!user.isIdentifiedUser()) {
 | 
					    if (!user.isIdentifiedUser()) {
 | 
				
			||||||
      throw new AuthException("Authentication required");
 | 
					      throw new AuthException("Authentication required");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,6 +45,7 @@ import com.google.inject.Inject;
 | 
				
			|||||||
import com.google.inject.Provider;
 | 
					import com.google.inject.Provider;
 | 
				
			||||||
import com.google.inject.Singleton;
 | 
					import com.google.inject.Singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.Collection;
 | 
					import java.util.Collection;
 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.HashSet;
 | 
					import java.util.HashSet;
 | 
				
			||||||
@@ -114,7 +115,7 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
 | 
				
			|||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public List<AccountInfo> apply(GroupResource resource, Input input)
 | 
					  public List<AccountInfo> apply(GroupResource resource, Input input)
 | 
				
			||||||
      throws AuthException, MethodNotAllowedException,
 | 
					      throws AuthException, MethodNotAllowedException,
 | 
				
			||||||
      UnprocessableEntityException, OrmException {
 | 
					      UnprocessableEntityException, OrmException, IOException {
 | 
				
			||||||
    AccountGroup internalGroup = resource.toAccountGroup();
 | 
					    AccountGroup internalGroup = resource.toAccountGroup();
 | 
				
			||||||
    if (internalGroup == null) {
 | 
					    if (internalGroup == null) {
 | 
				
			||||||
      throw new MethodNotAllowedException();
 | 
					      throw new MethodNotAllowedException();
 | 
				
			||||||
@@ -142,7 +143,7 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private Account findAccount(String nameOrEmail) throws AuthException,
 | 
					  private Account findAccount(String nameOrEmail) throws AuthException,
 | 
				
			||||||
      UnprocessableEntityException, OrmException {
 | 
					      UnprocessableEntityException, OrmException, IOException {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      return accounts.parse(nameOrEmail).getAccount();
 | 
					      return accounts.parse(nameOrEmail).getAccount();
 | 
				
			||||||
    } catch (UnprocessableEntityException e) {
 | 
					    } catch (UnprocessableEntityException e) {
 | 
				
			||||||
@@ -174,7 +175,8 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public void addMembers(AccountGroup.Id groupId,
 | 
					  public void addMembers(AccountGroup.Id groupId,
 | 
				
			||||||
      Collection<? extends Account.Id> newMemberIds) throws OrmException {
 | 
					      Collection<? extends Account.Id> newMemberIds)
 | 
				
			||||||
 | 
					          throws OrmException, IOException {
 | 
				
			||||||
    Map<Account.Id, AccountGroupMember> newAccountGroupMembers = new HashMap<>();
 | 
					    Map<Account.Id, AccountGroupMember> newAccountGroupMembers = new HashMap<>();
 | 
				
			||||||
    for (Account.Id accId : newMemberIds) {
 | 
					    for (Account.Id accId : newMemberIds) {
 | 
				
			||||||
      if (!newAccountGroupMembers.containsKey(accId)) {
 | 
					      if (!newAccountGroupMembers.containsKey(accId)) {
 | 
				
			||||||
@@ -197,7 +199,7 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private Account createAccountByLdap(String user) {
 | 
					  private Account createAccountByLdap(String user) throws IOException {
 | 
				
			||||||
    if (!user.matches(Account.USER_NAME_PATTERN)) {
 | 
					    if (!user.matches(Account.USER_NAME_PATTERN)) {
 | 
				
			||||||
      return null;
 | 
					      return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -238,7 +240,7 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
 | 
				
			|||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public AccountInfo apply(GroupResource resource, PutMember.Input input)
 | 
					    public AccountInfo apply(GroupResource resource, PutMember.Input input)
 | 
				
			||||||
        throws AuthException, MethodNotAllowedException,
 | 
					        throws AuthException, MethodNotAllowedException,
 | 
				
			||||||
        ResourceNotFoundException, OrmException {
 | 
					        ResourceNotFoundException, OrmException, IOException {
 | 
				
			||||||
      AddMembers.Input in = new AddMembers.Input();
 | 
					      AddMembers.Input in = new AddMembers.Input();
 | 
				
			||||||
      in._oneMember = id;
 | 
					      in._oneMember = id;
 | 
				
			||||||
      try {
 | 
					      try {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,6 +50,7 @@ import com.google.inject.assistedinject.Assisted;
 | 
				
			|||||||
import org.eclipse.jgit.lib.Config;
 | 
					import org.eclipse.jgit.lib.Config;
 | 
				
			||||||
import org.eclipse.jgit.lib.PersonIdent;
 | 
					import org.eclipse.jgit.lib.PersonIdent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Locale;
 | 
					import java.util.Locale;
 | 
				
			||||||
@@ -98,7 +99,7 @@ public class CreateGroup implements RestModifyView<TopLevelResource, GroupInput>
 | 
				
			|||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public GroupInfo apply(TopLevelResource resource, GroupInput input)
 | 
					  public GroupInfo apply(TopLevelResource resource, GroupInput input)
 | 
				
			||||||
      throws BadRequestException, UnprocessableEntityException,
 | 
					      throws BadRequestException, UnprocessableEntityException,
 | 
				
			||||||
      ResourceConflictException, OrmException {
 | 
					      ResourceConflictException, OrmException, IOException {
 | 
				
			||||||
    if (input == null) {
 | 
					    if (input == null) {
 | 
				
			||||||
      input = new GroupInput();
 | 
					      input = new GroupInput();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -138,7 +139,7 @@ public class CreateGroup implements RestModifyView<TopLevelResource, GroupInput>
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private AccountGroup createGroup(CreateGroupArgs createGroupArgs)
 | 
					  private AccountGroup createGroup(CreateGroupArgs createGroupArgs)
 | 
				
			||||||
      throws OrmException, ResourceConflictException {
 | 
					      throws OrmException, ResourceConflictException, IOException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Do not allow creating groups with the same name as system groups
 | 
					    // Do not allow creating groups with the same name as system groups
 | 
				
			||||||
    List<String> sysGroupNames = SystemGroupBackend.getNames();
 | 
					    List<String> sysGroupNames = SystemGroupBackend.getNames();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,7 @@ import com.google.inject.Inject;
 | 
				
			|||||||
import com.google.inject.Provider;
 | 
					import com.google.inject.Provider;
 | 
				
			||||||
import com.google.inject.Singleton;
 | 
					import com.google.inject.Singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.LinkedList;
 | 
					import java.util.LinkedList;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
@@ -62,7 +63,7 @@ public class DeleteMembers implements RestModifyView<GroupResource, Input> {
 | 
				
			|||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public Response<?> apply(GroupResource resource, Input input)
 | 
					  public Response<?> apply(GroupResource resource, Input input)
 | 
				
			||||||
      throws AuthException, MethodNotAllowedException,
 | 
					      throws AuthException, MethodNotAllowedException,
 | 
				
			||||||
      UnprocessableEntityException, OrmException {
 | 
					      UnprocessableEntityException, OrmException, IOException {
 | 
				
			||||||
    AccountGroup internalGroup = resource.toAccountGroup();
 | 
					    AccountGroup internalGroup = resource.toAccountGroup();
 | 
				
			||||||
    if (internalGroup == null) {
 | 
					    if (internalGroup == null) {
 | 
				
			||||||
      throw new MethodNotAllowedException();
 | 
					      throw new MethodNotAllowedException();
 | 
				
			||||||
@@ -125,7 +126,7 @@ public class DeleteMembers implements RestModifyView<GroupResource, Input> {
 | 
				
			|||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public Response<?> apply(MemberResource resource, Input input)
 | 
					    public Response<?> apply(MemberResource resource, Input input)
 | 
				
			||||||
        throws AuthException, MethodNotAllowedException,
 | 
					        throws AuthException, MethodNotAllowedException,
 | 
				
			||||||
        UnprocessableEntityException, OrmException {
 | 
					        UnprocessableEntityException, OrmException, IOException {
 | 
				
			||||||
      AddMembers.Input in = new AddMembers.Input();
 | 
					      AddMembers.Input in = new AddMembers.Input();
 | 
				
			||||||
      in._oneMember = resource.getMember().getAccountId().toString();
 | 
					      in._oneMember = resource.getMember().getAccountId().toString();
 | 
				
			||||||
      return delete.get().apply(resource, in);
 | 
					      return delete.get().apply(resource, in);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,7 @@ import com.google.common.util.concurrent.MoreExecutors;
 | 
				
			|||||||
import com.google.gerrit.lifecycle.LifecycleModule;
 | 
					import com.google.gerrit.lifecycle.LifecycleModule;
 | 
				
			||||||
import com.google.gerrit.server.config.GerritServerConfig;
 | 
					import com.google.gerrit.server.config.GerritServerConfig;
 | 
				
			||||||
import com.google.gerrit.server.git.WorkQueue;
 | 
					import com.google.gerrit.server.git.WorkQueue;
 | 
				
			||||||
 | 
					import com.google.gerrit.server.index.account.AccountIndexCollection;
 | 
				
			||||||
import com.google.gerrit.server.index.account.AccountIndexDefinition;
 | 
					import com.google.gerrit.server.index.account.AccountIndexDefinition;
 | 
				
			||||||
import com.google.gerrit.server.index.account.AccountSchemaDefinitions;
 | 
					import com.google.gerrit.server.index.account.AccountSchemaDefinitions;
 | 
				
			||||||
import com.google.gerrit.server.index.change.ChangeIndexCollection;
 | 
					import com.google.gerrit.server.index.change.ChangeIndexCollection;
 | 
				
			||||||
@@ -87,6 +88,10 @@ public class IndexModule extends LifecycleModule {
 | 
				
			|||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  protected void configure() {
 | 
					  protected void configure() {
 | 
				
			||||||
    bind(IndexRewriter.class);
 | 
					    bind(IndexRewriter.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bind(AccountIndexCollection.class);
 | 
				
			||||||
 | 
					    listener().to(AccountIndexCollection.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bind(ChangeIndexCollection.class);
 | 
					    bind(ChangeIndexCollection.class);
 | 
				
			||||||
    listener().to(ChangeIndexCollection.class);
 | 
					    listener().to(ChangeIndexCollection.class);
 | 
				
			||||||
    factory(ChangeIndexer.Factory.class);
 | 
					    factory(ChangeIndexer.Factory.class);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,6 +38,7 @@ import com.google.inject.Inject;
 | 
				
			|||||||
import org.kohsuke.args4j.Argument;
 | 
					import org.kohsuke.args4j.Argument;
 | 
				
			||||||
import org.kohsuke.args4j.Option;
 | 
					import org.kohsuke.args4j.Option;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.HashSet;
 | 
					import java.util.HashSet;
 | 
				
			||||||
import java.util.Set;
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -88,7 +89,7 @@ final class CreateGroupCommand extends SshCommand {
 | 
				
			|||||||
  private AddIncludedGroups addIncludedGroups;
 | 
					  private AddIncludedGroups addIncludedGroups;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  protected void run() throws Failure, OrmException {
 | 
					  protected void run() throws Failure, OrmException, IOException {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      GroupResource rsrc = createGroup();
 | 
					      GroupResource rsrc = createGroup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -104,7 +105,8 @@ final class CreateGroupCommand extends SshCommand {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private GroupResource createGroup() throws RestApiException, OrmException {
 | 
					  private GroupResource createGroup()
 | 
				
			||||||
 | 
					      throws RestApiException, OrmException, IOException {
 | 
				
			||||||
    GroupInput input = new GroupInput();
 | 
					    GroupInput input = new GroupInput();
 | 
				
			||||||
    input.description = groupDescription;
 | 
					    input.description = groupDescription;
 | 
				
			||||||
    input.visibleToAll = visibleToAll;
 | 
					    input.visibleToAll = visibleToAll;
 | 
				
			||||||
@@ -120,7 +122,7 @@ final class CreateGroupCommand extends SshCommand {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private void addMembers(GroupResource rsrc) throws RestApiException,
 | 
					  private void addMembers(GroupResource rsrc) throws RestApiException,
 | 
				
			||||||
      OrmException {
 | 
					      OrmException, IOException {
 | 
				
			||||||
    AddMembers.Input input =
 | 
					    AddMembers.Input input =
 | 
				
			||||||
        AddMembers.Input.fromMembers(FluentIterable
 | 
					        AddMembers.Input.fromMembers(FluentIterable
 | 
				
			||||||
            .from(initialMembers)
 | 
					            .from(initialMembers)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -256,8 +256,8 @@ final class SetAccountCommand extends SshCommand {
 | 
				
			|||||||
        new AccountResource.SshKey(user, sshKey), null);
 | 
					        new AccountResource.SshKey(user, sshKey), null);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private void addEmail(String email) throws UnloggedFailure, RestApiException,
 | 
					  private void addEmail(String email)
 | 
				
			||||||
      OrmException {
 | 
					      throws UnloggedFailure, RestApiException, OrmException, IOException {
 | 
				
			||||||
    EmailInput in = new EmailInput();
 | 
					    EmailInput in = new EmailInput();
 | 
				
			||||||
    in.email = email;
 | 
					    in.email = email;
 | 
				
			||||||
    in.noConfirmation = true;
 | 
					    in.noConfirmation = true;
 | 
				
			||||||
@@ -268,7 +268,8 @@ final class SetAccountCommand extends SshCommand {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private void deleteEmail(String email) throws RestApiException, OrmException {
 | 
					  private void deleteEmail(String email)
 | 
				
			||||||
 | 
					      throws RestApiException, OrmException, IOException {
 | 
				
			||||||
    if (email.equals("ALL")) {
 | 
					    if (email.equals("ALL")) {
 | 
				
			||||||
      List<EmailInfo> emails = getEmails.apply(rsrc);
 | 
					      List<EmailInfo> emails = getEmails.apply(rsrc);
 | 
				
			||||||
      for (EmailInfo e : emails) {
 | 
					      for (EmailInfo e : emails) {
 | 
				
			||||||
@@ -281,8 +282,8 @@ final class SetAccountCommand extends SshCommand {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private void putPreferred(String email) throws RestApiException,
 | 
					  private void putPreferred(String email)
 | 
				
			||||||
      OrmException {
 | 
					      throws RestApiException, OrmException, IOException {
 | 
				
			||||||
    for (EmailInfo e : getEmails.apply(rsrc)) {
 | 
					    for (EmailInfo e : getEmails.apply(rsrc)) {
 | 
				
			||||||
      if (e.email.equals(email)) {
 | 
					      if (e.email.equals(email)) {
 | 
				
			||||||
        putPreferred.apply(new AccountResource.Email(user, email), null);
 | 
					        putPreferred.apply(new AccountResource.Email(user, email), null);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user