Return only exact matches from InternalAccountQuery#byPreferredEmail

Doing an account query on the preferredemail field finds accounts with a
preferred email that matches the given email case insensitive or that
starts with that prefix (also case insensitive). However all callers are
only interested in exact matches. Instead of letting each caller filter
out non-exact matches do this filtering once in
InternalAccountQuery#byPreferredEmail.

Change-Id: If893d1bd8857fd69b3c2222ba104aa9ee212f936
Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
Edwin Kempin 2017-08-18 09:10:01 +02:00
parent 916112ed91
commit 790250d0c7
3 changed files with 28 additions and 15 deletions

View File

@ -223,8 +223,6 @@ class BecomeAnyAccountLoginServlet extends HttpServlet {
.get()
.byPreferredEmail(email)
.stream()
// the index query also matches prefixes, filter those out
.filter(a -> email.equalsIgnoreCase(a.getAccount().getPreferredEmail()))
.map(AccountState::getAccount)
.findFirst();
return match.isPresent() ? auth(match.get()) : null;

View File

@ -27,7 +27,6 @@ import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.IOException;
import java.util.List;
/** Class to access accounts by email. */
@Singleton
@ -61,15 +60,9 @@ public class Emails {
* @see #getAccountsFor(String...)
*/
public ImmutableSet<Account.Id> getAccountFor(String email) throws IOException, OrmException {
List<AccountState> byPreferredEmail = queryProvider.get().byPreferredEmail(email);
return Streams.concat(
externalIds.byEmail(email).stream().map(e -> e.accountId()),
byPreferredEmail
.stream()
// the index query also matches prefixes and emails with other case,
// filter those out
.filter(a -> email.equals(a.getAccount().getPreferredEmail()))
.map(a -> a.getAccount().getId()))
queryProvider.get().byPreferredEmail(email).stream().map(a -> a.getAccount().getId()))
.collect(toImmutableSet());
}
@ -91,9 +84,6 @@ public class Emails {
.byPreferredEmail(emails)
.entries()
.stream()
// the index query also matches prefixes and emails with other case,
// filter those out
.filter(e -> e.getKey().equals(e.getValue().getAccount().getPreferredEmail()))
.forEach(e -> builder.put(e.getKey(), e.getValue().getAccount().getId()));
return builder.build();
}

View File

@ -15,6 +15,7 @@
package com.google.gerrit.server.query.account;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import com.google.common.base.Joiner;
import com.google.common.collect.ArrayListMultimap;
@ -113,17 +114,41 @@ public class InternalAccountQuery extends InternalQuery<AccountState> {
return query(AccountPredicates.fullName(fullName));
}
/**
* Queries for accounts that have a preferred email that exactly matches the given email.
*
* @param email preferred email by which accounts should be found
* @return list of accounts that have a preferred email that exactly matches the given email
* @throws OrmException if query cannot be parsed
*/
public List<AccountState> byPreferredEmail(String email) throws OrmException {
return query(AccountPredicates.preferredEmail(email));
return query(AccountPredicates.preferredEmail(email))
.stream()
.filter(a -> a.getAccount().getPreferredEmail().equals(email))
.collect(toList());
}
/**
* Makes multiple queries for accounts by preferred email (exact match).
*
* @param emails preferred emails by which accounts should be found
* @return multimap of the given emails to accounts that have a preferred email that exactly
* matches this email
* @throws OrmException if query cannot be parsed
*/
public Multimap<String, AccountState> byPreferredEmail(String... emails) throws OrmException {
List<String> emailList = Arrays.asList(emails);
List<List<AccountState>> r =
query(emailList.stream().map(e -> AccountPredicates.preferredEmail(e)).collect(toList()));
Multimap<String, AccountState> accountsByEmail = ArrayListMultimap.create();
for (int i = 0; i < emailList.size(); i++) {
accountsByEmail.putAll(emailList.get(i), r.get(i));
String email = emailList.get(i);
Set<AccountState> matchingAccounts =
r.get(i)
.stream()
.filter(a -> a.getAccount().getPreferredEmail().equals(email))
.collect(toSet());
accountsByEmail.putAll(email, matchingAccounts);
}
return accountsByEmail;
}