| // Copyright (C) 2017 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.query.group; |
| |
| import static com.google.common.collect.ImmutableList.toImmutableList; |
| |
| import com.google.common.base.Strings; |
| import com.google.common.collect.Lists; |
| import com.google.common.primitives.Ints; |
| import com.google.gerrit.entities.Account; |
| import com.google.gerrit.entities.AccountGroup; |
| import com.google.gerrit.entities.GroupReference; |
| import com.google.gerrit.entities.InternalGroup; |
| import com.google.gerrit.index.query.LimitPredicate; |
| import com.google.gerrit.index.query.Predicate; |
| import com.google.gerrit.index.query.QueryBuilder; |
| import com.google.gerrit.index.query.QueryParseException; |
| import com.google.gerrit.index.query.QueryRequiresAuthException; |
| import com.google.gerrit.server.account.AccountResolver; |
| import com.google.gerrit.server.account.AccountResolver.UnresolvableAccountException; |
| import com.google.gerrit.server.account.GroupBackend; |
| import com.google.gerrit.server.account.GroupBackends; |
| import com.google.gerrit.server.account.GroupCache; |
| import com.google.inject.Inject; |
| import java.io.IOException; |
| import java.util.List; |
| import java.util.Optional; |
| import java.util.Set; |
| import org.eclipse.jgit.errors.ConfigInvalidException; |
| |
| /** Parses a query string meant to be applied to group objects. */ |
| public class GroupQueryBuilder extends QueryBuilder<InternalGroup, GroupQueryBuilder> { |
| public static final String FIELD_UUID = "uuid"; |
| public static final String FIELD_DESCRIPTION = "description"; |
| public static final String FIELD_INNAME = "inname"; |
| public static final String FIELD_NAME = "name"; |
| public static final String FIELD_OWNER = "owner"; |
| public static final String FIELD_LIMIT = "limit"; |
| |
| private static final QueryBuilder.Definition<InternalGroup, GroupQueryBuilder> mydef = |
| new QueryBuilder.Definition<>(GroupQueryBuilder.class); |
| |
| public static class Arguments { |
| final GroupCache groupCache; |
| final GroupBackend groupBackend; |
| final AccountResolver accountResolver; |
| |
| @Inject |
| Arguments(GroupCache groupCache, GroupBackend groupBackend, AccountResolver accountResolver) { |
| this.groupCache = groupCache; |
| this.groupBackend = groupBackend; |
| this.accountResolver = accountResolver; |
| } |
| } |
| |
| private final Arguments args; |
| |
| @Inject |
| GroupQueryBuilder(Arguments args) { |
| super(mydef, null); |
| this.args = args; |
| } |
| |
| @Operator |
| public Predicate<InternalGroup> uuid(String uuid) { |
| return GroupPredicates.uuid(AccountGroup.uuid(uuid)); |
| } |
| |
| @Operator |
| public Predicate<InternalGroup> description(String description) throws QueryParseException { |
| if (Strings.isNullOrEmpty(description)) { |
| throw error("description operator requires a value"); |
| } |
| |
| return GroupPredicates.description(description); |
| } |
| |
| @Operator |
| public Predicate<InternalGroup> inname(String namePart) { |
| if (namePart.isEmpty()) { |
| return name(namePart); |
| } |
| return GroupPredicates.inname(namePart); |
| } |
| |
| @Operator |
| public Predicate<InternalGroup> name(String name) { |
| return GroupPredicates.name(name); |
| } |
| |
| @Operator |
| public Predicate<InternalGroup> owner(String owner) throws QueryParseException { |
| AccountGroup.UUID groupUuid = parseGroup(owner); |
| return GroupPredicates.owner(groupUuid); |
| } |
| |
| @Operator |
| public Predicate<InternalGroup> is(String value) throws QueryParseException { |
| if ("visibletoall".equalsIgnoreCase(value)) { |
| return GroupPredicates.isVisibleToAll(); |
| } |
| throw error("Invalid query"); |
| } |
| |
| @Override |
| protected Predicate<InternalGroup> defaultField(String query) throws QueryParseException { |
| // Adapt the capacity of this list when adding more default predicates. |
| List<Predicate<InternalGroup>> preds = Lists.newArrayListWithCapacity(5); |
| preds.add(uuid(query)); |
| preds.add(name(query)); |
| preds.add(inname(query)); |
| if (!Strings.isNullOrEmpty(query)) { |
| preds.add(description(query)); |
| } |
| try { |
| preds.add(owner(query)); |
| } catch (QueryParseException e) { |
| // Skip. |
| } |
| return Predicate.or(preds); |
| } |
| |
| @Operator |
| public Predicate<InternalGroup> member(String query) |
| throws QueryParseException, ConfigInvalidException, IOException { |
| Set<Account.Id> accounts = parseAccount(query); |
| List<Predicate<InternalGroup>> predicates = |
| accounts.stream().map(GroupPredicates::member).collect(toImmutableList()); |
| return Predicate.or(predicates); |
| } |
| |
| @Operator |
| public Predicate<InternalGroup> subgroup(String query) throws QueryParseException { |
| AccountGroup.UUID groupUuid = parseGroup(query); |
| return GroupPredicates.subgroup(groupUuid); |
| } |
| |
| @Operator |
| public Predicate<InternalGroup> limit(String query) throws QueryParseException { |
| Integer limit = Ints.tryParse(query); |
| if (limit == null) { |
| throw error("Invalid limit: " + query); |
| } |
| return new LimitPredicate<>(FIELD_LIMIT, limit); |
| } |
| |
| private Set<Account.Id> parseAccount(String nameOrEmail) |
| throws QueryParseException, IOException, ConfigInvalidException { |
| try { |
| return args.accountResolver.resolve(nameOrEmail).asNonEmptyIdSet(); |
| } catch (UnresolvableAccountException e) { |
| if (e.isSelf()) { |
| throw new QueryRequiresAuthException(e.getMessage(), e); |
| } |
| throw new QueryParseException(e.getMessage(), e); |
| } |
| } |
| |
| private AccountGroup.UUID parseGroup(String groupNameOrUuid) throws QueryParseException { |
| Optional<InternalGroup> group = args.groupCache.get(AccountGroup.uuid(groupNameOrUuid)); |
| if (group.isPresent()) { |
| return group.get().getGroupUUID(); |
| } |
| GroupReference groupReference = |
| GroupBackends.findBestSuggestion(args.groupBackend, groupNameOrUuid); |
| if (groupReference == null) { |
| throw error("Group " + groupNameOrUuid + " not found"); |
| } |
| return groupReference.getUUID(); |
| } |
| } |