All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gerrit.server.group.ListGroups Maven / Gradle / Ivy

There is a newer version: 3.10.0-rc4
Show newest version
// 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.MoreObjects;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.gerrit.common.data.GroupDescription;
import com.google.gerrit.common.data.GroupDescriptions;
import com.google.gerrit.common.data.GroupReference;
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.RestReadView;
import com.google.gerrit.extensions.restapi.TopLevelResource;
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.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.GetGroups;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.GroupComparator;
import com.google.gerrit.server.account.GroupControl;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import org.kohsuke.args4j.Option;

/** List groups visible to the calling user. */
public class ListGroups implements RestReadView {

  protected final GroupCache groupCache;

  private final List projects = new ArrayList<>();
  private final Set groupsToInspect = new HashSet<>();
  private final GroupControl.Factory groupControlFactory;
  private final GroupControl.GenericFactory genericGroupControlFactory;
  private final Provider identifiedUser;
  private final IdentifiedUser.GenericFactory userFactory;
  private final GetGroups accountGetGroups;
  private final GroupJson json;
  private final GroupBackend groupBackend;

  private EnumSet options = EnumSet.noneOf(ListGroupsOption.class);
  private boolean visibleToAll;
  private Account.Id user;
  private boolean owned;
  private int limit;
  private int start;
  private String matchSubstring;
  private String suggest;

  @Option(
      name = "--project",
      aliases = {"-p"},
      usage = "projects for which the groups should be listed")
  public void addProject(ProjectControl project) {
    projects.add(project);
  }

  @Option(
      name = "--visible-to-all",
      usage = "to list only groups that are visible to all registered users")
  public void setVisibleToAll(boolean visibleToAll) {
    this.visibleToAll = visibleToAll;
  }

  @Option(
      name = "--user",
      aliases = {"-u"},
      usage = "user for which the groups should be listed")
  public void setUser(Account.Id user) {
    this.user = user;
  }

  @Option(
      name = "--owned",
      usage =
          "to list only groups that are owned by the"
              + " specified user or by the calling user if no user was specifed")
  public void setOwned(boolean owned) {
    this.owned = owned;
  }

  /**
   * Add a group to inspect.
   *
   * @param uuid UUID of the group
   * @deprecated use {@link #addGroup(AccountGroup.UUID)}.
   */
  @Deprecated
  @Option(
      name = "--query",
      aliases = {"-q"},
      usage = "group to inspect (deprecated: use --group/-g instead)")
  void addGroup_Deprecated(AccountGroup.UUID uuid) {
    addGroup(uuid);
  }

  @Option(
      name = "--group",
      aliases = {"-g"},
      usage = "group to inspect")
  public void addGroup(AccountGroup.UUID uuid) {
    groupsToInspect.add(uuid);
  }

  @Option(
      name = "--limit",
      aliases = {"-n"},
      metaVar = "CNT",
      usage = "maximum number of groups to list")
  public void setLimit(int limit) {
    this.limit = limit;
  }

  @Option(
      name = "--start",
      aliases = {"-S"},
      metaVar = "CNT",
      usage = "number of groups to skip")
  public void setStart(int start) {
    this.start = start;
  }

  @Option(
      name = "--match",
      aliases = {"-m"},
      metaVar = "MATCH",
      usage = "match group substring")
  public void setMatchSubstring(String matchSubstring) {
    this.matchSubstring = matchSubstring;
  }

  @Option(
      name = "--suggest",
      aliases = {"-s"},
      usage = "to get a suggestion of groups")
  public void setSuggest(String suggest) {
    this.suggest = suggest;
  }

  @Option(name = "-o", usage = "Output options per group")
  void addOption(ListGroupsOption o) {
    options.add(o);
  }

  @Option(name = "-O", usage = "Output option flags, in hex")
  void setOptionFlagsHex(String hex) {
    options.addAll(ListGroupsOption.fromBits(Integer.parseInt(hex, 16)));
  }

  @Inject
  protected ListGroups(
      final GroupCache groupCache,
      final GroupControl.Factory groupControlFactory,
      final GroupControl.GenericFactory genericGroupControlFactory,
      final Provider identifiedUser,
      final IdentifiedUser.GenericFactory userFactory,
      final GetGroups accountGetGroups,
      GroupJson json,
      GroupBackend groupBackend) {
    this.groupCache = groupCache;
    this.groupControlFactory = groupControlFactory;
    this.genericGroupControlFactory = genericGroupControlFactory;
    this.identifiedUser = identifiedUser;
    this.userFactory = userFactory;
    this.accountGetGroups = accountGetGroups;
    this.json = json;
    this.groupBackend = groupBackend;
  }

  public void setOptions(EnumSet options) {
    this.options = options;
  }

  public Account.Id getUser() {
    return user;
  }

  public List getProjects() {
    return projects;
  }

