Define AccountDirectory as an abstract backend for user data
Eventually this will fully support all account information, similar to GroupBackend. For now lets start by defining a simple base class that can supply name, email and avatar URLs to an AccountInfo for the REST API. Bind this in the Daemon and web application code so its at least partially pluggable at the static Guice injector level. Change-Id: I6e1b55fd46f3e99a982f7bd523f3e9d91b637b0d
This commit is contained in:
parent
f85f896bdd
commit
a750617d39
@ -39,6 +39,7 @@ import com.google.gerrit.pgm.util.LogFileCompressor;
|
||||
import com.google.gerrit.pgm.util.RuntimeShutdown;
|
||||
import com.google.gerrit.pgm.util.SiteProgram;
|
||||
import com.google.gerrit.reviewdb.client.AuthType;
|
||||
import com.google.gerrit.server.account.InternalAccountDirectory;
|
||||
import com.google.gerrit.server.cache.h2.DefaultCacheFactory;
|
||||
import com.google.gerrit.server.config.AuthConfig;
|
||||
import com.google.gerrit.server.config.AuthConfigModule;
|
||||
@ -250,6 +251,7 @@ public class Daemon extends SiteProgram {
|
||||
modules.add(new ReceiveCommitsExecutorModule());
|
||||
modules.add(new IntraLineWorkerPool.Module());
|
||||
modules.add(cfgInjector.getInstance(GerritGlobalModule.class));
|
||||
modules.add(new InternalAccountDirectory.Module());
|
||||
modules.add(new DefaultCacheFactory.Module());
|
||||
modules.add(new SmtpEmailSender.Module());
|
||||
modules.add(new SignedTokenEmailTokenVerifier.Module());
|
||||
|
@ -0,0 +1,59 @@
|
||||
// Copyright (C) 2013 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 java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* Directory of user account information.
|
||||
*
|
||||
* Implementations supply data to Gerrit about user accounts.
|
||||
*/
|
||||
public abstract class AccountDirectory {
|
||||
/** Fields to be populated for a REST API response. */
|
||||
public enum FillOptions {
|
||||
/** Human friendly display name presented in the web interface. */
|
||||
NAME,
|
||||
|
||||
/** Preferred email address to contact the user at. */
|
||||
EMAIL,
|
||||
|
||||
/** User profile images. */
|
||||
AVATARS,
|
||||
|
||||
/** Unique user identity to login to Gerrit, may be deprecated. */
|
||||
USERNAME;
|
||||
}
|
||||
|
||||
public abstract void fillAccountInfo(
|
||||
Iterable<? extends AccountInfo> in,
|
||||
EnumSet<FillOptions> options)
|
||||
throws DirectoryException;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class DirectoryException extends Exception {
|
||||
public DirectoryException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DirectoryException(String message, Throwable why) {
|
||||
super(message, why);
|
||||
}
|
||||
|
||||
public DirectoryException(Throwable why) {
|
||||
super(why);
|
||||
}
|
||||
}
|
||||
}
|
@ -14,50 +14,41 @@
|
||||
|
||||
package com.google.gerrit.server.account;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.avatar.AvatarProvider;
|
||||
import com.google.gerrit.server.account.AccountDirectory.DirectoryException;
|
||||
import com.google.gerrit.server.account.AccountDirectory.FillOptions;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AccountInfo {
|
||||
public static class Loader {
|
||||
private static EnumSet<FillOptions> DETAILED_OPTIONS = EnumSet.of(
|
||||
FillOptions.NAME,
|
||||
FillOptions.EMAIL,
|
||||
FillOptions.AVATARS);
|
||||
|
||||
public interface Factory {
|
||||
Loader create(boolean detailed);
|
||||
}
|
||||
|
||||
private final Provider<ReviewDb> db;
|
||||
private final AccountCache accountCache;
|
||||
private final DynamicItem<AvatarProvider> avatar;
|
||||
private final IdentifiedUser.GenericFactory userFactory;
|
||||
private final InternalAccountDirectory directory;
|
||||
private final boolean detailed;
|
||||
private final Map<Account.Id, AccountInfo> created;
|
||||
private final List<AccountInfo> provided;
|
||||
|
||||
@Inject
|
||||
Loader(Provider<ReviewDb> db,
|
||||
AccountCache accountCache,
|
||||
DynamicItem<AvatarProvider> avatar,
|
||||
IdentifiedUser.GenericFactory userFactory,
|
||||
@Assisted boolean detailed) {
|
||||
this.db = db;
|
||||
this.accountCache = accountCache;
|
||||
this.avatar = avatar;
|
||||
this.userFactory = userFactory;
|
||||
Loader(InternalAccountDirectory directory, @Assisted boolean detailed) {
|
||||
this.directory = directory;
|
||||
this.detailed = detailed;
|
||||
created = Maps.newHashMap();
|
||||
provided = Lists.newArrayList();
|
||||
@ -70,31 +61,29 @@ public class AccountInfo {
|
||||
AccountInfo info = created.get(id);
|
||||
if (info == null) {
|
||||
info = new AccountInfo(id);
|
||||
if (detailed) {
|
||||
info._account_id = id.get();
|
||||
}
|
||||
created.put(id, info);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
public void put(AccountInfo info) {
|
||||
if (detailed) {
|
||||
info._account_id = info._id.get();
|
||||
}
|
||||
provided.add(info);
|
||||
}
|
||||
|
||||
public void fill() throws OrmException {
|
||||
Multimap<Account.Id, AccountInfo> missing = ArrayListMultimap.create();
|
||||
for (AccountInfo info : Iterables.concat(created.values(), provided)) {
|
||||
AccountState state = accountCache.getIfPresent(info._id);
|
||||
if (state != null) {
|
||||
fill(info, state.getAccount());
|
||||
} else {
|
||||
missing.put(info._id, info);
|
||||
}
|
||||
}
|
||||
if (!missing.isEmpty()) {
|
||||
for (Account account : db.get().accounts().get(missing.keySet())) {
|
||||
for (AccountInfo info : missing.get(account.getId())) {
|
||||
fill(info, account);
|
||||
}
|
||||
}
|
||||
try {
|
||||
directory.fillAccountInfo(
|
||||
Iterables.concat(created.values(), provided),
|
||||
DETAILED_OPTIONS);
|
||||
} catch (DirectoryException e) {
|
||||
Throwables.propagateIfPossible(e.getCause(), OrmException.class);
|
||||
throw new OrmException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,28 +94,6 @@ public class AccountInfo {
|
||||
}
|
||||
fill();
|
||||
}
|
||||
|
||||
private void fill(AccountInfo info, Account account) {
|
||||
info.name = Strings.emptyToNull(account.getFullName());
|
||||
if (info.name == null) {
|
||||
info.name = account.getUserName();
|
||||
}
|
||||
|
||||
if (detailed) {
|
||||
info._account_id = account.getId().get();
|
||||
info.email = account.getPreferredEmail();
|
||||
info.username = account.getUserName();
|
||||
}
|
||||
|
||||
info.avatars = Lists.newArrayListWithCapacity(1);
|
||||
AvatarProvider ap = avatar.get();
|
||||
if (ap != null) {
|
||||
String u = ap.getUrl(userFactory.create(account.getId()), 26);
|
||||
if (u != null) {
|
||||
info.avatars.add(new AvatarInfo(u, 26));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public transient Account.Id _id;
|
||||
@ -142,8 +109,19 @@ public class AccountInfo {
|
||||
public List<AvatarInfo> avatars;
|
||||
|
||||
public static class AvatarInfo {
|
||||
String url;
|
||||
int height;
|
||||
/**
|
||||
* Size in pixels the UI prefers an avatar image to be.
|
||||
*
|
||||
* The web UI prefers avatar images to be square, both
|
||||
* the height and width of the image should be this size.
|
||||
* The height is the more important dimension to match
|
||||
* than the width.
|
||||
*/
|
||||
public static final int DEFAULT_SIZE = 26;
|
||||
|
||||
public String url;
|
||||
public Integer height;
|
||||
public Integer width;
|
||||
|
||||
AvatarInfo(String url, int height) {
|
||||
this.url = url;
|
||||
|
@ -0,0 +1,116 @@
|
||||
// Copyright (C) 2013 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 com.google.common.base.Strings;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.AccountInfo.AvatarInfo;
|
||||
import com.google.gerrit.server.avatar.AvatarProvider;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
@Singleton
|
||||
public class InternalAccountDirectory extends AccountDirectory {
|
||||
public static class Module extends AbstractModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(AccountDirectory.class).to(InternalAccountDirectory.class);
|
||||
}
|
||||
}
|
||||
|
||||
private final Provider<ReviewDb> db;
|
||||
private final AccountCache accountCache;
|
||||
private final DynamicItem<AvatarProvider> avatar;
|
||||
private final IdentifiedUser.GenericFactory userFactory;
|
||||
|
||||
@Inject
|
||||
InternalAccountDirectory(Provider<ReviewDb> db,
|
||||
AccountCache accountCache,
|
||||
DynamicItem<AvatarProvider> avatar,
|
||||
IdentifiedUser.GenericFactory userFactory) {
|
||||
this.db = db;
|
||||
this.accountCache = accountCache;
|
||||
this.avatar = avatar;
|
||||
this.userFactory = userFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillAccountInfo(
|
||||
Iterable<? extends AccountInfo> in,
|
||||
EnumSet<FillOptions> options)
|
||||
throws DirectoryException {
|
||||
Multimap<Account.Id, AccountInfo> missing = ArrayListMultimap.create();
|
||||
for (AccountInfo info : in) {
|
||||
AccountState state = accountCache.getIfPresent(info._id);
|
||||
if (state != null) {
|
||||
fill(info, state.getAccount(), options);
|
||||
} else {
|
||||
missing.put(info._id, info);
|
||||
}
|
||||
}
|
||||
if (!missing.isEmpty()) {
|
||||
try {
|
||||
for (Account account : db.get().accounts().get(missing.keySet())) {
|
||||
for (AccountInfo info : missing.get(account.getId())) {
|
||||
fill(info, account, options);
|
||||
}
|
||||
}
|
||||
} catch (OrmException e) {
|
||||
throw new DirectoryException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fill(AccountInfo info,
|
||||
Account account,
|
||||
EnumSet<FillOptions> options) {
|
||||
if (options.contains(FillOptions.NAME)) {
|
||||
info.name = Strings.emptyToNull(account.getFullName());
|
||||
if (info.name == null) {
|
||||
info.name = account.getUserName();
|
||||
}
|
||||
}
|
||||
if (options.contains(FillOptions.EMAIL)) {
|
||||
info.email = account.getPreferredEmail();
|
||||
}
|
||||
if (options.contains(FillOptions.USERNAME)) {
|
||||
info.username = account.getUserName();
|
||||
}
|
||||
if (options.contains(FillOptions.AVATARS)) {
|
||||
info.avatars = Lists.newArrayListWithCapacity(1);
|
||||
AvatarProvider ap = avatar.get();
|
||||
if (ap != null) {
|
||||
String u = ap.getUrl(
|
||||
userFactory.create(account.getId()),
|
||||
AvatarInfo.DEFAULT_SIZE);
|
||||
if (u != null) {
|
||||
info.avatars.add(new AvatarInfo(u, AvatarInfo.DEFAULT_SIZE));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ import com.google.gerrit.lifecycle.LifecycleManager;
|
||||
import com.google.gerrit.lifecycle.LifecycleModule;
|
||||
import com.google.gerrit.lucene.LuceneIndexModule;
|
||||
import com.google.gerrit.reviewdb.client.AuthType;
|
||||
import com.google.gerrit.server.account.InternalAccountDirectory;
|
||||
import com.google.gerrit.server.cache.h2.DefaultCacheFactory;
|
||||
import com.google.gerrit.server.config.AuthConfig;
|
||||
import com.google.gerrit.server.config.AuthConfigModule;
|
||||
@ -235,6 +236,7 @@ public class WebAppInitializer extends GuiceServletContextListener {
|
||||
modules.add(new ReceiveCommitsExecutorModule());
|
||||
modules.add(new IntraLineWorkerPool.Module());
|
||||
modules.add(cfgInjector.getInstance(GerritGlobalModule.class));
|
||||
modules.add(new InternalAccountDirectory.Module());
|
||||
modules.add(new DefaultCacheFactory.Module());
|
||||
modules.add(new SmtpEmailSender.Module());
|
||||
modules.add(new SignedTokenEmailTokenVerifier.Module());
|
||||
|
Loading…
Reference in New Issue
Block a user