Merge "ListGroups: Add support to list groups by owner"

This commit is contained in:
Edwin Kempin
2017-10-12 12:26:14 +00:00
committed by Gerrit Code Review
5 changed files with 107 additions and 4 deletions

View File

@@ -124,6 +124,40 @@ client so they are generally disabled by default. Optional fields are:
* `MEMBERS`: include list of direct group members.
--
==== Find groups that are owned by another group
By setting `ownedBy` and specifying the link:#group-id[\{group-id\}] of another
group, it is possible to find all the groups for which the owning group is the
given group.
.Request
----
GET /groups/?ownedBy=7ca042f4d5847936fcb90ca91057673157fd06fc HTTP/1.0
----
.Response
----
HTTP/1.1 200 OK
Content-Disposition: attachment
Content-Type: application/json; charset=UTF-8
)]}'
{
"MyProject-Committers": {
"id": "9999c971bb4ab872aab759d8c49833ee6b9ff320",
"url": "#/admin/groups/uuid-9999c971bb4ab872aab759d8c49833ee6b9ff320",
"options": {
"visible_to_all": true
},
"description":"contains all committers for MyProject",
"group_id": 551,
"owner": "MyProject-Owners",
"owner_id": "7ca042f4d5847936fcb90ca91057673157fd06fc",
"created_on": "2013-02-01 09:59:32.126000000"
}
}
----
==== Check if a group is owned by the calling user
By setting the option `owned` and specifying a group to inspect with
the option `group`/`g`, it is possible to find out if this group is

View File

