Add REST endpoint to add members to a group
With PUT on 'groups/*/members/<NEW-MEMBER>' it is now possible to add a
new member to a group.
In addition with PUT on 'groups/*/members' it is possible to add
multiple new members to a group at once.
The AccountGroupMembersScreen uses the new REST endpoint to add new
members. After a member was added the screen is reloaded. Other changes
should follow to update the displayed member list without reloading the
complete screen.
The Guice bindings needed to be modified to make AccountManager
injectable into PutMember. It was needed to bind an implementation of
SshKeyCache since AccountManager depends on ChangeUserName.Factory
which depends on SshKeyCache.
Change-Id: I8de09da94790a6ad55757a1051f9098f5e937312
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java
index d6ab9b6..78b8d08 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java
@@ -16,6 +16,8 @@
import com.google.gerrit.client.Dispatcher;
import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.groups.GroupApi;
+import com.google.gerrit.client.groups.MemberInfo;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.ui.AccountGroupSuggestOracle;
import com.google.gerrit.client.ui.AccountLink;
@@ -175,15 +177,10 @@
}
addMemberBox.setEnabled(false);
- Util.GROUP_SVC.addGroupMember(getGroupId(), nameEmail,
- new GerritCallback<GroupDetail>() {
- public void onSuccess(final GroupDetail result) {
- addMemberBox.setEnabled(true);
- addMemberBox.setText("");
- if (result.accounts != null && result.members != null) {
- accounts.merge(result.accounts);
- members.display(result.members);
- }
+ GroupApi.addMember(getGroupUUID(), nameEmail,
+ new GerritCallback<MemberInfo>() {
+ public void onSuccess(final MemberInfo memberInfo) {
+ Gerrit.display(Dispatcher.toGroup(getGroupUUID(), AccountGroupScreen.MEMBERS));
}
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupScreen.java
index 9ac6c9a..e7df8bf 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupScreen.java
@@ -60,6 +60,10 @@
return groupDetail.group.getId();
}
+ protected AccountGroup.UUID getGroupUUID() {
+ return groupDetail.group.getGroupUUID();
+ }
+
protected void setMembersTabVisible(final boolean visible) {
setLinkVisible(membersTabToken, visible);
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupApi.java
new file mode 100644
index 0000000..a222048
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupApi.java
@@ -0,0 +1,72 @@
+// 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.client.groups;
+
+import com.google.gerrit.client.rpc.NativeList;
+import com.google.gerrit.client.rpc.RestApi;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import java.util.Set;
+
+/**
+ * A collection of static methods which work on the Gerrit REST API for specific
+ * groups.
+ */
+public class GroupApi {
+
+ /** Add member to a group. */
+ public static void addMember(AccountGroup.UUID groupUUID,
+ String member, AsyncCallback<MemberInfo> cb) {
+ new RestApi(membersBase(groupUUID) + "/" + member).put(cb);
+ }
+
+ /** Add members to a group. */
+ public static void addMembers(AccountGroup.UUID groupUUID,
+ Set<String> members, AsyncCallback<NativeList<MemberInfo>> cb) {
+ RestApi call = new RestApi(membersBase(groupUUID));
+ MemberInput input = MemberInput.create();
+ for (String member : members) {
+ input.add_member(member);
+ }
+ call.data(input).put(cb);
+ }
+
+ private static String membersBase(AccountGroup.UUID groupUUID) {
+ return base(groupUUID) + "members";
+ }
+
+ private static String base(AccountGroup.UUID groupUUID) {
+ String id = URL.encodePathSegment(groupUUID.get());
+ return "/groups/" + id + "/";
+ }
+
+ private static class MemberInput extends JavaScriptObject {
+ final native void init() /*-{ this.members = []; }-*/;
+
+ final native void add_member(String n) /*-{ this.members.push(n); }-*/;
+
+ static MemberInput create() {
+ MemberInput m = (MemberInput) createObject();
+ m.init();
+ return m;
+ }
+
+ protected MemberInput() {
+ }
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/MemberInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/MemberInfo.java
new file mode 100644
index 0000000..60afeed
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/MemberInfo.java
@@ -0,0 +1,32 @@
+// 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.client.groups;
+
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gwt.core.client.JavaScriptObject;
+
+public class MemberInfo extends JavaScriptObject {
+ public final Account.Id getAccountId() {
+ return new Account.Id(account_id());
+ }
+
+ private final native int account_id() /*-{ return this.account_id; }-*/;
+
+ public final native String fullName() /*-{ return this.full_name; }-*/;
+ public final native String preferredEmail() /*-{ return this.preferred_email; }-*/;
+
+ protected MemberInfo() {
+ }
+}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
index 591d97c..f76927b 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
@@ -29,8 +29,6 @@
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.CmdLineParserModule;
import com.google.gerrit.server.RemotePeer;
-import com.google.gerrit.server.account.AccountManager;
-import com.google.gerrit.server.account.ChangeUserName;
import com.google.gerrit.server.account.ClearPassword;
import com.google.gerrit.server.account.GeneratePassword;
import com.google.gerrit.server.config.AuthConfig;
@@ -134,9 +132,6 @@
bind(GerritConfig.class).toProvider(GerritConfigProvider.class);
DynamicSet.setOf(binder(), WebUiPlugin.class);
- bind(AccountManager.class);
- bind(ChangeUserName.CurrentUser.class);
- factory(ChangeUserName.Factory.class);
factory(ClearPassword.Factory.class);
install(new CmdLineParserModule());
factory(GeneratePassword.Factory.class);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSshGlueModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSshGlueModule.java
index 82e9da7..eb06617 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSshGlueModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSshGlueModule.java
@@ -15,7 +15,6 @@
package com.google.gerrit.httpd;
import com.google.gerrit.server.ssh.SshInfo;
-import com.google.gerrit.server.ssh.SshKeyCache;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -29,18 +28,14 @@
*/
public class WebSshGlueModule extends AbstractModule {
private final Provider<SshInfo> sshInfoProvider;
- private final Provider<SshKeyCache> sshKeyCacheProvider;
@Inject
- WebSshGlueModule(Provider<SshInfo> sshInfoProvider,
- Provider<SshKeyCache> sshKeyCacheProvider) {
+ WebSshGlueModule(Provider<SshInfo> sshInfoProvider) {
this.sshInfoProvider = sshInfoProvider;
- this.sshKeyCacheProvider = sshKeyCacheProvider;
}
@Override
protected void configure() {
bind(SshInfo.class).toProvider(sshInfoProvider);
- bind(SshKeyCache.class).toProvider(sshKeyCacheProvider);
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
index 1cbaff2..45e6360 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
@@ -56,6 +56,7 @@
import com.google.gerrit.server.schema.SchemaVersionCheck;
import com.google.gerrit.server.schema.UpdateUI;
import com.google.gerrit.server.ssh.NoSshModule;
+import com.google.gerrit.sshd.SshKeyCacheImpl;
import com.google.gerrit.sshd.SshModule;
import com.google.gerrit.sshd.commands.MasterCommandModule;
import com.google.gerrit.sshd.commands.SlaveCommandModule;
@@ -310,6 +311,7 @@
}
});
}
+ modules.add(SshKeyCacheImpl.module());
if (!slave) {
modules.add(new MasterNodeStartup());
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/BadRequestHandler.java b/gerrit-server/src/main/java/com/google/gerrit/server/BadRequestHandler.java
new file mode 100644
index 0000000..26eb85d
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/BadRequestHandler.java
@@ -0,0 +1,57 @@
+// 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;
+
+import com.google.common.collect.Lists;
+import com.google.gerrit.extensions.restapi.BadRequestException;
+
+import java.util.List;
+
+public class BadRequestHandler {
+
+ private final List<String> errors = Lists.newLinkedList();
+ private String action;
+
+ public BadRequestHandler(final String action) {
+ this.action = action;
+ }
+
+ public void addError(final String message) {
+ errors.add(message);
+ }
+
+ public void addError(final Throwable t) {
+ errors.add(t.getMessage());
+ }
+
+ public void failOnError()
+ throws BadRequestException {
+ if (errors.isEmpty()) {
+ return;
+ }
+
+ if (errors.size() == 1) {
+ throw new BadRequestException(action + " failed: " + errors.get(0));
+ }
+
+ final StringBuilder b = new StringBuilder();
+ b.append("Multiple errors on " + action + ":");
+ for (final String error : errors) {
+ b.append("\n");
+ b.append(error);
+ }
+ throw new BadRequestException(b.toString());
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 2449bf5..217c8c3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -34,10 +34,12 @@
import com.google.gerrit.server.account.AccountByEmailCacheImpl;
import com.google.gerrit.server.account.AccountCacheImpl;
import com.google.gerrit.server.account.AccountInfoCacheFactory;
+import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AccountResolver;
import com.google.gerrit.server.account.AccountVisibility;
import com.google.gerrit.server.account.AccountVisibilityProvider;
import com.google.gerrit.server.account.CapabilityControl;
+import com.google.gerrit.server.account.ChangeUserName;
import com.google.gerrit.server.account.DefaultRealm;
import com.google.gerrit.server.account.EmailExpander;
import com.google.gerrit.server.account.GroupBackend;
@@ -214,5 +216,9 @@
bind(AnonymousUser.class);
factory(NotesBranchUtil.Factory.class);
+
+ bind(AccountManager.class);
+ bind(ChangeUserName.CurrentUser.class);
+ factory(ChangeUserName.Factory.class);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/MembersCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/MembersCollection.java
index 00d5896..003f54e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/MembersCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/MembersCollection.java
@@ -16,6 +16,7 @@
import com.google.gerrit.common.data.GroupDetail;
import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.restapi.AcceptsCreate;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.ChildCollection;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
@@ -24,32 +25,41 @@
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.account.AccountResolver;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.GroupDetailFactory;
+import com.google.gerrit.server.group.PutMembers.PutMember;
import com.google.gerrit.server.util.Url;
import com.google.inject.Inject;
import com.google.inject.Provider;
public class MembersCollection implements
- ChildCollection<GroupResource, MemberResource> {
+ ChildCollection<GroupResource, MemberResource>,
+ AcceptsCreate<GroupResource>{
private final DynamicMap<RestView<MemberResource>> views;
private final Provider<ListMembers> list;
private final IdentifiedUser.GenericFactory userGenericFactory;
private final GroupCache groupCache;
private final GroupDetailFactory.Factory groupDetailFactory;
+ private final AccountResolver accountResolver;
+ private final Provider<PutMembers> put;
@Inject
MembersCollection(final DynamicMap<RestView<MemberResource>> views,
final Provider<ListMembers> list,
final IdentifiedUser.GenericFactory userGenericFactory,
final GroupCache groupCache,
- final GroupDetailFactory.Factory groupDetailFactory) {
+ final GroupDetailFactory.Factory groupDetailFactory,
+ final AccountResolver accountResolver,
+ final Provider<PutMembers> put) {
this.views = views;
this.list = list;
this.userGenericFactory = userGenericFactory;
this.groupCache = groupCache;
this.groupDetailFactory = groupDetailFactory;
+ this.accountResolver = accountResolver;
+ this.put = put;
}
@Override
@@ -61,10 +71,8 @@
@Override
public MemberResource parse(final GroupResource parent, final String id)
throws ResourceNotFoundException, Exception {
- final Account.Id accountId;
- try {
- accountId = new Account.Id(Integer.parseInt(Url.decode(id)));
- } catch (NumberFormatException e) {
+ final Account a = accountResolver.find(Url.decode(id));
+ if (a == null) {
throw new ResourceNotFoundException(id);
}
@@ -74,15 +82,20 @@
groupDetailFactory.create(group.getId()).call();
if (groupDetail.members != null) {
for (final AccountGroupMember member : groupDetail.members) {
- if (member.getAccountId().equals(accountId)) {
- return new MemberResource(
- userGenericFactory.create(accountId));
+ if (member.getAccountId().equals(a.getId())) {
+ return new MemberResource(userGenericFactory.create(a.getId()));
}
}
}
throw new ResourceNotFoundException(id);
}
+ @SuppressWarnings("unchecked")
+ @Override
+ public PutMember create(final GroupResource group, final String id) {
+ return new PutMember(put, Url.decode(id));
+ }
+
@Override
public DynamicMap<RestView<MemberResource>> views() {
return views;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/Module.java
index 3bf1e1f..30401c2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/Module.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/Module.java
@@ -34,6 +34,7 @@
child(GROUP_KIND, "members").to(MembersCollection.class);
get(MEMBER_KIND).to(GetMember.class);
+ put(GROUP_KIND, "members").to(PutMembers.class);
child(GROUP_KIND, "groups").to(IncludedGroupsCollection.class);
get(INCLUDED_GROUP_KIND).to(GetIncludedGroup.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutMembers.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutMembers.java
new file mode 100644
index 0000000..8cda530
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutMembers.java
@@ -0,0 +1,218 @@
+// 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.group;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.gerrit.common.data.GroupDescription;
+import com.google.gerrit.common.errors.InactiveAccountException;
+import com.google.gerrit.common.errors.NoSuchAccountException;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.DefaultInput;
+import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
+import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupMember;
+import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
+import com.google.gerrit.reviewdb.client.AuthType;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.BadRequestHandler;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.account.AccountCache;
+import com.google.gerrit.server.account.AccountException;
+import com.google.gerrit.server.account.AccountManager;
+import com.google.gerrit.server.account.AccountResolver;
+import com.google.gerrit.server.account.AuthRequest;
+import com.google.gerrit.server.account.GroupControl;
+import com.google.gerrit.server.config.AuthConfig;
+import com.google.gerrit.server.group.MembersCollection.MemberInfo;
+import com.google.gerrit.server.group.PutMembers.Input;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import java.util.List;
+import java.util.Map;
+
+class PutMembers implements RestModifyView<GroupResource, Input> {
+ static class Input {
+ @DefaultInput
+ String _oneMember;
+
+ List<String> members;
+
+ static Input init(Input in) {
+ if (in == null) {
+ in = new Input();
+ }
+ if (in.members == null) {
+ in.members = Lists.newArrayListWithCapacity(1);
+ }
+ if (!Strings.isNullOrEmpty(in._oneMember)) {
+ in.members.add(in._oneMember);
+ }
+ return in;
+ }
+ }
+
+ private final GroupControl.Factory groupControlFactory;
+ private final AccountManager accountManager;
+ private final AuthType authType;
+ private final AccountResolver accountResolver;
+ private final AccountCache accountCache;
+ private final ReviewDb db;
+ private final Provider<CurrentUser> self;
+
+ @Inject
+ PutMembers(final GroupControl.Factory groupControlFactory,
+ final AccountManager accountManager,
+ final AuthConfig authConfig,
+ final AccountResolver accountResolver,
+ final AccountCache accountCache, final ReviewDb db,
+ final Provider<CurrentUser> self) {
+ this.groupControlFactory = groupControlFactory;
+ this.accountManager = accountManager;
+ this.authType = authConfig.getAuthType();
+ this.accountResolver = accountResolver;
+ this.accountCache = accountCache;
+ this.db = db;
+ this.self = self;
+ }
+
+ @Override
+ public Class<Input> inputType() {
+ return Input.class;
+ }
+
+ @Override
+ public List<MemberInfo> apply(GroupResource resource, Input input)
+ throws AuthException, MethodNotAllowedException, BadRequestException,
+ OrmException {
+ final GroupDescription.Basic group = resource.getGroup();
+ if (!(group instanceof GroupDescription.Internal)) {
+ throw new MethodNotAllowedException();
+ }
+
+ input = Input.init(input);
+
+ final AccountGroup internalGroup = ((GroupDescription.Internal) group).getAccountGroup();
+ final GroupControl control = groupControlFactory.controlFor(internalGroup);
+ final Map<Account.Id, AccountGroupMember> newAccountGroupMembers = Maps.newHashMap();
+ final List<AccountGroupMemberAudit> newAccountGroupMemberAudits = Lists.newLinkedList();
+ final BadRequestHandler badRequest = new BadRequestHandler("adding new group members");
+ final List<MemberInfo> newMembers = Lists.newLinkedList();
+ final Account.Id me = ((IdentifiedUser) self.get()).getAccountId();
+
+ for (final String nameOrEmail : input.members) {
+ final Account a = findAccount(nameOrEmail);
+ if (a == null) {
+ badRequest.addError(new NoSuchAccountException(nameOrEmail));
+ }
+
+ if (!a.isActive()) {
+ badRequest.addError(new InactiveAccountException(a.getFullName()));
+ continue;
+ }
+
+ if (!control.canAddMember(a.getId())) {
+ throw new AuthException("Cannot add member: " + a.getFullName());
+ }
+
+ if (!newAccountGroupMembers.containsKey(a.getId())) {
+ final AccountGroupMember.Key key =
+ new AccountGroupMember.Key(a.getId(), internalGroup.getId());
+ AccountGroupMember m = db.accountGroupMembers().get(key);
+ if (m == null) {
+ m = new AccountGroupMember(key);
+ newAccountGroupMembers.put(m.getAccountId(), m);
+ newAccountGroupMemberAudits.add(new AccountGroupMemberAudit(m, me));
+ }
+
+ newMembers.add(MembersCollection.parse(a));
+ }
+ }
+
+ badRequest.failOnError();
+
+ db.accountGroupMembersAudit().insert(newAccountGroupMemberAudits);
+ db.accountGroupMembers().insert(newAccountGroupMembers.values());
+ for (final AccountGroupMember m : newAccountGroupMembers.values()) {
+ accountCache.evict(m.getAccountId());
+ }
+
+ return newMembers;
+ }
+
+ private Account findAccount(final String nameOrEmail) throws OrmException {
+ Account r = accountResolver.find(nameOrEmail);
+ if (r == null) {
+ switch (authType) {
+ case HTTP_LDAP:
+ case CLIENT_SSL_CERT_LDAP:
+ case LDAP:
+ r = createAccountByLdap(nameOrEmail);
+ break;
+ default:
+ }
+ }
+ return r;
+ }
+
+ private Account createAccountByLdap(String user) {
+ if (!user.matches(Account.USER_NAME_PATTERN)) {
+ return null;
+ }
+
+ try {
+ final AuthRequest req = AuthRequest.forUser(user);
+ req.setSkipAuthentication(true);
+ return accountCache.get(accountManager.authenticate(req).getAccountId())
+ .getAccount();
+ } catch (AccountException e) {
+ return null;
+ }
+ }
+
+ static class PutMember implements RestModifyView<GroupResource, PutMember.Input> {
+ static class Input {
+ }
+
+ private final Provider<PutMembers> put;
+ private final String id;
+
+ PutMember(final Provider<PutMembers> put, String id) {
+ this.put = put;
+ this.id = id;
+ }
+
+ @Override
+ public Class<PutMember.Input> inputType() {
+ return PutMember.Input.class;
+ }
+
+ @Override
+ public Object apply(GroupResource resource, PutMember.Input input)
+ throws AuthException, MethodNotAllowedException, BadRequestException,
+ OrmException {
+ PutMembers.Input in = new PutMembers.Input();
+ in._oneMember = id;
+ return put.get().apply(resource, in);
+ }
+ }
+}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
index 7f4a1f7..7e76b46 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
@@ -22,8 +22,6 @@
import com.google.gerrit.server.CmdLineParserModule;
import com.google.gerrit.server.PeerDaemonUser;
import com.google.gerrit.server.RemotePeer;
-import com.google.gerrit.server.account.AccountManager;
-import com.google.gerrit.server.account.ChangeUserName;
import com.google.gerrit.server.config.FactoryModule;
import com.google.gerrit.server.config.GerritRequestModule;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -44,6 +42,7 @@
import org.apache.sshd.server.CommandFactory;
import org.apache.sshd.server.PublickeyAuthenticator;
import org.eclipse.jgit.lib.Config;
+
import java.net.SocketAddress;
import java.util.Map;
@@ -69,7 +68,6 @@
install(new CmdLineParserModule());
configureAliases();
- install(SshKeyCacheImpl.module());
bind(SshLog.class);
bind(SshInfo.class).to(SshDaemon.class).in(SINGLETON);
factory(DispatchCommand.Factory.class);
@@ -83,8 +81,6 @@
bind(WorkQueue.Executor.class).annotatedWith(StreamCommandExecutor.class)
.toProvider(StreamCommandExecutorProvider.class).in(SINGLETON);
bind(QueueProvider.class).to(CommandExecutorQueueProvider.class).in(SINGLETON);
- bind(AccountManager.class);
- factory(ChangeUserName.Factory.class);
bind(PublickeyAuthenticator.class).to(DatabasePubKeyAuth.class);
bind(KeyPairProvider.class).toProvider(HostKeyProvider.class).in(SINGLETON);
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
index 6dab0d3..19b31d9 100644
--- a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
@@ -46,6 +46,7 @@
import com.google.gerrit.server.schema.DatabaseModule;
import com.google.gerrit.server.schema.SchemaModule;
import com.google.gerrit.server.schema.SchemaVersionCheck;
+import com.google.gerrit.sshd.SshKeyCacheImpl;
import com.google.gerrit.sshd.SshModule;
import com.google.gerrit.sshd.commands.MasterCommandModule;
import com.google.inject.AbstractModule;
@@ -238,6 +239,7 @@
return HttpCanonicalWebUrlProvider.class;
}
});
+ modules.add(SshKeyCacheImpl.module());
modules.add(new MasterNodeStartup());
return cfgInjector.createChildInjector(modules);
}