Merge "Permit some diff cursor keyboard shortcuts when any diffs are expanded"
diff --git a/Documentation/user-search-accounts.txt b/Documentation/user-search-accounts.txt
index 04f40c0..6bcd18e 100644
--- a/Documentation/user-search-accounts.txt
+++ b/Documentation/user-search-accounts.txt
@@ -23,6 +23,11 @@
returned results. Search can also be performed by typing only a
text with no operator, which will match against a variety of fields.
+[[cansee]]
+cansee:'CHANGE'::
++
+Matches accounts that can see the change 'CHANGE'.
+
[[email]]
email:'EMAIL'::
+
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountApi.java
index 06ceb49..7f4522f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountApi.java
@@ -27,6 +27,7 @@
import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtorm.client.KeyUtil;
import java.util.HashSet;
import java.util.Set;
@@ -49,7 +50,7 @@
public static void suggest(String query, int limit, AsyncCallback<JsArray<AccountInfo>> cb) {
new RestApi("/accounts/")
.addParameterTrue("suggest")
- .addParameter("q", query)
+ .addParameterRaw("q", KeyUtil.encode(query))
.addParameter("n", limit)
.background()
.get(cb);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Assignee.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Assignee.java
index 0fd85f1..a376782 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Assignee.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Assignee.java
@@ -102,6 +102,7 @@
this.changeId = info.legacyId();
this.project = info.projectNameKey();
this.canEdit = info.hasActions() && info.actions().containsKey("assignee");
+ assigneeSuggestOracle.setChange(info);
setAssignee(info.assignee());
editAssigneeIcon.setVisible(canEdit);
if (!canEdit) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AssigneeSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AssigneeSuggestOracle.java
index 964f7ad..c8bbfc3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AssigneeSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AssigneeSuggestOracle.java
@@ -16,6 +16,7 @@
import com.google.gerrit.client.account.AccountApi;
import com.google.gerrit.client.info.AccountInfo;
+import com.google.gerrit.client.info.ChangeInfo;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.ui.AccountSuggestOracle.AccountSuggestion;
@@ -27,10 +28,17 @@
/** REST API based suggestion Oracle for assignee */
public class AssigneeSuggestOracle extends SuggestAfterTypingNCharsOracle {
+
+ private ChangeInfo change;
+
+ public void setChange(ChangeInfo change) {
+ this.change = change;
+ }
+
@Override
protected void _onRequestSuggestions(Request req, Callback cb) {
AccountApi.suggest(
- req.getQuery(),
+ getQuery(req),
req.getLimit(),
new GerritCallback<JsArray<AccountInfo>>() {
@Override
@@ -49,4 +57,13 @@
}
});
}
+
+ private String getQuery(Request req) {
+ StringBuilder query = new StringBuilder();
+ query.append(req.getQuery());
+ if (change != null) {
+ query.append(" cansee:").append(change._number());
+ }
+ return query.toString();
+ }
}
diff --git a/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java b/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java
index a470696..6905cf4 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java
@@ -21,6 +21,7 @@
import com.google.gerrit.index.query.IntegerRangePredicate;
import com.google.gerrit.index.query.NotPredicate;
import com.google.gerrit.index.query.OrPredicate;
+import com.google.gerrit.index.query.PostFilterPredicate;
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.index.query.RegexPredicate;
@@ -43,6 +44,8 @@
return not(p);
} else if (p instanceof IndexPredicate) {
return fieldQuery((IndexPredicate<T>) p);
+ } else if (p instanceof PostFilterPredicate) {
+ return QueryBuilders.matchAllQuery();
} else {
throw new QueryParseException("cannot create query for index: " + p);
}
diff --git a/java/com/google/gerrit/index/query/PostFilterPredicate.java b/java/com/google/gerrit/index/query/PostFilterPredicate.java
new file mode 100644
index 0000000..3e780bf
--- /dev/null
+++ b/java/com/google/gerrit/index/query/PostFilterPredicate.java
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 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.index.query;
+
+/**
+ * Matches all documents in the index, with additional filtering done in the subclass's {@code
+ * match} method.
+ */
+public abstract class PostFilterPredicate<T> extends Predicate<T> implements Matchable<T> {}
diff --git a/java/com/google/gerrit/lucene/QueryBuilder.java b/java/com/google/gerrit/lucene/QueryBuilder.java
index 2f2a1cd..4500942 100644
--- a/java/com/google/gerrit/lucene/QueryBuilder.java
+++ b/java/com/google/gerrit/lucene/QueryBuilder.java
@@ -28,6 +28,7 @@
import com.google.gerrit.index.query.IntegerRangePredicate;
import com.google.gerrit.index.query.NotPredicate;
import com.google.gerrit.index.query.OrPredicate;
+import com.google.gerrit.index.query.PostFilterPredicate;
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.index.query.RegexPredicate;
@@ -76,6 +77,8 @@
return not(p);
} else if (p instanceof IndexPredicate) {
return fieldQuery((IndexPredicate<V>) p);
+ } else if (p instanceof PostFilterPredicate) {
+ return new MatchAllDocsQuery();
} else {
throw new QueryParseException("cannot create query for index: " + p);
}
diff --git a/java/com/google/gerrit/server/ChangeFinder.java b/java/com/google/gerrit/server/ChangeFinder.java
index cb82778..677b091 100644
--- a/java/com/google/gerrit/server/ChangeFinder.java
+++ b/java/com/google/gerrit/server/ChangeFinder.java
@@ -110,6 +110,14 @@
this.allowedIdTypes = ImmutableSet.copyOf(configuredChangeIdTypes);
}
+ public ChangeNotes findOne(String id) throws OrmException {
+ List<ChangeNotes> ctls = find(id);
+ if (ctls.size() != 1) {
+ return null;
+ }
+ return ctls.get(0);
+ }
+
/**
* Find changes matching the given identifier.
*
diff --git a/java/com/google/gerrit/server/config/PluginConfigFactory.java b/java/com/google/gerrit/server/config/PluginConfigFactory.java
index 41230b2..a46efb8 100644
--- a/java/com/google/gerrit/server/config/PluginConfigFactory.java
+++ b/java/com/google/gerrit/server/config/PluginConfigFactory.java
@@ -15,11 +15,11 @@
package com.google.gerrit.server.config;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.git.ProjectLevelConfig;
import com.google.gerrit.server.plugins.Plugin;
import com.google.gerrit.server.plugins.ReloadPluginListener;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectLevelConfig;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.securestore.SecureStore;
import com.google.inject.Inject;
diff --git a/java/com/google/gerrit/server/git/SubmoduleOp.java b/java/com/google/gerrit/server/git/SubmoduleOp.java
index 0e3e146..d7af141 100644
--- a/java/com/google/gerrit/server/git/SubmoduleOp.java
+++ b/java/com/google/gerrit/server/git/SubmoduleOp.java
@@ -31,7 +31,6 @@
import com.google.gerrit.server.git.MergeOpRepoManager.OpenRepo;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.update.BatchUpdateListener;
import com.google.gerrit.server.update.RepoContext;
@@ -98,7 +97,6 @@
private final PersonIdent myIdent;
private final Config cfg;
private final ProjectCache projectCache;
- private final ProjectState.Factory projectStateFactory;
private final BatchUpdate.Factory batchUpdateFactory;
@Inject
@@ -107,27 +105,18 @@
@GerritPersonIdent PersonIdent myIdent,
@GerritServerConfig Config cfg,
ProjectCache projectCache,
- ProjectState.Factory projectStateFactory,
BatchUpdate.Factory batchUpdateFactory) {
this.gitmodulesFactory = gitmodulesFactory;
this.myIdent = myIdent;
this.cfg = cfg;
this.projectCache = projectCache;
- this.projectStateFactory = projectStateFactory;
this.batchUpdateFactory = batchUpdateFactory;
}
public SubmoduleOp create(Set<Branch.NameKey> updatedBranches, MergeOpRepoManager orm)
throws SubmoduleException {
return new SubmoduleOp(
- gitmodulesFactory,
- myIdent,
- cfg,
- projectCache,
- projectStateFactory,
- batchUpdateFactory,
- updatedBranches,
- orm);
+ gitmodulesFactory, myIdent, cfg, projectCache, batchUpdateFactory, updatedBranches, orm);
}
}
@@ -136,7 +125,6 @@
private final GitModules.Factory gitmodulesFactory;
private final PersonIdent myIdent;
private final ProjectCache projectCache;
- private final ProjectState.Factory projectStateFactory;
private final BatchUpdate.Factory batchUpdateFactory;
private final VerboseSuperprojectUpdate verboseSuperProject;
private final boolean enableSuperProjectSubscriptions;
@@ -163,7 +151,6 @@
PersonIdent myIdent,
Config cfg,
ProjectCache projectCache,
- ProjectState.Factory projectStateFactory,
BatchUpdate.Factory batchUpdateFactory,
Set<Branch.NameKey> updatedBranches,
MergeOpRepoManager orm)
@@ -171,7 +158,6 @@
this.gitmodulesFactory = gitmodulesFactory;
this.myIdent = myIdent;
this.projectCache = projectCache;
- this.projectStateFactory = projectStateFactory;
this.batchUpdateFactory = batchUpdateFactory;
this.verboseSuperProject =
cfg.getEnum("submodule", null, "verboseSuperprojectUpdate", VerboseSuperprojectUpdate.TRUE);
@@ -335,8 +321,7 @@
logDebug("Calculating possible superprojects for " + srcBranch);
Collection<SubmoduleSubscription> ret = new ArrayList<>();
Project.NameKey srcProject = srcBranch.getParentKey();
- ProjectConfig cfg = projectCache.get(srcProject).getConfig();
- for (SubscribeSection s : projectStateFactory.create(cfg).getSubscribeSections(srcBranch)) {
+ for (SubscribeSection s : projectCache.get(srcProject).getSubscribeSections(srcBranch)) {
logDebug("Checking subscribe section " + s);
Collection<Branch.NameKey> branches = getDestinationBranches(srcBranch, s);
for (Branch.NameKey targetBranch : branches) {
diff --git a/java/com/google/gerrit/server/index/account/IndexedAccountQuery.java b/java/com/google/gerrit/server/index/account/IndexedAccountQuery.java
index e8b1861..644f1eb 100644
--- a/java/com/google/gerrit/server/index/account/IndexedAccountQuery.java
+++ b/java/com/google/gerrit/server/index/account/IndexedAccountQuery.java
@@ -14,21 +14,41 @@
package com.google.gerrit.server.index.account;
+import static com.google.common.base.Preconditions.checkState;
+
import com.google.gerrit.index.Index;
import com.google.gerrit.index.IndexedQuery;
import com.google.gerrit.index.QueryOptions;
import com.google.gerrit.index.query.DataSource;
+import com.google.gerrit.index.query.Matchable;
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.account.AccountState;
+import com.google.gwtorm.server.OrmException;
public class IndexedAccountQuery extends IndexedQuery<Account.Id, AccountState>
- implements DataSource<AccountState> {
+ implements DataSource<AccountState>, Matchable<AccountState> {
public IndexedAccountQuery(
Index<Account.Id, AccountState> index, Predicate<AccountState> pred, QueryOptions opts)
throws QueryParseException {
super(index, pred, opts.convertForBackend());
}
+
+ @Override
+ public boolean match(AccountState accountState) throws OrmException {
+ Predicate<AccountState> pred = getChild(0);
+ checkState(
+ pred.isMatchable(),
+ "match invoked, but child predicate %s doesn't implement %s",
+ pred,
+ Matchable.class.getName());
+ return pred.asMatchable().match(accountState);
+ }
+
+ @Override
+ public int getCost() {
+ return 1;
+ }
}
diff --git a/java/com/google/gerrit/server/git/ProjectLevelConfig.java b/java/com/google/gerrit/server/project/ProjectLevelConfig.java
similarity index 97%
rename from java/com/google/gerrit/server/git/ProjectLevelConfig.java
rename to java/com/google/gerrit/server/project/ProjectLevelConfig.java
index 2044db0..ee1bbef 100644
--- a/java/com/google/gerrit/server/git/ProjectLevelConfig.java
+++ b/java/com/google/gerrit/server/project/ProjectLevelConfig.java
@@ -12,14 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.git;
+package com.google.gerrit.server.project;
import static java.util.stream.Collectors.toList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
import com.google.gerrit.reviewdb.client.RefNames;
-import com.google.gerrit.server.project.ProjectState;
+import com.google.gerrit.server.git.VersionedMetaData;
import java.io.IOException;
import java.util.Arrays;
import java.util.Set;
diff --git a/java/com/google/gerrit/server/project/ProjectState.java b/java/com/google/gerrit/server/project/ProjectState.java
index 48a8b9a..2ef7891 100644
--- a/java/com/google/gerrit/server/project/ProjectState.java
+++ b/java/com/google/gerrit/server/project/ProjectState.java
@@ -47,7 +47,6 @@
import com.google.gerrit.server.git.BranchOrderSection;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gerrit.server.git.ProjectLevelConfig;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.rules.PrologEnvironment;
import com.google.gerrit.server.rules.RulesCache;
diff --git a/java/com/google/gerrit/server/query/account/AccountPredicates.java b/java/com/google/gerrit/server/query/account/AccountPredicates.java
index e643470..acb963c 100644
--- a/java/com/google/gerrit/server/query/account/AccountPredicates.java
+++ b/java/com/google/gerrit/server/query/account/AccountPredicates.java
@@ -19,12 +19,15 @@
import com.google.gerrit.index.FieldDef;
import com.google.gerrit.index.Schema;
import com.google.gerrit.index.query.IndexPredicate;
+import com.google.gerrit.index.query.Matchable;
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryBuilder;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.index.account.AccountField;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gwtorm.server.OrmException;
import java.util.List;
public class AccountPredicates {
@@ -121,7 +124,14 @@
return new AccountPredicate(AccountField.WATCHED_PROJECT, project.get());
}
- static class AccountPredicate extends IndexPredicate<AccountState> {
+ public static Predicate<AccountState> cansee(
+ AccountQueryBuilder.Arguments args, ChangeNotes changeNotes) {
+ return new CanSeeChangePredicate(
+ args.db, args.permissionBackend, args.userFactory, changeNotes);
+ }
+
+ static class AccountPredicate extends IndexPredicate<AccountState>
+ implements Matchable<AccountState> {
AccountPredicate(FieldDef<AccountState, ?> def, String value) {
super(def, value);
}
@@ -129,6 +139,16 @@
AccountPredicate(FieldDef<AccountState, ?> def, String name, String value) {
super(def, name, value);
}
+
+ @Override
+ public boolean match(AccountState object) throws OrmException {
+ return true;
+ }
+
+ @Override
+ public int getCost() {
+ return 1;
+ }
}
private AccountPredicates() {}
diff --git a/java/com/google/gerrit/server/query/account/AccountQueryBuilder.java b/java/com/google/gerrit/server/query/account/AccountQueryBuilder.java
index 8f6ec8b..8b6e1e4 100644
--- a/java/com/google/gerrit/server/query/account/AccountQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/account/AccountQueryBuilder.java
@@ -25,14 +25,19 @@
import com.google.gerrit.index.query.QueryBuilder;
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.ChangeFinder;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.index.account.AccountField;
import com.google.gerrit.server.index.account.AccountIndexCollection;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.permissions.ChangePermission;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
@@ -56,17 +61,27 @@
new QueryBuilder.Definition<>(AccountQueryBuilder.class);
public static class Arguments {
+ final Provider<ReviewDb> db;
+ final ChangeFinder changeFinder;
+ final IdentifiedUser.GenericFactory userFactory;
+ final PermissionBackend permissionBackend;
+
private final Provider<CurrentUser> self;
private final AccountIndexCollection indexes;
- private final PermissionBackend permissionBackend;
@Inject
public Arguments(
Provider<CurrentUser> self,
AccountIndexCollection indexes,
+ Provider<ReviewDb> db,
+ ChangeFinder changeFinder,
+ IdentifiedUser.GenericFactory userFactory,
PermissionBackend permissionBackend) {
this.self = self;
this.indexes = indexes;
+ this.db = db;
+ this.changeFinder = changeFinder;
+ this.userFactory = userFactory;
this.permissionBackend = permissionBackend;
}
@@ -105,6 +120,22 @@
}
@Operator
+ public Predicate<AccountState> cansee(String change)
+ throws QueryParseException, OrmException, PermissionBackendException {
+ ChangeNotes changeNotes = args.changeFinder.findOne(change);
+ if (changeNotes == null
+ || !args.permissionBackend
+ .user(args.getUser())
+ .database(args.db)
+ .change(changeNotes)
+ .test(ChangePermission.READ)) {
+ throw error(String.format("change %s not found", change));
+ }
+
+ return AccountPredicates.cansee(args, changeNotes);
+ }
+
+ @Operator
public Predicate<AccountState> email(String email)
throws PermissionBackendException, QueryParseException {
if (canSeeSecondaryEmails()) {
@@ -167,6 +198,14 @@
protected Predicate<AccountState> defaultField(String query) {
Predicate<AccountState> defaultPredicate =
AccountPredicates.defaultPredicate(args.schema(), checkedCanSeeSecondaryEmails(), query);
+ if (query.startsWith("cansee:")) {
+ try {
+ return cansee(query.substring(7));
+ } catch (OrmException | QueryParseException | PermissionBackendException e) {
+ // Ignore, fall back to default query
+ }
+ }
+
if ("self".equalsIgnoreCase(query) || "me".equalsIgnoreCase(query)) {
try {
return Predicate.or(defaultPredicate, AccountPredicates.id(self()));
diff --git a/java/com/google/gerrit/server/query/account/CanSeeChangePredicate.java b/java/com/google/gerrit/server/query/account/CanSeeChangePredicate.java
new file mode 100644
index 0000000..f8b8cc7
--- /dev/null
+++ b/java/com/google/gerrit/server/query/account/CanSeeChangePredicate.java
@@ -0,0 +1,71 @@
+package com.google.gerrit.server.query.account;
+
+import com.google.gerrit.index.query.PostFilterPredicate;
+import com.google.gerrit.index.query.Predicate;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.permissions.ChangePermission;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Provider;
+import java.util.Collection;
+import java.util.Objects;
+
+public class CanSeeChangePredicate extends PostFilterPredicate<AccountState> {
+ private final Provider<ReviewDb> db;
+ private final PermissionBackend permissionBackend;
+ private final IdentifiedUser.GenericFactory userFactory;
+ private final ChangeNotes changeNotes;
+
+ CanSeeChangePredicate(
+ Provider<ReviewDb> db,
+ PermissionBackend permissionBackend,
+ IdentifiedUser.GenericFactory userFactory,
+ ChangeNotes changeNotes) {
+ this.db = db;
+ this.permissionBackend = permissionBackend;
+ this.userFactory = userFactory;
+ this.changeNotes = changeNotes;
+ }
+
+ @Override
+ public boolean match(AccountState accountState) throws OrmException {
+ try {
+ return permissionBackend
+ .user(userFactory.create(accountState.getAccount().getId()))
+ .database(db)
+ .change(changeNotes)
+ .test(ChangePermission.READ);
+ } catch (PermissionBackendException e) {
+ throw new OrmException("Failed to check if account can see change", e);
+ }
+ }
+
+ @Override
+ public int getCost() {
+ return 1;
+ }
+
+ @Override
+ public Predicate<AccountState> copy(Collection<? extends Predicate<AccountState>> children) {
+ return new CanSeeChangePredicate(db, permissionBackend, userFactory, changeNotes);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(changeNotes.getChange().getChangeId());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null) {
+ return false;
+ }
+ return getClass() == other.getClass()
+ && changeNotes.getChange().getChangeId()
+ == ((CanSeeChangePredicate) other).changeNotes.getChange().getChangeId();
+ }
+}
diff --git a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
index 019338e..e930f11 100644
--- a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
+++ b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
@@ -19,14 +19,24 @@
import static java.util.stream.Collectors.toList;
import static org.junit.Assert.fail;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.access.AccessSectionInfo;
+import com.google.gerrit.extensions.api.access.PermissionInfo;
+import com.google.gerrit.extensions.api.access.PermissionRuleInfo;
+import com.google.gerrit.extensions.api.access.ProjectAccessInput;
import com.google.gerrit.extensions.api.accounts.Accounts.QueryRequest;
+import com.google.gerrit.extensions.api.groups.GroupInput;
+import com.google.gerrit.extensions.api.projects.ProjectInput;
import com.google.gerrit.extensions.client.ListAccountsOption;
import com.google.gerrit.extensions.client.ProjectWatchInfo;
import com.google.gerrit.extensions.common.AccountExternalIdInfo;
import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.ChangeInput;
+import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
@@ -76,6 +86,7 @@
import com.google.inject.util.Providers;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
@@ -396,6 +407,22 @@
}
@Test
+ public void byCansee() throws Exception {
+ String domain = name("test.com");
+ AccountInfo user1 = newAccountWithEmail("account1", "account1@" + domain);
+ AccountInfo user2 = newAccountWithEmail("account2", "account2@" + domain);
+ AccountInfo user3 = newAccountWithEmail("account3", "account3@" + domain);
+
+ Project.NameKey p = createProject(name("p"));
+ ChangeInfo c = createChange(p);
+ assertQuery("name:" + domain + " cansee:" + c.changeId, user1, user2, user3);
+
+ GroupInfo group = createGroup(name("group"), user1, user2);
+ blockRead(p, group);
+ assertQuery("name:" + domain + " cansee:" + c.changeId, user3);
+ }
+
+ @Test
public void byWatchedProject() throws Exception {
Project.NameKey p = createProject(name("p"));
Project.NameKey p2 = createProject(name("p2"));
@@ -617,10 +644,43 @@
}
protected Project.NameKey createProject(String name) throws RestApiException {
- gApi.projects().create(name);
+ ProjectInput in = new ProjectInput();
+ in.name = name;
+ in.createEmptyCommit = true;
+ gApi.projects().create(in);
return new Project.NameKey(name);
}
+ protected void blockRead(Project.NameKey project, GroupInfo group) throws RestApiException {
+ ProjectAccessInput in = new ProjectAccessInput();
+ in.add = new HashMap<>();
+
+ AccessSectionInfo a = new AccessSectionInfo();
+ PermissionInfo p = new PermissionInfo(null, null);
+ p.rules =
+ ImmutableMap.of(group.id, new PermissionRuleInfo(PermissionRuleInfo.Action.BLOCK, false));
+ a.permissions = ImmutableMap.of("read", p);
+ in.add = ImmutableMap.of("refs/*", a);
+
+ gApi.projects().name(project.get()).access(in);
+ }
+
+ protected ChangeInfo createChange(Project.NameKey project) throws RestApiException {
+ ChangeInput in = new ChangeInput();
+ in.subject = "A change";
+ in.project = project.get();
+ in.branch = "master";
+ return gApi.changes().create(in).get();
+ }
+
+ protected GroupInfo createGroup(String name, AccountInfo... members) throws RestApiException {
+ GroupInput in = new GroupInput();
+ in.name = name;
+ in.members =
+ Arrays.asList(members).stream().map(a -> String.valueOf(a._accountId)).collect(toList());
+ return gApi.groups().create(in).get();
+ }
+
protected void watch(AccountInfo account, Project.NameKey project, String filter)
throws RestApiException {
List<ProjectWatchInfo> projectsToWatch = new ArrayList<>();
diff --git a/javatests/com/google/gerrit/server/query/account/BUILD b/javatests/com/google/gerrit/server/query/account/BUILD
index e0b59d5..497fc22 100644
--- a/javatests/com/google/gerrit/server/query/account/BUILD
+++ b/javatests/com/google/gerrit/server/query/account/BUILD
@@ -19,6 +19,7 @@
"//lib:truth-java8-extension",
"//lib/guice",
"//lib/jgit/org.eclipse.jgit:jgit",
+ "//prolog:gerrit-prolog-common",
],
)
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
index 3489db0..53f9ef5 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
@@ -285,10 +285,13 @@
},
_handleRKey(e) {
- if (this.shouldSuppressKeyboardShortcut(e) ||
- this.modifierPressed(e)) { return; }
+ if (this.shouldSuppressKeyboardShortcut(e)) { return; }
e.preventDefault();
+ this._reloadWindow();
+ },
+
+ _reloadWindow() {
window.location.reload();
},
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
index aed48e3..265e34e 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
@@ -190,6 +190,10 @@
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
assert.equal(element.selectedIndex, 0);
+ const reloadStub = sandbox.stub(element, '_reloadWindow');
+ MockInteractions.pressAndReleaseKeyOn(element, 82, 'shift', 'r');
+ assert.isTrue(reloadStub.called);
+
done();
});
});
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.html b/polygerrit-ui/app/elements/change/gr-message/gr-message.html
index 0898a60..7c6032d 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.html
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.html
@@ -123,6 +123,7 @@
}
.expanded .author {
cursor: pointer;
+ margin-bottom: .4em;
}
.date {
color: #666;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
index 9b830cf..c4c5ee6 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
@@ -101,8 +101,7 @@
id="lineWrappingInput"
on-tap="_handlelineWrappingTap">
</div>
- <div class="pref" id="columnsPref"
- hidden$="[[_newPrefs.line_wrapping]]">
+ <div class="pref" id="columnsPref">
<label for="columnsInput">Diff width</label>
<input is="iron-input" type="number" id="columnsInput"
prevent-invalid-input
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
index f06cd3a..f157640 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
@@ -77,18 +77,6 @@
assert.isFalse(element._newPrefs.syntax_highlighting);
});
- test('clicking fit to screen hides line length input', () => {
- element.prefs = {line_wrapping: false};
-
- assert.isFalse(element.$.columnsPref.hidden);
-
- MockInteractions.tap(element.$.lineWrappingInput);
- assert.isTrue(element.$.columnsPref.hidden);
-
- MockInteractions.tap(element.$.lineWrappingInput);
- assert.isFalse(element.$.columnsPref.hidden);
- });
-
test('clicking save button calls _handleSave function', () => {
const savePrefs = sinon.stub(element, '_handleSave');
MockInteractions.tap(element.$.saveButton);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
index 5ba62af..c166695 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
@@ -239,6 +239,19 @@
overflow: hidden;
width: 200px;
}
+ /** Since the line limit position is determined by charachter size, blank
+ lines also need to have the same font size as everything else */
+ .full-width .blank {
+ font-size: var(--font-size, var(--font-size-small));
+ }
+ /** Support the line length indicator **/
+ .full-width td.content,
+ .full-width td.blank {
+ /* Base 64 encoded 1x1px of #ddd */
+ background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mO8+x8AAr8B3gzOjaQAAAAASUVORK5CYII=');
+ background-position: var(--line-limit) 0;
+ background-repeat: repeat-y;
+ }
</style>
<style include="gr-theme-default"></style>
<div id="diffHeader" hidden$="[[_computeDiffHeaderHidden(_diffHeaderItems)]]">
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
index 19b3c6d..987c108 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
@@ -623,6 +623,7 @@
this._diffTableClass = 'full-width';
if (this.viewMode === 'SIDE_BY_SIDE') {
stylesToUpdate['--content-width'] = 'none';
+ stylesToUpdate['--line-limit'] = prefs.line_length + 'ch';
}
} else {
this._diffTableClass = '';
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
index 7526141..e2e9c84 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
@@ -70,6 +70,20 @@
assert.equal(element._diffLength(mock.diffResponse), 52);
});
+ test('line limit with line_wrapping', () => {
+ element = fixture('basic');
+ element.prefs = {line_wrapping: true, line_length: 80, tab_size: 2};
+ flushAsynchronousOperations();
+ assert.equal(element.customStyle['--line-limit'], '80ch');
+ });
+
+ test('line limit without line_wrapping', () => {
+ element = fixture('basic');
+ element.prefs = {line_wrapping: false, line_length: 80, tab_size: 2};
+ flushAsynchronousOperations();
+ assert.isNotOk(element.customStyle['--line-limit']);
+ });
+
suite('_get{PatchNum|IsParentComment}ByLineAndContent', () => {
let lineEl;
let contentEl;