@@ -490,6 +490,33 @@ public class GroupsIT extends AbstractDaemonTest {
.inOrder();
}
@Test
public void getGroupsByOwner() throws Exception {
String parent = createGroup("test-parent");
List<String> children =
Arrays.asList(createGroup("test-child1", parent), createGroup("test-child2", parent));
// By UUID
List<GroupInfo> owned =
gApi.groups().list().withOwnedBy(getFromCache(parent).getGroupUUID().get()).get();
assertThat(owned.stream().map(g -> g.name).collect(toList()))
.containsExactlyElementsIn(children);
// By name
owned = gApi.groups().list().withOwnedBy(parent).get();
assertThat(owned.stream().map(g -> g.name).collect(toList()))
.containsExactlyElementsIn(children);
// By group that does not own any others
owned = gApi.groups().list().withOwnedBy(owned.get(0).id).get();
assertThat(owned).isEmpty();
// By non-existing group
exception.expect(UnprocessableEntityException.class);
exception.expectMessage("Group Not Found: does-not-exist");
gApi.groups().list().withOwnedBy("does-not-exist").get();
}
@Test
public void onlyVisibleGroupsReturned() throws Exception {
String newGroupName = name("newGroup");

View File

@@ -80,6 +80,7 @@ public interface Groups {
private String substring;
private String suggest;
private String regex;
private String ownedBy;
public List<GroupInfo> get() throws RestApiException {
Map<String, GroupInfo> map = getAsMap();
@@ -160,6 +161,11 @@ public interface Groups {
return this;
}
public ListRequest withOwnedBy(String ownedBy) {
this.ownedBy = ownedBy;
return this;
}
public EnumSet<ListGroupsOption> getOptions() {
return options;
}
@@ -203,6 +209,10 @@ public interface Groups {
public String getSuggest() {
return suggest;
}
public String getOwnedBy() {
return ownedBy;
}
}
/**

View File

@@ -133,6 +133,10 @@ class GroupsImpl implements Groups {
list.setVisibleToAll(req.getVisibleToAll());
if (req.getOwnedBy() != null) {
list.setOwnedBy(req.getOwnedBy());
}
if (req.getUser() != null) {
try {
list.setUser(accounts.parse(req.getUser()).getAccountId());

View File

@@ -28,6 +28,7 @@ import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.extensions.client.ListGroupsOption;
import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.extensions.restapi.Url;
@@ -55,6 +56,7 @@ import java.util.Locale;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.kohsuke.args4j.Option;
@@ -76,6 +78,7 @@ public class ListGroups implements RestReadView<TopLevelResource> {
private final GroupJson json;
private final GroupBackend groupBackend;
private final Groups groups;
private final GroupsCollection groupsCollection;
private final Provider<ReviewDb> db;
private EnumSet<ListGroupsOption> options = EnumSet.noneOf(ListGroupsOption.class);
@@ -87,6 +90,7 @@ public class ListGroups implements RestReadView<TopLevelResource> {
private String matchSubstring;
private String matchRegex;
private String suggest;
private String ownedBy;
@Option(
name = "--project",
@@ -208,6 +212,11 @@ public class ListGroups implements RestReadView<TopLevelResource> {
options.addAll(ListGroupsOption.fromBits(Integer.parseInt(hex, 16)));
}
@Option(name = "--owned-by", usage = "list groups owned by the given group uuid")
public void setOwnedBy(String ownedBy) {
this.ownedBy = ownedBy;
}
@Inject
protected ListGroups(
final GroupCache groupCache,
@@ -216,6 +225,7 @@ public class ListGroups implements RestReadView<TopLevelResource> {
final Provider<IdentifiedUser> identifiedUser,
final IdentifiedUser.GenericFactory userFactory,
final GetGroups accountGetGroups,
final GroupsCollection groupsCollection,
GroupJson json,
GroupBackend groupBackend,
Groups groups,
@@ -229,6 +239,7 @@ public class ListGroups implements RestReadView<TopLevelResource> {
this.json = json;
this.groupBackend = groupBackend;
this.groups = groups;
this.groupsCollection = groupsCollection;
this.db = db;
}
@@ -246,7 +257,7 @@ public class ListGroups implements RestReadView<TopLevelResource> {
@Override
public SortedMap<String, GroupInfo> apply(TopLevelResource resource)
throws OrmException, BadRequestException {
throws OrmException, RestApiException {
SortedMap<String, GroupInfo> output = new TreeMap<>();
for (GroupInfo info : get()) {
output.put(MoreObjects.firstNonNull(info.name, "Group " + Url.decode(info.id)), info);
@@ -255,7 +266,7 @@ public class ListGroups implements RestReadView<TopLevelResource> {
return output;
}
public List<GroupInfo> get() throws OrmException, BadRequestException {
public List<GroupInfo> get() throws OrmException, RestApiException {
if (!Strings.isNullOrEmpty(suggest)) {
return suggestGroups();
}
@@ -264,6 +275,10 @@ public class ListGroups implements RestReadView<TopLevelResource> {
throw new BadRequestException("Specify one of m/r");
}
if (ownedBy != null) {
return getGroupsOwnedBy(ownedBy);
}
if (owned) {
return getGroupsOwnedBy(user != null ? userFactory.create(user) : identifiedUser.get());
}
@@ -345,6 +360,9 @@ public class ListGroups implements RestReadView<TopLevelResource> {
if (owned) {
return true;
}
if (ownedBy != null) {
return true;
}
if (start != 0) {
return true;
}
@@ -360,14 +378,15 @@ public class ListGroups implements RestReadView<TopLevelResource> {
return false;
}
private List<GroupInfo> getGroupsOwnedBy(IdentifiedUser user) throws OrmException {
private List<GroupInfo> filterGroupsOwnedBy(Predicate<GroupDescription.Internal> filter)
throws OrmException {
Pattern pattern = getRegexPattern();
Stream<GroupDescription.Internal> foundGroups =
groups
.getAll(db.get())
.map(GroupDescriptions::forAccountGroup)
.filter(group -> !isNotRelevant(pattern, group))
.filter(group -> isOwner(user, group))
.filter(filter)
.sorted(GROUP_COMPARATOR)
.skip(start);
if (limit > 0) {
@@ -381,6 +400,15 @@ public class ListGroups implements RestReadView<TopLevelResource> {
return groupInfos;
}
private List<GroupInfo> getGroupsOwnedBy(String id) throws OrmException, RestApiException {
String uuid = groupsCollection.parse(id).getGroupUUID().get();
return filterGroupsOwnedBy(group -> group.getOwnerGroupUUID().get().equals(uuid));
}
private List<GroupInfo> getGroupsOwnedBy(IdentifiedUser user) throws OrmException {
return filterGroupsOwnedBy(group -> isOwner(user, group));
}
private boolean isOwner(CurrentUser user, GroupDescription.Internal group) {
try {
return genericGroupControlFactory.controlFor(user, group.getGroupUUID()).isOwner();