Support creation of groups via REST
A new group can now be created by POST on '/groups/'. The WebUI was adapted to create groups via REST. Change-Id: Ib11150cc4aa7944c5e79fff194fe97797cb77de2 Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
		| @@ -20,12 +20,13 @@ import com.google.gerrit.client.Dispatcher; | |||||||
| import com.google.gerrit.client.Gerrit; | import com.google.gerrit.client.Gerrit; | ||||||
| import com.google.gerrit.client.NotFoundScreen; | import com.google.gerrit.client.NotFoundScreen; | ||||||
| import com.google.gerrit.client.account.AccountCapabilities; | import com.google.gerrit.client.account.AccountCapabilities; | ||||||
|  | import com.google.gerrit.client.groups.GroupApi; | ||||||
|  | import com.google.gerrit.client.groups.GroupInfo; | ||||||
| import com.google.gerrit.client.rpc.GerritCallback; | import com.google.gerrit.client.rpc.GerritCallback; | ||||||
| import com.google.gerrit.client.ui.OnEditEnabler; | import com.google.gerrit.client.ui.OnEditEnabler; | ||||||
| import com.google.gerrit.client.ui.Screen; | import com.google.gerrit.client.ui.Screen; | ||||||
| import com.google.gerrit.client.ui.SmallHeading; | import com.google.gerrit.client.ui.SmallHeading; | ||||||
| import com.google.gerrit.common.PageLinks; | import com.google.gerrit.common.PageLinks; | ||||||
| import com.google.gerrit.reviewdb.client.AccountGroup; |  | ||||||
| import com.google.gwt.event.dom.client.ClickEvent; | import com.google.gwt.event.dom.client.ClickEvent; | ||||||
| import com.google.gwt.event.dom.client.ClickHandler; | import com.google.gwt.event.dom.client.ClickHandler; | ||||||
| import com.google.gwt.event.dom.client.KeyCodes; | import com.google.gwt.event.dom.client.KeyCodes; | ||||||
| @@ -106,9 +107,10 @@ public class CreateGroupScreen extends Screen { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     addNew.setEnabled(false); |     addNew.setEnabled(false); | ||||||
|     Util.GROUP_SVC.createGroup(newName, new GerritCallback<AccountGroup.Id>() { |     GroupApi.createGroup(newName, new GerritCallback<GroupInfo>() { | ||||||
|       public void onSuccess(final AccountGroup.Id result) { |       public void onSuccess(final GroupInfo result) { | ||||||
|         History.newItem(Dispatcher.toGroup(result, AccountGroupScreen.MEMBERS)); |         History.newItem(Dispatcher.toGroup(result.getGroupId(), | ||||||
|  |             AccountGroupScreen.MEMBERS)); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       @Override |       @Override | ||||||
|   | |||||||
| @@ -31,6 +31,13 @@ import java.util.Set; | |||||||
|  */ |  */ | ||||||
| public class GroupApi { | public class GroupApi { | ||||||
|  |  | ||||||
|  |   /** Create a new group */ | ||||||
|  |   public static void createGroup(String groupName, AsyncCallback<GroupInfo> cb) { | ||||||
|  |     GroupInput in = GroupInput.create(); | ||||||
|  |     in.name(groupName); | ||||||
|  |     new RestApi("/groups/").data(in).post(cb); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /** Add member to a group. */ |   /** Add member to a group. */ | ||||||
|   public static void addMember(AccountGroup.UUID groupUUID, |   public static void addMember(AccountGroup.UUID groupUUID, | ||||||
|       String member, AsyncCallback<MemberInfo> cb) { |       String member, AsyncCallback<MemberInfo> cb) { | ||||||
| @@ -101,4 +108,15 @@ public class GroupApi { | |||||||
|     protected MemberInput() { |     protected MemberInput() { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   private static class GroupInput extends JavaScriptObject { | ||||||
|  |     final native void name(String n) /*-{ if(n)this.name=n; }-*/; | ||||||
|  |  | ||||||
|  |     static GroupInput create() { | ||||||
|  |       return (GroupInput) createObject(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected GroupInput() { | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -56,6 +56,6 @@ class CreateGroup extends Handler<AccountGroup.Id> { | |||||||
|     final PerformCreateGroup performCreateGroup = performCreateGroupFactory.create(); |     final PerformCreateGroup performCreateGroup = performCreateGroupFactory.create(); | ||||||
|     final Account.Id me = user.getAccountId(); |     final Account.Id me = user.getAccountId(); | ||||||
|     return performCreateGroup.createGroup(groupName, null, visibleToAll, null, |     return performCreateGroup.createGroup(groupName, null, visibleToAll, null, | ||||||
|         Collections.singleton(me), null); |         Collections.singleton(me), null).getId(); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -84,7 +84,7 @@ public class PerformCreateGroup { | |||||||
|    *         name already exists |    *         name already exists | ||||||
|    * @throws PermissionDeniedException user cannot create a group. |    * @throws PermissionDeniedException user cannot create a group. | ||||||
|    */ |    */ | ||||||
|   public AccountGroup.Id createGroup(final String groupName, |   public AccountGroup createGroup(final String groupName, | ||||||
|       final String groupDescription, final boolean visibleToAll, |       final String groupDescription, final boolean visibleToAll, | ||||||
|       final AccountGroup.Id ownerGroupId, |       final AccountGroup.Id ownerGroupId, | ||||||
|       final Collection<? extends Account.Id> initialMembers, |       final Collection<? extends Account.Id> initialMembers, | ||||||
| @@ -133,7 +133,7 @@ public class PerformCreateGroup { | |||||||
|  |  | ||||||
|     groupCache.onCreateGroup(nameKey); |     groupCache.onCreateGroup(nameKey); | ||||||
|  |  | ||||||
|     return groupId; |     return group; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private void addMembers(final AccountGroup.Id groupId, |   private void addMembers(final AccountGroup.Id groupId, | ||||||
|   | |||||||
| @@ -52,6 +52,7 @@ import com.google.gerrit.server.account.GroupIncludeCacheImpl; | |||||||
| import com.google.gerrit.server.account.GroupInfoCacheFactory; | import com.google.gerrit.server.account.GroupInfoCacheFactory; | ||||||
| import com.google.gerrit.server.account.IncludingGroupMembership; | import com.google.gerrit.server.account.IncludingGroupMembership; | ||||||
| import com.google.gerrit.server.account.InternalGroupBackend; | import com.google.gerrit.server.account.InternalGroupBackend; | ||||||
|  | import com.google.gerrit.server.account.PerformCreateGroup; | ||||||
| import com.google.gerrit.server.account.Realm; | import com.google.gerrit.server.account.Realm; | ||||||
| import com.google.gerrit.server.account.UniversalGroupBackend; | import com.google.gerrit.server.account.UniversalGroupBackend; | ||||||
| import com.google.gerrit.server.auth.AuthBackend; | import com.google.gerrit.server.auth.AuthBackend; | ||||||
| @@ -159,6 +160,7 @@ public class GerritGlobalModule extends FactoryModule { | |||||||
|     factory(ChangeQueryBuilder.Factory.class); |     factory(ChangeQueryBuilder.Factory.class); | ||||||
|     factory(GroupInfoCacheFactory.Factory.class); |     factory(GroupInfoCacheFactory.Factory.class); | ||||||
|     factory(GroupDetailFactory.Factory.class); |     factory(GroupDetailFactory.Factory.class); | ||||||
|  |     factory(PerformCreateGroup.Factory.class); | ||||||
|     factory(InternalUser.Factory.class); |     factory(InternalUser.Factory.class); | ||||||
|     factory(ProjectNode.Factory.class); |     factory(ProjectNode.Factory.class); | ||||||
|     factory(ProjectState.Factory.class); |     factory(ProjectState.Factory.class); | ||||||
|   | |||||||
| @@ -20,7 +20,6 @@ import com.google.gerrit.server.ApprovalsUtil; | |||||||
| import com.google.gerrit.server.IdentifiedUser; | import com.google.gerrit.server.IdentifiedUser; | ||||||
| import com.google.gerrit.server.RequestCleanup; | import com.google.gerrit.server.RequestCleanup; | ||||||
| import com.google.gerrit.server.account.GroupMembers; | 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.account.PerformRenameGroup; | ||||||
| import com.google.gerrit.server.changedetail.DeleteDraftPatchSet; | import com.google.gerrit.server.changedetail.DeleteDraftPatchSet; | ||||||
| import com.google.gerrit.server.changedetail.PublishDraft; | import com.google.gerrit.server.changedetail.PublishDraft; | ||||||
| @@ -79,7 +78,6 @@ public class GerritRequestModule extends FactoryModule { | |||||||
|     factory(RemoveReviewer.Factory.class); |     factory(RemoveReviewer.Factory.class); | ||||||
|     factory(MergedSender.Factory.class); |     factory(MergedSender.Factory.class); | ||||||
|     factory(MergeFailSender.Factory.class); |     factory(MergeFailSender.Factory.class); | ||||||
|     factory(PerformCreateGroup.Factory.class); |  | ||||||
|     factory(PerformRenameGroup.Factory.class); |     factory(PerformRenameGroup.Factory.class); | ||||||
|     factory(GroupMembers.Factory.class); |     factory(GroupMembers.Factory.class); | ||||||
|     factory(CreateProject.Factory.class); |     factory(CreateProject.Factory.class); | ||||||
|   | |||||||
| @@ -0,0 +1,90 @@ | |||||||
|  | // 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.gerrit.common.data.GroupDescriptions; | ||||||
|  | import com.google.gerrit.common.errors.NameAlreadyUsedException; | ||||||
|  | import com.google.gerrit.common.errors.PermissionDeniedException; | ||||||
|  | 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.RestModifyView; | ||||||
|  | import com.google.gerrit.extensions.restapi.TopLevelResource; | ||||||
|  | import com.google.gerrit.reviewdb.client.AccountGroup; | ||||||
|  | import com.google.gerrit.server.CurrentUser; | ||||||
|  | import com.google.gerrit.server.IdentifiedUser; | ||||||
|  | import com.google.gerrit.server.account.GroupCache; | ||||||
|  | import com.google.gerrit.server.account.PerformCreateGroup; | ||||||
|  | import com.google.gerrit.server.group.CreateGroup.Input; | ||||||
|  | import com.google.gwtorm.server.OrmException; | ||||||
|  | import com.google.inject.Provider; | ||||||
|  |  | ||||||
|  | import org.eclipse.jgit.lib.Config; | ||||||
|  |  | ||||||
|  | import java.util.Collections; | ||||||
|  |  | ||||||
|  | public class CreateGroup implements RestModifyView<TopLevelResource, Input> { | ||||||
|  |   static class Input { | ||||||
|  |     @DefaultInput | ||||||
|  |     String name; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private final PerformCreateGroup.Factory performCreateGroupFactory; | ||||||
|  |   private final GroupCache groupCache; | ||||||
|  |   private final Provider<CurrentUser> self; | ||||||
|  |   final boolean visibleToAll; | ||||||
|  |  | ||||||
|  |   CreateGroup(final PerformCreateGroup.Factory performCreateGroupFactory, | ||||||
|  |       final GroupCache groupCache, final Provider<CurrentUser> self, | ||||||
|  |       final Config cfg) { | ||||||
|  |     this.performCreateGroupFactory = performCreateGroupFactory; | ||||||
|  |     this.groupCache = groupCache; | ||||||
|  |     this.self = self; | ||||||
|  |     this.visibleToAll = cfg.getBoolean("groups", "newGroupsVisibleToAll", false); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public Class<Input> inputType() { | ||||||
|  |     return Input.class; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public GroupInfo apply(TopLevelResource resource, Input input) | ||||||
|  |       throws AuthException, BadRequestException, OrmException, | ||||||
|  |       NameAlreadyUsedException { | ||||||
|  |     final IdentifiedUser me = ((IdentifiedUser) self.get()); | ||||||
|  |     if (!me.getCapabilities().canCreateGroup()) { | ||||||
|  |       throw new AuthException("Cannot create group"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (input == null || Strings.isNullOrEmpty(input.name)) { | ||||||
|  |       throw new BadRequestException("group name missing"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     AccountGroup group = groupCache.get(new AccountGroup.NameKey(input.name)); | ||||||
|  |     if (group != null) { | ||||||
|  |       return new GroupInfo(GroupDescriptions.forAccountGroup(group)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     try { | ||||||
|  |       group = performCreateGroupFactory.create().createGroup(input.name, null, | ||||||
|  |           visibleToAll, null, Collections.singleton(me.getAccountId()), null); | ||||||
|  |     } catch (PermissionDeniedException e) { | ||||||
|  |       throw new AuthException(e.getMessage()); | ||||||
|  |     } | ||||||
|  |     return new GroupInfo(GroupDescriptions.forAccountGroup(group)); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -18,6 +18,7 @@ import com.google.common.collect.Iterables; | |||||||
| import com.google.gerrit.common.data.GroupReference; | import com.google.gerrit.common.data.GroupReference; | ||||||
| import com.google.gerrit.common.errors.NoSuchGroupException; | import com.google.gerrit.common.errors.NoSuchGroupException; | ||||||
| import com.google.gerrit.extensions.registration.DynamicMap; | import com.google.gerrit.extensions.registration.DynamicMap; | ||||||
|  | import com.google.gerrit.extensions.restapi.AcceptsPost; | ||||||
| import com.google.gerrit.extensions.restapi.AuthException; | import com.google.gerrit.extensions.restapi.AuthException; | ||||||
| import com.google.gerrit.extensions.restapi.ResourceNotFoundException; | import com.google.gerrit.extensions.restapi.ResourceNotFoundException; | ||||||
| import com.google.gerrit.extensions.restapi.RestCollection; | import com.google.gerrit.extensions.restapi.RestCollection; | ||||||
| @@ -28,32 +29,45 @@ import com.google.gerrit.server.AnonymousUser; | |||||||
| import com.google.gerrit.server.CurrentUser; | import com.google.gerrit.server.CurrentUser; | ||||||
| import com.google.gerrit.server.IdentifiedUser; | import com.google.gerrit.server.IdentifiedUser; | ||||||
| import com.google.gerrit.server.account.GroupBackend; | import com.google.gerrit.server.account.GroupBackend; | ||||||
|  | import com.google.gerrit.server.account.GroupCache; | ||||||
| import com.google.gerrit.server.account.GroupControl; | import com.google.gerrit.server.account.GroupControl; | ||||||
|  | import com.google.gerrit.server.account.PerformCreateGroup; | ||||||
|  | import com.google.gerrit.server.config.GerritServerConfig; | ||||||
| import com.google.gerrit.server.util.Url; | import com.google.gerrit.server.util.Url; | ||||||
| import com.google.inject.Inject; | import com.google.inject.Inject; | ||||||
| import com.google.inject.Provider; | import com.google.inject.Provider; | ||||||
|  |  | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
|  | import org.eclipse.jgit.lib.Config; | ||||||
|  |  | ||||||
| public class GroupsCollection implements | public class GroupsCollection implements | ||||||
|     RestCollection<TopLevelResource, GroupResource> { |     RestCollection<TopLevelResource, GroupResource>, | ||||||
|  |     AcceptsPost<TopLevelResource> { | ||||||
|   private final DynamicMap<RestView<GroupResource>> views; |   private final DynamicMap<RestView<GroupResource>> views; | ||||||
|   private final Provider<ListGroups> list; |   private final Provider<ListGroups> list; | ||||||
|   private final GroupControl.Factory groupControlFactory; |   private final GroupControl.Factory groupControlFactory; | ||||||
|   private final GroupBackend groupBackend; |   private final GroupBackend groupBackend; | ||||||
|   private final Provider<CurrentUser> self; |   private final Provider<CurrentUser> self; | ||||||
|  |   private final PerformCreateGroup.Factory performCreateGroupFactory; | ||||||
|  |   private final GroupCache groupCache; | ||||||
|  |   private final Config cfg; | ||||||
|  |  | ||||||
|   @Inject |   @Inject | ||||||
|   GroupsCollection(final DynamicMap<RestView<GroupResource>> views, |   GroupsCollection(final DynamicMap<RestView<GroupResource>> views, | ||||||
|       final Provider<ListGroups> list, |       final Provider<ListGroups> list, | ||||||
|       final GroupControl.Factory groupControlFactory, |       final GroupControl.Factory groupControlFactory, | ||||||
|       final GroupBackend groupBackend, |       final GroupBackend groupBackend, | ||||||
|       final Provider<CurrentUser> self) { |       final Provider<CurrentUser> self, | ||||||
|  |       final PerformCreateGroup.Factory performCreateGroupFactory, | ||||||
|  |       final GroupCache groupCache, @GerritServerConfig final Config cfg) { | ||||||
|     this.views = views; |     this.views = views; | ||||||
|     this.list = list; |     this.list = list; | ||||||
|     this.groupControlFactory = groupControlFactory; |     this.groupControlFactory = groupControlFactory; | ||||||
|     this.groupBackend = groupBackend; |     this.groupBackend = groupBackend; | ||||||
|     this.self = self; |     this.self = self; | ||||||
|  |     this.performCreateGroupFactory = performCreateGroupFactory; | ||||||
|  |     this.groupCache = groupCache; | ||||||
|  |     this.cfg = cfg; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
| @@ -120,6 +134,12 @@ public class GroupsCollection implements | |||||||
|     throw new ResourceNotFoundException(urlId); |     throw new ResourceNotFoundException(urlId); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @SuppressWarnings("unchecked") | ||||||
|  |   @Override | ||||||
|  |   public CreateGroup post(TopLevelResource parent) { | ||||||
|  |     return new CreateGroup(performCreateGroupFactory, groupCache, self, cfg); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
|   public DynamicMap<RestView<GroupResource>> views() { |   public DynamicMap<RestView<GroupResource>> views() { | ||||||
|     return views; |     return views; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Edwin Kempin
					Edwin Kempin