Merge changes I695ce026,I87868087,I79bfb06e,I97006ab1,I0516cfa1, ...

* changes:
  Merge PerformRenameGroup into PutName
  Use REST implementation from rename-group SSH command
  Remove duplicate code to add group members
  Merge PerformCreateGroup into CreateGroup
  Remove support for initial groups from PerformCreateGroup
  Use REST implementation to create groups during tests
  Use REST implementation from create-group SSH command
This commit is contained in:
Shawn Pearce 2015-04-12 19:54:10 +00:00 committed by Gerrit Code Review
commit 34a6db2d32
10 changed files with 309 additions and 411 deletions

View File

@ -25,10 +25,15 @@ import com.google.gerrit.acceptance.GerritConfigs;
import com.google.gerrit.acceptance.RestSession;
import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.data.GroupDescription;
import com.google.gerrit.common.data.GroupDescriptions;
import com.google.gerrit.extensions.common.SuggestedReviewerInfo;
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.account.CreateGroupArgs;
import com.google.gerrit.server.account.PerformCreateGroup;
import com.google.gerrit.server.group.CreateGroup;
import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gerrit.server.group.GroupsCollection;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Inject;
@ -37,12 +42,14 @@ import org.junit.Test;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class SuggestReviewersIT extends AbstractDaemonTest {
@Inject
private PerformCreateGroup.Factory createGroupFactory;
private CreateGroup.Factory createGroupFactory;
@Inject
private GroupsCollection groups;
private AccountGroup group1;
private AccountGroup group2;
@ -218,10 +225,10 @@ public class SuggestReviewersIT extends AbstractDaemonTest {
}
private AccountGroup group(String name) throws Exception {
CreateGroupArgs args = new CreateGroupArgs();
args.setGroupName(name(name));
args.initialMembers = Collections.singleton(admin.getId());
return createGroupFactory.create(args).createGroup();
GroupInfo group = createGroupFactory.create(name(name))
.apply(TopLevelResource.INSTANCE, null);
GroupDescription.Basic d = groups.parseInternal(Url.decode(group.id));
return GroupDescriptions.toAccountGroup(d);
}
private TestAccount user(String name, AccountGroup... groups) throws Exception {

View File

@ -25,7 +25,6 @@ public class CreateGroupArgs {
public boolean visibleToAll;
public AccountGroup.Id ownerGroupId;
public Collection<? extends Account.Id> initialMembers;
public Collection<? extends AccountGroup.UUID> initialGroups;
public AccountGroup.NameKey getGroup() {
return groupName;

View File

@ -1,158 +0,0 @@
// Copyright (C) 2011 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.gerrit.audit.AuditService;
import com.google.gerrit.common.errors.NameAlreadyUsedException;
import com.google.gerrit.common.errors.PermissionDeniedException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupById;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupName;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gwtorm.server.OrmDuplicateKeyException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.lib.PersonIdent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class PerformCreateGroup {
public interface Factory {
PerformCreateGroup create(CreateGroupArgs createGroupArgs);
}
private final ReviewDb db;
private final AccountCache accountCache;
private final GroupIncludeCache groupIncludeCache;
private final IdentifiedUser currentUser;
private final PersonIdent serverIdent;
private final GroupCache groupCache;
private final CreateGroupArgs createGroupArgs;
private final AuditService auditService;
@Inject
PerformCreateGroup(ReviewDb db, AccountCache accountCache,
GroupIncludeCache groupIncludeCache, IdentifiedUser currentUser,
@GerritPersonIdent PersonIdent serverIdent, GroupCache groupCache,
@Assisted CreateGroupArgs createGroupArgs, AuditService auditService) {
this.db = db;
this.accountCache = accountCache;
this.groupIncludeCache = groupIncludeCache;
this.currentUser = currentUser;
this.serverIdent = serverIdent;
this.groupCache = groupCache;
this.createGroupArgs = createGroupArgs;
this.auditService = auditService;
}
/**
* Creates a new group.
* @return the new group
* @throws OrmException is thrown in case of any data store read or write
* error
* @throws NameAlreadyUsedException is thrown in case a group with the given
* name already exists
* @throws PermissionDeniedException user cannot create a group.
*/
public AccountGroup createGroup() throws OrmException,
NameAlreadyUsedException, PermissionDeniedException {
if (!currentUser.getCapabilities().canCreateGroup()) {
throw new PermissionDeniedException(String.format(
"%s does not have \"Create Group\" capability.",
currentUser.getUserName()));
}
AccountGroup.Id groupId = new AccountGroup.Id(db.nextAccountGroupId());
AccountGroup.UUID uuid = GroupUUID.make(
createGroupArgs.getGroupName(),
currentUser.newCommitterIdent(
serverIdent.getWhen(),
serverIdent.getTimeZone()));
AccountGroup group =
new AccountGroup(createGroupArgs.getGroup(), groupId, uuid);
group.setVisibleToAll(createGroupArgs.visibleToAll);
if (createGroupArgs.ownerGroupId != null) {
AccountGroup ownerGroup = groupCache.get(createGroupArgs.ownerGroupId);
if (ownerGroup != null) {
group.setOwnerGroupUUID(ownerGroup.getGroupUUID());
}
}
if (createGroupArgs.groupDescription != null) {
group.setDescription(createGroupArgs.groupDescription);
}
AccountGroupName gn = new AccountGroupName(group);
// first insert the group name to validate that the group name hasn't
// already been used to create another group
try {
db.accountGroupNames().insert(Collections.singleton(gn));
} catch (OrmDuplicateKeyException e) {
throw new NameAlreadyUsedException(createGroupArgs.getGroupName());
}
db.accountGroups().insert(Collections.singleton(group));
addMembers(groupId, createGroupArgs.initialMembers);
if (createGroupArgs.initialGroups != null) {
addGroups(groupId, createGroupArgs.initialGroups);
groupIncludeCache.evictSubgroupsOf(uuid);
}
groupCache.onCreateGroup(createGroupArgs.getGroup());
return group;
}
private void addMembers(final AccountGroup.Id groupId,
final Collection<? extends Account.Id> members) throws OrmException {
List<AccountGroupMember> memberships = new ArrayList<>();
for (Account.Id accountId : members) {
final AccountGroupMember membership =
new AccountGroupMember(new AccountGroupMember.Key(accountId, groupId));
memberships.add(membership);
}
db.accountGroupMembers().insert(memberships);
auditService.dispatchAddAccountsToGroup(currentUser.getAccountId(), memberships);
for (Account.Id accountId : members) {
accountCache.evict(accountId);
}
}
private void addGroups(final AccountGroup.Id groupId,
final Collection<? extends AccountGroup.UUID> groups) throws OrmException {
List<AccountGroupById> includeList = new ArrayList<>();
for (AccountGroup.UUID includeUUID : groups) {
final AccountGroupById groupInclude =
new AccountGroupById(new AccountGroupById.Key(groupId, includeUUID));
includeList.add(groupInclude);
}
db.accountGroupById().insert(includeList);
auditService.dispatchAddGroupsToGroup(currentUser.getAccountId(), includeList);
for (AccountGroup.UUID uuid : groups) {
groupIncludeCache.evictParentGroupsOf(uuid);
}
}
}

View File

@ -1,125 +0,0 @@
// Copyright (C) 2011 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.gerrit.common.data.GroupDetail;
import com.google.gerrit.common.errors.InvalidNameException;
import com.google.gerrit.common.errors.NameAlreadyUsedException;
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupName;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.git.RenameGroupOp;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import java.util.Collections;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
public class PerformRenameGroup {
public interface Factory {
PerformRenameGroup create();
}
private final ReviewDb db;
private final GroupCache groupCache;
private final GroupControl.Factory groupControlFactory;
private final GroupDetailFactory.Factory groupDetailFactory;
private final RenameGroupOp.Factory renameGroupOpFactory;
private final IdentifiedUser currentUser;
@Inject
PerformRenameGroup(final ReviewDb db, final GroupCache groupCache,
final GroupControl.Factory groupControlFactory,
final GroupDetailFactory.Factory groupDetailFactory,
final RenameGroupOp.Factory renameGroupOpFactory,
final IdentifiedUser currentUser) {
this.db = db;
this.groupCache = groupCache;
this.groupControlFactory = groupControlFactory;
this.groupDetailFactory = groupDetailFactory;
this.renameGroupOpFactory = renameGroupOpFactory;
this.currentUser = currentUser;
}
public GroupDetail renameGroup(final String groupName,
final String newGroupName) throws OrmException, NameAlreadyUsedException,
NoSuchGroupException, InvalidNameException {
final AccountGroup.NameKey groupNameKey =
new AccountGroup.NameKey(groupName);
final AccountGroup group = groupCache.get(groupNameKey);
if (group == null) {
throw new NoSuchGroupException(groupNameKey);
}
return renameGroup(group.getId(), newGroupName);
}
public GroupDetail renameGroup(final AccountGroup.Id groupId,
final String newName) throws OrmException, NameAlreadyUsedException,
NoSuchGroupException, InvalidNameException {
final GroupControl ctl = groupControlFactory.validateFor(groupId);
final AccountGroup group = db.accountGroups().get(groupId);
if (group == null || !ctl.isOwner()) {
throw new NoSuchGroupException(groupId);
}
if (newName.trim().isEmpty()) {
throw new InvalidNameException();
}
final AccountGroup.NameKey old = group.getNameKey();
final AccountGroup.NameKey key = new AccountGroup.NameKey(newName);
try {
final AccountGroupName id = new AccountGroupName(key, groupId);
db.accountGroupNames().insert(Collections.singleton(id));
} catch (OrmException e) {
AccountGroupName other = db.accountGroupNames().get(key);
if (other != null) {
// If we are using this identity, don't report the exception.
//
if (other.getId().equals(groupId)) {
return groupDetailFactory.create(groupId).call();
}
// Otherwise, someone else has this identity.
//
throw new NameAlreadyUsedException(newName);
} else {
throw e;
}
}
group.setNameKey(key);
db.accountGroups().update(Collections.singleton(group));
AccountGroupName priorName = db.accountGroupNames().get(old);
if (priorName != null) {
db.accountGroupNames().delete(Collections.singleton(priorName));
}
groupCache.evict(group);
groupCache.evictAfterRename(old, key);
renameGroupOpFactory.create( //
currentUser.newCommitterIdent(new Date(), TimeZone.getDefault()), //
group.getGroupUUID(), //
old.get(), newName).start(0, TimeUnit.MILLISECONDS);
return groupDetailFactory.create(groupId).call();
}
}

View File

@ -63,8 +63,6 @@ import com.google.gerrit.server.account.GroupDetailFactory;
import com.google.gerrit.server.account.GroupIncludeCacheImpl;
import com.google.gerrit.server.account.GroupInfoCacheFactory;
import com.google.gerrit.server.account.GroupMembers;
import com.google.gerrit.server.account.PerformCreateGroup;
import com.google.gerrit.server.account.PerformRenameGroup;
import com.google.gerrit.server.auth.AuthBackend;
import com.google.gerrit.server.auth.UniversalAuthBackend;
import com.google.gerrit.server.avatar.AvatarProvider;
@ -197,8 +195,6 @@ public class GerritGlobalModule extends FactoryModule {
factory(MergeFailSender.Factory.class);
factory(MergeUtil.Factory.class);
factory(PatchScriptFactory.Factory.class);
factory(PerformCreateGroup.Factory.class);
factory(PerformRenameGroup.Factory.class);
factory(PluginUser.Factory.class);
factory(ProjectNode.Factory.class);
factory(ProjectState.Factory.class);

View File

@ -45,8 +45,11 @@ import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Singleton
public class AddMembers implements RestModifyView<GroupResource, Input> {
@ -75,6 +78,7 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
}
}
private final Provider<IdentifiedUser> self;
private final AccountManager accountManager;
private final AuthType authType;
private final AccountsCollection accounts;
@ -85,7 +89,8 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
private final AuditService auditService;
@Inject
AddMembers(AccountManager accountManager,
AddMembers(Provider<IdentifiedUser> self,
AccountManager accountManager,
AuthConfig authConfig,
AccountsCollection accounts,
AccountResolver accountResolver,
@ -93,6 +98,7 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
AccountLoader.Factory infoFactory,
Provider<ReviewDb> db,
AuditService auditService) {
this.self = self;
this.accountManager = accountManager;
this.auditService = auditService;
this.authType = authConfig.getAuthType();
@ -114,11 +120,8 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
input = Input.init(input);
GroupControl control = resource.getControl();
Map<Account.Id, AccountGroupMember> newAccountGroupMembers = Maps.newHashMap();
List<AccountInfo> result = Lists.newLinkedList();
Account.Id me = ((IdentifiedUser) control.getCurrentUser()).getAccountId();
AccountLoader loader = infoFactory.create(true);
Set<Account.Id> newMemberIds = new HashSet<>();
for (String nameOrEmail : input.members) {
Account a = findAccount(nameOrEmail);
if (!a.isActive()) {
@ -129,27 +132,11 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
if (!control.canAddMember()) {
throw new AuthException("Cannot add member: " + a.getFullName());
}
if (!newAccountGroupMembers.containsKey(a.getId())) {
AccountGroupMember.Key key =
new AccountGroupMember.Key(a.getId(), internalGroup.getId());
AccountGroupMember m = db.get().accountGroupMembers().get(key);
if (m == null) {
m = new AccountGroupMember(key);
newAccountGroupMembers.put(m.getAccountId(), m);
}
}
result.add(loader.get(a.getId()));
newMemberIds.add(a.getId());
}
auditService.dispatchAddAccountsToGroup(me, newAccountGroupMembers.values());
db.get().accountGroupMembers().insert(newAccountGroupMembers.values());
for (AccountGroupMember m : newAccountGroupMembers.values()) {
accountCache.evict(m.getAccountId());
}
loader.fill();
return result;
addMembers(internalGroup.getId(), newMemberIds);
return toAccountInfoList(newMemberIds);
}
private Account findAccount(String nameOrEmail) throws AuthException,
@ -177,6 +164,29 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
}
}
public void addMembers(AccountGroup.Id groupId,
Collection<? extends Account.Id> newMemberIds) throws OrmException {
Map<Account.Id, AccountGroupMember> newAccountGroupMembers = Maps.newHashMap();
for (Account.Id accId : newMemberIds) {
if (!newAccountGroupMembers.containsKey(accId)) {
AccountGroupMember.Key key =
new AccountGroupMember.Key(accId, groupId);
AccountGroupMember m = db.get().accountGroupMembers().get(key);
if (m == null) {
m = new AccountGroupMember(key);
newAccountGroupMembers.put(m.getAccountId(), m);
}
}
}
auditService.dispatchAddAccountsToGroup(self.get().getAccountId(),
newAccountGroupMembers.values());
db.get().accountGroupMembers().insert(newAccountGroupMembers.values());
for (AccountGroupMember m : newAccountGroupMembers.values()) {
accountCache.evict(m.getAccountId());
}
}
private Account createAccountByLdap(String user) {
if (!user.matches(Account.USER_NAME_PATTERN)) {
return null;
@ -192,6 +202,17 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
}
}
private List<AccountInfo> toAccountInfoList(Set<Account.Id> accountIds)
throws OrmException {
List<AccountInfo> result = Lists.newLinkedList();
AccountLoader loader = infoFactory.create(true);
for (Account.Id accId : accountIds) {
result.add(loader.get(accId));
}
loader.fill();
return result;
}
static class PutMember implements RestModifyView<GroupResource, PutMember.Input> {
static class Input {
}

View File

@ -19,8 +19,6 @@ import com.google.common.base.Strings;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.data.GroupDescription;
import com.google.gerrit.common.data.GroupDescriptions;
import com.google.gerrit.common.errors.NameAlreadyUsedException;
import com.google.gerrit.common.errors.PermissionDeniedException;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.AuthException;
@ -32,20 +30,26 @@ import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupName;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.CreateGroupArgs;
import com.google.gerrit.server.account.PerformCreateGroup;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.GroupUUID;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.group.CreateGroup.Input;
import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gerrit.server.validators.GroupCreationValidationListener;
import com.google.gerrit.server.validators.ValidationException;
import com.google.gwtorm.server.OrmDuplicateKeyException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.PersonIdent;
import java.util.Collections;
@ -63,23 +67,36 @@ public class CreateGroup implements RestModifyView<TopLevelResource, Input> {
}
private final Provider<IdentifiedUser> self;
private final PersonIdent serverIdent;
private final ReviewDb db;
private final GroupCache groupCache;
private final GroupsCollection groups;
private final PerformCreateGroup.Factory op;
private final GroupJson json;
private final DynamicSet<GroupCreationValidationListener> groupCreationValidationListeners;
private final AddMembers addMembers;
private final boolean defaultVisibleToAll;
private final String name;
@Inject
CreateGroup(Provider<IdentifiedUser> self, GroupsCollection groups,
PerformCreateGroup.Factory performCreateGroupFactory, GroupJson json,
CreateGroup(
Provider<IdentifiedUser> self,
@GerritPersonIdent PersonIdent serverIdent,
ReviewDb db,
GroupCache groupCache,
GroupsCollection groups,
GroupJson json,
DynamicSet<GroupCreationValidationListener> groupCreationValidationListeners,
@GerritServerConfig Config cfg, @Assisted String name) {
AddMembers addMembers,
@GerritServerConfig Config cfg,
@Assisted String name) {
this.self = self;
this.serverIdent = serverIdent;
this.db = db;
this.groupCache = groupCache;
this.groups = groups;
this.op = performCreateGroupFactory;
this.json = json;
this.groupCreationValidationListeners = groupCreationValidationListeners;
this.addMembers = addMembers;
this.defaultVisibleToAll = cfg.getBoolean("groups", "newGroupsVisibleToAll", false);
this.name = name;
}
@ -96,33 +113,25 @@ public class CreateGroup implements RestModifyView<TopLevelResource, Input> {
}
AccountGroup.Id ownerId = owner(input);
AccountGroup group;
try {
CreateGroupArgs args = new CreateGroupArgs();
args.setGroupName(name);
args.groupDescription = Strings.emptyToNull(input.description);
args.visibleToAll = MoreObjects.firstNonNull(input.visibleToAll,
defaultVisibleToAll);
args.ownerGroupId = ownerId;
args.initialMembers = ownerId == null
? Collections.singleton(self.get().getAccountId())
: Collections.<Account.Id> emptySet();
CreateGroupArgs args = new CreateGroupArgs();
args.setGroupName(name);
args.groupDescription = Strings.emptyToNull(input.description);
args.visibleToAll = MoreObjects.firstNonNull(input.visibleToAll,
defaultVisibleToAll);
args.ownerGroupId = ownerId;
args.initialMembers = ownerId == null
? Collections.singleton(self.get().getAccountId())
: Collections.<Account.Id> emptySet();
for (GroupCreationValidationListener l : groupCreationValidationListeners) {
try {
l.validateNewGroup(args);
} catch (ValidationException e) {
throw new ResourceConflictException(e.getMessage(), e);
}
for (GroupCreationValidationListener l : groupCreationValidationListeners) {
try {
l.validateNewGroup(args);
} catch (ValidationException e) {
throw new ResourceConflictException(e.getMessage(), e);
}
group = op.create(args).createGroup();
} catch (PermissionDeniedException e) {
throw new AuthException(e.getMessage());
} catch (NameAlreadyUsedException e) {
throw new ResourceConflictException(e.getMessage());
}
return json.format(GroupDescriptions.forAccountGroup(group));
return json.format(GroupDescriptions.forAccountGroup(createGroup(args)));
}
private AccountGroup.Id owner(Input input)
@ -133,4 +142,42 @@ public class CreateGroup implements RestModifyView<TopLevelResource, Input> {
}
return null;
}
private AccountGroup createGroup(CreateGroupArgs createGroupArgs)
throws OrmException, ResourceConflictException {
AccountGroup.Id groupId = new AccountGroup.Id(db.nextAccountGroupId());
AccountGroup.UUID uuid =
GroupUUID.make(
createGroupArgs.getGroupName(),
self.get().newCommitterIdent(serverIdent.getWhen(),
serverIdent.getTimeZone()));
AccountGroup group =
new AccountGroup(createGroupArgs.getGroup(), groupId, uuid);
group.setVisibleToAll(createGroupArgs.visibleToAll);
if (createGroupArgs.ownerGroupId != null) {
AccountGroup ownerGroup = groupCache.get(createGroupArgs.ownerGroupId);
if (ownerGroup != null) {
group.setOwnerGroupUUID(ownerGroup.getGroupUUID());
}
}
if (createGroupArgs.groupDescription != null) {
group.setDescription(createGroupArgs.groupDescription);
}
AccountGroupName gn = new AccountGroupName(group);
// first insert the group name to validate that the group name hasn't
// already been used to create another group
try {
db.accountGroupNames().insert(Collections.singleton(gn));
} catch (OrmDuplicateKeyException e) {
throw new ResourceConflictException("group '"
+ createGroupArgs.getGroupName() + "' already exists");
}
db.accountGroups().insert(Collections.singleton(group));
addMembers.addMembers(groupId, createGroupArgs.initialMembers);
groupCache.onCreateGroup(createGroupArgs.getGroup());
return group;
}
}

View File

@ -15,8 +15,7 @@
package com.google.gerrit.server.group;
import com.google.common.base.Strings;
import com.google.gerrit.common.errors.InvalidNameException;
import com.google.gerrit.common.errors.NameAlreadyUsedException;
import com.google.gerrit.common.data.GroupDetail;
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
@ -25,12 +24,24 @@ import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.server.account.PerformRenameGroup;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupName;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.GroupDetailFactory;
import com.google.gerrit.server.git.RenameGroupOp;
import com.google.gerrit.server.group.PutName.Input;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.util.Collections;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
@Singleton
public class PutName implements RestModifyView<GroupResource, Input> {
public static class Input {
@ -38,39 +49,92 @@ public class PutName implements RestModifyView<GroupResource, Input> {
public String name;
}
private final PerformRenameGroup.Factory performRenameGroupFactory;
private final Provider<ReviewDb> db;
private final GroupCache groupCache;
private final GroupDetailFactory.Factory groupDetailFactory;
private final RenameGroupOp.Factory renameGroupOpFactory;
private final Provider<IdentifiedUser> currentUser;
@Inject
PutName(PerformRenameGroup.Factory performRenameGroupFactory) {
this.performRenameGroupFactory = performRenameGroupFactory;
PutName(Provider<ReviewDb> db,
GroupCache groupCache,
GroupDetailFactory.Factory groupDetailFactory,
RenameGroupOp.Factory renameGroupOpFactory,
Provider<IdentifiedUser> currentUser) {
this.db = db;
this.groupCache = groupCache;
this.groupDetailFactory = groupDetailFactory;
this.renameGroupOpFactory = renameGroupOpFactory;
this.currentUser = currentUser;
}
@Override
public String apply(GroupResource resource, Input input)
public String apply(GroupResource rsrc, Input input)
throws MethodNotAllowedException, AuthException, BadRequestException,
ResourceNotFoundException, ResourceConflictException, OrmException {
if (resource.toAccountGroup() == null) {
ResourceNotFoundException, ResourceConflictException, OrmException,
NoSuchGroupException {
if (rsrc.toAccountGroup() == null) {
throw new MethodNotAllowedException();
} else if (!resource.getControl().isOwner()) {
} else if (!rsrc.getControl().isOwner()) {
throw new AuthException("Not group owner");
} else if (input == null || Strings.isNullOrEmpty(input.name)) {
throw new BadRequestException("name is required");
}
String newName = input.name.trim();
if (newName.isEmpty()) {
throw new BadRequestException("name is required");
}
final String newName = input.name.trim();
if (resource.toAccountGroup().getName().equals(newName)) {
if (rsrc.toAccountGroup().getName().equals(newName)) {
return newName;
}
return renameGroup(rsrc.toAccountGroup(), newName).group.getName();
}
private GroupDetail renameGroup(AccountGroup group, String newName)
throws ResourceConflictException, OrmException,
NoSuchGroupException {
AccountGroup.Id groupId = group.getId();
AccountGroup.NameKey old = group.getNameKey();
AccountGroup.NameKey key = new AccountGroup.NameKey(newName);
try {
return performRenameGroupFactory.create().renameGroup(
resource.toAccountGroup().getId(), newName).group.getName();
} catch (NoSuchGroupException e) {
throw new ResourceNotFoundException();
} catch (InvalidNameException e) {
throw new BadRequestException(e.getMessage());
} catch (NameAlreadyUsedException e) {
throw new ResourceConflictException(e.getMessage());
AccountGroupName id = new AccountGroupName(key, groupId);
db.get().accountGroupNames().insert(Collections.singleton(id));
} catch (OrmException e) {
AccountGroupName other = db.get().accountGroupNames().get(key);
if (other != null) {
// If we are using this identity, don't report the exception.
//
if (other.getId().equals(groupId)) {
return groupDetailFactory.create(groupId).call();
}
// Otherwise, someone else has this identity.
//
throw new ResourceConflictException("group with name " + newName
+ "already exists");
} else {
throw e;
}
}
group.setNameKey(key);
db.get().accountGroups().update(Collections.singleton(group));
AccountGroupName priorName = db.get().accountGroupNames().get(old);
if (priorName != null) {
db.get().accountGroupNames().delete(Collections.singleton(priorName));
}
groupCache.evict(group);
groupCache.evictAfterRename(old, key);
renameGroupOpFactory.create(
currentUser.get().newCommitterIdent(new Date(), TimeZone.getDefault()),
group.getGroupUUID(),
old.get(), newName).start(0, TimeUnit.MILLISECONDS);
return groupDetailFactory.create(groupId).call();
}
}

View File

@ -14,17 +14,21 @@
package com.google.gerrit.sshd.commands;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.errors.NameAlreadyUsedException;
import com.google.gerrit.common.errors.PermissionDeniedException;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.account.CreateGroupArgs;
import com.google.gerrit.server.account.PerformCreateGroup;
import com.google.gerrit.server.validators.GroupCreationValidationListener;
import com.google.gerrit.server.validators.ValidationException;
import com.google.gerrit.server.group.AddIncludedGroups;
import com.google.gerrit.server.group.AddMembers;
import com.google.gerrit.server.group.CreateGroup;
import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gerrit.server.group.GroupResource;
import com.google.gerrit.server.group.GroupsCollection;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.gwtorm.server.OrmException;
@ -71,36 +75,75 @@ final class CreateGroupCommand extends SshCommand {
}
@Inject
private PerformCreateGroup.Factory performCreateGroupFactory;
private CreateGroup.Factory createGroupFactory;
@Inject
private DynamicSet<GroupCreationValidationListener> groupCreationValidationListeners;
private GroupsCollection groups;
@Inject
private AddMembers addMembers;
@Inject
private AddIncludedGroups addIncludedGroups;
@Override
protected void run() throws Failure, OrmException {
try {
CreateGroupArgs args = new CreateGroupArgs();
args.setGroupName(groupName);
args.groupDescription = groupDescription;
args.visibleToAll = visibleToAll;
args.ownerGroupId = ownerGroupId;
args.initialMembers = initialMembers;
args.initialGroups = initialGroups;
GroupResource rsrc = createGroup();
for (GroupCreationValidationListener l : groupCreationValidationListeners) {
try {
l.validateNewGroup(args);
} catch (ValidationException e) {
die(e);
}
if (!initialMembers.isEmpty()) {
addMembers(rsrc);
}
performCreateGroupFactory.create(args).createGroup();
} catch (PermissionDeniedException e) {
throw die(e);
} catch (NameAlreadyUsedException e) {
if (!initialGroups.isEmpty()) {
addIncludedGroups(rsrc);
}
} catch (RestApiException e) {
throw die(e);
}
}
private GroupResource createGroup() throws RestApiException, OrmException {
CreateGroup.Input input = new CreateGroup.Input();
input.description = groupDescription;
input.visibleToAll = visibleToAll;
if (ownerGroupId != null) {
input.ownerId = String.valueOf(ownerGroupId.get());
}
GroupInfo group = createGroupFactory.create(groupName)
.apply(TopLevelResource.INSTANCE, input);
return groups.parse(TopLevelResource.INSTANCE,
IdString.fromUrl(group.id));
}
private void addMembers(GroupResource rsrc) throws RestApiException,
OrmException {
AddMembers.Input input =
AddMembers.Input.fromMembers(FluentIterable
.from(initialMembers)
.transform(new Function<Account.Id, String>() {
@Override
public String apply(Account.Id id) {
return String.valueOf(id.get());
}
})
.toList());
addMembers.apply(rsrc, input);
}
private void addIncludedGroups(GroupResource rsrc) throws RestApiException,
OrmException {
AddIncludedGroups.Input input =
AddIncludedGroups.Input.fromGroups(FluentIterable.from(initialGroups)
.transform(new Function<AccountGroup.UUID, String>() {
@Override
public String apply(AccountGroup.UUID id) {
return id.get();
}
}).toList());
addIncludedGroups.apply(rsrc, input);
}
}

View File

@ -14,10 +14,13 @@
package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.errors.InvalidNameException;
import com.google.gerrit.common.errors.NameAlreadyUsedException;
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.server.account.PerformRenameGroup;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.server.group.GroupResource;
import com.google.gerrit.server.group.GroupsCollection;
import com.google.gerrit.server.group.PutName;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.gwtorm.server.OrmException;
@ -34,19 +37,20 @@ public class RenameGroupCommand extends SshCommand {
private String newGroupName;
@Inject
private PerformRenameGroup.Factory performRenameGroupFactory;
private GroupsCollection groups;
@Inject
private PutName putName;
@Override
protected void run() throws Failure {
try {
performRenameGroupFactory.create().renameGroup(groupName, newGroupName);
} catch (OrmException e) {
throw die(e);
} catch (InvalidNameException e) {
throw die(e);
} catch (NameAlreadyUsedException e) {
throw die(e);
} catch (NoSuchGroupException e) {
GroupResource rsrc = groups.parse(TopLevelResource.INSTANCE,
IdString.fromDecoded(groupName));
PutName.Input input = new PutName.Input();
input.name = newGroupName;
putName.apply(rsrc, input);
} catch (RestApiException | OrmException | NoSuchGroupException e) {
throw die(e);
}
}