Merge changes Id81c291a,I15d97ec7
* changes: VisibleRefFilter: break out special cases to methods Optimize edit handling in VisibleRefFilter
This commit is contained in:
@@ -164,29 +164,17 @@ public class RefNames {
|
|||||||
* @return reference prefix for this change edit
|
* @return reference prefix for this change edit
|
||||||
*/
|
*/
|
||||||
public static String refsEditPrefix(Account.Id accountId, Change.Id changeId) {
|
public static String refsEditPrefix(Account.Id accountId, Change.Id changeId) {
|
||||||
return new StringBuilder(refsUsers(accountId))
|
return refsEditPrefix(accountId) + changeId.get() + '/';
|
||||||
.append('/')
|
}
|
||||||
.append(EDIT_PREFIX)
|
|
||||||
.append(changeId.get())
|
public static String refsEditPrefix(Account.Id accountId) {
|
||||||
.append('/')
|
return refsUsers(accountId) + '/' + EDIT_PREFIX;
|
||||||
.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isRefsEdit(String ref) {
|
public static boolean isRefsEdit(String ref) {
|
||||||
return ref.startsWith(REFS_USERS) && ref.contains(EDIT_PREFIX);
|
return ref.startsWith(REFS_USERS) && ref.contains(EDIT_PREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isRefsEditOf(String ref, Account.Id accountId) {
|
|
||||||
if (accountId == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String prefix = new StringBuilder(refsUsers(accountId))
|
|
||||||
.append('/')
|
|
||||||
.append(EDIT_PREFIX)
|
|
||||||
.toString();
|
|
||||||
return ref.startsWith(prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Integer parseShardedRefPart(String name) {
|
static Integer parseShardedRefPart(String name) {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -80,30 +80,6 @@ public class RefNamesTest {
|
|||||||
assertThat(RefNames.isRefsEdit("refs/heads/master")).isFalse();
|
assertThat(RefNames.isRefsEdit("refs/heads/master")).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void isRefsEditOf() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
RefNames.isRefsEditOf("refs/users/23/1011123/edit-67473/42", accountId))
|
|
||||||
.isTrue();
|
|
||||||
|
|
||||||
// other user
|
|
||||||
assertThat(
|
|
||||||
RefNames.isRefsEditOf("refs/users/20/1078620/edit-67473/42", accountId))
|
|
||||||
.isFalse();
|
|
||||||
|
|
||||||
// user ref, but no edit ref
|
|
||||||
assertThat(RefNames.isRefsEditOf("refs/users/23/1011123", accountId))
|
|
||||||
.isFalse();
|
|
||||||
|
|
||||||
// bad user shard
|
|
||||||
assertThat(
|
|
||||||
RefNames.isRefsEditOf("refs/users/77/1011123/edit-67473/42", accountId))
|
|
||||||
.isFalse();
|
|
||||||
|
|
||||||
// other ref
|
|
||||||
assertThat(RefNames.isRefsEditOf("refs/heads/master", accountId)).isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseShardedRefsPart() throws Exception {
|
public void testParseShardedRefsPart() throws Exception {
|
||||||
assertThat(parseShardedRefPart("01/1")).isEqualTo(1);
|
assertThat(parseShardedRefPart("01/1")).isEqualTo(1);
|
||||||
|
|||||||
@@ -14,8 +14,12 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server.git;
|
package com.google.gerrit.server.git;
|
||||||
|
|
||||||
|
import static com.google.gerrit.reviewdb.client.RefNames.REFS_CACHE_AUTOMERGE;
|
||||||
|
import static com.google.gerrit.reviewdb.client.RefNames.REFS_CHANGES;
|
||||||
|
import static com.google.gerrit.reviewdb.client.RefNames.REFS_CONFIG;
|
||||||
|
import static com.google.gerrit.reviewdb.client.RefNames.REFS_USERS_SELF;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
import com.google.gerrit.common.Nullable;
|
import com.google.gerrit.common.Nullable;
|
||||||
import com.google.gerrit.reviewdb.client.Account;
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
import com.google.gerrit.reviewdb.client.Change;
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
@@ -60,6 +64,7 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
|
|||||||
private final ProjectControl projectCtl;
|
private final ProjectControl projectCtl;
|
||||||
private final ReviewDb reviewDb;
|
private final ReviewDb reviewDb;
|
||||||
private final boolean showMetadata;
|
private final boolean showMetadata;
|
||||||
|
private String userEditPrefix;
|
||||||
private Set<Change.Id> visibleChanges;
|
private Set<Change.Id> visibleChanges;
|
||||||
|
|
||||||
public VisibleRefFilter(
|
public VisibleRefFilter(
|
||||||
@@ -81,86 +86,62 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Ref> filter(Map<String, Ref> refs, boolean filterTagsSeparately) {
|
public Map<String, Ref> filter(Map<String, Ref> refs, boolean filterTagsSeparately) {
|
||||||
if (projectCtl.getProjectState().isAllUsers()
|
if (projectCtl.getProjectState().isAllUsers()) {
|
||||||
&& projectCtl.getUser().isIdentifiedUser()) {
|
refs = addUsersSelfSymref(refs);
|
||||||
Ref userRef =
|
|
||||||
refs.get(RefNames.refsUsers(projectCtl.getUser().getAccountId()));
|
|
||||||
if (userRef != null) {
|
|
||||||
SymbolicRef refsUsersSelf =
|
|
||||||
new SymbolicRef(RefNames.REFS_USERS_SELF, userRef);
|
|
||||||
refs = new HashMap<>(refs);
|
|
||||||
refs.put(refsUsersSelf.getName(), refsUsersSelf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (projectCtl.allRefsAreVisible(ImmutableSet.of(RefNames.REFS_CONFIG))) {
|
if (projectCtl.allRefsAreVisible(ImmutableSet.of(REFS_CONFIG))) {
|
||||||
Map<String, Ref> r = Maps.newHashMap(refs);
|
return fastHideRefsMetaConfig(refs);
|
||||||
if (!projectCtl.controlForRef(RefNames.REFS_CONFIG).isVisible()) {
|
|
||||||
r.remove(RefNames.REFS_CONFIG);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Account.Id currAccountId;
|
Account.Id userId;
|
||||||
boolean canViewMetadata;
|
boolean viewMetadata;
|
||||||
if (projectCtl.getUser().isIdentifiedUser()) {
|
if (projectCtl.getUser().isIdentifiedUser()) {
|
||||||
IdentifiedUser user = projectCtl.getUser().asIdentifiedUser();
|
IdentifiedUser user = projectCtl.getUser().asIdentifiedUser();
|
||||||
currAccountId = user.getAccountId();
|
userId = user.getAccountId();
|
||||||
canViewMetadata = user.getCapabilities().canAccessDatabase();
|
viewMetadata = user.getCapabilities().canAccessDatabase();
|
||||||
|
userEditPrefix = RefNames.refsEditPrefix(userId);
|
||||||
} else {
|
} else {
|
||||||
currAccountId = null;
|
userId = null;
|
||||||
canViewMetadata = false;
|
viewMetadata = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Ref> result = new HashMap<>();
|
Map<String, Ref> result = new HashMap<>();
|
||||||
List<Ref> deferredTags = new ArrayList<>();
|
List<Ref> deferredTags = new ArrayList<>();
|
||||||
|
|
||||||
for (Ref ref : refs.values()) {
|
for (Ref ref : refs.values()) {
|
||||||
|
String name = ref.getName();
|
||||||
Change.Id changeId;
|
Change.Id changeId;
|
||||||
Account.Id accountId;
|
Account.Id accountId;
|
||||||
if (ref.getName().startsWith(RefNames.REFS_CACHE_AUTOMERGE)) {
|
if (name.startsWith(REFS_CACHE_AUTOMERGE)
|
||||||
|
|| (!showMetadata && isMetadata(name))) {
|
||||||
continue;
|
continue;
|
||||||
} else if (showMetadata
|
} else if (RefNames.isRefsEdit(name)) {
|
||||||
&& (RefNames.isRefsEditOf(ref.getLeaf().getName(), currAccountId)
|
// Edits are visible only to the owning user, if change is visible.
|
||||||
|| (RefNames.isRefsEdit(ref.getLeaf().getName())
|
if (viewMetadata || visibleEdit(name)) {
|
||||||
&& canViewMetadata))) {
|
result.put(name, ref);
|
||||||
// Change edit reference related is visible to the account that owns the
|
}
|
||||||
// change edit.
|
} else if ((changeId = Change.Id.fromRef(name)) != null) {
|
||||||
//
|
// Change ref is visible only if the change is visible.
|
||||||
// TODO(dborowitz): Verify if change is visible (to exclude edits on
|
if (viewMetadata || visible(changeId)) {
|
||||||
// changes that the user has lost access to).
|
result.put(name, ref);
|
||||||
result.put(ref.getName(), ref);
|
}
|
||||||
|
} else if ((accountId = Account.Id.fromRef(name)) != null) {
|
||||||
} else if ((changeId = Change.Id.fromRef(ref.getName())) != null) {
|
// Account ref is visible only to corresponding account.
|
||||||
// Reference related to a change is visible if the change is visible.
|
if (viewMetadata || (accountId.equals(userId)
|
||||||
if (showMetadata && (canViewMetadata || visible(changeId))) {
|
&& projectCtl.controlForRef(name).isVisible())) {
|
||||||
result.put(ref.getName(), ref);
|
result.put(name, ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (isTag(ref)) {
|
} else if (isTag(ref)) {
|
||||||
// If its a tag, consider it later.
|
// If its a tag, consider it later.
|
||||||
//
|
|
||||||
if (ref.getObjectId() != null) {
|
if (ref.getObjectId() != null) {
|
||||||
deferredTags.add(ref);
|
deferredTags.add(ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (projectCtl.controlForRef(ref.getLeaf().getName()).isVisible()) {
|
} else if (projectCtl.controlForRef(ref.getLeaf().getName()).isVisible()) {
|
||||||
// Use the leaf to lookup the control data. If the reference is
|
// Use the leaf to lookup the control data. If the reference is
|
||||||
// symbolic we want the control around the final target. If its
|
// symbolic we want the control around the final target. If its
|
||||||
// not symbolic then getLeaf() is a no-op returning ref itself.
|
// not symbolic then getLeaf() is a no-op returning ref itself.
|
||||||
//
|
result.put(name, ref);
|
||||||
|
|
||||||
if ((accountId =
|
|
||||||
Account.Id.fromRef(ref.getLeaf().getName())) != null) {
|
|
||||||
// Reference related to an account is visible only for the current
|
|
||||||
// account.
|
|
||||||
if (showMetadata
|
|
||||||
&& (canViewMetadata || accountId.equals(currAccountId))) {
|
|
||||||
result.put(ref.getName(), ref);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.put(ref.getName(), ref);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,6 +163,28 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, Ref> fastHideRefsMetaConfig(Map<String, Ref> refs) {
|
||||||
|
if (refs.containsKey(REFS_CONFIG)
|
||||||
|
&& !projectCtl.controlForRef(REFS_CONFIG).isVisible()) {
|
||||||
|
Map<String, Ref> r = new HashMap<>(refs);
|
||||||
|
r.remove(REFS_CONFIG);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return refs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Ref> addUsersSelfSymref(Map<String, Ref> refs) {
|
||||||
|
if (projectCtl.getUser().isIdentifiedUser()) {
|
||||||
|
Ref r = refs.get(RefNames.refsUsers(projectCtl.getUser().getAccountId()));
|
||||||
|
if (r != null) {
|
||||||
|
SymbolicRef s = new SymbolicRef(REFS_USERS_SELF, r);
|
||||||
|
refs = new HashMap<>(refs);
|
||||||
|
refs.put(s.getName(), s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return refs;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Map<String, Ref> getAdvertisedRefs(Repository repository,
|
protected Map<String, Ref> getAdvertisedRefs(Repository repository,
|
||||||
RevWalk revWalk) throws ServiceMayNotContinueException {
|
RevWalk revWalk) throws ServiceMayNotContinueException {
|
||||||
@@ -211,6 +214,16 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
|
|||||||
return visibleChanges.contains(changeId);
|
return visibleChanges.contains(changeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean visibleEdit(String name) {
|
||||||
|
if (userEditPrefix != null && name.startsWith(userEditPrefix)) {
|
||||||
|
Change.Id id = Change.Id.fromEditRefPart(name);
|
||||||
|
if (id != null) {
|
||||||
|
return visible(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private Set<Change.Id> visibleChangesBySearch() {
|
private Set<Change.Id> visibleChangesBySearch() {
|
||||||
Project project = projectCtl.getProject();
|
Project project = projectCtl.getProject();
|
||||||
try {
|
try {
|
||||||
@@ -247,6 +260,10 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isMetadata(String name) {
|
||||||
|
return name.startsWith(REFS_CHANGES) || RefNames.isRefsEdit(name);
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isTag(Ref ref) {
|
private static boolean isTag(Ref ref) {
|
||||||
return ref.getLeaf().getName().startsWith(Constants.R_TAGS);
|
return ref.getLeaf().getName().startsWith(Constants.R_TAGS);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user