  @Override
  public SortedMap apply(TopLevelResource resource)
      throws OrmException, BadRequestException {
    SortedMap output = new TreeMap<>();
    for (GroupInfo info : get()) {
      output.put(MoreObjects.firstNonNull(info.name, "Group " + Url.decode(info.id)), info);
      info.name = null;
    }
    return output;
  }

  public List get() throws OrmException, BadRequestException {
    if (!Strings.isNullOrEmpty(suggest)) {
      return suggestGroups();
    }

    if (owned) {
      return getGroupsOwnedBy(user != null ? userFactory.create(user) : identifiedUser.get());
    }

    if (user != null) {
      return accountGetGroups.apply(new AccountResource(userFactory.create(user)));
    }

    return getAllGroups();
  }

  private List getAllGroups() throws OrmException {
    List groupInfos;
    List groupList;
    if (!projects.isEmpty()) {
      Map groups = new HashMap<>();
      for (final ProjectControl projectControl : projects) {
        final Set groupsRefs = projectControl.getAllGroups();
        for (final GroupReference groupRef : groupsRefs) {
          final AccountGroup group = groupCache.get(groupRef.getUUID());
          if (group != null) {
            groups.put(group.getGroupUUID(), group);
          }
        }
      }
      groupList = filterGroups(groups.values());
    } else {
      groupList = filterGroups(groupCache.all());
    }
    groupInfos = Lists.newArrayListWithCapacity(groupList.size());
    int found = 0;
    int foundIndex = 0;
    for (AccountGroup group : groupList) {
      if (foundIndex++ < start) {
        continue;
      }
      if (limit > 0 && ++found > limit) {
        break;
      }
      groupInfos.add(json.addOptions(options).format(GroupDescriptions.forAccountGroup(group)));
    }
    return groupInfos;
  }

  private List suggestGroups() throws OrmException, BadRequestException {
    if (conflictingSuggestParameters()) {
      throw new BadRequestException(
          "You should only have no more than one --project and -n with --suggest");
    }

    List groupRefs =
        Lists.newArrayList(
            Iterables.limit(
                groupBackend.suggest(suggest, Iterables.getFirst(projects, null)),
                limit <= 0 ? 10 : Math.min(limit, 10)));

    List groupInfos = Lists.newArrayListWithCapacity(groupRefs.size());
    for (final GroupReference ref : groupRefs) {
      GroupDescription.Basic desc = groupBackend.get(ref.getUUID());
      if (desc != null) {
        groupInfos.add(json.addOptions(options).format(desc));
      }
    }
    return groupInfos;
  }

  private boolean conflictingSuggestParameters() {
    if (Strings.isNullOrEmpty(suggest)) {
      return false;
    }
    if (projects.size() > 1) {
      return true;
    }
    if (visibleToAll) {
      return true;
    }
    if (user != null) {
      return true;
    }
    if (owned) {
      return true;
    }
    if (start != 0) {
      return true;
    }
    if (!groupsToInspect.isEmpty()) {
      return true;
    }
    if (!Strings.isNullOrEmpty(matchSubstring)) {
      return true;
    }
    return false;
  }

  private List getGroupsOwnedBy(IdentifiedUser user) throws OrmException {
    List groups = new ArrayList<>();
    int found = 0;
    int foundIndex = 0;
    for (AccountGroup g : filterGroups(groupCache.all())) {
      GroupControl ctl = groupControlFactory.controlFor(g);
      try {
        if (genericGroupControlFactory.controlFor(user, g.getGroupUUID()).isOwner()) {
          if (foundIndex++ < start) {
            continue;
          }
          if (limit > 0 && ++found > limit) {
            break;
          }
          groups.add(json.addOptions(options).format(ctl.getGroup()));
        }
      } catch (NoSuchGroupException e) {
        continue;
      }
    }
    return groups;
  }

  private List filterGroups(Collection groups) {
    List filteredGroups = new ArrayList<>(groups.size());
    boolean isAdmin = identifiedUser.get().getCapabilities().canAdministrateServer();
    for (AccountGroup group : groups) {
      if (!Strings.isNullOrEmpty(matchSubstring)) {
        if (!group
            .getName()
            .toLowerCase(Locale.US)
            .contains(matchSubstring.toLowerCase(Locale.US))) {
          continue;
        }
      }
      if (visibleToAll && !group.isVisibleToAll()) {
        continue;
      }
      if (!groupsToInspect.isEmpty() && !groupsToInspect.contains(group.getGroupUUID())) {
        continue;
      }
      if (!isAdmin) {
        GroupControl c = groupControlFactory.controlFor(group);
        if (!c.isVisible()) {
          continue;
        }
      }
      filteredGroups.add(group);
    }
    Collections.sort(filteredGroups, new GroupComparator());
    return filteredGroups;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy