Add REST endpoint to retrieve groups
The '/groups/' REST endpoint lists the groups accessible by the caller. This is the same as using the ls-groups command over SSH, and accepts the same options as query parameters. Information for a certain group can be accessed by '/groups/uuid-<group-uuid>' or '/groups/<group-id>'. Change-Id: I8c21cd1618bdf593ebff7e55f25f31f1e32ae9c1 Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
		@@ -243,6 +243,78 @@ To retrieve only the default dashboard, add `default` to the URL:
 | 
			
		||||
  }
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
[[groups]]
 | 
			
		||||
/groups/ (List Groups)
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
Lists the groups accessible by the caller. This is the same as
 | 
			
		||||
using the link:cmd-ls-groups.html[ls-groups] command over SSH,
 | 
			
		||||
and accepts the same options as query parameters.
 | 
			
		||||
 | 
			
		||||
----
 | 
			
		||||
  GET /groups/ HTTP/1.0
 | 
			
		||||
 | 
			
		||||
  HTTP/1.1 200 OK
 | 
			
		||||
  Content-Disposition: attachment
 | 
			
		||||
  Content-Type: application/json;charset=UTF-8
 | 
			
		||||
 | 
			
		||||
  )]}'
 | 
			
		||||
  {
 | 
			
		||||
    "Administrators": {
 | 
			
		||||
      "kind": "gerritcodereview#group",
 | 
			
		||||
      "id": "uuid-6a1e70e1a88782771a91808c8af9bbb7a9871389",
 | 
			
		||||
      "uuid": "6a1e70e1a88782771a91808c8af9bbb7a9871389",
 | 
			
		||||
      "group_id": 1,
 | 
			
		||||
      "description": "Gerrit Site Administrators",
 | 
			
		||||
      "is_visible_to_all": false,
 | 
			
		||||
      "owner_uuid": "6a1e70e1a88782771a91808c8af9bbb7a9871389"
 | 
			
		||||
    },
 | 
			
		||||
    "Anonymous Users": {
 | 
			
		||||
      "kind": "gerritcodereview#group",
 | 
			
		||||
      "id": "uuid-global%3AAnonymous-Users",
 | 
			
		||||
      "uuid": "global:Anonymous-Users",
 | 
			
		||||
      "group_id": 2,
 | 
			
		||||
      "description": "Any user, signed-in or not",
 | 
			
		||||
      "is_visible_to_all": false,
 | 
			
		||||
      "owner_uuid": "6a1e70e1a88782771a91808c8af9bbb7a9871389"
 | 
			
		||||
    },
 | 
			
		||||
    "MyProject_Committers": {
 | 
			
		||||
      "kind": "gerritcodereview#group",
 | 
			
		||||
      "id": "uuid-834ec36dd5e0ed21a2ff5d7e2255da082d63bbd7",
 | 
			
		||||
      "uuid": "834ec36dd5e0ed21a2ff5d7e2255da082d63bbd7",
 | 
			
		||||
      "group_id": 6,
 | 
			
		||||
      "is_visible_to_all": true,
 | 
			
		||||
      "owner_uuid": "834ec36dd5e0ed21a2ff5d7e2255da082d63bbd7"
 | 
			
		||||
    },
 | 
			
		||||
    "Non-Interactive Users": {
 | 
			
		||||
      "kind": "gerritcodereview#group",
 | 
			
		||||
      "id": "uuid-5057f3cbd3519d6ab69364429a89ffdffba50f73",
 | 
			
		||||
      "uuid": "5057f3cbd3519d6ab69364429a89ffdffba50f73",
 | 
			
		||||
      "group_id": 4,
 | 
			
		||||
      "description": "Users who perform batch actions on Gerrit",
 | 
			
		||||
      "is_visible_to_all": false,
 | 
			
		||||
      "owner_uuid": "6a1e70e1a88782771a91808c8af9bbb7a9871389"
 | 
			
		||||
    },
 | 
			
		||||
    "Project Owners": {
 | 
			
		||||
      "kind": "gerritcodereview#group",
 | 
			
		||||
      "id": "uuid-global%3AProject-Owners",
 | 
			
		||||
      "uuid": "global:Project-Owners",
 | 
			
		||||
      "group_id": 5,
 | 
			
		||||
      "description": "Any owner of the project",
 | 
			
		||||
      "is_visible_to_all": false,
 | 
			
		||||
      "owner_uuid": "6a1e70e1a88782771a91808c8af9bbb7a9871389"
 | 
			
		||||
    },
 | 
			
		||||
    "Registered Users": {
 | 
			
		||||
      "kind": "gerritcodereview#group",
 | 
			
		||||
      "id": "uuid-global%3ARegistered-Users",
 | 
			
		||||
      "uuid": "global:Registered-Users",
 | 
			
		||||
      "group_id": 3,
 | 
			
		||||
      "description": "Any signed-in user",
 | 
			
		||||
      "is_visible_to_all": false,
 | 
			
		||||
      "owner_uuid": "6a1e70e1a88782771a91808c8af9bbb7a9871389"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
[[changes]]
 | 
			
		||||
/changes/ (Query Changes)
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,7 @@ import com.google.gerrit.httpd.raw.ToolServlet;
 | 
			
		||||
import com.google.gerrit.httpd.rpc.account.AccountsRestApiServlet;
 | 
			
		||||
import com.google.gerrit.httpd.rpc.change.ChangesRestApiServlet;
 | 
			
		||||
import com.google.gerrit.httpd.rpc.change.DeprecatedChangeQueryServlet;
 | 
			
		||||
import com.google.gerrit.httpd.rpc.group.GroupsRestApiServlet;
 | 
			
		||||
import com.google.gerrit.httpd.rpc.project.ProjectsRestApiServlet;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.Change;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.Project;
 | 
			
		||||
@@ -97,6 +98,7 @@ class UrlModule extends ServletModule {
 | 
			
		||||
    filter("/a/*").through(RequireIdentifiedUserFilter.class);
 | 
			
		||||
    serveRegex("^/(?:a/)?accounts/(.*)$").with(AccountsRestApiServlet.class);
 | 
			
		||||
    serveRegex("^/(?:a/)?changes/(.*)$").with(ChangesRestApiServlet.class);
 | 
			
		||||
    serveRegex("^/(?:a/)?groups/(.*)?$").with(GroupsRestApiServlet.class);
 | 
			
		||||
    serveRegex("^/(?:a/)?projects/(.*)?$").with(ProjectsRestApiServlet.class);
 | 
			
		||||
 | 
			
		||||
    if (cfg.deprecatedQuery) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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.httpd.rpc.group;
 | 
			
		||||
 | 
			
		||||
import com.google.gerrit.httpd.restapi.RestApiServlet;
 | 
			
		||||
import com.google.gerrit.server.group.GroupsCollection;
 | 
			
		||||
import com.google.inject.Inject;
 | 
			
		||||
import com.google.inject.Provider;
 | 
			
		||||
import com.google.inject.Singleton;
 | 
			
		||||
 | 
			
		||||
@Singleton
 | 
			
		||||
public class GroupsRestApiServlet extends RestApiServlet {
 | 
			
		||||
  private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
  @Inject
 | 
			
		||||
  GroupsRestApiServlet(RestApiServlet.Globals globals,
 | 
			
		||||
      Provider<GroupsCollection> groups) {
 | 
			
		||||
    super(globals, groups);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -84,6 +84,10 @@ public class GroupControl {
 | 
			
		||||
    this(who, GroupDescriptions.forAccountGroup(ag));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public GroupDescription.Basic getGroup() {
 | 
			
		||||
    return group;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public CurrentUser getCurrentUser() {
 | 
			
		||||
    return user;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,7 @@ import com.google.gerrit.server.account.IncludingGroupMembership;
 | 
			
		||||
import com.google.gerrit.server.account.InternalGroupBackend;
 | 
			
		||||
import com.google.gerrit.server.account.Realm;
 | 
			
		||||
import com.google.gerrit.server.account.UniversalGroupBackend;
 | 
			
		||||
import com.google.gerrit.server.account.VisibleGroups;
 | 
			
		||||
import com.google.gerrit.server.auth.AuthBackend;
 | 
			
		||||
import com.google.gerrit.server.auth.InternalAuthBackend;
 | 
			
		||||
import com.google.gerrit.server.auth.UniversalAuthBackend;
 | 
			
		||||
@@ -151,6 +152,7 @@ public class GerritGlobalModule extends FactoryModule {
 | 
			
		||||
    factory(CapabilityControl.Factory.class);
 | 
			
		||||
    factory(ChangeQueryBuilder.Factory.class);
 | 
			
		||||
    factory(GroupInfoCacheFactory.Factory.class);
 | 
			
		||||
    factory(VisibleGroups.Factory.class);
 | 
			
		||||
    factory(InternalUser.Factory.class);
 | 
			
		||||
    factory(ProjectNode.Factory.class);
 | 
			
		||||
    factory(ProjectState.Factory.class);
 | 
			
		||||
@@ -194,6 +196,7 @@ public class GerritGlobalModule extends FactoryModule {
 | 
			
		||||
    install(new AuditModule());
 | 
			
		||||
    install(new com.google.gerrit.server.account.Module());
 | 
			
		||||
    install(new com.google.gerrit.server.change.Module());
 | 
			
		||||
    install(new com.google.gerrit.server.group.Module());
 | 
			
		||||
    install(new com.google.gerrit.server.project.Module());
 | 
			
		||||
 | 
			
		||||
    bind(GitReferenceUpdated.class);
 | 
			
		||||
 
 | 
			
		||||
@@ -85,7 +85,6 @@ public class GerritRequestModule extends FactoryModule {
 | 
			
		||||
    factory(MergeFailSender.Factory.class);
 | 
			
		||||
    factory(PerformCreateGroup.Factory.class);
 | 
			
		||||
    factory(PerformRenameGroup.Factory.class);
 | 
			
		||||
    factory(VisibleGroups.Factory.class);
 | 
			
		||||
    factory(GroupDetailFactory.Factory.class);
 | 
			
		||||
    factory(GroupMembers.Factory.class);
 | 
			
		||||
    factory(CreateProject.Factory.class);
 | 
			
		||||
 
 | 
			
		||||
@@ -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.group;
 | 
			
		||||
 | 
			
		||||
import com.google.common.base.Strings;
 | 
			
		||||
import com.google.gerrit.common.data.GroupDescription;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.AuthException;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.BadRequestException;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.RestReadView;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.AccountGroup;
 | 
			
		||||
import com.google.gerrit.server.util.Url;
 | 
			
		||||
 | 
			
		||||
class GetGroup implements RestReadView<GroupResource> {
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public Object apply(GroupResource resource) throws AuthException,
 | 
			
		||||
      BadRequestException, ResourceConflictException, Exception {
 | 
			
		||||
    GroupDescription.Basic group = resource.getControl().getGroup();
 | 
			
		||||
    GroupInfo info = new GroupInfo();
 | 
			
		||||
    info.name = resource.getName();
 | 
			
		||||
    info.uuid = resource.getGroupUUID().get();
 | 
			
		||||
    info.isVisibleToAll = group.isVisibleToAll();
 | 
			
		||||
    if (group instanceof GroupDescription.Internal) {
 | 
			
		||||
      final AccountGroup internalGroup =
 | 
			
		||||
          ((GroupDescription.Internal) group).getAccountGroup();
 | 
			
		||||
      info.description = Strings.emptyToNull(internalGroup.getDescription());
 | 
			
		||||
      info.ownerUuid = internalGroup.getOwnerGroupUUID().get();
 | 
			
		||||
    }
 | 
			
		||||
    info.finish();
 | 
			
		||||
    return info;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static class GroupInfo {
 | 
			
		||||
    final String kind = "gerritcodereview#group";
 | 
			
		||||
    String id;
 | 
			
		||||
    String name;
 | 
			
		||||
    String uuid;
 | 
			
		||||
    String description;
 | 
			
		||||
    boolean isVisibleToAll;
 | 
			
		||||
    String ownerUuid;
 | 
			
		||||
 | 
			
		||||
    void finish() {
 | 
			
		||||
      id = Url.encode(GroupsCollection.UUID_PREFIX + uuid);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,44 @@
 | 
			
		||||
// 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.gerrit.extensions.restapi.RestResource;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.RestView;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.AccountGroup;
 | 
			
		||||
import com.google.gerrit.server.account.GroupControl;
 | 
			
		||||
import com.google.inject.TypeLiteral;
 | 
			
		||||
 | 
			
		||||
public class GroupResource implements RestResource {
 | 
			
		||||
  public static final TypeLiteral<RestView<GroupResource>> GROUP_KIND =
 | 
			
		||||
      new TypeLiteral<RestView<GroupResource>>() {};
 | 
			
		||||
 | 
			
		||||
  private final GroupControl control;
 | 
			
		||||
 | 
			
		||||
  GroupResource(GroupControl control) {
 | 
			
		||||
    this.control = control;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public String getName() {
 | 
			
		||||
    return control.getGroup().getName();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public AccountGroup.UUID getGroupUUID() {
 | 
			
		||||
    return control.getGroup().getGroupUUID();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public GroupControl getControl() {
 | 
			
		||||
    return control;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,103 @@
 | 
			
		||||
// 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.gerrit.common.errors.NoSuchGroupException;
 | 
			
		||||
import com.google.gerrit.extensions.registration.DynamicMap;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.AuthException;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.RestCollection;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.RestView;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.TopLevelResource;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.AccountGroup;
 | 
			
		||||
import com.google.gerrit.server.AnonymousUser;
 | 
			
		||||
import com.google.gerrit.server.CurrentUser;
 | 
			
		||||
import com.google.gerrit.server.IdentifiedUser;
 | 
			
		||||
import com.google.gerrit.server.account.GroupControl;
 | 
			
		||||
import com.google.gerrit.server.util.Url;
 | 
			
		||||
import com.google.inject.Inject;
 | 
			
		||||
import com.google.inject.Provider;
 | 
			
		||||
 | 
			
		||||
public class GroupsCollection implements
 | 
			
		||||
    RestCollection<TopLevelResource, GroupResource> {
 | 
			
		||||
  public final static String UUID_PREFIX = "uuid-";
 | 
			
		||||
 | 
			
		||||
  private final DynamicMap<RestView<GroupResource>> views;
 | 
			
		||||
  private final Provider<ListGroups> list;
 | 
			
		||||
  private final GroupControl.Factory groupControlFactory;
 | 
			
		||||
  private final Provider<CurrentUser> self;
 | 
			
		||||
 | 
			
		||||
  @Inject
 | 
			
		||||
  GroupsCollection(final DynamicMap<RestView<GroupResource>> views,
 | 
			
		||||
      final Provider<ListGroups> list,
 | 
			
		||||
      final GroupControl.Factory groupControlFactory,
 | 
			
		||||
      final Provider<CurrentUser> self) {
 | 
			
		||||
    this.views = views;
 | 
			
		||||
    this.list = list;
 | 
			
		||||
    this.groupControlFactory = groupControlFactory;
 | 
			
		||||
    this.self = self;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public RestView<TopLevelResource> list() throws ResourceNotFoundException,
 | 
			
		||||
      AuthException {
 | 
			
		||||
    final CurrentUser user = self.get();
 | 
			
		||||
    if (user instanceof AnonymousUser) {
 | 
			
		||||
      throw new AuthException("Authentication required");
 | 
			
		||||
    } else if(!(user instanceof IdentifiedUser)) {
 | 
			
		||||
      throw new ResourceNotFoundException();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return list.get();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public GroupResource parse(TopLevelResource parent, String id)
 | 
			
		||||
      throws ResourceNotFoundException, Exception {
 | 
			
		||||
    final CurrentUser user = self.get();
 | 
			
		||||
    if (user instanceof AnonymousUser) {
 | 
			
		||||
      throw new AuthException("Authentication required");
 | 
			
		||||
    } else if(!(user instanceof IdentifiedUser)) {
 | 
			
		||||
      throw new ResourceNotFoundException(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final String decodedId = Url.decode(id);
 | 
			
		||||
    final GroupControl ctl;
 | 
			
		||||
    try {
 | 
			
		||||
      if (decodedId.startsWith(UUID_PREFIX)) {
 | 
			
		||||
        final String uuid = decodedId.substring(UUID_PREFIX.length());
 | 
			
		||||
        ctl = groupControlFactory.controlFor(new AccountGroup.UUID(uuid));
 | 
			
		||||
      } else {
 | 
			
		||||
        try {
 | 
			
		||||
          ctl = groupControlFactory.controlFor(
 | 
			
		||||
              new AccountGroup.Id(Integer.parseInt(decodedId)));
 | 
			
		||||
        } catch (NumberFormatException e) {
 | 
			
		||||
          throw new ResourceNotFoundException(id);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } catch (NoSuchGroupException e) {
 | 
			
		||||
      throw new ResourceNotFoundException(id);
 | 
			
		||||
    }
 | 
			
		||||
    if (!ctl.isVisible() && !ctl.isOwner()) {
 | 
			
		||||
      throw new ResourceNotFoundException(id);
 | 
			
		||||
    }
 | 
			
		||||
    return new GroupResource(ctl);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public DynamicMap<RestView<GroupResource>> views() {
 | 
			
		||||
    return views;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,183 @@
 | 
			
		||||
// 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.collect.Maps;
 | 
			
		||||
import com.google.gerrit.common.data.GroupList;
 | 
			
		||||
import com.google.gerrit.common.errors.NoSuchGroupException;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.AuthException;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.BadRequestException;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.RestReadView;
 | 
			
		||||
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.IdentifiedUser;
 | 
			
		||||
import com.google.gerrit.server.OutputFormat;
 | 
			
		||||
import com.google.gerrit.server.account.GroupCache;
 | 
			
		||||
import com.google.gerrit.server.account.VisibleGroups;
 | 
			
		||||
import com.google.gerrit.server.ioutil.ColumnFormatter;
 | 
			
		||||
import com.google.gerrit.server.project.ProjectControl;
 | 
			
		||||
import com.google.gerrit.server.util.Url;
 | 
			
		||||
import com.google.gson.JsonElement;
 | 
			
		||||
import com.google.gson.reflect.TypeToken;
 | 
			
		||||
import com.google.gwtorm.client.KeyUtil;
 | 
			
		||||
import com.google.inject.Inject;
 | 
			
		||||
 | 
			
		||||
import org.kohsuke.args4j.Option;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedWriter;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.io.OutputStreamWriter;
 | 
			
		||||
import java.io.PrintWriter;
 | 
			
		||||
import java.io.UnsupportedEncodingException;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/** List groups visible to the calling user. */
 | 
			
		||||
public class ListGroups implements RestReadView<TopLevelResource> {
 | 
			
		||||
 | 
			
		||||
  private final GroupCache groupCache;
 | 
			
		||||
  private final VisibleGroups.Factory visibleGroupsFactory;
 | 
			
		||||
  private final IdentifiedUser.GenericFactory userFactory;
 | 
			
		||||
 | 
			
		||||
  @Option(name = "--project", aliases = {"-p"},
 | 
			
		||||
      usage = "projects for which the groups should be listed")
 | 
			
		||||
  private final List<ProjectControl> projects = new ArrayList<ProjectControl>();
 | 
			
		||||
 | 
			
		||||
  @Option(name = "--visible-to-all", usage = "to list only groups that are visible to all registered users")
 | 
			
		||||
  private boolean visibleToAll;
 | 
			
		||||
 | 
			
		||||
  @Option(name = "--type", usage = "type of group")
 | 
			
		||||
  private AccountGroup.Type groupType;
 | 
			
		||||
 | 
			
		||||
  @Option(name = "--user", aliases = {"-u"},
 | 
			
		||||
      usage = "user for which the groups should be listed")
 | 
			
		||||
  private Account.Id user;
 | 
			
		||||
 | 
			
		||||
  @Option(name = "--verbose", aliases = {"-v"},
 | 
			
		||||
      usage = "verbose output format with tab-separated columns for the " +
 | 
			
		||||
          "group name, UUID, description, type, owner group name, " +
 | 
			
		||||
          "owner group UUID, and whether the group is visible to all")
 | 
			
		||||
  private boolean verboseOutput;
 | 
			
		||||
 | 
			
		||||
  @Inject
 | 
			
		||||
  protected ListGroups(final GroupCache groupCache,
 | 
			
		||||
      final VisibleGroups.Factory visibleGroupsFactory,
 | 
			
		||||
      final IdentifiedUser.GenericFactory userFactory) {
 | 
			
		||||
    this.groupCache = groupCache;
 | 
			
		||||
    this.visibleGroupsFactory = visibleGroupsFactory;
 | 
			
		||||
    this.userFactory = userFactory;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public Account.Id getUser() {
 | 
			
		||||
    return user;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public List<ProjectControl> getProjects() {
 | 
			
		||||
    return projects;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public Object apply(TopLevelResource resource) throws AuthException,
 | 
			
		||||
      BadRequestException, ResourceConflictException, Exception {
 | 
			
		||||
    return display(null);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public JsonElement display(OutputStream displayOutputStream)
 | 
			
		||||
      throws NoSuchGroupException {
 | 
			
		||||
    PrintWriter stdout = null;
 | 
			
		||||
    if (displayOutputStream != null) {
 | 
			
		||||
      try {
 | 
			
		||||
        stdout = new PrintWriter(new BufferedWriter(
 | 
			
		||||
            new OutputStreamWriter(displayOutputStream, "UTF-8")));
 | 
			
		||||
      } catch (UnsupportedEncodingException e) {
 | 
			
		||||
        throw new RuntimeException("JVM lacks UTF-8 encoding", e);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      final VisibleGroups visibleGroups = visibleGroupsFactory.create();
 | 
			
		||||
      visibleGroups.setOnlyVisibleToAll(visibleToAll);
 | 
			
		||||
      visibleGroups.setGroupType(groupType);
 | 
			
		||||
      final GroupList groupList;
 | 
			
		||||
      if (!projects.isEmpty()) {
 | 
			
		||||
        groupList = visibleGroups.get(projects);
 | 
			
		||||
      } else if (user != null) {
 | 
			
		||||
        groupList = visibleGroups.get(userFactory.create(user));
 | 
			
		||||
      } else {
 | 
			
		||||
        groupList = visibleGroups.get();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (stdout == null) {
 | 
			
		||||
        final Map<String, GroupInfo> output = Maps.newTreeMap();
 | 
			
		||||
        for (final AccountGroup g : groupList.getGroups()) {
 | 
			
		||||
          final GroupInfo info = new GroupInfo();
 | 
			
		||||
          info.name = g.getName();
 | 
			
		||||
          info.groupId = g.getId().get();
 | 
			
		||||
          info.setUuid(g.getGroupUUID());
 | 
			
		||||
          info.description = g.getDescription();
 | 
			
		||||
          info.isVisibleToAll = g.isVisibleToAll();
 | 
			
		||||
          info.ownerUuid = g.getOwnerGroupUUID().get();
 | 
			
		||||
          output.put(info.name, info);
 | 
			
		||||
        }
 | 
			
		||||
        return OutputFormat.JSON.newGson().toJsonTree(output,
 | 
			
		||||
            new TypeToken<Map<String, GroupInfo>>() {}.getType());
 | 
			
		||||
      } else {
 | 
			
		||||
        final ColumnFormatter formatter = new ColumnFormatter(stdout, '\t');
 | 
			
		||||
        for (final AccountGroup g : groupList.getGroups()) {
 | 
			
		||||
          formatter.addColumn(g.getName());
 | 
			
		||||
          if (verboseOutput) {
 | 
			
		||||
            formatter.addColumn(KeyUtil.decode(g.getGroupUUID().toString()));
 | 
			
		||||
            formatter.addColumn(
 | 
			
		||||
                g.getDescription() != null ? g.getDescription() : "");
 | 
			
		||||
            formatter.addColumn(g.getType().toString());
 | 
			
		||||
            final AccountGroup owningGroup =
 | 
			
		||||
                groupCache.get(g.getOwnerGroupUUID());
 | 
			
		||||
            formatter.addColumn(
 | 
			
		||||
                owningGroup != null ? owningGroup.getName() : "n/a");
 | 
			
		||||
            formatter.addColumn(KeyUtil.decode(g.getOwnerGroupUUID().toString()));
 | 
			
		||||
            formatter.addColumn(Boolean.toString(g.isVisibleToAll()));
 | 
			
		||||
          }
 | 
			
		||||
          formatter.nextLine();
 | 
			
		||||
        }
 | 
			
		||||
        formatter.finish();
 | 
			
		||||
        return null;
 | 
			
		||||
      }
 | 
			
		||||
    } finally {
 | 
			
		||||
      if (stdout != null) {
 | 
			
		||||
        stdout.flush();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static class GroupInfo {
 | 
			
		||||
    final String kind = "gerritcodereview#group";
 | 
			
		||||
 | 
			
		||||
    transient String name;
 | 
			
		||||
    String id;
 | 
			
		||||
    String uuid;
 | 
			
		||||
    int groupId;
 | 
			
		||||
    String description;
 | 
			
		||||
    boolean isVisibleToAll;
 | 
			
		||||
    String ownerUuid;
 | 
			
		||||
 | 
			
		||||
    void setUuid(AccountGroup.UUID u) {
 | 
			
		||||
      uuid = u.get();
 | 
			
		||||
      id = Url.encode(GroupsCollection.UUID_PREFIX + uuid);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
// 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 static com.google.gerrit.server.group.GroupResource.GROUP_KIND;
 | 
			
		||||
 | 
			
		||||
import com.google.gerrit.extensions.registration.DynamicMap;
 | 
			
		||||
import com.google.gerrit.extensions.restapi.RestApiModule;
 | 
			
		||||
 | 
			
		||||
public class Module extends RestApiModule {
 | 
			
		||||
  @Override
 | 
			
		||||
  protected void configure() {
 | 
			
		||||
    bind(GroupsCollection.class);
 | 
			
		||||
 | 
			
		||||
    DynamicMap.mapOf(binder(), GROUP_KIND);
 | 
			
		||||
 | 
			
		||||
    get(GROUP_KIND).to(GetGroup.class);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -14,93 +14,27 @@
 | 
			
		||||
 | 
			
		||||
package com.google.gerrit.sshd.commands;
 | 
			
		||||
 | 
			
		||||
import com.google.gerrit.common.data.GroupList;
 | 
			
		||||
import com.google.gerrit.common.errors.NoSuchGroupException;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.Account;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.AccountGroup;
 | 
			
		||||
import com.google.gerrit.server.IdentifiedUser;
 | 
			
		||||
import com.google.gerrit.server.account.GroupCache;
 | 
			
		||||
import com.google.gerrit.server.account.VisibleGroups;
 | 
			
		||||
import com.google.gerrit.server.ioutil.ColumnFormatter;
 | 
			
		||||
import com.google.gerrit.server.project.ProjectControl;
 | 
			
		||||
import com.google.gerrit.sshd.SshCommand;
 | 
			
		||||
import com.google.gwtorm.client.KeyUtil;
 | 
			
		||||
import com.google.gerrit.server.group.ListGroups;
 | 
			
		||||
import com.google.gerrit.sshd.BaseCommand;
 | 
			
		||||
import com.google.inject.Inject;
 | 
			
		||||
 | 
			
		||||
import org.kohsuke.args4j.Option;
 | 
			
		||||
import org.apache.sshd.server.Environment;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class ListGroupsCommand extends SshCommand {
 | 
			
		||||
public class ListGroupsCommand extends BaseCommand {
 | 
			
		||||
  @Inject
 | 
			
		||||
  private GroupCache groupCache;
 | 
			
		||||
 | 
			
		||||
  @Inject
 | 
			
		||||
  private VisibleGroups.Factory visibleGroupsFactory;
 | 
			
		||||
 | 
			
		||||
  @Inject
 | 
			
		||||
  private IdentifiedUser.GenericFactory userFactory;
 | 
			
		||||
 | 
			
		||||
  @Option(name = "--project", aliases = {"-p"},
 | 
			
		||||
      usage = "projects for which the groups should be listed")
 | 
			
		||||
  private final List<ProjectControl> projects = new ArrayList<ProjectControl>();
 | 
			
		||||
 | 
			
		||||
  @Option(name = "--visible-to-all", usage = "to list only groups that are visible to all registered users")
 | 
			
		||||
  private boolean visibleToAll;
 | 
			
		||||
 | 
			
		||||
  @Option(name = "--type", usage = "type of group")
 | 
			
		||||
  private AccountGroup.Type groupType;
 | 
			
		||||
 | 
			
		||||
  @Option(name = "--user", aliases = {"-u"},
 | 
			
		||||
      usage = "user for which the groups should be listed")
 | 
			
		||||
  private Account.Id user;
 | 
			
		||||
 | 
			
		||||
  @Option(name = "--verbose", aliases = {"-v"},
 | 
			
		||||
      usage = "verbose output format with tab-separated columns for the " +
 | 
			
		||||
          "group name, UUID, description, type, owner group name, " +
 | 
			
		||||
          "owner group UUID, and whether the group is visible to all")
 | 
			
		||||
  private boolean verboseOutput;
 | 
			
		||||
  private ListGroups impl;
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  protected void run() throws Failure {
 | 
			
		||||
    try {
 | 
			
		||||
      if (user != null && !projects.isEmpty()) {
 | 
			
		||||
        throw new UnloggedFailure(1, "fatal: --user and --project options are not compatible.");
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      final VisibleGroups visibleGroups = visibleGroupsFactory.create();
 | 
			
		||||
      visibleGroups.setOnlyVisibleToAll(visibleToAll);
 | 
			
		||||
      visibleGroups.setGroupType(groupType);
 | 
			
		||||
      final GroupList groupList;
 | 
			
		||||
      if (!projects.isEmpty()) {
 | 
			
		||||
        groupList = visibleGroups.get(projects);
 | 
			
		||||
      } else if (user != null) {
 | 
			
		||||
        groupList = visibleGroups.get(userFactory.create(user));
 | 
			
		||||
      } else {
 | 
			
		||||
        groupList = visibleGroups.get();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      final ColumnFormatter formatter = new ColumnFormatter(stdout, '\t');
 | 
			
		||||
      for (final AccountGroup g : groupList.getGroups()) {
 | 
			
		||||
        formatter.addColumn(g.getName());
 | 
			
		||||
        if (verboseOutput) {
 | 
			
		||||
          formatter.addColumn(KeyUtil.decode(g.getGroupUUID().toString()));
 | 
			
		||||
          formatter.addColumn(
 | 
			
		||||
              g.getDescription() != null ? g.getDescription() : "");
 | 
			
		||||
          formatter.addColumn(g.getType().toString());
 | 
			
		||||
          final AccountGroup owningGroup =
 | 
			
		||||
              groupCache.get(g.getOwnerGroupUUID());
 | 
			
		||||
          formatter.addColumn(
 | 
			
		||||
              owningGroup != null ? owningGroup.getName() : "n/a");
 | 
			
		||||
          formatter.addColumn(KeyUtil.decode(g.getOwnerGroupUUID().toString()));
 | 
			
		||||
          formatter.addColumn(Boolean.toString(g.isVisibleToAll()));
 | 
			
		||||
  public void start(final Environment env) {
 | 
			
		||||
    startThread(new CommandRunnable() {
 | 
			
		||||
      @Override
 | 
			
		||||
      public void run() throws Exception {
 | 
			
		||||
        parseCommandLine(impl);
 | 
			
		||||
        if (impl.getUser() != null && !impl.getProjects().isEmpty()) {
 | 
			
		||||
          throw new UnloggedFailure(1, "fatal: --user and --project options are not compatible.");
 | 
			
		||||
        }
 | 
			
		||||
        formatter.nextLine();
 | 
			
		||||
        impl.display(out);
 | 
			
		||||
      }
 | 
			
		||||
      formatter.finish();
 | 
			
		||||
    } catch (NoSuchGroupException e) {
 | 
			
		||||
      throw die(e);
 | 
			
		||||
    }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user