Admin-Project UI page accessible to users

Make the Admin->Projects page in the UI available to non-admin users.
The page will only show projects in which the user has read access.

Change-Id: I803609da4631cf037ba8b667ec927d1f9e3f8620
This commit is contained in:
rafael.rabelosilva
2010-05-12 10:33:01 -03:00
committed by Shawn O. Pearce
parent 7e6d9808db
commit 702810d11e
18 changed files with 288 additions and 126 deletions

View File

@@ -23,6 +23,7 @@ import com.google.gerrit.reviewdb.RefRight;
public class InheritedRefRight { public class InheritedRefRight {
private RefRight right; private RefRight right;
private boolean inherited; private boolean inherited;
private boolean owner;
/** /**
* Creates a instance of a {@link RefRight} with data about inheritance * Creates a instance of a {@link RefRight} with data about inheritance
@@ -35,10 +36,12 @@ public class InheritedRefRight {
* *
* @param right the right * @param right the right
* @param inherited true if the right is inherited, false otherwise * @param inherited true if the right is inherited, false otherwise
* @param owner true if right is owned by current user, false otherwise
*/ */
public InheritedRefRight(RefRight right, boolean inherited) { public InheritedRefRight(RefRight right, boolean inherited, boolean owner) {
this.right = right; this.right = right;
this.inherited = inherited; this.inherited = inherited;
this.owner = owner;
} }
public RefRight getRight() { public RefRight getRight() {
@@ -49,6 +52,10 @@ public class InheritedRefRight {
return inherited; return inherited;
} }
public boolean isOwner() {
return owner;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (o instanceof InheritedRefRight) { if (o instanceof InheritedRefRight) {

View File

@@ -0,0 +1,53 @@
// Copyright (C) 2010 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.common.data;
import com.google.gerrit.reviewdb.Branch;
import java.util.List;
/**
* It holds list of branches and boolean to indicate
* if it is allowed to add new branches.
*/
public final class ListBranchesResult {
protected boolean canAdd;
protected List<Branch> branches;
protected ListBranchesResult() {
}
public ListBranchesResult(final List<Branch> branches, boolean canAdd) {
this.branches = branches;
this.canAdd = canAdd;
}
public boolean getCanAdd() {
return canAdd;
}
public void setCanAdd(boolean canAdd) {
this.canAdd = canAdd;
}
public List<Branch> getBranches() {
return branches;
}
public void setBranches(List<Branch> branches) {
this.branches = branches;
}
}

View File

@@ -22,7 +22,6 @@ import com.google.gerrit.reviewdb.RefRight;
import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwtjsonrpc.client.RemoteJsonService; import com.google.gwtjsonrpc.client.RemoteJsonService;
import com.google.gwtjsonrpc.client.RpcImpl; import com.google.gwtjsonrpc.client.RpcImpl;
import com.google.gwtjsonrpc.client.VoidResult;
import com.google.gwtjsonrpc.client.RpcImpl.Version; import com.google.gwtjsonrpc.client.RpcImpl.Version;
import java.util.List; import java.util.List;
@@ -31,7 +30,7 @@ import java.util.Set;
@RpcImpl(version = Version.V2_0) @RpcImpl(version = Version.V2_0)
public interface ProjectAdminService extends RemoteJsonService { public interface ProjectAdminService extends RemoteJsonService {
@SignInRequired @SignInRequired
void ownedProjects(AsyncCallback<List<Project>> callback); void visibleProjects(AsyncCallback<List<Project>> callback);
@SignInRequired @SignInRequired
void projectDetail(Project.NameKey projectName, void projectDetail(Project.NameKey projectName,
@@ -43,7 +42,7 @@ public interface ProjectAdminService extends RemoteJsonService {
@SignInRequired @SignInRequired
void deleteRight(Project.NameKey projectName, Set<RefRight.Key> ids, void deleteRight(Project.NameKey projectName, Set<RefRight.Key> ids,
AsyncCallback<VoidResult> callback); AsyncCallback<ProjectDetail> callback);
@SignInRequired @SignInRequired
void addRight(Project.NameKey projectName, ApprovalCategory.Id categoryId, void addRight(Project.NameKey projectName, ApprovalCategory.Id categoryId,
@@ -52,11 +51,11 @@ public interface ProjectAdminService extends RemoteJsonService {
@SignInRequired @SignInRequired
void listBranches(Project.NameKey projectName, void listBranches(Project.NameKey projectName,
AsyncCallback<List<Branch>> callback); AsyncCallback<ListBranchesResult> callback);
@SignInRequired @SignInRequired
void addBranch(Project.NameKey projectName, String branchName, void addBranch(Project.NameKey projectName, String branchName,
String startingRevision, AsyncCallback<List<Branch>> callback); String startingRevision, AsyncCallback<ListBranchesResult> callback);
@SignInRequired @SignInRequired
void deleteBranch(Project.NameKey projectName, Set<Branch.NameKey> ids, void deleteBranch(Project.NameKey projectName, Set<Branch.NameKey> ids,

View File

@@ -24,6 +24,10 @@ public class ProjectDetail {
public Project project; public Project project;
public Map<AccountGroup.Id, AccountGroup> groups; public Map<AccountGroup.Id, AccountGroup> groups;
public List<InheritedRefRight> rights; public List<InheritedRefRight> rights;
public boolean canModifyDescription;
public boolean canModifyMergeType;
public boolean canModifyAgreements;
public boolean canModifyAccess;
public ProjectDetail() { public ProjectDetail() {
} }
@@ -39,4 +43,20 @@ public class ProjectDetail {
public void setRights(final List<InheritedRefRight> r) { public void setRights(final List<InheritedRefRight> r) {
rights = r; rights = r;
} }
public void setCanModifyDescription(final boolean cmd) {
canModifyDescription = cmd;
}
public void setCanModifyMergeType(final boolean cmmt) {
canModifyMergeType = cmmt;
}
public void setCanModifyAgreements(final boolean cma) {
canModifyAgreements = cma;
}
public void setCanModifyAccess(final boolean cma) {
canModifyAccess = cma;
}
} }

View File

@@ -17,6 +17,7 @@ package com.google.gerrit.client.admin;
import com.google.gerrit.client.Gerrit; import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.rpc.GerritCallback; import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.ui.FancyFlexTable; import com.google.gerrit.client.ui.FancyFlexTable;
import com.google.gerrit.common.data.ListBranchesResult;
import com.google.gerrit.common.data.GitwebLink; import com.google.gerrit.common.data.GitwebLink;
import com.google.gerrit.common.errors.InvalidNameException; import com.google.gerrit.common.errors.InvalidNameException;
import com.google.gerrit.common.errors.InvalidRevisionException; import com.google.gerrit.common.errors.InvalidRevisionException;
@@ -57,6 +58,8 @@ public class ProjectBranchesPanel extends Composite {
private NpTextBox nameTxtBox; private NpTextBox nameTxtBox;
private NpTextBox irevTxtBox; private NpTextBox irevTxtBox;
private final FlowPanel addPanel = new FlowPanel();
public ProjectBranchesPanel(final Project.NameKey toShow) { public ProjectBranchesPanel(final Project.NameKey toShow) {
final FlowPanel body = new FlowPanel(); final FlowPanel body = new FlowPanel();
initBranches(body); initBranches(body);
@@ -71,14 +74,20 @@ public class ProjectBranchesPanel extends Composite {
super.onLoad(); super.onLoad();
Util.PROJECT_SVC.listBranches(projectName, Util.PROJECT_SVC.listBranches(projectName,
new GerritCallback<List<Branch>>() { new GerritCallback<ListBranchesResult>() {
public void onSuccess(final List<Branch> result) { public void onSuccess(final ListBranchesResult result) {
enableForm(true); enableForm(true);
branches.display(result); display(result.getBranches());
addPanel.setVisible(result.getCanAdd());
} }
}); });
} }
private void display(final List<Branch> listBranches) {
branches.display(listBranches);
delBranch.setVisible(branches.hasBranchCanDelete());
}
private void enableForm(final boolean on) { private void enableForm(final boolean on) {
delBranch.setEnabled(on); delBranch.setEnabled(on);
addBranch.setEnabled(on); addBranch.setEnabled(on);
@@ -87,7 +96,6 @@ public class ProjectBranchesPanel extends Composite {
} }
private void initBranches(final Panel body) { private void initBranches(final Panel body) {
final FlowPanel addPanel = new FlowPanel();
addPanel.setStyleName(Gerrit.RESOURCES.css().addSshKeyPanel()); addPanel.setStyleName(Gerrit.RESOURCES.css().addSshKeyPanel());
final Grid addGrid = new Grid(2, 2); final Grid addGrid = new Grid(2, 2);
@@ -209,12 +217,12 @@ public class ProjectBranchesPanel extends Composite {
addBranch.setEnabled(false); addBranch.setEnabled(false);
Util.PROJECT_SVC.addBranch(projectName, branchName, rev, Util.PROJECT_SVC.addBranch(projectName, branchName, rev,
new GerritCallback<List<Branch>>() { new GerritCallback<ListBranchesResult>() {
public void onSuccess(final List<Branch> result) { public void onSuccess(final ListBranchesResult result) {
addBranch.setEnabled(true); addBranch.setEnabled(true);
nameTxtBox.setText(""); nameTxtBox.setText("");
irevTxtBox.setText(""); irevTxtBox.setText("");
branches.display(result); display(result.getBranches());
} }
@Override @Override
@@ -239,6 +247,8 @@ public class ProjectBranchesPanel extends Composite {
} }
private class BranchesTable extends FancyFlexTable<Branch> { private class BranchesTable extends FancyFlexTable<Branch> {
boolean canDelete;
BranchesTable() { BranchesTable() {
table.setWidth(""); table.setWidth("");
table.setText(0, 2, Util.C.columnBranchName()); table.setText(0, 2, Util.C.columnBranchName());
@@ -282,6 +292,8 @@ public class ProjectBranchesPanel extends Composite {
} }
void display(final List<Branch> result) { void display(final List<Branch> result) {
canDelete = false;
while (1 < table.getRowCount()) while (1 < table.getRowCount())
table.removeRow(table.getRowCount() - 1); table.removeRow(table.getRowCount() - 1);
@@ -296,7 +308,13 @@ public class ProjectBranchesPanel extends Composite {
void populate(final int row, final Branch k) { void populate(final int row, final Branch k) {
final GitwebLink c = Gerrit.getConfig().getGitwebLink(); final GitwebLink c = Gerrit.getConfig().getGitwebLink();
if (k.getCanDelete()) {
table.setWidget(row, 1, new CheckBox()); table.setWidget(row, 1, new CheckBox());
canDelete = true;
} else {
table.setText(row, 1, "");
}
table.setText(row, 2, k.getShortName()); table.setText(row, 2, k.getShortName());
if (k.getRevision() != null) { if (k.getRevision() != null) {
@@ -320,5 +338,9 @@ public class ProjectBranchesPanel extends Composite {
setRowItem(row, k); setRowItem(row, k);
} }
boolean hasBranchCanDelete() {
return canDelete;
}
} }
} }

View File

@@ -70,7 +70,7 @@ public class ProjectInfoPanel extends Composite {
@Override @Override
protected void onLoad() { protected void onLoad() {
enableForm(false); enableForm(false, false, false);
saveProject.setEnabled(false); saveProject.setEnabled(false);
super.onLoad(); super.onLoad();
refresh(); refresh();
@@ -80,18 +80,26 @@ public class ProjectInfoPanel extends Composite {
Util.PROJECT_SVC.projectDetail(projectName, Util.PROJECT_SVC.projectDetail(projectName,
new GerritCallback<ProjectDetail>() { new GerritCallback<ProjectDetail>() {
public void onSuccess(final ProjectDetail result) { public void onSuccess(final ProjectDetail result) {
enableForm(true); enableForm(result.canModifyAgreements,
result.canModifyDescription, result.canModifyMergeType);
saveProject.setVisible(
result.canModifyAgreements ||
result.canModifyDescription ||
result.canModifyMergeType);
saveProject.setEnabled(false); saveProject.setEnabled(false);
display(result); display(result);
} }
}); });
} }
private void enableForm(final boolean on) { private void enableForm(final boolean canModifyAgreements,
submitType.setEnabled(on); final boolean canModifyDescription, final boolean canModifyMergeType) {
descTxt.setEnabled(on); submitType.setEnabled(canModifyMergeType);
useContributorAgreements.setEnabled(on); descTxt.setEnabled(canModifyDescription);
useSignedOffBy.setEnabled(on); useContributorAgreements.setEnabled(canModifyAgreements);
useSignedOffBy.setEnabled(canModifyAgreements);
saveProject.setEnabled(
canModifyAgreements || canModifyDescription || canModifyMergeType);
} }
private void initDescription(final Panel body) { private void initDescription(final Panel body) {
@@ -185,13 +193,14 @@ public class ProjectInfoPanel extends Composite {
.getValue(submitType.getSelectedIndex()))); .getValue(submitType.getSelectedIndex())));
} }
enableForm(false); enableForm(false, false, false);
saveProject.setEnabled(false); saveProject.setEnabled(false);
Util.PROJECT_SVC.changeProjectSettings(project, Util.PROJECT_SVC.changeProjectSettings(project,
new GerritCallback<ProjectDetail>() { new GerritCallback<ProjectDetail>() {
public void onSuccess(final ProjectDetail result) { public void onSuccess(final ProjectDetail result) {
enableForm(true); enableForm(result.canModifyAgreements,
result.canModifyDescription, result.canModifyMergeType);
display(result); display(result);
} }

View File

@@ -39,7 +39,7 @@ public class ProjectListScreen extends AccountScreen {
@Override @Override
protected void onLoad() { protected void onLoad() {
super.onLoad(); super.onLoad();
Util.PROJECT_SVC.ownedProjects(new ScreenLoadCallback<List<Project>>(this) { Util.PROJECT_SVC.visibleProjects(new ScreenLoadCallback<List<Project>>(this) {
@Override @Override
protected void preDisplay(final List<Project> result) { protected void preDisplay(final List<Project> result) {
projects.display(result); projects.display(result);

View File

@@ -54,7 +54,6 @@ import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
import com.google.gwtexpui.globalkey.client.NpTextBox; import com.google.gwtexpui.globalkey.client.NpTextBox;
import com.google.gwtexpui.safehtml.client.SafeHtml; import com.google.gwtexpui.safehtml.client.SafeHtml;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder; import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
import com.google.gwtjsonrpc.client.VoidResult;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@@ -76,6 +75,8 @@ public class ProjectRightsPanel extends Composite {
private SuggestBox nameTxt; private SuggestBox nameTxt;
private NpTextBox referenceTxt; private NpTextBox referenceTxt;
private final FlowPanel addPanel = new FlowPanel();
public ProjectRightsPanel(final Project.NameKey toShow) { public ProjectRightsPanel(final Project.NameKey toShow) {
projectName = toShow; projectName = toShow;
@@ -121,7 +122,6 @@ public class ProjectRightsPanel extends Composite {
} }
private void initRights(final Panel body) { private void initRights(final Panel body) {
final FlowPanel addPanel = new FlowPanel();
addPanel.setStyleName(Gerrit.RESOURCES.css().addSshKeyPanel()); addPanel.setStyleName(Gerrit.RESOURCES.css().addSshKeyPanel());
final Grid addGrid = new Grid(5, 2); final Grid addGrid = new Grid(5, 2);
@@ -223,7 +223,8 @@ public class ProjectRightsPanel extends Composite {
delRight.addClickHandler(new ClickHandler() { delRight.addClickHandler(new ClickHandler() {
@Override @Override
public void onClick(final ClickEvent event) { public void onClick(final ClickEvent event) {
rights.deleteChecked(); final HashSet<RefRight.Key> refRightIds = rights.getRefRightIdsChecked();
doDeleteRefRights(refRightIds);
} }
}); });
@@ -254,6 +255,22 @@ public class ProjectRightsPanel extends Composite {
parentName.setText(parent.get()); parentName.setText(parent.get());
rights.display(result.groups, result.rights); rights.display(result.groups, result.rights);
addPanel.setVisible(result.canModifyAccess);
delRight.setVisible(rights.getCanDelete());
}
private void doDeleteRefRights(final HashSet<RefRight.Key> refRightIds) {
if (!refRightIds.isEmpty()) {
Util.PROJECT_SVC.deleteRight(projectName, refRightIds,
new GerritCallback<ProjectDetail>() {
@Override
public void onSuccess(final ProjectDetail result) {
//The user could no longer modify access after deleting a ref right.
display(result);
}
});
}
} }
private void doAddNewRight() { private void doAddNewRight() {
@@ -393,6 +410,8 @@ public class ProjectRightsPanel extends Composite {
} }
private class RightsTable extends FancyFlexTable<RefRight> { private class RightsTable extends FancyFlexTable<RefRight> {
boolean canDelete;
RightsTable() { RightsTable() {
table.setWidth(""); table.setWidth("");
table.setText(0, 2, Util.C.columnApprovalCategory()); table.setText(0, 2, Util.C.columnApprovalCategory());
@@ -408,7 +427,7 @@ public class ProjectRightsPanel extends Composite {
fmt.addStyleName(0, 5, Gerrit.RESOURCES.css().dataHeader()); fmt.addStyleName(0, 5, Gerrit.RESOURCES.css().dataHeader());
} }
void deleteChecked() { HashSet<RefRight.Key> getRefRightIdsChecked() {
final HashSet<RefRight.Key> refRightIds = new HashSet<RefRight.Key>(); final HashSet<RefRight.Key> refRightIds = new HashSet<RefRight.Key>();
for (int row = 1; row < table.getRowCount(); row++) { for (int row = 1; row < table.getRowCount(); row++) {
RefRight r = getRowItem(row); RefRight r = getRowItem(row);
@@ -417,28 +436,13 @@ public class ProjectRightsPanel extends Composite {
refRightIds.add(r.getKey()); refRightIds.add(r.getKey());
} }
} }
return refRightIds;
GerritCallback<VoidResult> updateTable =
new GerritCallback<VoidResult>() {
@Override
public void onSuccess(final VoidResult result) {
for (int row = 1; row < table.getRowCount();) {
RefRight r = getRowItem(row);
if (r != null && refRightIds.contains(r.getKey())) {
table.removeRow(row);
} else {
row++;
}
}
}
};
if (!refRightIds.isEmpty()) {
Util.PROJECT_SVC.deleteRight(projectName, refRightIds, updateTable);
}
} }
void display(final Map<AccountGroup.Id, AccountGroup> groups, void display(final Map<AccountGroup.Id, AccountGroup> groups,
final List<InheritedRefRight> refRights) { final List<InheritedRefRight> refRights) {
canDelete = false;
while (1 < table.getRowCount()) while (1 < table.getRowCount())
table.removeRow(table.getRowCount() - 1); table.removeRow(table.getRowCount() - 1);
@@ -450,8 +454,7 @@ public class ProjectRightsPanel extends Composite {
} }
} }
void populate(final int row, void populate(final int row, final Map<AccountGroup.Id, AccountGroup> groups,
final Map<AccountGroup.Id, AccountGroup> groups,
final InheritedRefRight r) { final InheritedRefRight r) {
final GerritConfig config = Gerrit.getConfig(); final GerritConfig config = Gerrit.getConfig();
final RefRight right = r.getRight(); final RefRight right = r.getRight();
@@ -460,10 +463,11 @@ public class ProjectRightsPanel extends Composite {
right.getApprovalCategoryId()); right.getApprovalCategoryId());
final AccountGroup group = groups.get(right.getAccountGroupId()); final AccountGroup group = groups.get(right.getAccountGroupId());
if (r.isInherited()) { if (r.isInherited() || !r.isOwner()) {
table.setText(row, 1, ""); table.setText(row, 1, "");
} else { } else {
table.setWidget(row, 1, new CheckBox()); table.setWidget(row, 1, new CheckBox());
canDelete = true;
} }
if (ar != null) { if (ar != null) {
@@ -525,5 +529,9 @@ public class ProjectRightsPanel extends Composite {
m.append(e.getName()); m.append(e.getName());
} }
} }
private boolean getCanDelete() {
return canDelete;
}
} }
} }

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.httpd.rpc.project; package com.google.gerrit.httpd.rpc.project;
import com.google.gerrit.common.data.ListBranchesResult;
import com.google.gerrit.common.errors.InvalidNameException; import com.google.gerrit.common.errors.InvalidNameException;
import com.google.gerrit.common.errors.InvalidRevisionException; import com.google.gerrit.common.errors.InvalidRevisionException;
import com.google.gerrit.httpd.rpc.Handler; import com.google.gerrit.httpd.rpc.Handler;
@@ -42,9 +43,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.util.List;
class AddBranch extends Handler<List<Branch>> { class AddBranch extends Handler<ListBranchesResult> {
private static final Logger log = LoggerFactory.getLogger(AddBranch.class); private static final Logger log = LoggerFactory.getLogger(AddBranch.class);
interface Factory { interface Factory {
@@ -85,7 +85,7 @@ class AddBranch extends Handler<List<Branch>> {
} }
@Override @Override
public List<Branch> call() throws NoSuchProjectException, public ListBranchesResult call() throws NoSuchProjectException,
InvalidNameException, InvalidRevisionException, IOException { InvalidNameException, InvalidRevisionException, IOException {
final ProjectControl projectControl = final ProjectControl projectControl =
projectControlFactory.controlFor(projectName); projectControlFactory.controlFor(projectName);

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.httpd.rpc.project; package com.google.gerrit.httpd.rpc.project;
import com.google.gerrit.common.data.ProjectDetail;
import com.google.gerrit.httpd.rpc.Handler; import com.google.gerrit.httpd.rpc.Handler;
import com.google.gerrit.reviewdb.Project; import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.reviewdb.RefRight; import com.google.gerrit.reviewdb.RefRight;
@@ -23,7 +24,6 @@ import com.google.gerrit.server.project.NoSuchRefException;
import com.google.gerrit.server.project.ProjectCache; import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl; import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.RefControl; import com.google.gerrit.server.project.RefControl;
import com.google.gwtjsonrpc.client.VoidResult;
import com.google.gwtorm.client.OrmException; import com.google.gwtorm.client.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
@@ -31,12 +31,13 @@ import com.google.inject.assistedinject.Assisted;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
class DeleteRefRights extends Handler<VoidResult> { class DeleteRefRights extends Handler<ProjectDetail> {
interface Factory { interface Factory {
DeleteRefRights create(@Assisted Project.NameKey projectName, DeleteRefRights create(@Assisted Project.NameKey projectName,
@Assisted Set<RefRight.Key> toRemove); @Assisted Set<RefRight.Key> toRemove);
} }
private final ProjectDetailFactory.Factory projectDetailFactory;
private final ProjectControl.Factory projectControlFactory; private final ProjectControl.Factory projectControlFactory;
private final ProjectCache projectCache; private final ProjectCache projectCache;
private final ReviewDb db; private final ReviewDb db;
@@ -45,11 +46,13 @@ class DeleteRefRights extends Handler<VoidResult> {
private final Set<RefRight.Key> toRemove; private final Set<RefRight.Key> toRemove;
@Inject @Inject
DeleteRefRights(final ProjectControl.Factory projectControlFactory, DeleteRefRights(final ProjectDetailFactory.Factory projectDetailFactory,
final ProjectControl.Factory projectControlFactory,
final ProjectCache projectCache, final ReviewDb db, final ProjectCache projectCache, final ReviewDb db,
@Assisted final Project.NameKey projectName, @Assisted final Project.NameKey projectName,
@Assisted final Set<RefRight.Key> toRemove) { @Assisted final Set<RefRight.Key> toRemove) {
this.projectDetailFactory = projectDetailFactory;
this.projectControlFactory = projectControlFactory; this.projectControlFactory = projectControlFactory;
this.projectCache = projectCache; this.projectCache = projectCache;
this.db = db; this.db = db;
@@ -59,7 +62,7 @@ class DeleteRefRights extends Handler<VoidResult> {
} }
@Override @Override
public VoidResult call() throws NoSuchProjectException, OrmException, public ProjectDetail call() throws NoSuchProjectException, OrmException,
NoSuchRefException { NoSuchRefException {
final ProjectControl projectControl = final ProjectControl projectControl =
projectControlFactory.controlFor(projectName); projectControlFactory.controlFor(projectName);
@@ -80,7 +83,7 @@ class DeleteRefRights extends Handler<VoidResult> {
} }
} }
projectCache.evictAll(); projectCache.evictAll();
return VoidResult.INSTANCE; return projectDetailFactory.create(projectName).call();
} }
private RefControl controlForRef(ProjectControl p, String ref) { private RefControl controlForRef(ProjectControl p, String ref) {

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.httpd.rpc.project; package com.google.gerrit.httpd.rpc.project;
import com.google.gerrit.common.data.ListBranchesResult;
import com.google.gerrit.httpd.rpc.Handler; import com.google.gerrit.httpd.rpc.Handler;
import com.google.gerrit.reviewdb.Branch; import com.google.gerrit.reviewdb.Branch;
import com.google.gerrit.reviewdb.Project; import com.google.gerrit.reviewdb.Project;
@@ -21,6 +22,7 @@ import com.google.gerrit.reviewdb.RevId;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.project.NoSuchProjectException; import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectControl; import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.RefControl;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
@@ -36,7 +38,7 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
class ListBranches extends Handler<List<Branch>> { class ListBranches extends Handler<ListBranchesResult> {
interface Factory { interface Factory {
ListBranches create(@Assisted Project.NameKey name); ListBranches create(@Assisted Project.NameKey name);
} }
@@ -58,7 +60,7 @@ class ListBranches extends Handler<List<Branch>> {
} }
@Override @Override
public List<Branch> call() throws NoSuchProjectException, public ListBranchesResult call() throws NoSuchProjectException,
RepositoryNotFoundException { RepositoryNotFoundException {
final ProjectControl pctl = projectControlFactory.validateFor( // final ProjectControl pctl = projectControlFactory.validateFor( //
projectName, // projectName, //
@@ -91,7 +93,8 @@ class ListBranches extends Handler<List<Branch>> {
// showing the resolved value, show the name it references. // showing the resolved value, show the name it references.
// //
String target = ref.getTarget().getName(); String target = ref.getTarget().getName();
if (!pctl.controlForRef(target).isVisible()) { RefControl targetRefControl = pctl.controlForRef(target);
if (!targetRefControl.isVisible()) {
continue; continue;
} }
if (target.startsWith(Constants.R_HEADS)) { if (target.startsWith(Constants.R_HEADS)) {
@@ -100,6 +103,8 @@ class ListBranches extends Handler<List<Branch>> {
Branch b = createBranch(Constants.HEAD); Branch b = createBranch(Constants.HEAD);
b.setRevision(new RevId(target)); b.setRevision(new RevId(target));
b.setCanDelete(targetRefControl.canDelete());
if (Constants.HEAD.equals(ref.getName())) { if (Constants.HEAD.equals(ref.getName())) {
headBranch = b; headBranch = b;
} else { } else {
@@ -108,12 +113,17 @@ class ListBranches extends Handler<List<Branch>> {
continue; continue;
} }
RefControl refControl = pctl.controlForRef(ref.getName());
if (ref.getName().startsWith(Constants.R_HEADS) if (ref.getName().startsWith(Constants.R_HEADS)
&& pctl.controlForRef(ref.getName()).isVisible()) { && refControl.isVisible()) {
final Branch b = createBranch(ref.getName()); final Branch b = createBranch(ref.getName());
if (ref.getObjectId() != null) { if (ref.getObjectId() != null) {
b.setRevision(new RevId(ref.getObjectId().name())); b.setRevision(new RevId(ref.getObjectId().name()));
} }
b.setCanDelete(refControl.canDelete());
branches.add(b); branches.add(b);
} }
} }
@@ -129,7 +139,7 @@ class ListBranches extends Handler<List<Branch>> {
if (headBranch != null) { if (headBranch != null) {
branches.add(0, headBranch); branches.add(0, headBranch);
} }
return branches; return new ListBranchesResult(branches, pctl.canAddRefs());
} }
private Branch createBranch(final String name) { private Branch createBranch(final String name) {

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.httpd.rpc.project; package com.google.gerrit.httpd.rpc.project;
import com.google.gerrit.common.data.ListBranchesResult;
import com.google.gerrit.common.data.ProjectAdminService; import com.google.gerrit.common.data.ProjectAdminService;
import com.google.gerrit.common.data.ProjectDetail; import com.google.gerrit.common.data.ProjectDetail;
import com.google.gerrit.reviewdb.ApprovalCategory; import com.google.gerrit.reviewdb.ApprovalCategory;
@@ -21,7 +22,6 @@ import com.google.gerrit.reviewdb.Branch;
import com.google.gerrit.reviewdb.Project; import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.reviewdb.RefRight; import com.google.gerrit.reviewdb.RefRight;
import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwtjsonrpc.client.VoidResult;
import com.google.inject.Inject; import com.google.inject.Inject;
import java.util.List; import java.util.List;
@@ -32,7 +32,7 @@ class ProjectAdminServiceImpl implements ProjectAdminService {
private final ChangeProjectSettings.Factory changeProjectSettingsFactory; private final ChangeProjectSettings.Factory changeProjectSettingsFactory;
private final DeleteBranches.Factory deleteBranchesFactory; private final DeleteBranches.Factory deleteBranchesFactory;
private final ListBranches.Factory listBranchesFactory; private final ListBranches.Factory listBranchesFactory;
private final OwnedProjects.Factory ownedProjectsFactory; private final VisibleProjects.Factory visibleProjectsFactory;
private final ProjectDetailFactory.Factory projectDetailFactory; private final ProjectDetailFactory.Factory projectDetailFactory;
private final AddRefRight.Factory addRefRightFactory; private final AddRefRight.Factory addRefRightFactory;
private final DeleteRefRights.Factory deleteRefRightsFactory; private final DeleteRefRights.Factory deleteRefRightsFactory;
@@ -42,7 +42,7 @@ class ProjectAdminServiceImpl implements ProjectAdminService {
final ChangeProjectSettings.Factory changeProjectSettingsFactory, final ChangeProjectSettings.Factory changeProjectSettingsFactory,
final DeleteBranches.Factory deleteBranchesFactory, final DeleteBranches.Factory deleteBranchesFactory,
final ListBranches.Factory listBranchesFactory, final ListBranches.Factory listBranchesFactory,
final OwnedProjects.Factory ownedProjectsFactory, final VisibleProjects.Factory visibleProjectsFactory,
final ProjectDetailFactory.Factory projectDetailFactory, final ProjectDetailFactory.Factory projectDetailFactory,
final AddRefRight.Factory addRefRightFactory, final AddRefRight.Factory addRefRightFactory,
final DeleteRefRights.Factory deleteRefRightsFactory) { final DeleteRefRights.Factory deleteRefRightsFactory) {
@@ -50,15 +50,15 @@ class ProjectAdminServiceImpl implements ProjectAdminService {
this.changeProjectSettingsFactory = changeProjectSettingsFactory; this.changeProjectSettingsFactory = changeProjectSettingsFactory;
this.deleteBranchesFactory = deleteBranchesFactory; this.deleteBranchesFactory = deleteBranchesFactory;
this.listBranchesFactory = listBranchesFactory; this.listBranchesFactory = listBranchesFactory;
this.ownedProjectsFactory = ownedProjectsFactory; this.visibleProjectsFactory = visibleProjectsFactory;
this.projectDetailFactory = projectDetailFactory; this.projectDetailFactory = projectDetailFactory;
this.addRefRightFactory = addRefRightFactory; this.addRefRightFactory = addRefRightFactory;
this.deleteRefRightsFactory = deleteRefRightsFactory; this.deleteRefRightsFactory = deleteRefRightsFactory;
} }
@Override @Override
public void ownedProjects(final AsyncCallback<List<Project>> callback) { public void visibleProjects(final AsyncCallback<List<Project>> callback) {
ownedProjectsFactory.create().to(callback); visibleProjectsFactory.create().to(callback);
} }
@Override @Override
@@ -75,7 +75,7 @@ class ProjectAdminServiceImpl implements ProjectAdminService {
@Override @Override
public void deleteRight(final Project.NameKey projectName, public void deleteRight(final Project.NameKey projectName,
final Set<RefRight.Key> toRemove, final AsyncCallback<VoidResult> callback) { final Set<RefRight.Key> toRemove, final AsyncCallback<ProjectDetail> callback) {
deleteRefRightsFactory.create(projectName, toRemove).to(callback); deleteRefRightsFactory.create(projectName, toRemove).to(callback);
} }
@@ -90,7 +90,7 @@ class ProjectAdminServiceImpl implements ProjectAdminService {
@Override @Override
public void listBranches(final Project.NameKey projectName, public void listBranches(final Project.NameKey projectName,
final AsyncCallback<List<Branch>> callback) { final AsyncCallback<ListBranchesResult> callback) {
listBranchesFactory.create(projectName).to(callback); listBranchesFactory.create(projectName).to(callback);
} }
@@ -104,7 +104,7 @@ class ProjectAdminServiceImpl implements ProjectAdminService {
@Override @Override
public void addBranch(final Project.NameKey projectName, public void addBranch(final Project.NameKey projectName,
final String branchName, final String startingRevision, final String branchName, final String startingRevision,
final AsyncCallback<List<Branch>> callback) { final AsyncCallback<ListBranchesResult> callback) {
addBranchFactory.create(projectName, branchName, startingRevision).to( addBranchFactory.create(projectName, branchName, startingRevision).to(
callback); callback);
} }

View File

@@ -26,6 +26,7 @@ import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.project.NoSuchProjectException; import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectControl; import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.ProjectState; import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.project.RefControl;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
@@ -64,10 +65,10 @@ class ProjectDetailFactory extends Handler<ProjectDetail> {
@Override @Override
public ProjectDetail call() throws NoSuchProjectException { public ProjectDetail call() throws NoSuchProjectException {
final ProjectState projectState = final ProjectControl pc =
projectControlFactory.validateFor(projectName, projectControlFactory.validateFor(projectName, ProjectControl.OWNER
ProjectControl.OWNER | ProjectControl.VISIBLE).getProjectState(); | ProjectControl.VISIBLE);
final ProjectState projectState = pc.getProjectState();
final ProjectDetail detail = new ProjectDetail(); final ProjectDetail detail = new ProjectDetail();
detail.setProject(projectState.getProject()); detail.setProject(projectState.getProject());
@@ -75,7 +76,8 @@ class ProjectDetailFactory extends Handler<ProjectDetail> {
final List<InheritedRefRight> refRights = new ArrayList<InheritedRefRight>(); final List<InheritedRefRight> refRights = new ArrayList<InheritedRefRight>();
for (final RefRight r : projectState.getInheritedRights()) { for (final RefRight r : projectState.getInheritedRights()) {
InheritedRefRight refRight = new InheritedRefRight(r, true); InheritedRefRight refRight = new InheritedRefRight(
r, true, controlForRef(pc, r.getRefPattern()).isOwner());
if (!refRights.contains(refRight)) { if (!refRights.contains(refRight)) {
refRights.add(refRight); refRights.add(refRight);
wantGroup(r.getAccountGroupId()); wantGroup(r.getAccountGroupId());
@@ -83,7 +85,8 @@ class ProjectDetailFactory extends Handler<ProjectDetail> {
} }
for (final RefRight r : projectState.getLocalRights()) { for (final RefRight r : projectState.getLocalRights()) {
refRights.add(new InheritedRefRight(r, false)); refRights.add(new InheritedRefRight(
r, false, controlForRef(pc, r.getRefPattern()).isOwner()));
wantGroup(r.getAccountGroupId()); wantGroup(r.getAccountGroupId());
} }
@@ -118,8 +121,15 @@ class ProjectDetailFactory extends Handler<ProjectDetail> {
} }
}); });
final boolean userIsOwner = pc.isOwner();
final boolean userIsOwnerAnyRef = pc.isOwnerAnyRef();
detail.setRights(refRights); detail.setRights(refRights);
detail.setGroups(groups); detail.setGroups(groups);
detail.setCanModifyAccess(userIsOwnerAnyRef);
detail.setCanModifyAgreements(userIsOwner);
detail.setCanModifyDescription(userIsOwner);
detail.setCanModifyMergeType(userIsOwner);
return detail; return detail;
} }
@@ -134,4 +144,11 @@ class ProjectDetailFactory extends Handler<ProjectDetail> {
groups.put(groupId, groupCache.get(groupId)); groups.put(groupId, groupCache.get(groupId));
} }
} }
private RefControl controlForRef(ProjectControl p, String ref) {
if (ref.endsWith("/*")) {
ref = ref.substring(0, ref.length() - 1);
}
return p.controlForRef(ref);
}
} }

View File

@@ -34,7 +34,7 @@ public class ProjectModule extends RpcServletModule {
factory(DeleteBranches.Factory.class); factory(DeleteBranches.Factory.class);
factory(DeleteRefRights.Factory.class); factory(DeleteRefRights.Factory.class);
factory(ListBranches.Factory.class); factory(ListBranches.Factory.class);
factory(OwnedProjects.Factory.class); factory(VisibleProjects.Factory.class);
factory(ProjectDetailFactory.Factory.class); factory(ProjectDetailFactory.Factory.class);
} }
}); });

View File

@@ -14,27 +14,23 @@
package com.google.gerrit.httpd.rpc.project; package com.google.gerrit.httpd.rpc.project;
import com.google.gerrit.httpd.rpc.Handler; import com.google.gerrit.httpd.rpc.Handler;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.ApprovalCategory;
import com.google.gerrit.reviewdb.Project; import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.reviewdb.RefRight;
import com.google.gerrit.reviewdb.ReviewDb; import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.project.NoSuchProjectException; import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectControl; import com.google.gerrit.server.project.ProjectControl;
import com.google.gwtorm.client.OrmException; import com.google.gwtorm.client.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet;
import java.util.List; import java.util.List;
class OwnedProjects extends Handler<List<Project>> { class VisibleProjects extends Handler<List<Project>> {
interface Factory { interface Factory {
OwnedProjects create(); VisibleProjects create();
} }
private final ProjectControl.Factory projectControlFactory; private final ProjectControl.Factory projectControlFactory;
@@ -42,7 +38,7 @@ class OwnedProjects extends Handler<List<Project>> {
private final ReviewDb db; private final ReviewDb db;
@Inject @Inject
OwnedProjects(final ProjectControl.Factory projectControlFactory, VisibleProjects(final ProjectControl.Factory projectControlFactory,
final IdentifiedUser user, final ReviewDb db) { final IdentifiedUser user, final ReviewDb db) {
this.projectControlFactory = projectControlFactory; this.projectControlFactory = projectControlFactory;
this.user = user; this.user = user;
@@ -54,28 +50,19 @@ class OwnedProjects extends Handler<List<Project>> {
final List<Project> result; final List<Project> result;
if (user.isAdministrator()) { if (user.isAdministrator()) {
result = db.projects().all().toList(); result = db.projects().all().toList();
} else { } else {
final HashSet<Project.NameKey> seen = new HashSet<Project.NameKey>();
result = new ArrayList<Project>(); result = new ArrayList<Project>();
for (final AccountGroup.Id groupId : user.getEffectiveGroups()) { for (Project p : db.projects().all().toList()) {
for (final RefRight r : db.refRights().byCategoryGroup(
ApprovalCategory.OWN, groupId)) {
final Project.NameKey name = r.getProjectNameKey();
if (!seen.add(name)) {
continue;
}
try { try {
ProjectControl c = projectControlFactory.controlFor(name); ProjectControl c = projectControlFactory.controlFor(p.getNameKey());
if (c.isOwnerAnyRef()) { if (c.isVisible() || c.isOwner()) {
result.add(c.getProject()); result.add(p);
} }
} catch (NoSuchProjectException e) { } catch (NoSuchProjectException e) {
continue; continue;
} }
} }
} }
}
Collections.sort(result, new Comparator<Project>() { Collections.sort(result, new Comparator<Project>() {
public int compare(final Project a, final Project b) { public int compare(final Project a, final Project b) {
return a.getName().compareTo(b.getName()); return a.getName().compareTo(b.getName());

View File

@@ -24,6 +24,7 @@ import static org.eclipse.jgit.lib.Constants.HEAD;
import static org.eclipse.jgit.lib.Constants.R_HEADS; import static org.eclipse.jgit.lib.Constants.R_HEADS;
import static org.eclipse.jgit.lib.Ref.Storage.LOOSE; import static org.eclipse.jgit.lib.Ref.Storage.LOOSE;
import com.google.gerrit.common.data.ListBranchesResult;
import com.google.gerrit.reviewdb.Branch; import com.google.gerrit.reviewdb.Branch;
import com.google.gerrit.reviewdb.Project; import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
@@ -121,11 +122,12 @@ public class ListBranchesTest extends LocalDiskRepositoryTestCase {
} }
private List<Branch> permitted(boolean getHead) private ListBranchesResult permitted(boolean getHead)
throws NoSuchProjectException, IOException { throws NoSuchProjectException, IOException {
Map<String, Ref> refs = realDb.getAllRefs(); Map<String, Ref> refs = realDb.getAllRefs();
validate().andReturn(pc); validate().andReturn(pc);
expect(grm.openRepository(eq(name.get()))).andReturn(mockDb); expect(grm.openRepository(eq(name.get()))).andReturn(mockDb);
expect(mockDb.getAllRefs()).andDelegateTo(realDb); expect(mockDb.getAllRefs()).andDelegateTo(realDb);
if (getHead) { if (getHead) {
@@ -140,12 +142,16 @@ public class ListBranchesTest extends LocalDiskRepositoryTestCase {
} }
mockDb.close(); mockDb.close();
expect(pc.canAddRefs()).andReturn(true);
expectLastCall(); expectLastCall();
doReplay(); doReplay();
final List<Branch> r = new ListBranches(pcf, grm, name).call(); final ListBranchesResult r = new ListBranches(pcf, grm, name).call();
doVerify(); doVerify();
assertNotNull(r); assertNotNull(r);
assertNotNull(r.getBranches());
return r; return r;
} }
@@ -153,6 +159,9 @@ public class ListBranchesTest extends LocalDiskRepositoryTestCase {
RefControl rc = createStrictMock(RefControl.class); RefControl rc = createStrictMock(RefControl.class);
refMocks.add(rc); refMocks.add(rc);
expect(rc.isVisible()).andReturn(visible); expect(rc.isVisible()).andReturn(visible);
if (visible) {
expect(rc.canDelete()).andReturn(true);
}
if (ref.isSymbolic()) { if (ref.isSymbolic()) {
expect(pc.controlForRef(ref.getTarget().getName())).andReturn(rc); expect(pc.controlForRef(ref.getTarget().getName())).andReturn(rc);
@@ -162,10 +171,11 @@ public class ListBranchesTest extends LocalDiskRepositoryTestCase {
} }
public void testEmptyProject() throws Exception { public void testEmptyProject() throws Exception {
List<Branch> r = permitted(true); ListBranchesResult r = permitted(true);
assertEquals(1, r.size());
Branch b = r.get(0); assertEquals(1, r.getBranches().size());
Branch b = r.getBranches().get(0);
assertNotNull(b); assertNotNull(b);
assertNotNull(b.getNameKey()); assertNotNull(b.getNameKey());
@@ -182,10 +192,10 @@ public class ListBranchesTest extends LocalDiskRepositoryTestCase {
public void testMasterBranch() throws Exception { public void testMasterBranch() throws Exception {
set("master", idA); set("master", idA);
List<Branch> r = permitted(false); ListBranchesResult r = permitted(false);
assertEquals(2, r.size()); assertEquals(2, r.getBranches().size());
Branch b = r.get(0); Branch b = r.getBranches().get(0);
assertNotNull(b); assertNotNull(b);
assertNotNull(b.getNameKey()); assertNotNull(b.getNameKey());
@@ -198,7 +208,7 @@ public class ListBranchesTest extends LocalDiskRepositoryTestCase {
assertNotNull(b.getRevision()); assertNotNull(b.getRevision());
assertEquals("master", b.getRevision().get()); assertEquals("master", b.getRevision().get());
b = r.get(1); b = r.getBranches().get(1);
assertNotNull(b); assertNotNull(b);
assertNotNull(b.getNameKey()); assertNotNull(b.getNameKey());
@@ -215,10 +225,10 @@ public class ListBranchesTest extends LocalDiskRepositoryTestCase {
public void testBranchNotHead() throws Exception { public void testBranchNotHead() throws Exception {
set("foo", idA); set("foo", idA);
List<Branch> r = permitted(true); ListBranchesResult r = permitted(true);
assertEquals(2, r.size()); assertEquals(2, r.getBranches().size());
Branch b = r.get(0); Branch b = r.getBranches().get(0);
assertNotNull(b); assertNotNull(b);
assertNotNull(b.getNameKey()); assertNotNull(b.getNameKey());
@@ -231,7 +241,7 @@ public class ListBranchesTest extends LocalDiskRepositoryTestCase {
assertNotNull(b.getRevision()); assertNotNull(b.getRevision());
assertEquals("master", b.getRevision().get()); assertEquals("master", b.getRevision().get());
b = r.get(1); b = r.getBranches().get(1);
assertNotNull(b); assertNotNull(b);
assertNotNull(b.getNameKey()); assertNotNull(b.getNameKey());
@@ -258,18 +268,19 @@ public class ListBranchesTest extends LocalDiskRepositoryTestCase {
for (Ref ref : u.values()) { for (Ref ref : u.values()) {
assumeVisible(ref, true); assumeVisible(ref, true);
} }
expect(pc.canAddRefs()).andReturn(true);
mockDb.close(); mockDb.close();
expectLastCall(); expectLastCall();
doReplay(); doReplay();
final List<Branch> r = new ListBranches(pcf, grm, name).call(); final ListBranchesResult r = new ListBranches(pcf, grm, name).call();
doVerify(); doVerify();
assertNotNull(r); assertNotNull(r);
assertEquals(3, r.size()); assertEquals(3, r.getBranches().size());
assertEquals(HEAD, r.get(0).getShortName()); assertEquals(HEAD, r.getBranches().get(0).getShortName());
assertEquals("bar", r.get(1).getShortName()); assertEquals("bar", r.getBranches().get(1).getShortName());
assertEquals("foo", r.get(2).getShortName()); assertEquals("foo", r.getBranches().get(2).getShortName());
} }
public void testHeadNotVisible() throws Exception { public void testHeadNotVisible() throws Exception {
@@ -284,14 +295,15 @@ public class ListBranchesTest extends LocalDiskRepositoryTestCase {
expect(mockDb.getAllRefs()).andReturn(u); expect(mockDb.getAllRefs()).andReturn(u);
assumeVisible(bar, false); assumeVisible(bar, false);
assumeVisible(bar, false); assumeVisible(bar, false);
expect(pc.canAddRefs()).andReturn(true);
mockDb.close(); mockDb.close();
expectLastCall(); expectLastCall();
doReplay(); doReplay();
final List<Branch> r = new ListBranches(pcf, grm, name).call(); final ListBranchesResult r = new ListBranches(pcf, grm, name).call();
doVerify(); doVerify();
assertNotNull(r); assertNotNull(r);
assertTrue(r.isEmpty()); assertTrue(r.getBranches().isEmpty());
} }
public void testHeadVisibleButBranchHidden() throws Exception { public void testHeadVisibleButBranchHidden() throws Exception {
@@ -311,16 +323,17 @@ public class ListBranchesTest extends LocalDiskRepositoryTestCase {
assumeVisible(bar, true); assumeVisible(bar, true);
assumeVisible(bar, true); assumeVisible(bar, true);
assumeVisible(foo, false); assumeVisible(foo, false);
expect(pc.canAddRefs()).andReturn(true);
mockDb.close(); mockDb.close();
expectLastCall(); expectLastCall();
doReplay(); doReplay();
final List<Branch> r = new ListBranches(pcf, grm, name).call(); final ListBranchesResult r = new ListBranches(pcf, grm, name).call();
doVerify(); doVerify();
assertNotNull(r); assertNotNull(r);
assertEquals(2, r.size()); assertEquals(2, r.getBranches().size());
assertEquals(HEAD, r.get(0).getShortName()); assertEquals(HEAD, r.getBranches().get(0).getShortName());
assertEquals("bar", r.get(1).getShortName()); assertEquals("bar", r.getBranches().get(1).getShortName());
} }
} }

View File

@@ -71,6 +71,7 @@ public final class Branch {
protected NameKey name; protected NameKey name;
protected RevId revision; protected RevId revision;
protected boolean canDelete;
protected Branch() { protected Branch() {
} }
@@ -98,4 +99,12 @@ public final class Branch {
public void setRevision(final RevId id) { public void setRevision(final RevId id) {
revision = id; revision = id;
} }
public boolean getCanDelete() {
return canDelete;
}
public void setCanDelete(boolean canDelete) {
this.canDelete = canDelete;
}
} }

View File

@@ -121,6 +121,11 @@ public class ProjectControl {
|| canPerformOnAnyRef(ApprovalCategory.READ, (short) 1); || canPerformOnAnyRef(ApprovalCategory.READ, (short) 1);
} }
public boolean canAddRefs() {
return (canPerformOnAnyRef(ApprovalCategory.PUSH_HEAD, ApprovalCategory.PUSH_HEAD_CREATE)
|| isOwnerAnyRef());
}
/** Can this user see all the refs in this projects? */ /** Can this user see all the refs in this projects? */
public boolean allRefsAreVisible() { public boolean allRefsAreVisible() {
return visibleForReplication() return visibleForReplication()