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:
Edwin Kempin
2013-01-07 11:18:05 +01:00
parent 06dd083af8
commit 5948443a18
12 changed files with 547 additions and 81 deletions

View File

@@ -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]]
/changes/ (Query Changes) /changes/ (Query Changes)
~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -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.account.AccountsRestApiServlet;
import com.google.gerrit.httpd.rpc.change.ChangesRestApiServlet; import com.google.gerrit.httpd.rpc.change.ChangesRestApiServlet;
import com.google.gerrit.httpd.rpc.change.DeprecatedChangeQueryServlet; 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.httpd.rpc.project.ProjectsRestApiServlet;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
@@ -97,6 +98,7 @@ class UrlModule extends ServletModule {
filter("/a/*").through(RequireIdentifiedUserFilter.class); filter("/a/*").through(RequireIdentifiedUserFilter.class);
serveRegex("^/(?:a/)?accounts/(.*)$").with(AccountsRestApiServlet.class); serveRegex("^/(?:a/)?accounts/(.*)$").with(AccountsRestApiServlet.class);
serveRegex("^/(?:a/)?changes/(.*)$").with(ChangesRestApiServlet.class); serveRegex("^/(?:a/)?changes/(.*)$").with(ChangesRestApiServlet.class);
serveRegex("^/(?:a/)?groups/(.*)?$").with(GroupsRestApiServlet.class);
serveRegex("^/(?:a/)?projects/(.*)?$").with(ProjectsRestApiServlet.class); serveRegex("^/(?:a/)?projects/(.*)?$").with(ProjectsRestApiServlet.class);
if (cfg.deprecatedQuery) { if (cfg.deprecatedQuery) {

View File

@@ -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);
}
}

View File

@@ -84,6 +84,10 @@ public class GroupControl {
this(who, GroupDescriptions.forAccountGroup(ag)); this(who, GroupDescriptions.forAccountGroup(ag));
} }
public GroupDescription.Basic getGroup() {
return group;
}
public CurrentUser getCurrentUser() { public CurrentUser getCurrentUser() {
return user; return user;
} }

View File

@@ -49,6 +49,7 @@ 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.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.account.VisibleGroups;
import com.google.gerrit.server.auth.AuthBackend; import com.google.gerrit.server.auth.AuthBackend;
import com.google.gerrit.server.auth.InternalAuthBackend; import com.google.gerrit.server.auth.InternalAuthBackend;
import com.google.gerrit.server.auth.UniversalAuthBackend; import com.google.gerrit.server.auth.UniversalAuthBackend;
@@ -151,6 +152,7 @@ public class GerritGlobalModule extends FactoryModule {
factory(CapabilityControl.Factory.class); factory(CapabilityControl.Factory.class);
factory(ChangeQueryBuilder.Factory.class); factory(ChangeQueryBuilder.Factory.class);
factory(GroupInfoCacheFactory.Factory.class); factory(GroupInfoCacheFactory.Factory.class);
factory(VisibleGroups.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);
@@ -194,6 +196,7 @@ public class GerritGlobalModule extends FactoryModule {
install(new AuditModule()); install(new AuditModule());
install(new com.google.gerrit.server.account.Module()); install(new com.google.gerrit.server.account.Module());
install(new com.google.gerrit.server.change.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()); install(new com.google.gerrit.server.project.Module());
bind(GitReferenceUpdated.class); bind(GitReferenceUpdated.class);

View File

@@ -85,7 +85,6 @@ public class GerritRequestModule extends FactoryModule {
factory(MergeFailSender.Factory.class); factory(MergeFailSender.Factory.class);
factory(PerformCreateGroup.Factory.class); factory(PerformCreateGroup.Factory.class);
factory(PerformRenameGroup.Factory.class); factory(PerformRenameGroup.Factory.class);
factory(VisibleGroups.Factory.class);
factory(GroupDetailFactory.Factory.class); factory(GroupDetailFactory.Factory.class);
factory(GroupMembers.Factory.class); factory(GroupMembers.Factory.class);
factory(CreateProject.Factory.class); factory(CreateProject.Factory.class);

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -14,93 +14,27 @@
package com.google.gerrit.sshd.commands; package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.data.GroupList; import com.google.gerrit.server.group.ListGroups;
import com.google.gerrit.common.errors.NoSuchGroupException; import com.google.gerrit.sshd.BaseCommand;
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.inject.Inject; import com.google.inject.Inject;
import org.kohsuke.args4j.Option; import org.apache.sshd.server.Environment;
import java.util.ArrayList; public class ListGroupsCommand extends BaseCommand {
import java.util.List;
public class ListGroupsCommand extends SshCommand {
@Inject @Inject
private GroupCache groupCache; private ListGroups impl;
@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;
@Override @Override
protected void run() throws Failure { public void start(final Environment env) {
try { startThread(new CommandRunnable() {
if (user != null && !projects.isEmpty()) { @Override
throw new UnloggedFailure(1, "fatal: --user and --project options are not compatible."); public void run() throws Exception {
} parseCommandLine(impl);
if (impl.getUser() != null && !impl.getProjects().isEmpty()) {
final VisibleGroups visibleGroups = visibleGroupsFactory.create(); throw new UnloggedFailure(1, "fatal: --user and --project options are not compatible.");
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()));
} }
formatter.nextLine(); impl.display(out);
} }
formatter.finish(); });
} catch (NoSuchGroupException e) {
throw die(e);
}
} }
} }